在PyQt中構建 Python 菜單欄、菜單和工具欄

語言: CN / TW / HK

摘要: 菜單、工具欄和狀態欄是大多數GUI 應用程序的常見且重要的圖形組件。您可以使用它們為您的用户提供一種快速訪問應用程序選項和功能的方法。

本文分享自華為雲社區《 Python 和 PyQt:創建菜單、工具欄和狀態欄 》,作者:Yuchuan。

在使用 Python 和PyQt開發圖形用户界面 (GUI)應用程序時,您將使用的一些最有用和最通用的圖形元素是菜單、工具欄和狀態欄。

菜單和工具欄可以使您的應用程序看起來 精美專業 ,為用户提供一組可訪問的選項,而狀態欄允許您顯示有關應用程序狀態的相關信息。

在本教程中,您將學習:

• 什麼菜單,工具欄和狀態欄是

• 如何以編程方式創建菜單、工具欄和狀態欄

• 如何使用PyQt 操作填充 Python 菜單和工具欄

• 如何使用狀態欄顯示狀態信息

此外,您將學習一些編程最佳實踐,您可以在使用 Python 和 PyQt 創建菜單、工具欄和狀態欄時應用這些實踐。

在 PyQt 中構建 Python 菜單欄、菜單和工具欄

一個 菜單欄 是一個GUI應用程序的區域主窗口中保存菜單。菜單是選項的下拉列表,可以方便地訪問應用程序的選項。例如,如果您正在創建一個文本編輯器,那麼您的菜單欄中可能會有以下一些菜單:

• 一個文件菜單,提供以下的一些菜單選項:

o 新建用於創建新文檔

o 打開以打開現有文檔

o 打開最近打開最近的文檔

o Save用於保存文檔

o Exit退出應用程序

• 提供以下一些菜單選項的“編輯”菜單:

o Copy用於複製一些文本

o Paste用於粘貼一些文本

o Cut用於剪切一些文本

• 一個幫助菜單,提供以下一些菜單選項:

o 幫助內容用於啟動用户手冊和幫助內容

o 關於啟動關於對話框

您還可以將其中一些選項添加到 工具欄 。工具欄是帶有有意義圖標的按鈕面板,可提供對應用程序中最常用選項的快速訪問。在您的文本編輯器示例中,您可以向工具欄添加New、Open、Save、Copy和Paste等選項。

注意:在本教程中,您將開發一個實現上述所有菜單和選項的示例應用程序。您可以使用此示例應用程序作為創建文本編輯器項目的起點。

在本節中,您將學習如何使用 Python 和 PyQt 向 GUI 應用程序添加菜單欄、菜單和工具欄的基礎知識。

在繼續之前,您將創建一個示例 PyQt 應用程序,您將在本教程中使用該應用程序。在每個部分中,您將向此示例應用程序添加新特性和功能。該應用程序將是一個主窗口風格的應用程序。這意味着它將有一個菜單欄、一個工具欄、一個狀態欄和一箇中央小部件。

打開您最喜歡的代碼編輯器或 IDE並創建一個名為sample_app.py. 然後在其中添加以下代碼:

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow

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)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec_())

現在sample_app.py包含創建示例 PyQt 應用程序所需的所有代碼。在這種情況下,Window繼承自QMainWindow. 因此,您正在構建一個主窗口樣式的應用程序。

注意:不幸的是,PyQt5 的官方文檔有一些不完整的部分。要解決此問題,您可以查看PyQt4 文檔或原始Qt 文檔。

在類初始化程序中.__init__(),您首先使用 調用父類的初始化程序super()。然後使用 設置窗口的標題.setWindowTitle()並使用調整窗口大小.resize()。

注意:如果您不熟悉 PyQt 應用程序以及如何創建它們,那麼您可以查看Python 和 PyQt:構建 GUI 桌面計算器。

窗口的中央小部件是一個QLabel對象,您將使用它來顯示消息以響應某些用户操作。這些消息將顯示在窗口的中央。要做到這一點,你叫.setAlignment()上QLabel對象與一對夫婦的對齊標誌。

如果您從命令行運行該應用程序,那麼您將在屏幕上看到以下窗口:

就是這樣!您已經使用 Python 和 PyQt 創建了一個主窗口風格的應用程序。您將在本教程中即將出現的所有示例中使用此示例應用程序。

創建菜單欄

在 PyQt 主窗口風格的應用程序中,默認QMainWindow提供一個空QMenuBar對象。要訪問此菜單欄,您需要調用.menuBar()您的QMainWindow對象。此方法將返回一個空的菜單欄。此菜單欄的父級將是您的主窗口對象。

現在返回到您的示例應用程序並在 的定義中添加以下方法Window:

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        menuBar = self.menuBar()

這是在 PyQt 中創建菜單欄的首選方式。在這裏,menuBar變量將包含一個空的菜單欄,這將是您的主窗口的菜單欄。

注意: PyQt 編程中的一個常見做法是將局部變量用於您不會使用或從其定義方法之外需要的對象。Python垃圾收集所有超出範圍的對象,因此您可能認為menuBar在上面的示例中,一旦._createMenuBar() 返回就會消失。

事實是 PyQt 保留對本地對象的引用,例如menuBar使用它們的所有權或父子關係。換句話説,由於menuBar它歸您的主窗口對象所有,Python 將無法對其進行垃圾收集。

向 PyQt 應用程序添加菜單欄的另一種方法是創建一個QMenuBar對象,然後使用.setMenuBar(). 考慮到這一點,您還可以._createMenuBar()按以下方式編寫:

from PyQt5.QtWidgets import QMenuBar
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        menuBar = QMenuBar(self)
        self.setMenuBar(menuBar)

在上面的例子中,menuBar持有一個QMenuBar父級設置為的對象self,它是應用程序的主窗口。一旦你有了菜單欄對象,你就可以.setMenuBar()將它添加到你的主窗口中。最後,需要注意的是在這個例子中工作,你首先需要進口 QMenuBar的PyQt5.QWidgets。

在 GUI 應用程序中,菜單欄會根據底層操作系統顯示在不同的位置:

• Windows:在應用程序主窗口的頂部,標題欄下方

• macOS:在屏幕頂部

• Linux:在主窗口頂部或屏幕頂部,取決於您的桌面環境

為應用程序創建菜單欄的最後一步是._createMenuBar()從主窗口的初始化程序調用.__init__():

class Window(QMainWindow):
    """Main Window."""
    def __init__(self, parent=None):
        # Snip...
        self._createMenuBar()

如果您使用這些新更改運行示例應用程序,那麼您將看不到應用程序主窗口中顯示的菜單欄。那是因為您的菜單欄仍然是空的。要查看應用程序主窗口上的菜單欄,您需要創建一些菜單。這就是你接下來要學習的內容。

將菜單添加到菜單欄

菜單是菜單選項的下拉列表,您可以通過單擊它們或按鍵盤快捷鍵來觸發。在 PyQt 中,至少有三種方法可以將菜單添加到菜單欄對象:

  1. QMenuBar.addMenu(menu) 將QMenu對象 ( menu)附加到菜單欄對象。它返回與此菜單關聯的操作。
  2. QMenuBar.addMenu(title) 創建一個QMenu以字符串 ( title) 作為標題的新對象並將其附加到菜單欄。菜單欄取得菜單的所有權,該方法返回新QMenu對象。
  3. QMenuBar.addMenu(icon, title) 創建並追加新的QMenu物品與icon和title一個菜單欄對象。菜單欄取得菜單的所有權,該方法返回新QMenu對象。

如果使用第一個選項,則需要先創建自定義QMenu對象。為此,您可以使用以下構造函數之一:

  1. QMenu(parent)
  2. QMenu(title, parent)

在這兩種情況下,parent是QWidget將持有QMenu對象的所有權。您通常會設置parent到您將在其中使用菜單的窗口。在第二個構造函數中,title將保存一個帶有描述菜單選項的文本的字符串。

以下是將File、Edit和Help菜單添加到示例應用程序的菜單欄的方法:

from PyQt5.QtWidgets import QMenu
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        menuBar = self.menuBar()
        # Creating menus using a QMenu object
        fileMenu = QMenu("&File", self)
        menuBar.addMenu(fileMenu)
        # Creating menus using a title
        editMenu = menuBar.addMenu("&Edit")
        helpMenu = menuBar.addMenu("&Help")

首先,你導入 QMenu的PyQt5.QtWidgets。然後在 中._createMenuBar(),使用 的前兩個變體向菜單欄添加三個菜單.addMenu()。第三個變體需要一個圖標對象,但您還沒有學會如何創建和使用圖標。您將在使用 PyQt 中的圖標和資源部分中瞭解如何使用圖標。

如果您運行示例應用程序,那麼您將看到您現在有一個如下所示的菜單欄:

應用程序的菜單欄有菜單File、Edit和Help。當您單擊這些菜單時,它們不會顯示菜單選項的下拉列表。那是因為您還沒有添加菜單選項。您將在使用操作填充菜單部分中瞭解如何向菜單添加菜單選項。

最後,請注意&包含在每個菜單標題中的與符號 ( ) 會在菜單欄顯示中創建帶下劃線的字母。這在定義菜單和工具欄選項的鍵盤快捷鍵一節中有更詳細的討論。

創建工具欄

甲工具欄是保存按鈕和其他部件,以提供到GUI應用的最普通的選項快速訪問的可移動面板。工具欄按鈕可以顯示圖標、文本或兩者來表示它們執行的任務。PyQt 中工具欄的基類是QToolBar. 此類將允許您為 GUI 應用程序創建自定義工具欄。

當您向主窗口樣式應用程序添加工具欄時,默認位置在窗口頂部。但是,您可以在以下四個工具欄區域之一中放置工具欄:

工具欄區域在 PyQt 中被定義為常量。如果您需要使用它們,那麼您必須導入QtfromPyQt5.QtCore然後像 in 一樣使用完全限定名稱Qt.LeftToolBarArea。

在 PyQt 中,可以通過三種方法向主窗口應用程序添加工具欄:

  1. QMainWindow.addToolBar(title) 創建一個新的空QToolBar對象並將其窗口標題設置為title. 此方法將工具欄插入頂部工具欄區域並返回新創建的工具欄。
  2. QMainWindow.addToolBar(toolbar) 將QToolBar對象 ( toolbar) 插入頂部工具欄區域。
  3. QMainWindow.addToolBar(area, toolbar) 將QToolBar對象 ( toolbar) 插入指定的工具欄區域 ( area)。如果主窗口已有工具欄,則toolbar放置在最後一個現有工具欄之後。如果toolbar已經存在於主窗口中,那麼它只會被移動到area.

如果您使用最後兩個選項之一,那麼您需要自己創建工具欄。為此,您可以使用以下構造函數之一:

  1. QToolBar(parent)
  2. QToolBar(title, parent)

在這兩種情況下,parent代表QWidget將擁有工具欄所有權的對象。您通常會將工具欄所有權設置為將在其中使用工具欄的窗口。在第二個構造函數中,title將是一個帶有工具欄窗口標題的字符串。PyQt 使用這個窗口標題來構建一個默認的上下文菜單,允許你隱藏和顯示你的工具欄。

現在您可以返回到您的示例應用程序並將以下方法添加到Window:

from PyQt5.QtWidgets import QToolBar
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createToolBars(self):
        # Using a title
        fileToolBar = self.addToolBar("File")
        # Using a QToolBar object
        editToolBar = QToolBar("Edit", self)
        self.addToolBar(editToolBar)
        # Using a QToolBar object and a toolbar area
        helpToolBar = QToolBar("Help", self)
        self.addToolBar(Qt.LeftToolBarArea, helpToolBar)

首先,您QToolBar從PyQt5.QtWidgets. 然後,在 中._createToolBars(),您首先使用標題創建文件工具欄.addToolBar()。接下來,您創建一個QToolBar帶有標題的對象,"Edit"並使用.addToolBar()不傳遞工具欄區域將其添加到工具欄。在這種情況下,編輯工具欄位於頂部工具欄區域。最後,創建幫助工具欄並使用 將其放置在左側工具欄區域Qt.LeftToolBarArea。

完成這項工作的最後一步是._createToolBars()從 的初始化程序調用Window:

class Window(QMainWindow):
    """Main Window."""
    def __init__(self, parent=None):
        # Snip...
        self._createToolBars()

._createToolBars()對初始化器內部的調用Window將創建三個工具欄並將它們添加到您的主窗口中。以下是您的應用程序現在的外觀:

現在,菜單欄正下方有兩個工具欄,窗口左側有一個工具欄。每個工具欄都有一條雙虛線。當您將鼠標移到虛線上時,指針會變成一隻手。如果單擊並按住虛線,則可以將工具欄移動到窗口上的任何其他位置或工具欄區域。

如果右鍵單擊工具欄,PyQt 將顯示一個上下文菜單,允許您根據需要隱藏和顯示現有工具欄。

到目前為止,您的應用程序窗口中有三個工具欄。這些工具欄仍然是空的——您需要添加一些工具欄按鈕才能使它們起作用。為此,您可以使用 PyQt actions,它們是QAction. 您將在後面的部分中學習如何在 PyQt 中創建操作。現在,您將學習如何在 PyQt 應用程序中使用圖標和其他資源。

在 PyQt 中使用圖標和資源

在Qt庫包括Qt的資源系統,這是增加的二進制文件,如圖標,圖像,翻譯文件和其他資源對應用程序的一種便捷方式。

要使用資源系統,您需要在資源集合文件或.qrc文件中列出您的資源。一個.qrc文件是一個XML包含位置,或文件路徑,文件系統中的每個資源的。

假設您的示例應用程序有一個resources目錄,其中包含您要在應用程序的 GUI 中使用的圖標。您有New、Open等選項的圖標。您可以創建一個.qrc包含每個圖標路徑的文件:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file alias="file-new.svg">resources/file-new.svg</file>
    <file alias="file-open.svg">resources/file-open.svg</file>
    <file alias="file-save.svg">resources/file-save.svg</file>
    <file alias="file-exit.svg">resources/file-exit.svg</file>
    <file alias="edit-copy.svg">resources/edit-copy.svg</file>
    <file alias="edit-cut.svg">resources/edit-cut.svg</file>
    <file alias="edit-paste.svg">resources/edit-paste.svg</file>
    <file alias="help-content.svg">resources/help-content.svg</file>
</qresource>
</RCC>

每個<file>條目必須包含文件系統中資源的路徑。指定的路徑相對於包含.qrc文件的目錄。在上面的例子中,resources目錄需要和.qrc文件在同一個目錄下。

alias 是一個可選屬性,它定義了一個簡短的替代名稱,您可以在代碼中使用它來訪問每個資源。

一旦您擁有應用程序的資源,您就可以運行pyrcc5針對您的.qrc文件的命令行工具。pyrcc5隨 PyQt 一起提供,並且必須在安裝 PyQt 後在您的Python 環境中完全正常運行。

pyrcc5讀取一個.qrc文件並生成一個 Python 模塊,其中包含所有資源的二進制代碼:

$ pyrcc5 -o qrc_resources.py resources.qrc

此命令將讀取resources.qrc並生成qrc_resources.py包含每個資源的二進制代碼。您將能夠通過導入在 Python 代碼中使用這些資源qrc_resources。

注意:如果運行時出現問題pyrcc5,請確保您使用的是正確的 Python 環境。如果您在 Python 虛擬環境中安裝 PyQt,那麼您將無法pyrcc5在該環境之外使用。

這qrc_resources.py是對應於您的代碼片段resources.qrc:

# -*- coding: utf-8 -*-

# Resource object code
#
# Created by: The Resource Compiler for PyQt5 (Qt v5.9.5)
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore

qt_resource_data = b"\
\x00\x00\x03\xb1\
\x3c\
\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\
...

隨着qrc_resources.py在地方,你可以將其導入到你的應用程序,並通過鍵入一個冒號(請參閲各資源:),然後無論是它的alias或它的路徑。例如,要使用file-new.svg其別名進行訪問,您可以使用 訪問字符串 ":file-new.svg"。如果您沒有alias,則可以通過帶有訪問字符串的路徑訪問它":resources/file-new.svg"。

如果您有別名,但由於某種原因您想通過其路徑訪問給定資源,那麼您可能必須從訪問字符串中刪除冒號才能使其正常工作。

要在您的操作中使用圖標,您首先需要導入您的資源模塊:

import qrc_resources

導入包含資源的模塊後,您可以在應用程序的 GUI 中使用這些資源。

注意: Linters、編輯器和 IDE可能會將上述 import 語句標記為未使用,因為您的代碼不會包含對它的任何顯式使用。某些 IDE 可能會更進一步並自動刪除該行。

在這些情況下,您必須覆蓋您的 linter、編輯器或 IDE 的建議,並將該導入保留在您的代碼中。否則,您的應用程序將無法顯示您的資源。

要使用資源系統創建圖標,您需要實例化QIcon,將別名或路徑傳遞給類構造函數:

newIcon = QIcon(":file-new.svg")

在此示例中,您將QIcon使用文件創建一個對象,該對象file-new.svg位於您的資源模塊中。這提供了一種在整個 GUI 應用程序中使用圖標和資源的便捷方式。

現在返回到您的示例應用程序並更新最後一行._createMenuBar():

from PyQt5.QtGui import QIcon

import qrc_resources
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        menuBar = self.menuBar()
        # Using a QMenu object
        fileMenu = QMenu("&File", self)
        menuBar.addMenu(fileMenu)
        # Using a title
        editMenu = menuBar.addMenu("&Edit")
        # Using an icon and a title
        helpMenu = menuBar.addMenu(QIcon(":help-content.svg"), "&Help")

要使此代碼正常工作,您首先需要QIcon從PyQt5.QtGui. 您還需要導入qrc_resources. 在最後突出顯示的行中,您從資源模塊中添加了一個helpMenu使用圖標help-content.svg。

如果您使用此更新運行示例應用程序,您將獲得以下輸出:

應用程序的主窗口現在在其幫助菜單上顯示一個圖標。當您單擊該圖標時,菜單會顯示文本Help。在菜單欄中使用圖標並不常見,但 PyQt 允許您這樣做。

在 PyQt 中為 Python 菜單和工具欄創建操作

PyQt動作是表示應用程序中給定命令、操作或動作的對象。當您需要為不同的 GUI 組件(例如菜單選項、工具欄按鈕和鍵盤快捷鍵)提供相同的功能時,它們非常有用。

您可以通過實例化QAction. 創建操作後,您需要將其添加到小部件中才能在實踐中使用它。

您還需要將您的操作與某些功能聯繫起來。換句話説,您需要將它們連接到觸發操作時要運行的函數或方法。這將允許您的應用程序執行操作以響應 GUI 中的用户操作。

行動是相當多才多藝的。它們允許您跨菜單選項、工具欄按鈕和鍵盤快捷鍵重複使用並保持同步相同的功能。這在整個應用程序中提供了一致的行為。

例如,當用户單擊打開...菜單選項、單擊打開工具欄按鈕或按鍵盤上的Ctrl+O時,他們可能希望應用程序執行相同的操作。

QAction 提供了一個抽象,允許您跟蹤以下元素:

• 菜單選項上的文字

• 工具欄按鈕上的文本

• 工具欄選項上的幫助提示(工具提示)

• 這是什麼幫助提示

• 狀態欄上的幫助提示(狀態提示)

• 與選項關聯的鍵盤快捷鍵

• 與菜單和工具欄選項相關聯的圖標

• 動作enabled或disabled狀態

• 動作on或off狀態

要創建操作,您需要實例化QAction. 至少有三種通用方法可以做到這一點:

  1. QAction(parent)
  2. QAction(text, parent)
  3. QAction(icon, text, parent)

在所有三種情況下,都parent表示擁有操作所有權的對象。此參數可以是任何QObject. 最佳實踐是將操作創建為您將在其中使用它們的窗口的子項。

在第二個和第三個構造函數中,text保存操作將在菜單選項或工具欄按鈕上顯示的文本。

操作文本在菜單選項和工具欄按鈕上的顯示方式不同。例如,文本&Open...顯示為打開...菜單中的選項,如打開的工具欄按鈕。

在第三個構造函數中,icon是一個QIcon保存動作圖標的對象。此圖標將顯示在菜單選項中文本的左側。圖標在工具欄按鈕中的位置取決於工具欄的.toolButtonStyle屬性,可以採用以下值之一:

您還可以設置該操作的文本和圖標通過各自的setter方法,.setText()和.setIcon()。

注意:有關QAction屬性的完整列表,您可以查看文檔。

以下是如何使用 的不同構造函數為示例應用程序創建一些操作QAction:

from PyQt5.QtWidgets import QAction
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createActions(self):
        # Creating action using the first constructor
        self.newAction = QAction(self)
        self.newAction.setText("&New")
        # Creating actions using the second constructor
        self.openAction = QAction("&Open...", self)
        self.saveAction = QAction("&Save", self)
        self.exitAction = QAction("&Exit", self)
        self.copyAction = QAction("&Copy", self)
        self.pasteAction = QAction("&Paste", self)
        self.cutAction = QAction("C&ut", self)
        self.helpContentAction = QAction("&Help Content", self)
        self.aboutAction = QAction("&About", self)

在 中._createActions(),您為示例應用程序創建了一些操作。這些操作將允許您嚮應用程序的菜單和工具欄添加選項。

請注意,您將操作創建為實例屬性,因此您可以._createActions()使用self. 這樣,您就可以在菜單和工具欄上使用這些操作。

注意:在 中._createActions(),您不使用的第三個構造函數,QAction因為如果您還看不到操作,則使用圖標是沒有意義的。您將在使用操作填充工具欄部分中瞭解如何向操作添加圖標。

下一步是調用._createActions()form 的初始化程序Window:

class Window(QMainWindow):
    """Main Window."""
    def __init__(self, parent=None):
        # Snip...
        self._createActions()
        self._createMenuBar()
        self._createToolBars()

如果您現在運行該應用程序,那麼您將不會在 GUI 上看到任何更改。這是因為在將操作添加到菜單或工具欄之前不會顯示它們。請注意,您在調用._createActions()之前先調用._createMenuBar(),._createToolBars()因為您將在菜單和工具欄上使用這些操作。

如果您向菜單添加操作,則該操作將成為菜單選項。如果向工具欄添加操作,則該操作將成為工具欄按鈕。這就是接下來幾節的主題。

在 PyQt 中為 Python 菜單添加選項

如果要向 PyQt 中的給定菜單添加選項列表,則需要使用操作。到目前為止,您已經學習瞭如何使用QAction. 在 PyQt 中創建菜單時,操作是一個關鍵組件。

在本節中,您將學習如何使用操作來填充帶有菜單選項的菜單。

用動作填充菜單

要使用菜單選項填充菜單,您將使用操作。在菜單中,操作表示為一個水平選項,其中至少有一個描述性文本,如New、Open、Save等。菜單選項還可以在其左側顯示一個圖標,並在其右側顯示快捷鍵序列,例如Ctrl+S。

您可以QMenu使用向對象添加操作.addAction()。此方法有多種變體。他們中的大多數被認為是即時創建操作。在本教程中,但是,你要使用的變化.addAction()是QMenu從繼承QWidget。這是此變體的簽名:

QWidget.addAction(action)
參數action表示QAction要添加到給定QWidget對象的對象。使用 的這種變體.addAction(),您可以預先創建您的操作,然後根據需要將它們添加到您的菜單中。

注意: QWidget還提供.addActions(). 此方法採用一系列操作並將它們附加到當前小部件對象。

使用此工具,您可以開始向示例應用程序的菜單添加操作。為此,您需要更新._createMenuBar():

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        menuBar = self.menuBar()
        # File menu
        fileMenu = QMenu("&File", self)
        menuBar.addMenu(fileMenu)
        fileMenu.addAction(self.newAction)
        fileMenu.addAction(self.openAction)
        fileMenu.addAction(self.saveAction)
        fileMenu.addAction(self.exitAction)
        # Edit menu
        editMenu = menuBar.addMenu("&Edit")
        editMenu.addAction(self.copyAction)
        editMenu.addAction(self.pasteAction)
        editMenu.addAction(self.cutAction)
        # Help menu
        helpMenu = menuBar.addMenu(QIcon(":help-content.svg"), "&Help")
        helpMenu.addAction(self.helpContentAction)
        helpMenu.addAction(self.aboutAction)

通過對 的更新._createMenuBar(),您可以向示例應用程序的三個菜單添加許多選項。

現在文件菜單有四個選項:

  1. 新建用於創建新文件
  2. Open...用於打開現有文件
  3. Save用於保存對文件所做的更改
  4. 退出以關閉應用程序

在編輯菜單中有三個選項:

  1. 將內容複製到系統剪貼板
  2. Paste用於從系統剪貼板粘貼內容
  3. Cut用於將內容剪切到系統剪貼板

在幫助菜單中有兩個選項:

  1. 用於啟動應用程序幫助手冊的幫助內容
  2. 關於用於顯示關於對話框

選項在菜單中從上到下顯示的順序對應於您在代碼中添加選項的順序。

如果您運行該應用程序,您將在屏幕上看到以下窗口:

如果您單擊某個菜單,則該應用程序會顯示一個包含您之前看到的選項的下拉列表。

創建 Python 子菜單

有時您需要在 GUI 應用程序中使用子菜單。子菜單是一個嵌套的菜單,當您將光標移到給定的菜單選項上時會顯示該菜單。要將子菜單添加到應用程序,您需要調用.addMenu()容器菜單對象。

假設您需要在示例應用程序的Edit菜單中添加一個子菜單。您的子菜單將包含用於查找和替換內容的選項,因此您將其稱為Find and Replace。該子菜單將有兩個選項:

  1. 查找...以查找一些內容
  2. 替換...用於查找舊內容並將其替換為新內容

以下是將此子菜單添加到示例應用程序的方法:

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        # Snip...
        editMenu.addAction(self.cutAction)
        # Find and Replace submenu in the Edit menu
        findMenu = editMenu.addMenu("Find and Replace")
        findMenu.addAction("Find...")
        findMenu.addAction("Replace...")
        # Snip...

在突出顯示的第一行中,您使用on將QMenu帶有文本的對象添加"Find and Replace"到“編輯”菜單。下一步是使用您迄今為止所做的操作填充子菜單。如果您再次運行示例應用程序,您將在Edit菜單下看到一個新的菜單選項:.addMenu()editMenu

在編輯菜單現在有一個新的條目稱為查找和替換。當您將鼠標懸停在這個新菜單選項上時,會出現一個子菜單,為您提供兩個新選項,Find...和Replace...。就是這樣!您已經創建了一個子菜單。

在 PyQt 中向工具欄添加選項

在使用 Python 和 PyQt 構建 GUI 應用程序時,工具欄是一個非常有用的組件。您可以使用工具欄向您的用户提供一種快速訪問應用程序中最常用選項的方法。您還可以向工具欄添加諸如旋轉框和組合框之類的小部件,以允許用户直接從應用程序的 GUI 修改某些屬性和變量。

在以下幾節中,您將學習如何使用操作向工具欄添加選項或按鈕,以及如何使用.addWidget().

用動作填充工具欄

要將選項或按鈕添加到工具欄,您需要調用.addAction()。在本節中,你會依靠的變化.addAction()是QToolBar從繼承QWidget。因此,您將.addAction()使用動作作為參數進行調用。這將允許您在菜單和工具欄之間共享您的操作。

創建工具欄時,您通常會面臨決定向其中添加哪些選項的問題。通常,您只想將最常用的操作添加到工具欄。

如果返回到示例應用程序,您會記得您添加了三個工具欄:

  1. File
  2. Edit
  3. Help

在文件工具欄中,您可以添加如下選項:

• New

• Open

• Save

在編輯工具欄中,您可以添加以下選項:

• Copy

• Paste

• Cut

通常,當您要向工具欄添加按鈕時,首先要選擇要在每個按鈕上使用的圖標。這不是強制性的,但它是最佳實踐。選擇圖標後,您需要將它們添加到相應的操作中。

以下是向示例應用程序的操作添加圖標的方法:

class Window(QMainWindow):
    # Snip...
    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)
        # 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)
        # Snip...

要將圖標添加到您的操作,請更新突出顯示的行。在 的情況下newAction,您使用.setIcon(). 在其餘的操作中,您使用帶有icon、 atitle和parent對象作為參數的構造函數。

一旦您選擇的操作具有圖標,您可以通過調用.addAction()工具欄對象將這些操作添加到相應的工具欄:

class Window(QMainWindow):
    # Snip...
    def _createToolBars(self):
        # File toolbar
        fileToolBar = self.addToolBar("File")
        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)

通過此更新._createToolBars(),您可以將新建、打開和保存選項的按鈕添加到文件工具欄。您還可以將Copy、Paste和Cut選項的按鈕添加到“編輯”工具欄。

注意:按鈕在工具欄上從左到右顯示的順序對應於您在代碼中添加按鈕的順序。

如果您現在運行示例應用程序,您將在屏幕上看到以下窗口:

示例應用程序現在顯示兩個工具欄,每個工具欄都有幾個按鈕。您的用户可以單擊這些按鈕以快速訪問應用程序最常用的選項。

注意:當您第一次._createToolBars()在創建工具欄部分回信時,您創建了一個幫助工具欄。此工具欄旨在展示如何使用不同的.addToolBar().

在 的上述更新中._createToolBars(),您去掉了幫助工具欄,只是為了使示例簡短明瞭。

請注意,由於您在菜單和工具欄之間共享相同的操作,因此菜單選項也會在其左側顯示圖標,這在生產力和資源使用方面是一個巨大的勝利。這是使用 PyQt 操作通過 Python 創建菜單和工具欄的優勢之一。

向工具欄添加小部件

在某些情況下,您會發現將特定小部件(如旋轉框、組合框或其他)添加到工具欄很有用。一個常見的例子是大多數文字處理器使用的組合框,允許用户更改文檔的字體或所選文本的大小。

要將小部件添加到工具欄,您首先需要創建小部件,設置其屬性,然後調用.addWidget()工具欄對象,將小部件作為參數傳遞。

假設您想向示例應用程序QSpinBox的“編輯”工具欄添加一個對象,以允許用户更改某些內容的大小,可能是字體大小。您需要更新._createToolBars():

from PyQt5.QtWidgets import QSpinBox
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createToolBars(self):
        # Snip...
        # Adding a widget to the Edit toolbar
        self.fontSizeSpinBox = QSpinBox()
        self.fontSizeSpinBox.setFocusPolicy(Qt.NoFocus)
        editToolBar.addWidget(self.fontSizeSpinBox)

在這裏,您首先導入旋轉框類。然後您創建一個QSpinBox對象,將其設置focusPolicy為Qt.NoFocus,最後將其添加到您的編輯工具欄。

注意:在上面的代碼中,您將focusPolicy旋轉框的屬性設置為,Qt.NoFocus因為如果此小部件獲得焦點,則應用程序的鍵盤快捷鍵將無法正常工作。

現在,如果您運行該應用程序,那麼您將獲得以下輸出:

此處,“編輯”工具欄顯示了一個QSpinBox對象,您的用户可以使用該對象來設置應用程序上的字體大小或任何其他數字屬性。

自定義工具欄

PyQt 工具欄非常靈活且可定製。您可以在工具欄對象上設置一堆屬性。下表顯示了一些最有用的屬性:

所有這些屬性都有一個關聯的 setter 方法。例如,您可以使用.setAllowedAreas()to set allowedAreas、.setFloatable()to setfloatable等。

現在,假設您不希望用户在窗口周圍移動文件工具欄。在這種情況下,您可以設置movable為False使用.setMovable():

class Window(QMainWindow):
    # Snip...
    def _createToolBars(self):
        # File toolbar
        fileToolBar = self.addToolBar("File")
        fileToolBar.setMovable(False)
        # Snip...

突出顯示的線使這裏變得神奇。現在您的用户無法在應用程序窗口周圍移動工具欄:

該文件的工具欄不顯示雙虛線了,所以你的用户將無法將其移動。請注意,編輯工具欄仍然是可移動的。您可以使用相同的方法更改工具欄上的其他屬性,並根據您的需要自定義它們。

組織菜單和工具欄選項

為了在 GUI 應用程序中增加清晰度並改善用户體驗,您可以使用分隔符來組織菜單選項和工具欄按鈕。分隔符呈現為分隔或分隔菜單選項的水平線或分隔工具欄按鈕的垂直線。

要在菜單、子菜單或工具欄對象中插入或添加分隔符,您可以調用.addSeparator()這些對象中的任何一個。

例如,您可以使用分隔符將“文件”菜單上的“退出”選項與其餘選項分開,以明確“退出”與菜單上的其餘選項在邏輯上無關。您還可以使用分隔符將“編輯”菜單上的“查找和替換”選項與遵循相同規則的其餘選項分開。

轉到您的示例應用程序並._createMenuBar()按照以下代碼進行更新:

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        # File menu
        # Snip...
        fileMenu.addAction(self.saveAction)
        # Adding a separator
        fileMenu.addSeparator()
        fileMenu.addAction(self.exitAction)
        # Edit menu
        # Snip...
        editMenu.addAction(self.cutAction)
        # Adding a separator
        editMenu.addSeparator()
        # Find and Replace submenu in the Edit menu
        findMenu = editMenu.addMenu("Find and Replace")
        # Snip...

在突出顯示的第一行中,在“文件”菜單中的“保存”和“退出”選項之間添加一個分隔符。在第二個突出顯示的行中,添加一個分隔符,將“查找和替換”選項與“編輯”菜單中的其餘選項分開。以下是這些添加的工作原理:

您的“文件”菜單現在顯示一條水平線,將“編輯”選項與菜單中的其餘選項分開。在編輯菜單中還顯示,在選項的下拉列表中的最後一個分隔符。分隔符的連貫使用可以巧妙地提高菜單和工具欄的清晰度,使您的 GUI 應用程序更加用户友好。

作為練習,您可以轉到 的定義._createToolBars()並添加一個分隔符,將QSpinBox對象與工具欄上的其餘選項分開。

在 PyQt 中構建上下文或彈出菜單

上下文菜單,也稱為彈出菜單,是一種特殊類型的菜單,它會響應某些用户操作(例如右鍵單擊給定的小部件或窗口)而出現。這些菜單提供了一小部分選項,這些選項在您使用的操作系統或應用程序的給定上下文中可用。

例如,如果您右鍵單擊 Windows 計算機的桌面,您將獲得一個菜單,其中包含與操作系統的特定上下文或空間相對應的選項。如果您右鍵單擊文本編輯器的工作區,您將獲得一個完全不同的上下文菜單,具體取決於您使用的編輯器。

在 PyQt 中,您有多種創建上下文菜單的選項。在本教程中,您將瞭解其中兩個選項:

  1. 將contextMenuPolicy特定小部件的屬性設置為Qt.ActionsContextMenu
  2. 通過處理應用程序窗口上的上下文菜單事件contextMenuEvent()

第一個選項是兩者中最常見和用户友好的,因此您將首先了解它。

第二個選項稍微複雜一些,並且依賴於處理用户事件。在 GUI 編程中,事件是應用程序上的任何用户操作,例如單擊按鈕或菜單、從組合框中選擇項目、在文本字段中輸入或更新文本、按下鍵盤上的鍵等.

通過上下文菜單策略創建上下文菜單

所有派生自的 PyQt 圖形組件或小部件都QWidget繼承了一個名為contextMenuPolicy. 此屬性控制小部件如何顯示上下文菜單。此屬性最常用的值之一是Qt.ActionsContextMenu。這使得小部件將其內部操作列表顯示為上下文菜單。

要使小部件根據其內部操作顯示上下文菜單,您需要運行兩個步驟:

  1. 使用 向小部件添加一些操作QWidget.addAction()。
  2. 設置contextMenuPolicy於Qt.ActionsContextMenu上使用的小工具.setContextMenuPolicy()。

設置contextMenuPolicy為Qt.ActionsContextMenu使具有操作的小部件在上下文菜單中顯示它們。這是使用 Python 和 PyQt 創建上下文菜單的一種非常快速的方法。

使用這種技術,您可以向示例應用程序的中央小部件添加上下文菜單,併為您的用户提供一種快速訪問某些應用程序選項的方法。為此,您可以將以下方法添加到Window:

class Window(QMainWindow):
    # Snip...
    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)

在 中._createContextMenu(),您首先設置contextMenuPolicy為Qt.ActionsContextMenu使用 setter 方法.setContextMenuPolicy()。然後.addAction()像往常一樣向小部件添加操作。最後一步是._createContextMenu()從 的初始化程序調用Window:

class Window(QMainWindow):
    """Main Window."""
    def __init__(self, parent=None):
        # Snip...
        self._createToolBars()
        self._createContextMenu()

如果您在添加這些內容後運行示例應用程序,那麼當您右鍵單擊該應用程序的中央小部件時,您會看到它顯示一個上下文菜單:

現在,您的示例應用程序有一個上下文菜單,只要您右鍵單擊應用程序的中央小部件,就會彈出該菜單。中央小部件伸展以佔據窗口中的所有可用空間,因此您不僅限於右鍵單擊標籤文本以查看上下文菜單。

最後,由於您在整個應用程序中使用相同的操作,上下文菜單上的選項顯示相同的圖標集。

通過事件處理創建上下文菜單

在 PyQt 中創建上下文菜單的另一種方法是處理應用程序主窗口的上下文菜單事件。為此,您需要運行以下步驟:

  1. 覆蓋對象.contextMenuEvent()上的事件處理程序方法QMainWindow。
  2. 創建一個QMenu傳遞小部件(上下文小部件)作為其父對象的對象。
  3. 用動作填充菜單對象。
  4. 使用QMenu.exec()事件.globalPos()作為參數啟動菜單對象。

這種管理上下文菜單的方式有點複雜。但是,它使您可以很好地控制調用上下文菜單時發生的情況。例如,您可以根據應用程序的狀態等啟用或禁用菜單選項。

注意:在繼續本節之前,您需要禁用您在上一節中編寫的代碼。為此,只需轉到的初始化程序Window並註釋掉調用self._createContextMenu().

以下是如何重新實現示例應用程序的上下文菜單,覆蓋主窗口對象上的事件處理程序方法:

class Window(QMainWindow):
    # Snip...
    def contextMenuEvent(self, event):
        # Creating a menu object with the central widget as parent
        menu = QMenu(self.centralWidget)
        # Populating the menu with actions
        menu.addAction(self.newAction)
        menu.addAction(self.openAction)
        menu.addAction(self.saveAction)
        menu.addAction(self.copyAction)
        menu.addAction(self.pasteAction)
        menu.addAction(self.cutAction)
        # Launching the menu
        menu.exec(event.globalPos())

在 中contextMenuEvent(),您首先創建一個QMenu對象 ( menu)centralWidget作為其父小部件。接下來,您使用.addAction. 最後,調用.exec()上QMenu的對象,以顯示在屏幕上。

的第二個參數.contextMenuEvent()表示該方法捕獲的事件。在這種情況下,event將右鍵單擊應用程序的中央小部件。

在對 的調用中.exec(),您將其event.globalPos()用作參數。當用户單擊 PyQt 窗口或小部件時,此方法返回鼠標指針的全局位置。鼠標位置將吿訴.exec()窗口上顯示上下文菜單的位置。

如果您使用這些新更改運行示例應用程序,那麼您將獲得與上一節中相同的結果。

組織上下文菜單選項

與菜單和工具欄不同,在上下文菜單中,您不能使用.addSeparator()添加分隔符並根據它們之間的關係在視覺上分隔菜單選項。在組織上下文菜單時,您需要創建一個分隔符操作:

separator = QAction(parent)
separator.setSeparator(True)

.setSeparator(True)對動作對象的調用將把該動作變成一個分隔符。完成分隔符操作後,您需要使用 將其插入上下文菜單中的正確位置QMenu.addAction()。

如果您回顧一下您的示例應用程序,那麼您可能希望在視覺上將來自File菜單的選項與來自Edit菜單的選項分開。為此,您可以更新.contextMenuEvent():

class Window(QMainWindow):
    # Snip...
    def contextMenuEvent(self, event):
        # Snip...
        menu.addAction(self.saveAction)
        # Creating a separator action
        separator = QAction(self)
        separator.setSeparator(True)
        # Adding the separator to the menu
        menu.addAction(separator)
        menu.addAction(self.copyAction)
        # Snip...

在前兩行突出顯示的行中,您創建了分隔符操作。在第三個突出顯示的行中,您使用 將分隔符操作添加到菜單中.addAction()。

這將在文件選項和編輯選項之間添加一條水平線。以下是添加此內容的上下文菜單的外觀:

現在,您的上下文菜單包含一條水平線,可直觀地將來自File的選項與來自Edit的選項分開。這樣,您改進了菜單的視覺質量並提供了更好的用户體驗。

在菜單和工具欄中連接信號和插槽

在 PyQt 中,您使用信號和槽為 GUI 應用程序提供功能。每次在PyQt 小部件上發生諸如鼠標單擊、按鍵或窗口大小調整等事件時,它們都會發出信號。

一個插槽是一個Python可調用,您可以連接到一個小部件的信號,以響應用户事件執行某些操作。

如果連接了一個信號和一個插槽,那麼每次發出信號時都會自動調用該插槽。如果給定的信號未連接到插槽,則在發出信號時不會發生任何事情。

為了讓你的菜單選項和工具欄按鈕在用户點擊它們時啟動一些操作,你需要將底層操作的信號與一些自定義或內置插槽連接起來。

QAction物體可以發出各種信號。但是,菜單和工具欄中最常用的信號是.triggered()。每次用户單擊菜單選項或工具欄按鈕時都會發出此信號。要.triggered()與插槽連接,您可以使用以下語法:

action = QAction("Action Text", parent)
# Connect action's triggered() with a slot
action.triggered.connect(slot)

在這個例子中,slot是一個 Python 可調用的。換句話説,slot可以是一個函數、一個方法、一個類或一個實現 的類的實例.__call__()。

您的示例應用程序中已經有一組操作。現在,您需要對每次用户單擊菜單選項或工具欄按鈕時調用的插槽進行編碼。轉到的定義Window並添加以下方法:

class Window(QMainWindow):
    # Snip...
    def newFile(self):
        # Logic for creating a new file goes here...
        self.centralWidget.setText("<b>File > New</b> clicked")

    def openFile(self):
        # Logic for opening an existing file goes here...
        self.centralWidget.setText("<b>File > Open...</b> clicked")

    def saveFile(self):
        # Logic for saving a file goes here...
        self.centralWidget.setText("<b>File > Save</b> clicked")

    def copyContent(self):
        # Logic for copying content goes here...
        self.centralWidget.setText("<b>Edit > Copy</b> clicked")

    def pasteContent(self):
        # Logic for pasting content goes here...
        self.centralWidget.setText("<b>Edit > Paste</b> clicked")

    def cutContent(self):
        # Logic for cutting content goes here...
        self.centralWidget.setText("<b>Edit > Cut</b> clicked")

    def helpContent(self):
        # Logic for launching help goes here...
        self.centralWidget.setText("<b>Help > Help Content...</b> clicked")

    def about(self):
        # Logic for showing an about dialog content goes here...
        self.centralWidget.setText("<b>Help > About...</b> clicked")

這些方法將扮演示例應用程序的插槽的角色。每次用户單擊相應的菜單選項或工具欄按鈕時都會調用它們。

一旦有了提供功能的插槽,就需要將它們與動作的.triggered()信號連接起來。這樣,應用程序將根據用户事件執行操作。要進行這些連接,請轉到示例應用程序並將以下方法添加到Window:

class Window(QMainWindow):
    # Snip...
    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)

此方法會將您所有操作的.triggered()信號與其各自的插槽或回調連接起來。通過此更新,您的示例應用程序將在QLabel您設置為中央小部件的對象上顯示一條消息,吿訴您單擊了哪個菜單選項或工具欄按鈕。

在 的情況下exitAction,您將其triggered()信號與內置插槽連接QMainWindow.close()。這樣,如果您選擇File → Exit,那麼您的應用程序將關閉。

最後,轉到 的初始化程序Window並添加對 的調用._connectActions():

class Window(QMainWindow):
    """Main Window."""
    def __init__(self, parent=None):
        # Snip...
        # self._createContextMenu()
        self._connectActions()

通過此最終更新,您可以再次運行該應用程序。以下是所有這些更改的工作原理:

如果單擊菜單選項、工具欄按鈕或上下文菜單選項,則應用程序窗口中央的標籤會顯示一條消息,指示已執行的操作。此功能在學習環境之外不是很有用,但它可以讓您瞭解如何在用户與 GUI 交互時讓您的應用程序執行現實世界的操作。

最後,當您選擇File → Exit 時,應用程序將關閉,因為 的.triggered()信號exitAction已連接到內置插槽QMainWindow.close()。

作為練習,您可以嘗試為查找和替換子菜單中的查找...和替換...選項創建自定義插槽,然後將它們的信號連接到這些插槽以使其生效。您還可以嘗試使用您在本節中編寫的插槽並嘗試用它們做新的事情。.triggered()

動態填充 Python 菜單

為應用程序創建菜單時,有時需要使用創建應用程序 GUI 時未知的選項填充這些菜單。例如,文本編輯器中的“打開最近”菜單顯示最近打開的文檔列表。您無法在創建應用程序的 GUI 時填充此菜單,因為每個用户都會打開不同的文檔,並且無法提前知道此信息。

在這種情況下,您需要動態填充菜單以響應用户操作或應用程序的狀態。QMenu有一個稱為.aboutToShow()您可以連接到自定義插槽的信號,以在菜單對象顯示在屏幕上之前動態填充它。

要繼續開發示例應用程序,假設您需要在文件下創建一個打開最近的子菜單,並用最近打開的文件或文檔動態填充它。為此,您需要運行以下步驟:

  1. 在File下創建Open 最近的子菜單。
  2. 編寫動態生成操作以填充菜單的自定義插槽。
  3. 將.aboutToShow()菜單信號與自定義插槽連接。

下面是創建子菜單的代碼:

class Window(QMainWindow):
    # Snip...
    def _createMenuBar(self):
        # Snip...
        fileMenu.addAction(self.openAction)
        # Adding an Open Recent submenu
        self.openRecentMenu = fileMenu.addMenu("Open Recent")
        fileMenu.addAction(self.saveAction)
        # Snip...

在突出顯示的行中,您在“文件”菜單下添加一個標題為 的子菜單"Open Recent"。這個子菜單還沒有菜單選項。您需要動態創建操作以填充它。

您可以通過編寫一種方法來動態創建操作並將它們添加到子菜單來實現此目的。這是一個示例,顯示了您可以使用的一般邏輯:

from functools import partial
# Snip...

class Window(QMainWindow):
    # Snip...
    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)

在 中.populateOpenRecent(),首先使用 刪除菜單中的舊選項(如果有).clear()。然後添加用於動態創建和連接操作的邏輯。最後,您使用 將操作添加到菜單中.addActions()。

在for循環中,您使用functools.partial()來連接.triggered()信號 ,.openRecentFile()因為您想filename作為參數傳遞給.openRecentFile()。當將信號與需要額外參數的插槽連接時,這是一種非常有用的技術。要使其正常工作,您需要partial()從functools.

注意:本示例第二步中的邏輯並沒有真正加載最近打開的文件列表。它只是創建了list五個假設文件中的一個,其唯一目的是展示實現此技術的方法。

下一步是連接.aboutToShow()的信號.openRecentMenu到.populateOpenRecent()。為此,請在末尾添加以下行._connectActions():

class Window(QMainWindow):
    # Snip...
    def _connectActions(self):
        # Snip...
        self.aboutAction.triggered.connect(self.about)
        # Connect Open Recent to dynamically populate it
        self.openRecentMenu.aboutToShow.connect(self.populateOpenRecent)

在突出顯示的行中,您將.aboutToShow信號與連接.populateOpenRecent()。這可確保您的菜單在顯示之前就被填充。

現在您需要編碼.openRecentFile()。這是當您的用户單擊任何動態創建的操作時您的應用程序將調用的方法:

class Window(QMainWindow):
    # Snip...
    def openRecentFile(self, filename):
        # Logic for opening a recent file goes here...
        self.centralWidget.setText(f"<b>{filename}</b> opened")

此方法將更新QLabel您用作示例應用程序的中央小部件的對象的文本。

以下是動態創建的子菜單在實踐中的工作方式:

當您的鼠標指針懸停在打開最近菜單上時,菜單會發出.aboutToShow()信號。這會導致調用.populateOpenRecent(),從而創建並連接操作。如果單擊文件名,您將看到中央標籤相應地更改以顯示消息。

定義菜單和工具欄選項的鍵盤快捷鍵

鍵盤快捷鍵是 GUI 應用程序中的一項重要功能。鍵盤快捷鍵是一個組合鍵,您可以在鍵盤上按下它以快速訪問應用程序中的一些最常見選項。

以下是鍵盤快捷鍵的一些示例:

• Ctrl+ 將C某些內容複製到剪貼板。

• Ctrl+V從剪貼板粘貼一些東西。

• Ctrl+Z撤消上次操作。

• Ctrl+O打開文件。

• Ctrl+S保存文件。

在下面的部分中,您將學習如何嚮應用程序添加鍵盤快捷鍵以提高用户的工作效率和體驗。

使用按鍵序列

到目前為止,您已經瞭解到這QAction是一個用於填充菜單和工具欄的多功能類。QAction還提供了一種用户友好的方式來定義菜單選項和工具欄按鈕的鍵盤快捷鍵。

QAction實施.setShortcut(). 此方法將QKeySequence對象作為參數並返回鍵盤快捷鍵。

QKeySequence提供了幾個構造函數。在本教程中,您將瞭解其中兩個:

  1. QKeySequence(ks, format) 將基於字符串的鍵序列 ( ks) 和格式 ( format) 作為參數並創建一個QKeySequence對象。
  2. QKeySequence(key) 接受一個StandardKey常量作為參數並創建一個QKeySequence與底層平台上的鍵序列匹配的對象。

第一個構造函數識別以下字符串:

• "Ctrl"

• "Shift"

• "Alt"

• "Meta"

您可以通過將這些字符串與字母、標點符號、數字、命名鍵(Up、Down、Home)和功能鍵("Ctrl+S"、"Ctrl+5"、"Alt+Home"、"Alt+F4")組合來創建基於字符串的鍵序列。您最多可以在逗號分隔列表中傳遞四個基於字符串的鍵序列。

注:有關在不同平台上的標準快捷的完整參考,請參閲標準快捷鍵部分中的QKeySequence文檔。

如果您正在開發多平台應用程序並希望堅持每個平台的標準鍵盤快捷鍵,則第二個構造函數很方便。

例如,QKeySequence.Copy將返回用於將對象複製到剪貼板的平台標準鍵盤快捷鍵。

注意:有關 PyQt 提供的標準密鑰的完整參考,請參閲QKeySequence.StandardKey 文檔。

有了關於如何在 PyQt 中為操作定義鍵盤快捷鍵的一般背景,您可以返回示例應用程序並添加一些快捷鍵。為此,您需要更新._createActions():

from PyQt5.QtGui import QKeySequence
# Snip...

class Window(QMainWindow):
    # Snip...
    def _createActions(self):
        # File actions
        # Snip...
        # Using string-based key sequences
        self.newAction.setShortcut("Ctrl+N")
        self.openAction.setShortcut("Ctrl+O")
        self.saveAction.setShortcut("Ctrl+S")
        # Edit actions
        # Snip...
        # Using standard keys
        self.copyAction.setShortcut(QKeySequence.Copy)
        self.pasteAction.setShortcut(QKeySequence.Paste)
        self.cutAction.setShortcut(QKeySequence.Cut)
        # Snip...

您首先需要導入QKeySequence. 在裏面._createActions(),前三個突出顯示的行使用基於字符串的鍵序列創建鍵盤快捷鍵。這是向您的操作添加鍵盤快捷鍵的快速方法。在後三個突出顯示的行中,您用於QKeySequence提供標準鍵盤快捷鍵。

如果您運行帶有這些添加的示例應用程序,那麼您的菜單將如下所示:

您的菜單選項現在會在其右側顯示鍵盤快捷鍵。如果您按這些組合鍵中的任何一個,那麼您將執行相應的操作。

使用鍵盤加速器

您可以使用另一種替代方法將鍵盤快捷鍵或鍵盤加速器添加到應用程序的菜單選項中。

您可能已經注意到,當您為菜單或菜單選項設置文本時,通常會&在文本中插入一個與符號 ( )。這樣做是為了當顯示在菜單或菜單選項的文本中時,緊跟在&符號之後的字母將帶有下劃線。例如,如果您在“文件”菜單 ( )的標題中的字母F之前放置一個與號,則在顯示菜單標題時F將帶有下劃線。"&File"

注意:如果您需要在菜單文本上顯示與號符號,則需要使用雙與號 ( &&) 來逃避此符號的默認功能。

在菜單欄的情況下,使用與號允許您通過Alt與菜單標題中帶下劃線的字母組合按下來調用任何菜單。

啟動菜單後,您可以通過按選項文本中帶下劃線的字母來訪問任何菜單選項。例如,在文件中,您可以通過按字母E訪問退出選項。

注意:當您使用與號來提供鍵盤加速器時,請記住在同一菜單下不能有兩個選項共享相同的訪問字母。

如果您將C設置為Copy選項的訪問字母,則不能將C設置為Cut選項的訪問字母。換句話説,在給定的菜單下,訪問字母必須是唯一的。

此功能將允許您為喜歡使用鍵盤來處理您的應用程序的用户提供快速鍵盤加速器。此技術對於不提供顯式鍵盤快捷鍵的選項特別有用。

創建菜單和工具欄:最佳實踐和技巧

當您使用 Python 和 PyQt 創建菜單和工具欄時,您應該遵循一些通常被認為是 GUI 編程最佳實踐的標準。這是一個快速列表:

1. 按照普遍接受的順序排列菜單。例如,如果您有一個文件菜單,那麼它應該是從左到右的第一個菜單。如果你有一個編輯菜單,那麼它應該是第二個。幫助應該是最右邊的菜單,依此類推。

2. 使用您正在開發的應用程序類型的常用選項填充您的菜單。例如,在文本編輯器中,文件菜單通常包括諸如New、Open、Save和Exit 之類的選項。編輯菜單通常包括複製、粘貼、剪切、撤消等選項。

3. 對常用選項使用標準鍵盤快捷鍵。例如,使用Ctrl+C進行復制,Ctrl+V用於粘貼,Ctrl+X用於切割,等等。

4. 使用分隔符分隔不相關的選項。這些視覺提示將使您的應用程序更易於導航。

5. 將省略號 ( ...)添加到啟動其他對話框的選項的標題。例如,使用Save As...而不是Save As,使用About...而不是About,等等。

6. &在菜單選項中使用與號 ( ) 來提供方便的鍵盤加速器。例如,"&Open代替"Open","&Exit"代替"Exit"。

如果您遵循這些準則,那麼您的 GUI 應用程序將為您的用户提供熟悉且誘人的體驗。

在 PyQt 中構建 Python 狀態欄

甲狀態欄是水平面板通常在GUI應用程序放置在底部的主窗口。它的主要目的是顯示有關應用程序當前狀態的信息。狀態欄也可以分為多個部分,以顯示每個部分的不同信息。

根據Qt 文檔,狀態指示器分為三種類型:

  1. 臨時 指示器會在短時間內佔據幾乎整個狀態欄以顯示工具提示文本、菜單項和其他時間敏感信息。
  2. 普通 指示器佔據狀態欄的一部分並顯示用户可能希望定期參考的信息,例如文字處理器中的字數統計。這些可能會被臨時指標暫時隱藏。
  3. 永久 指示器始終顯示在狀態欄中,即使臨時指示器被激活也是如此。它們用於顯示有關應用程序當前模式的重要信息,例如按下 Caps Lock 鍵的時間。

您可以使用以下選項之一向主窗口樣式的應用程序添加狀態欄:

• 調用.statusBar()你的QMainWindow對象。.statusBar()創建並返回主窗口的空狀態欄。

• 創建一個QStatusBar對象,然後.setStatusBar()使用狀態欄對象作為參數調用主窗口。這樣,.setStatusBar()將您的狀態欄對象設置為主窗口的狀態欄。

在這裏,您有兩種替代實現來向示例應用程序添加狀態欄:

# 1. Using .statusBar()
def _createStatusBar(self):
    self.statusbar = self.statusBar()

# 2. Using .setStatusBar()
def _createStatusBar(self):
    self.statusbar = QStatusBar()
    self.setStatusBar(self.statusbar)

兩種實現產生相同的結果。但是,大多數情況下,您將使用第一個實現來創建狀態欄。請注意,要使第二個實現工作,您需要QStatusBar從PyQt5.QtWidgets.

將上述實現之一添加到您的應用程序Window,然後調用._createStatusBar()類初始值設定項。通過這些添加,當您再次運行您的應用程序時,您將看到一個如下所示的窗口:

您的應用程序現在在其主窗口底部有一個狀態欄。狀態欄幾乎不可見,但如果仔細觀察,您會注意到窗口右下角有一個小的虛線三角形。

顯示臨時狀態消息

狀態欄的主要目的是嚮應用程序的用户顯示狀態信息。要在狀態欄中顯示臨時狀態消息,您需要使用QStatusBar.showMessage(). 此方法採用以下兩個參數:

  1. message 將狀態指示消息作為字符串保存。
  2. timeout 保存消息將顯示在狀態欄上的毫秒數。

如果timeout是0,這是其默認值,則消息將保留在狀態欄上,直到您調用.clearMessage()或.showMessage()狀態欄上。

如果您的狀態欄上有一條活動消息並且您.showMessage()用新消息呼叫,那麼新消息將掩蓋或替換舊消息。

轉到您的示例應用程序並將以下行添加到._createStatusBar():

class Window(QMainWindow):
    # Snip...
    def _createStatusBar(self):
        self.statusbar = self.statusBar()
        # Adding a temporary message
        self.statusbar.showMessage("Ready", 3000)

最後一行._createStatusBar()將使您的應用程序Ready在應用程序的狀態欄上顯示一條消息3000幾毫秒:

運行應用程序時,狀態欄會顯示消息Ready。之後3000毫秒,此消息消失,狀態欄被清除,並準備展現出新的狀態信息。

在狀態欄中顯示永久消息

您還可以在應用程序的狀態欄上顯示永久消息。一條永久消息讓用户瞭解應用程序的一些一般狀態。例如,在文本編輯器中,您可能希望顯示一條永久消息,其中包含有關當前打開文件的文本編碼的信息。

要將永久消息添加到狀態欄,請使用QLabel對象來保存消息。然後通過調用將標籤添加到狀態欄.addPermanentWidget()。此方法將給定的小部件永久添加到當前狀態欄。小部件的父級設置為狀態欄。

.addPermanentWidget() 採用以下兩個參數:

  1. widget 保存要添加到狀態欄的小部件對象。這個角色的一些常用小部件QLabel,QToolButton以及QProgressBar。
  2. stretch 用於隨着狀態欄的增長和收縮計算小部件的合適大小。它默認為0,這意味着小部件將佔用最少的空間。

請記住,永久小部件不會被臨時消息遮蔽或替換。.addPermanentWidget()在狀態欄的右側定位小部件。

注意:您.addPermanentWidget()不僅可以使用在狀態欄上顯示永久消息,還可以向用户顯示進度條以監控給定操作的持續時間。您還可以在狀態欄上提供按鈕,以允許用户在文本編輯器上更改文件編碼等屬性。

當您在狀態欄上使用這些類型的小部件時,儘量堅持使用最常用的小部件來滿足您正在開發的應用程序類型。這樣,您的用户就會有賓至如歸的感覺。

假設您想將示例應用程序轉換為文本編輯器,並且您想向狀態欄添加一條消息,以顯示有關當前文件字數的信息。為此,您可以創建一個調用的方法.getWordCount(),然後使用.addPermanentWidget()和QLabel對象添加永久消息:

class Window(QMainWindow):
    # Snip...
    def getWordCount(self):
        # Logic for computing the word count goes here...
        return 42

該方法添加了計算當前打開文檔中字數的邏輯。現在,您可以將此信息顯示為永久消息:

class Window(QMainWindow):

# Snip...
  def _createStatusBar(self):
      self.statusbar = self.statusBar()
      # Adding a temporary message
      self.statusbar.showMessage("Ready", 3000)
      # Adding a permanent message
      self.wcLabel = QLabel(f"{self.getWordCount()} Words")
      self.statusbar.addPermanentWidget(self.wcLabel)

在最後兩行中,您首先創建一個QLabel對象 ( wcLabel) 來保存有關字數的消息。要創建消息,請使用f-string,在其中插入對 的調用.getWordCount()以獲取字數信息。然後使用 將標籤添加到狀態欄.addPermanentWidget()。

在這種情況下,您將QLabel對象創建為實例屬性,因為需要根據用户對當前文件所做的更改來更新字數。

如果您使用此更新運行應用程序,那麼您將在狀態欄的右側看到字數統計消息:

狀態欄會顯示一條消息,通知用户假設當前文件中的字數。在狀態欄中向用户顯示永久信息或其他選項的能力非常有用,可以幫助您極大地改善應用程序的用户體驗。

向操作添加幫助提示

在創建 GUI 應用程序時,向用户提供有關應用程序界面特定功能的幫助提示非常重要。幫助提示是短消息,可為用户提供有關應用程序提供的某些選項的快速指南。

PyQt 操作允許您定義以下類型的幫助提示:

狀態提示 是當用户將鼠標指針懸停在菜單選項或工具欄按鈕上時應用程序顯示在狀態欄上的幫助提示。默認情況下,狀態提示包含一個空字符串。

工具提示 是當用户將鼠標指針懸停在工具欄按鈕或小部件上時應用程序顯示為浮動消息的幫助提示。默認情況下,工具提示包含標識手頭操作的文本。

注意: PyQt 還提供了What's This幫助提示,您可以在小部件和動作中使用它來顯示對小部件或動作提供的功能的更豐富的描述。但是,該主題超出了本教程的範圍。

要了解幫助提示的工作原理,您可以向示例應用程序添加一些狀態提示和工具提示。轉到._createActions()並添加以下代碼行:

class Window(QMainWindow):
    # Snip...
    def _createActions(self):
        # File actions
        # Snip...
        self.saveAction.setShortcut("Ctrl+S")
        # Adding help tips
        newTip = "Create a new file"
        self.newAction.setStatusTip(newTip)
        self.newAction.setToolTip(newTip)
        # Edit actions
        self.copyAction = QAction(QIcon(":edit-copy.svg"), "&Copy", self)
        # Snip...

三個突出顯示的行將消息設置"Create a new file"為“新建”選項的狀態和工具提示。如果您現在運行該應用程序,您將看到New選項向用户顯示了一個簡短但描述性的幫助提示:

當您單擊File菜單並將鼠標指針放在New 上時,您可以看到狀態欄左側顯示的幫助提示消息。另一方面,如果您將鼠標指針移到“新建”工具欄按鈕上,則您可以在狀態欄上看到消息,也可以在鼠標指針旁邊看到一個小的浮動框。

通常,向 Python 菜單和工具欄添加幫助提示被認為是最佳實踐。它將使您的 GUI 應用程序更易於用户導航和學習。作為最後的練習,您可以繼續向示例應用程序的其餘操作添加幫助提示,並查看完成後的效果。

結論

菜單、工具欄和狀態欄是大多數GUI 應用程序的常見且重要的圖形組件。您可以使用它們為您的用户提供一種快速訪問應用程序選項和功能的方法。它們還使您的應用程序看起來精美和專業,併為您的用户提供出色的體驗。

在本教程中,您學習瞭如何:

• 以編程方式創建菜單、工具欄和狀態欄

• 使用 PyQt操作填充菜單和工具欄

• 使用狀態欄提供狀態信息

在此過程中,您學習了一些在 GUI 應用程序中添加和使用菜單、工具欄和狀態欄時值得考慮的最佳編程實踐。

您還編寫了一個示例應用程序,在其中應用了您對菜單和工具欄的所有知識。您可以通過單擊下面的框來獲取該應用程序的完整源代碼和其他資源:

點擊關注,第一時間瞭解華為雲新鮮技術~