PyQt5: QMenuBar, QMenu
Torna all’indice degli appunti
La classe QMenuBar crea una barra orizzontale dove è possibile sistemare elementi detti pull-down Menu.
Il costruttore della menubar è QMenuBar:
>>> from PyQt5.QtWidgets import QApplication, QMenuBar >>> app = QApplication([]) >>> menubar = QMenuBar()
Per aggiungere i menu sulla menubar appena creata, si utilizza il metodo addMenu(menu), dove menu è un oggetto QMenu, ovvero un widget che contiene una lista di elementi detti actions.
Vediamo nello specifico l’oggetto QMenu.
QMENU
Questa classe QMenu crea il widget che viene comunemente utilizzato nelle menubar, menu contestuali (es. bottone destro del mouse) e popup menu.
Come già anticipato, un oggetto QMenu, consiste in una lista di elementi “Action”.
Un elemento Action può avere una label, una icona ed una shortcut (scorciatoia da tastiera).
Il costruttore di un oggetto QMenu è appunto QMenu(text), dove text una stringa che rappresenta il nome del menu.
Per settare un’icona di menu, si utilizza il metodo setIcon(icon), dove icon è ovviamente un oggetto QIcon.
Aggiungiamo quindi alla menubar un menu “File” con tanto di Icona:
>>> from PyQt5.QtWidgets import QMenu >>> from PyQt5.QtGui import QIcon >>> menufile = QMenu("File") >>> menufile.setIcon(QIcon("file.png")) >>> menubar.addMenu(menufile) <PyQt5.QtWidgets.QAction object at 0x0373D3A0>
Il metodo addMenu, ritorna l’oggetto QAction relativo al menu appena inserito.
L’oggetto qaction contiene tutte le informazioni relative al menu e può contenere appunto una icona, un testo, un tip.
E’ possibile ottenere le actions collegate ad una menubar, con il metodo actions()
>>> menubar.actions() [<PyQt5.QtWidgets.QAction object at 0x0373D210>] >>> fileaction = menubar.actions()[0] >>> fileaction.icon() <PyQt5.QtGui.QIcon object at 0x0373D3F0> >>> fileaction.text() 'File'
Ora che abbiamo creato un menu, dobbiamo creare le voci di menu.
Per fare questo, utilizziamo il metodo addAction(text), dove text è il nome della voce di menu.
E’ possibile anche inserire un’icona in fase di aggiunta della action, passandola al metodo precedente come primo parametro, ma è anche possibile farlo successivamente, utilizzando il metodo setIcon(icon).
In realtà, dal momento che l’utilizzo del metodo addAction(text), ritorna l’oggetto QAction, è possibile aggiungere tutti gli elementi in seguito, con i metodi:
setIcon(icon), setToolTip(tooltip):
>>> newtxt_action = menufile.addAction("New &Txt file") >>> newtxt_action <PyQt5.QtWidgets.QAction object at 0x0373D530> >>> newtxt_action.setIcon(QIcon("txt.png")) >>> menufile.addAction(QIcon("pdf.png"), "New &Pdf file") <PyQt5.QtWidgets.QAction object at 0x0373D5D0> >>> menufile.addAction(QIcon("doc.png"), "New &Doc file") <PyQt5.QtWidgets.QAction object at 0x0373D670> >>> menufile.actions() [<PyQt5.QtWidgets.QAction object at 0x0373D530>, <PyQt5.QtWidgets.QAction object at 0x0373D5D0>, <PyQt5.QtWidgets.QAction object at 0x0373D670>] >>> for action in menufile.actions(): ... print(action.text(), action.icon().isNull()) ... New &Txt file False New &Pdf file False New &Doc file False
SEGNALI
I due segnali da tenere in considerazione sono
hovered: segnale emesso quando la voce di menu viene evidenziata al passaggio del mouse;
triggered: segnale emesso quando clicchiamo sulla voce di menu;
Entrambi i segnali rendono disponibile action, ovvero l’oggetto QAction che ha causato l’emissione del segnale.
Vediamo un esempio pratico:
from PyQt5.QtWidgets import QMainWindow from PyQt5.QtWidgets import QApplication, QMenuBar, QMenu, QAction, QWidget from PyQt5.QtGui import QIcon import sys class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle("QMenu Example") menubar = QMenuBar(parent=self) menufile = QMenu("File", parent=menubar) for text, ext, shortcut in [("New &Txt file", "txt", "CTRL+T"), ("New &Pdf file", "pdf", "CTRL+P"), ("New &Doc file", "doc", "CTRL+D")]: action = QAction(text, parent=menufile) action.setShortcut(shortcut) action.setToolTip("Create new %s file" % ext) action.setIcon(QIcon("%s.png" % ext)) menufile.addAction(action) menufile.setToolTipsVisible(True) menubar.addMenu(menufile) self.setMenuBar(menubar) self.resize(250, 300) self.central_widget = FormWidget(self) self.setCentralWidget(self.central_widget) menufile.triggered.connect(self.on_menu) def on_menu(self, action): print("[SIG] %s menu clicked!" % action.text()) class FormWidget(QWidget): def __init__(self, parent): super(FormWidget, self).__init__(parent) if __name__ == '__main__': app = QApplication(sys.argv) main_window = MainWindow(parent=None) main_window.show() sys.exit(app.exec_())
Nota:
Per far sì che i tooltips siano visibili, è fondamentale chiamare il metodo dell’oggetto QMenu, setToolTipsVisible(True).
TEAR-OFF
Quando un menu viene usato intensivamente, è possibile abilitarne la modalità TEAROFF, ovvero è possibile “staccare” una copia del menù e appoggiarla in una parte delle schermo a noi congeniale. Questa copia, rimane fissa e non si disattiva ad ogni click, rendendo più comode le operazioni ripetitive.
Per abilitare tale funzione si deve utilizzare il metodo setTearOffEnabled(True) dell’oggetto QMenu.
Basterà cliccare sul menu e sulla linea tratteggiata dello stesso, apparirà così un menu, in una finestra propria, da muovere a proprio piacimento.
ICON SIZE
L’oggetto QMenu non ha un metodo che consenta di modificare la dimensione delle icone nelle voci di menu.
Per avere delle icone maggiorate, bisogna appoggiarsi alla classe QProxyStyle.
La classe suddetta, permette il wrapping della classe QStyle, che gestisce lo stile di default del sistema, semplificando di fatto l’override degli elementi della classe Qstyle.
Il trucco sta nel creare una classe che erediti da QStyle ed eseguire l’override dell’elemento che ci interessa.
class CustomProxyStyle(QProxyStyle): def pixelMetric(self, QStyle_PixelMetric, option=None, widget=None): if QStyle_PixelMetric == QStyle.PM_SmallIconSize and \ isinstance(widget, QMenu): return 36 else: return QProxyStyle.pixelMetric(self, QStyle_PixelMetric, option, widget)
L’override avviene proprio sul metodo pixelMetric di QStyle, che restituisce il pixel Metric relativo al QStyle enum passato come argomento e al widget.
Se il valore del QStyle enum equivale a PM_SmallIconSize e il widget di riferimento è un QMenu, allora il metodo ritorna il valore di pixel personalizzato, altrimenti ritorna quello di default.
Non resta che associare il nostro stile custom, alla nostra applicazione, con il metodo setStyle(style):
Per verificare che l’impostazione sia giusta, mettiamo nello slot dedicato al click su menu, due print che controllino i valori ritornati dal metodo pixeMetric del
nostro proxy style:
... def on_menu(self, action): menufile = self.sender() style = self.style() print("[SIG] %s menu clicked!" % action.text()) print(style) print("QMenu: %s" % style.pixelMetric(QStyle.PM_SmallIconSize, widget=menufile)) print("widgets: %s" % style.pixelMetric(QStyle.PM_SmallIconSize)) if __name__ == '__main__': app = QApplication(sys.argv) custom_style = CustomProxyStyle('bancaldo') main_window = MainWindow(parent=None) main_window.show() app.setStyle(custom_style) sys.exit(app.exec_())
[SIG] New &Txt file menu clicked! <__main__.CustomProxyStyle object at 0x010F3850> QMenu: 36 widgets: 16
Commenti recenti