#event-handling #wxpython
#обработка событий #wxpython
Вопрос:
Мое приложение wxPython использует wx.ScrolledWindow для основной области рисования — взято прямо из демо и переделано под мои нужды. Когда пользователь дважды щелкает в области прокрутки, я хочу открыть (возможно, модальное) диалоговое окно для редактирования параметров объектов, которые они нарисовали. Итак, я открыл диалоговое окно с помощью кода из другой демонстрации:
def OnLeftDoubleClickEvent(self, event):
dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200),
#style=wx.CAPTION | wx.SYSTEM_MENU | wx.THICK_FRAME,
style=wx.DEFAULT_DIALOG_STYLE, # amp; ~wx.CLOSE_BOX
)
dlg.CenterOnScreen()
# this does not return until the dialog is closed.
val = dlg.ShowModal()
Конечно, это всего лишь тест. Само диалоговое окно было грамотно определено в одной из демонстраций. В любом случае, при закрытии всплывающего окна область прокрутки переходит в новую позицию, и в Windows события мыши больше не отображаются в правильных координатах. Смещение произойдет, только если вы переместите всплывающее окно таким образом, что вы щелкните мышью за пределами области прокрутки, чтобы закрыть его. Имейте в виду, что «OK» и «Отмена» находятся в совершенно другом диалоговом окне, чем область прокрутки. В Linux прокручиваемая область, по-видимому, перемещается в зависимости от того, насколько далеко за пределы области был нажат указатель мыши — и в том же направлении. В Windows область прокрутки перемещается и запутывается — дальнейшие щелчки мыши также сместят ее и (потому что?) щелчок записан в неправильном месте.
Итак, версия проблемы для Linux, похоже, указывает на то, что событие щелчка во всплывающем окне фактически обрабатывается прокручиваемой областью в исходном окне.
Похоже ли это на то, что происходит?
Если да, то как мне предотвратить это?
РЕДАКТИРОВАТЬ: дополнительная информация. Я попытался закрыть всплывающее окно, нажав на кнопку OK или Cancel. Каждый раз, когда фокус перемещается на другой элемент управления, область прокрутки в другом окне перемещается. Это зависит от того, где находится всплывающее окно по отношению к другому окну. Теперь я в полном замешательстве.
ПРАВКА 2: Я добавил опцию в меню главного окна, чтобы вызвать всплывающее диалоговое окно. При активации таким образом, похоже, никаких проблем не возникает. Я думаю, проблема каким-то образом связана с созданием всплывающего окна в событии двойного щелчка в области прокрутки, в результате чего некоторые события обрабатываются обоими. Имеет ли это смысл? Когда у меня будет время, я собираюсь попробовать отправить событие (пользовательское?) в родительское диалоговое окно и сопоставить его с той же функцией, что и новый пункт меню. Это приведет к появлению моего всплывающего окна из главного окна и, надеюсь, устранит проблему. Посмотрим.
ТЕСТОВЫЙ ПРИМЕР EDIT3
Чтобы увидеть это, возьмите файл: ScrolledWindow.py из демо-версии добавьте следующее:
from Dialog import *
Затем в области событий мыши класса MyCanvas свяжите двойной щелчок с этим:
self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDoubleClickEvent)
Затем добавьте следующую функцию в тот же класс (взятую из диалоговой демонстрации):
def OnLeftDoubleClickEvent(self, event):
useMetal = False
if 'wxMac' in wx.PlatformInfo:
useMetal = self.cb.IsChecked()
dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200),
#style=wx.CAPTION | wx.SYSTEM_MENU | wx.THICK_FRAME,
style=wx.DEFAULT_DIALOG_STYLE, # amp; ~wx.CLOSE_BOX,
useMetal=useMetal,
)
dlg.CenterOnScreen()
# this does not return until the dialog is closed.
val = dlg.ShowModal()
if val == wx.ID_OK:
self.log.WriteText("You pressed OKn")
else:
self.log.WriteText("You pressed Canceln")
dlg.Destroy()
Теперь запустите демонстрационную версию и выберите основные окна / элементы управления и «ScrolledWindow». Вы сможете нацарапать в области прокрутки, как обычно, но теперь вы можете дважды щелкнуть там, и появится диалоговое окно. Пожалуйста, переместите это новое диалоговое окно за пределы области рисования, а затем закруглите поля ввода или нажмите OK. Действие в этом диалоговом окне приведет к изменению положения прокручиваемого рисунка в другом окне.
И вот оно. Что является причиной этого? Я адаптировал демонстрацию для рисования своих собственных пользовательских объектов, и я хочу иметь возможность дважды щелкнуть, чтобы вызвать диалоговое окно свойств объекта. Это ошибка или неправильный способ решения проблемы? Мой план из Edit2 больше похож на «правильный путь»?
Комментарии:
1. Я не вижу этой проблемы при двойном щелчке в демо. Можете ли вы привести небольшой работоспособный пример проблемы?
2. Чтобы было понятно, мой редактор основан на демонстрации области прокрутки (где вы рисуете объекты), и приведенный выше фрагмент был помещен в событие dclick области прокрутки, и появляется диалоговое окно, также взятое из демонстрации. В самой демо-версии нет этой комбинации. Я посмотрю, смогу ли я создать сокращенный тестовый пример. Вы должны переместить диалоговое окно за пределы области прокрутки, чтобы увидеть проблему.
Ответ №1:
Решение оказывается тем, что я предложил в Edit2. Я не уверен, почему, но выполнение всплывающего окна изнутри события двойного щелчка ScrolledArea вызывало проблемы. Решение состоит в том, чтобы создать пользовательское сообщение и отправить его self внутри события двойного щелчка. Пользовательское событие обрабатывается окном верхнего уровня, а не областью прокрутки. Это работает нормально, но теперь я должен где-то сохранить идентификатор выбранного объекта, чтобы окно верхнего уровня могло передать его в диалоговое окно. Это требует немного больше работы, но это кажется более «правильным», чем всплывающее окно внутри события двойного щелчка в области рисования. Однако окно все еще появляется внутри обработчика событий, это просто другой объект, обрабатывающий его с помощью другого события. Особенности того, почему это работает, все еще ускользают от меня.
Я уверен, что есть способ подумать об этом, который делает это решение очевидно правильным. Я все равно проголосую за ответ, который дает представление о том, почему один метод работает, а другой нет, или каков «правильный» способ сделать что-то подобного рода.
Что касается других новостей, я публикую это после истечения срока действия вознаграждения 50 по этому вопросу. Да, я опубликовал награду, прежде чем попробовать свою собственную идею — глупый я. В следующий раз я попробую список рассылки wxPython, прежде чем предлагать вознаграждение, хотя мне не нравятся списки рассылки.