Windows & Menus¶
QtPie makes creating application windows with menu bars completely declarative. Use @window for main windows, @menu for menu bars, and @action for menu items.
Creating a Window¶
The @window decorator transforms a class into a QMainWindow:
from qtpie import window, make
from qtpy.QtWidgets import QMainWindow, QTextEdit
@window(title="My App", size=(800, 600))
class MainWindow(QMainWindow):
central_widget: QTextEdit = make(QTextEdit)
Window Parameters¶
@window(
title="Text Editor", # Window title
size=(1024, 768), # Width x height in pixels
center=True, # Center on screen
icon="app.png", # Path to icon file
name="EditorWindow", # Object name for QSS
classes=["dark", "modern"] # CSS-like classes for styling
)
class EditorWindow(QMainWindow):
...
Central Widget¶
Any field named central_widget is automatically set as the window's central widget:
@window(title="Editor")
class EditorWindow(QMainWindow):
central_widget: QTextEdit = make(QTextEdit)
# Automatically calls self.setCentralWidget(self.central_widget)
Auto-Naming¶
If you don't specify title or name, QtPie derives them from your class name:
@window # title="Editor", objectName="Editor"
class EditorWindow(QMainWindow):
...
@window # title="Main", objectName="Main"
class MainWindow(QMainWindow):
...
The "Window" suffix is automatically stripped.
Creating Menus¶
The @menu decorator transforms a class into a QMenu. Menus automatically add their actions and submenus in declaration order.
Basic Menu¶
from qtpie import menu, action, make
from qtpy.QtWidgets import QMenu
from qtpy.QtGui import QAction
@action("&New", shortcut="Ctrl+N")
class NewAction(QAction):
def on_triggered(self) -> None:
print("New file")
@action("E&xit", shortcut="Ctrl+Q")
class ExitAction(QAction):
def on_triggered(self) -> None:
print("Exit")
@menu("&File")
class FileMenu(QMenu):
new: NewAction = make(NewAction)
exit_app: ExitAction = make(ExitAction)
Auto-Adding to Menu Bar¶
When you add a QMenu field to a @window, it's automatically added to the menu bar:
from dataclasses import field
@window(title="My App")
class MainWindow(QMainWindow):
file_menu: FileMenu = make(FileMenu)
edit_menu: QMenu = field(default_factory=lambda: QMenu("&Edit"))
# Both menus appear in the menu bar automatically
Submenus¶
Menu fields can contain other menus as submenus:
@menu("&Recent Files")
class RecentMenu(QMenu):
pass
@menu("&File")
class FileMenu(QMenu):
new: NewAction = make(NewAction)
recent: RecentMenu = make(RecentMenu) # Appears as submenu
exit_app: ExitAction = make(ExitAction)
Menu Separators¶
Use separator() to add visual separators between menu items:
from qtpie import separator
@menu("&File")
class FileMenu(QMenu):
new: NewAction = make(NewAction)
open_file: OpenAction = make(OpenAction)
sep1: QAction = separator() # Visual separator
exit_app: ExitAction = make(ExitAction)
Auto-Naming Menus¶
Like windows, menus auto-derive their title from the class name:
The "Menu" suffix is automatically stripped.
Creating Actions¶
The @action decorator transforms a class into a QAction. Actions represent menu items, toolbar buttons, and keyboard shortcuts.
Basic Action¶
from qtpie import action
from qtpy.QtGui import QAction
@action("&New File", shortcut="Ctrl+N", tooltip="Create a new file")
class NewAction(QAction):
def on_triggered(self) -> None:
print("Creating new file...")
Action Parameters¶
@action(
text="&Save", # Menu text (& for keyboard shortcut)
shortcut="Ctrl+S", # Keyboard shortcut
tooltip="Save the current file", # Tooltip and status bar text
icon="save.png", # Icon path, QIcon, or StandardPixmap
checkable=True # Make it a toggle action
)
class SaveAction(QAction):
...
Text as Positional Argument¶
You can pass the action text as the first argument:
Auto-Connect Signals¶
Define on_triggered() or on_toggled() methods to handle action signals:
@action("&Bold", shortcut="Ctrl+B", checkable=True)
class BoldAction(QAction):
def on_toggled(self, checked: bool) -> None:
print(f"Bold formatting: {checked}")
@action("&Save", shortcut="Ctrl+S")
class SaveAction(QAction):
def on_triggered(self) -> None:
print("Saving...")
These methods are automatically connected to the triggered and toggled signals.
Action Icons¶
Icons can be specified three ways:
# 1. Path to image file
@action("&Open", icon="icons/open.png")
class OpenAction(QAction):
...
# 2. QIcon object
from qtpy.QtGui import QIcon
icon = QIcon("path/to/icon.png")
@action("&Open", icon=icon)
class OpenAction(QAction):
...
# 3. Standard system icon
from qtpy.QtWidgets import QStyle
@action("&Info", icon=QStyle.StandardPixmap.SP_MessageBoxInformation)
class InfoAction(QAction):
...
Checkable Actions¶
Use checkable=True for toggle actions (like Bold, Italic, etc.):
@action("Show &Toolbar", checkable=True)
class ToolbarToggleAction(QAction):
def on_toggled(self, checked: bool) -> None:
toolbar.setVisible(checked)
Keyboard Shortcuts¶
Shortcuts can be strings or Qt constants:
# String shortcuts
@action("&New", shortcut="Ctrl+N")
@action("&Find", shortcut="Ctrl+F")
@action("&Quit", shortcut="Ctrl+Q")
# Standard Qt shortcuts
from qtpy.QtGui import QKeySequence
@action("&Save", shortcut=QKeySequence.StandardKey.Save)
@action("&Copy", shortcut=QKeySequence.StandardKey.Copy)
Auto-Naming Actions¶
Actions auto-derive their text from the class name:
@action # text="Save"
class SaveAction(QAction):
...
@action # text="Copy"
class CopyAction(QAction):
...
The "Action" suffix is automatically stripped.
Complete Example¶
Here's a complete application with window, menus, and actions:
from qtpie import window, menu, action, make, separator, entrypoint
from qtpy.QtWidgets import QMainWindow, QMenu, QTextEdit
from qtpy.QtGui import QAction
# Define actions
@action("&New", shortcut="Ctrl+N", tooltip="Create a new file")
class NewAction(QAction):
def on_triggered(self) -> None:
print("New file")
@action("&Open", shortcut="Ctrl+O", tooltip="Open a file")
class OpenAction(QAction):
def on_triggered(self) -> None:
print("Open file")
@action("&Save", shortcut="Ctrl+S", tooltip="Save the file")
class SaveAction(QAction):
def on_triggered(self) -> None:
print("Save file")
@action("E&xit", shortcut="Ctrl+Q", tooltip="Exit application")
class ExitAction(QAction):
def on_triggered(self) -> None:
print("Exit")
@action("&Undo", shortcut="Ctrl+Z")
class UndoAction(QAction):
def on_triggered(self) -> None:
print("Undo")
@action("&Redo", shortcut="Ctrl+Y")
class RedoAction(QAction):
def on_triggered(self) -> None:
print("Redo")
# Define menus
@menu("&File")
class FileMenu(QMenu):
new: NewAction = make(NewAction)
open_file: OpenAction = make(OpenAction)
save: SaveAction = make(SaveAction)
sep1: QAction = separator()
exit_app: ExitAction = make(ExitAction)
@menu("&Edit")
class EditMenu(QMenu):
undo: UndoAction = make(UndoAction)
redo: RedoAction = make(RedoAction)
# Define window
@entrypoint
@window(title="Text Editor", size=(1024, 768), center=True)
class EditorWindow(QMainWindow):
file_menu: FileMenu = make(FileMenu)
edit_menu: EditMenu = make(EditMenu)
central_widget: QTextEdit = make(QTextEdit)
def setup(self) -> None:
self.statusBar().showMessage("Ready")
Connecting Actions to Methods¶
You can connect actions to methods using make():
@menu("&File")
class FileMenu(QMenu):
save: QAction = make(QAction, "&Save", triggered="on_save")
def on_save(self) -> None:
print("Saving from menu method...")
Or use lambdas:
@menu("&File")
class FileMenu(QMenu):
save: QAction = make(
QAction,
"&Save",
triggered=lambda: print("Saving...")
)
Lifecycle Hooks¶
All three decorators support the setup() hook:
Window Hook¶
@window(title="My App")
class MainWindow(QMainWindow):
def setup(self) -> None:
"""Called after all fields are initialized"""
pass
Menu and Action Hooks¶
Menus and actions support setup():
@menu("&File")
class FileMenu(QMenu):
def setup(self) -> None:
"""Called after menu initialization"""
pass
@action("&Save")
class SaveAction(QAction):
def setup(self) -> None:
"""Called after action initialization"""
pass
Private Fields¶
Fields starting with _ are not automatically added to menus or menu bars:
@window(title="App")
class MainWindow(QMainWindow):
file_menu: FileMenu = make(FileMenu) # Added to menu bar
_debug_menu: QMenu = make(QMenu, "Debug") # NOT added to menu bar
@menu("&File")
class FileMenu(QMenu):
save: SaveAction = make(SaveAction) # Added to menu
_internal: QAction = make(QAction) # NOT added to menu
See Also¶
- Widgets - Using the
@widgetdecorator - Styling - CSS classes and styling
- @entrypoint - Application entry points
- make() - Creating widget instances
- separator() - Menu separators