Following @G.M. advice I was able to partially solve my problem.
My code current code looks like:
#!/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()
This works with a few limitations:
- I have been able to add just a single widget using
setDefaultWidget()
, if I try to
add a fill QWidget
or a container (e.g.: QFrame
) nothing appears in menu.
- I have therefore not been able to prepend an icon (or a
QLabel
) to the widget.
- Widget does not behave like a menu item (it does not close when activated); I tried to overcome that as implemented in
ActionSize
, but looks rather kludgy and I'm unsure if it's the right way to go.
I will therefore not accept my own answer in hope someone can refine it enough to be generally useful.