Предотвратить попадание события wxPython в несколько окон?

#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, прежде чем предлагать вознаграждение, хотя мне не нравятся списки рассылки.