Контекстные меню в PyQt
Есть несколько способов обработать контекстные меню:- Переопределение contextMenuEvent
- Использование Actions
- Использование CustomMenu и сигнала customContextMenuRequested
Любой из этих способов требует правильной установки проперти contextMenuPolicy.
Обработчики могут быть как в родительском объекте, так и в наследных классах.
Вариант с наследными классами не рассматриваем — не удобно возиться с дизайнером. По итогам экспериментов остановился на третьем варианте — и нормально "ловит" объект-источник, и подменю сделать можно, что в данном проектике оказалось актуально.
Для правильного позиционирования меню надо вызывать функцию mapToGlobal(pos) активного элемента, а не родительского окна!
contextMenuEvent(self, QContextMenuEvent)
- Перехватывает обращения к контекстному меню объекта, в котором переопределён
- Для того, чтобы перехватить контекстные меню у контролов-детей надо установить им contextMenuPolicy == QtCore.Qt.NoContextMenu.
- Внутри обработчика получаем координаты, создаём (если надо) и показываем требуемое меню
- Может быть использован для расширения существующего меню
- Неправильно возвращает виджет, вызвавший срабатывание. Для QPlainTextEdit возвращается QWidget. Возможно это его viewport, но разбираться стало лень.
Actions
- Позволяет автоматически создавать контекстное меню на основании списка actions.
- Для того, чтобы перехватить контекстные меню у контролов-детей надо установить им contextMenuPolicy == QtCore.Qt.ActionsContextMenu.
- Actions должны храниться в self тем или иным способом.
- Нельзя сделать подменю
- Нельзя расширить встроенное меню
CustomMenu
- Перехватывает обращения к контекстному меню объекта, в котором переопределён
- Для того, чтобы перехватить контекстные меню у контролов-детей надо установить им contextMenuPolicy == QtCore.Qt.CustomMenu.
- Необходимо привязать обработчик ко всем контролам, где требуется переопределить поведение
- Внутри обработчика получаем координаты, создаём (если надо) и показываем требуемое меню
- Может быть использован для расширения существующего меню
class ExpUSLTEdit(QtGui.QDialog):
def __init__(self, parent=None):
super(ExpUSLTEdit, self).__init__(parent)
uic.loadUi(os.path.join(APP_PATH,'exp_uslt.ui'), self)
# На каждый элемент привязываем обработчик контекстного меню
self.desc.customContextMenuRequested.connect(self.onCustomMenu)
self.text.customContextMenuRequested.connect(self.onCustomMenu)
def onCustomMenu(self, pos):
# Вызывается для всех нужных нам элементов
w = self.focusWidget() # Откуда позвали
if w:
try:
m = w.createStandardContextMenu() # Получаем "встроенное" меню
except:
return
# Добавляем свои элементы и подменю
m.addSeparator()
m1 = QtGui.QMenu(self.tr("Fix encoding"))
for s in ENCODINGS:
a = m1.addAction(s)
m1.triggered.connect(self.onMnu)
m.addMenu(m1)
a = m.exec_(w.mapToGlobal(pos))
def onMnu(self, act):
# Обрабатываем собственное подменю.
# быдло-код: Текст меню используется как управляющий эелемент
w = self.focusWidget()
if not w: return
try:
# QPlainTextEdit
if hasattr(w, "toPlainText"):
s = (u"%s" % w.toPlainText()).encode('iso-8859-1').decode(u"%s" % act.text())
w.setPlainText(s)
# QLineEdit
elif hasattr(w, "text"):
s = (u"%s" % w.text()).encode('iso-8859-1').decode(u"%s" % act.text())
w.setText(s)
except Exception, e:
QtGui.QMessageBox.warning(
self,
self.tr(u"Failed to change encoding"),
u"Error: %s" % (e,)
)
Комментариев нет:
Отправить комментарий