# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""Sample PyQt application."""
import sys
from functools import partial
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QKeySequence
from PyQt5.QtWidgets import (
QAction,
QApplication,
QLabel,
QMainWindow,
QMenu,
QSpinBox,
QToolBar,
)
# NOTE: Uncomment this import to enable icons
# import qrc_resources
class Window(QMainWindow):
"""Main Window."""
def __init__(self, parent=None):
"""Initializer."""
super().__init__(parent)
self.setWindowTitle("Python Menus & Toolbars")
self.resize(400, 200)
self.centralWidget = QLabel("Hello, World")
self.centralWidget.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.setCentralWidget(self.centralWidget)
self._createActions()
self._createMenuBar()
self._createToolBars()
# Uncomment the call to ._createContextMenu() below to create a context
# menu using menu policies. To test this out, you also need to
# comment .contextMenuEvent() and uncomment ._createContextMenu()
# self._createContextMenu()
self._connectActions()
self._createStatusBar()
def _createMenuBar(self):
menuBar = self.menuBar()
# File menu
fileMenu = QMenu("&File", self)
menuBar.addMenu(fileMenu)
fileMenu.addAction(self.newAction)
fileMenu.addAction(self.openAction)
# Open Recent submenu
self.openRecentMenu = fileMenu.addMenu("Open Recent")
fileMenu.addAction(self.saveAction)
# Separator
fileMenu.addSeparator()
fileMenu.addAction(self.exitAction)
# Edit menu
editMenu = menuBar.addMenu("&Edit")
editMenu.addAction(self.copyAction)
editMenu.addAction(self.pasteAction)
editMenu.addAction(self.cutAction)
# Separator
editMenu.addSeparator()
# Find and Replace submenu
findMenu = editMenu.addMenu("Find and Replace")
findMenu.addAction("Find...")
findMenu.addAction("Replace...")
# Help menu
helpMenu = menuBar.addMenu(QIcon(":help-content.svg"), "&Help")
helpMenu.addAction(self.helpContentAction)
helpMenu.addAction(self.aboutAction)
def _createToolBars(self):
# File toolbar
fileToolBar = self.addToolBar("File")
fileToolBar.setMovable(False)
fileToolBar.addAction(self.newAction)
fileToolBar.addAction(self.openAction)
fileToolBar.addAction(self.saveAction)
# Edit toolbar
editToolBar = QToolBar("Edit", self)
self.addToolBar(editToolBar)
editToolBar.addAction(self.copyAction)
editToolBar.addAction(self.pasteAction)
editToolBar.addAction(self.cutAction)
# Widgets
self.fontSizeSpinBox = QSpinBox()
self.fontSizeSpinBox.setFocusPolicy(Qt.NoFocus)
editToolBar.addWidget(self.fontSizeSpinBox)
def _createStatusBar(self):
self.statusbar = self.statusBar()
# Temporary message
self.statusbar.showMessage("Ready", 3000)
# Permanent widget
self.wcLabel = QLabel(f"{self.getWordCount()} Words")
self.statusbar.addPermanentWidget(self.wcLabel)
def _createActions(self):
# File actions
self.newAction = QAction(self)
self.newAction.setText("&New")
self.newAction.setIcon(QIcon(":file-new.svg"))
self.openAction = QAction(QIcon(":file-open.svg"), "&Open...", self)
self.saveAction = QAction(QIcon(":file-save.svg"), "&Save", self)
self.exitAction = QAction("&Exit", self)
# String-based key sequences
self.newAction.setShortcut("Ctrl+N")
self.openAction.setShortcut("Ctrl+O")
self.saveAction.setShortcut("Ctrl+S")
# Help tips
newTip = "Create a new file"
self.newAction.setStatusTip(newTip)
self.newAction.setToolTip(newTip)
self.newAction.setWhatsThis("Create a new and empty text file")
# Edit actions
self.copyAction = QAction(QIcon(":edit-copy.svg"), "&Copy", self)
self.pasteAction = QAction(QIcon(":edit-paste.svg"), "&Paste", self)
self.cutAction = QAction(QIcon(":edit-cut.svg"), "C&ut", self)
# Standard key sequence
self.copyAction.setShortcut(QKeySequence.Copy)
self.pasteAction.setShortcut(QKeySequence.Paste)
self.cutAction.setShortcut(QKeySequence.Cut)
# Help actions
self.helpContentAction = QAction("&Help Content...", self)
self.aboutAction = QAction("&About...", self)
# Uncomment this method to create a context menu using menu policies
# def _createContextMenu(self):
# # Setting contextMenuPolicy
# self.centralWidget.setContextMenuPolicy(Qt.ActionsContextMenu)
# # Populating the widget with actions
# self.centralWidget.addAction(self.newAction)
# self.centralWidget.addAction(self.openAction)
# self.centralWidget.addAction(self.saveAction)
# self.centralWidget.addAction(self.copyAction)
# self.centralWidget.addAction(self.pasteAction)
# self.centralWidget.addAction(self.cutAction)
def contextMenuEvent(self, event):
# Context menu
menu = QMenu(self.centralWidget)
# Populating the menu with actions
menu.addAction(self.newAction)
menu.addAction(self.openAction)
menu.addAction(self.saveAction)
# Separator
separator = QAction(self)
separator.setSeparator(True)
menu.addAction(separator)
menu.addAction(self.copyAction)
menu.addAction(self.pasteAction)
menu.addAction(self.cutAction)
# Launching the menu
menu.exec(event.globalPos())
def _connectActions(self):
# Connect File actions
self.newAction.triggered.connect(self.newFile)
self.openAction.triggered.connect(self.openFile)
self.saveAction.triggered.connect(self.saveFile)
self.exitAction.triggered.connect(self.close)
# Connect Edit actions
self.copyAction.triggered.connect(self.copyContent)
self.pasteAction.triggered.connect(self.pasteContent)
self.cutAction.triggered.connect(self.cutContent)
# Connect Help actions
self.helpContentAction.triggered.connect(self.helpContent)
self.aboutAction.triggered.connect(self.about)
# Connect Open Recent to dynamically populate it
self.openRecentMenu.aboutToShow.connect(self.populateOpenRecent)
# Slots
def newFile(self):
# Logic for creating a new file goes here...
self.centralWidget.setText("File > New clicked")
def openFile(self):
# Logic for opening an existing file goes here...
self.centralWidget.setText("File > Open... clicked")
def saveFile(self):
# Logic for saving a file goes here...
self.centralWidget.setText("File > Save clicked")
def copyContent(self):
# Logic for copying content goes here...
self.centralWidget.setText("Edit > Copy clicked")
def pasteContent(self):
# Logic for pasting content goes here...
self.centralWidget.setText("Edit > Pate clicked")
def cutContent(self):
# Logic for cutting content goes here...
self.centralWidget.setText("Edit > Cut clicked")
def helpContent(self):
# Logic for launching help goes here...
self.centralWidget.setText("Help > Help Content... clicked")
def about(self):
# Logic for showing an about dialog content goes here...
self.centralWidget.setText("Help > About... clicked")
def populateOpenRecent(self):
# Step 1. Remove the old options from the menu
self.openRecentMenu.clear()
# Step 2. Dynamically create the actions
actions = []
filenames = [f"File-{n}" for n in range(5)]
for filename in filenames:
action = QAction(filename, self)
action.triggered.connect(partial(self.openRecentFile, filename))
actions.append(action)
# Step 3. Add the actions to the menu
self.openRecentMenu.addActions(actions)
def openRecentFile(self, filename):
# Logic for opening a recent file goes here...
self.centralWidget.setText(f"{filename} opened")
def getWordCount(self):
# Logic for computing the word count goes here...
return 42
if __name__ == "__main__":
# Create the application
app = QApplication(sys.argv)
# Create and show the main window
win = Window()
win.show()
# Run the event loop
sys.exit(app.exec_())