Название: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Март 30, 2012, 17:20 Переползаю с универских познаний Delphi на более-менее сурёзное программрование.
Понадобилось тут переопределить правый клик мыши по QLineEdit и QTextEdit, чтобы выделялся в них весь текст и появлялось контекстное меню с одним лишь пунктом "Копировать". Вот сделал такой вариант с множественном наследованием. Все работает. Но гложат сомнения, все ли правильно сделал? Код
Название: Re: Множественное наследование в PyQt для чайников. Со свистком. Отправлено: kambala от Март 30, 2012, 17:36 может проще просто подконнектить сигнал contextMenuRequested нужных объектов в слот, где будет создаваться меню?
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Март 31, 2012, 20:46 Спасибо. Заставили поработать головой) Действительно, Custom Context Menu выглядит более удачным решением, чем переопределение методов класса.
Набросал такой код, работает. Но если для QLineEdit меню появляется нормально, то для QTextEdit оно появляется выше курсора. Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Март 31, 2012, 21:13 Разобрался с появлением меню над курсором для QTextEdit. Нужно вызывать метод mapToGlobal() не основного виджета, а того, по которому произвели клик. Вообще правильно ли определять виджет, у которого вызвали контекстное меню, методом focusWidget() ? В документации другого способа не увидел(
Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: iroln от Апрель 01, 2012, 09:06 Кто послал сигнал, можно узнать через sender.
Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: iroln от Апрель 01, 2012, 09:14 А вообще вашу задачу надо не так решать.
Необходимо установить фильтр событий на те объекты, в которых вы хотите изменить контекстное меню. И обрабатывать всё в функции eventFilter. Как пример для вашего кода: Код
В этом случае вам даже не нужно знать того, кто создал событие, но если потребуется, в метод eventFilter первым (вторым не считая self) аргументом приходит ссылка на объект (obj). Проверка на тип объекта может потребоваться, если у вас фильтр установлен на разные объекты, и вы ловите разные события, тогда надо проверять объект: Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Апрель 02, 2012, 14:09 Да, совсем забыл, что виджеты еще и от такого мощного класса QObject наследуются)
Подправил свой код: Код Но что-то я делаю не так. При вызове меню, sender() возвращает ссылку на виджет, по которому был произведен клик и меню появляется где надо. Но при использования в слоте copy_action() он возвращает, соответственно, QAction, и возникает исключение "AttributeError: 'QAction' object has no attribute 'selectAll'". И ещё у меня по какой-то причине для QTextEdit не возникает событие QContextMenuEvent. Хотя для QLineEdit все нормально обрабатывается. P.S. В данном случае super(SomeClass, self).__init__() абсолютно эквивалентен SomeClass.__init__(self) ? Хотя это уже отдельная тема, на хабре был хороший топик про множественное наследование, алгоритм MRO С3 и линеаризацию. Надо будет перечитать) В итоге пока такой код рабочий: Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: iroln от Апрель 02, 2012, 15:15 Цитировать При вызове меню, sender() возвращает ссылку на виджет, по которому был произведен клик и меню появляется где надо. Потому что вызываете его не в слоте, который вызвали, а в слоте, который вызывается из QAction, вот он его и возвращает. Зачем вам sender при использовании eventFilter? Передавайте в copy_action объект, который сгенерировал событие (obj). Можете через поле класса его передавать, ну то есть сохранять ссылку как поле класса, а в функции copy_action её использовать.Но при использования в слоте copy_action() он возвращает, соответственно, QAction, и возникает исключение "AttributeError: 'QAction' object has no attribute 'selectAll'". Цитировать И ещё у меня по какой-то причине для QTextEdit не возникает событие QContextMenuEvent. Хотя для QLineEdit все нормально обрабатывается. Сделайте для textEdit вот так:Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Апрель 02, 2012, 15:48 Действительно, sender() тут и не нужен. С QLineEdir все получилось. А с QTextEdit опять проблема.
Используя self.textEdit.viewport() , контекстное меню подключилось, но тогда в obj передается ссылка не на QTextEdit, а на QWidget. А в этом случае уже не работает obj.selectAll() и obj.copy(). Вот получившийся код: Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: iroln от Апрель 02, 2012, 16:17 Ну в этом случае можно
Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Апрель 02, 2012, 16:52 Спасибо, но проверку немного переделал, чтоб не каждый экземпляр QTextEdit таким образом проверять)
Код
Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: iroln от Апрель 02, 2012, 17:06 Цитировать чтоб не каждый экземпляр QTextEdit таким образом проверять Получается что, таким образом вы проверяете каждый объект и это правильно, если у вас много QTextEdit, а не один, как в случае с моей проверкой.Название: Re: Custom Context Menu в PyQt для чайников. Со свистком. Отправлено: RockBomber от Апрель 02, 2012, 19:22 Я и имел это в виду, но некорректно выразил мысль) Чтобы для каждого экземпляра QTextEdit не писать отдельную проверку.
Но местами пишут, что проверка объекта на принадлежность классу - дурной тон, и лучше реализовывать свой алгоритм по другому, если возможно. |