Сложное контекстное меню подменю - PullRequest
1 голос
/ 18 мая 2019

У меня есть приложение Qt5, в основном управляемое контекстным меню.

Прямо сейчас у меня есть стандартная структура с меню (ями), подменю (ями) и действиями.

Я бы хотел добавить вместо подменю небольшой диалог с несколькими входными виджетами, что-то вроде этого:

Context-menu mockup

Есть ли (возможно простой) способ получить это?

Я знаю, что могу открыть обычный диалог из всплывающего окна, но я не об этом. Я хотел бы иметь нормальное поведение подменю, с возможностью вернуться в родительское меню ... если это возможно.

Примечание: на самом деле я использую PyQt5, но я думаю, что это более общий вопрос Qt.

1 Ответ

0 голосов
/ 20 мая 2019

Следуя совету @GM, я смог частично решить мою проблему.

Мой код текущего кода выглядит так:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class ActionFont(QWidgetAction):
    def __init__(self, parent: QWidget, target: QPlainTextEdit):
        super(ActionFont, self).__init__(parent)
        self.setIcon(QIcon("font-face.svg"))
        self.setText("Face")
        w = QFontComboBox()
        w.currentFontChanged.connect(self.doit)
        self.setDefaultWidget(w)
        self.cursor = target.textCursor()
        self.char_format = self.cursor.charFormat()
        font = self.char_format.font()
        w.setCurrentFont(font)
        # self.triggered.connect(self.doit)

    def doit(self, font):
        self.char_format.setFont(font)
        self.cursor.setCharFormat(self.char_format)


class ActionSize(QWidgetAction):
    def __init__(self, parent: QWidget, target: QPlainTextEdit):
        super(ActionSize, self).__init__(parent)
        self.setIcon(QIcon("font-size.svg"))
        self.setText("Size")
        self.has_changed = False
        w = QSpinBox()
        self.setDefaultWidget(w)
        self.cursor = target.textCursor()
        self.char_format = self.cursor.charFormat()
        font = self.char_format.font()
        size = font.pointSize()
        w.setRange(6, 100)
        w.setValue(size)
        w.valueChanged.connect(self.doit)
        w.editingFinished.connect(self.quit)

    def doit(self, size):
        print(f'ActionSize.doit({size})')
        self.char_format.setFontPointSize(size)
        self.cursor.setCharFormat(self.char_format)
        self.has_changed = True

    def quit(self):
        print(f'ActionSize.quit()')
        if self.has_changed:
            print(f'ActionSize.quit(quitting)')


class Window(QMainWindow):
    def __init__(self, parent=None):
        from lorem import text
        super().__init__(parent)
        self.text = QPlainTextEdit(self)
        self.setCentralWidget(self.text)

        self.text.setContextMenuPolicy(Qt.CustomContextMenu)
        self.text.customContextMenuRequested.connect(self.context)

        self.text.appendPlainText(text())

        self.setGeometry(100, 100, 1030, 800)
        self.setWindowTitle("Writer")

    def context(self, pos):
        m = QMenu(self)
        w = QComboBox()
        w.addItems(list('ABCDE'))
        wa = QWidgetAction(self)
        wa.setDefaultWidget(w)
        m.addAction('Some action')
        m.addAction(wa)
        m.addAction('Some other action')
        sub = QMenu(m)
        sub.setTitle('Font')
        sub.addAction(ActionFont(self, self.text))
        sub.addAction(ActionSize(self, self.text))
        m.addMenu(sub)

        pos = self.mapToGlobal(pos)
        m.move(pos)
        m.show()


app = QApplication([])

w = Window()
w.show()

app.exec()

Это работает с несколькими ограничениями:

  • Мне удалось добавить только один виджет, используя setDefaultWidget(), если я пытаюсь добавить заливку QWidget или контейнер (например: QFrame), в меню ничего не появляется.
  • Поэтому я не смог добавить значок (или QLabel) к виджету.
  • Виджет не ведет себя как элемент меню (он не закрывается при активации);Я пытался преодолеть это, как это реализовано в ActionSize, но выглядит довольно глупо, и я не уверен, что это правильный путь.

Поэтому я не приму мойсобственный ответ в надежде, что кто-то сможет его уточнить, чтобы он был в целом полезным.

...