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

華為雲開發者社群發表於2021-08-28
摘要:選單、工具欄和狀態列是大多數GUI 應用程式的常見且重要的圖形元件。您可以使用它們為您的使用者提供一種快速訪問應用程式選項和功能的方法。

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

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

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

在本教程中,您將學習:

  • 什麼選單,工具欄和狀態列是
  • 如何以程式設計方式建立選單、工具欄和狀態列
  • 如何使用PyQt 操作填充 Python 選單和工具欄
  • 如何使用狀態列顯示狀態資訊

此外,您將學習一些程式設計最佳實踐,您可以在使用 Python 和 PyQt 建立選單、工具欄和狀態列時應用這些實踐。

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

一個選單欄是一個GUI應用程式的區域主視窗中儲存選單。選單是選項的下拉選單,可以方便地訪問應用程式的選項。例如,如果您正在建立一個文字編輯器,那麼您的選單欄中可能會有以下一些選單:

  • 一個檔案選單,提供以下的一些選單選項:
    • 新建用於建立新文件
    • 開啟以開啟現有文件
    • 開啟最近開啟最近的文件
    • Save用於儲存文件
    • Exit退出應用程式
  • 提供以下一些選單選項的“編輯”選單:
    • Copy用於複製一些文字
    • Paste用於貼上一些文字
    • Cut用於剪下一些文字
  • 一個幫助選單,提供以下一些選單選項:
    • 幫助內容用於啟動使用者手冊和幫助內容
    • 關於啟動關於對話方塊

您還可以將其中一些選項新增到工具欄。工具欄是帶有有意義圖示的按鈕皮膚,可提供對應用程式中最常用選項的快速訪問。在您的文字編輯器示例中,您可以向工具欄新增NewOpenSaveCopyPaste等選項。

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

在本節中,您將學習如何使用 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物件與一對夫婦的對齊標誌。

如果您從命令列執行該應用程式,那麼您將在螢幕上看到以下視窗:

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

就是這樣!您已經使用 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將儲存一個帶有描述選單選項的文字的字串。

以下是將FileEditHelp選單新增到示例應用程式的選單欄的方法:

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 中的圖示和資源部分中瞭解如何使用圖示。

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

PyQt 選單欄

應用程式的選單欄有選單FileEditHelp。當您單擊這些選單時,它們不會顯示選單選項的下拉選單。那是因為您還沒有新增選單選項。您將在使用操作填充選單部分中瞭解如何向選單新增選單選項。

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

建立工具欄

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

當您向主視窗樣式應用程式新增工具欄時,預設位置在視窗頂部。但是,您可以在以下四個工具欄區域之一中放置工具欄:

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

工具欄區域在 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 將顯示一個上下文選單,允許您根據需要隱藏和顯示現有工具欄。

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

在 PyQt 中使用圖示和資源

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

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

假設您的示例應用程式有一個resources目錄,其中包含您要在應用程式的 GUI 中使用的圖示。您有NewOpen等選項的圖示。您可以建立一個.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\
 \
\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。

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

帶有圖示的 PyQt 選單欄

應用程式的主視窗現在在其幫助選單上顯示一個圖示。當您單擊該圖示時,選單會顯示文字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屬性,可以採用以下值之一:

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

您還可以設定該操作的文字和圖示通過各自的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 中建立選單時,操作是一個關鍵元件。

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

用動作填充選單

要使用選單選項填充選單,您將使用操作。在選單中,操作表示為一個水平選項,其中至少有一個描述性文字,如NewOpenSave等。選單選項還可以在其左側顯示一個圖示,並在其右側顯示快捷鍵序列,例如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. 關於用於顯示關於對話方塊

選項在選單中從上到下顯示的順序對應於您在程式碼中新增選項的順序。

如果您執行該應用程式,您將在螢幕上看到以下視窗:

帶選項的 PyQt 選單

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

建立 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

PyQt 子選單

編輯選單現在有一個新的條目稱為查詢和替換。當您將滑鼠懸停在這個新選單選項上時,會出現一個子選單,為您提供兩個新選項,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(),您可以將新建開啟儲存選項的按鈕新增到檔案工具欄。您還可以將CopyPasteCut選項的按鈕新增到“編輯”工具欄。

注意:按鈕在工具欄上從左到右顯示的順序對應於您在程式碼中新增按鈕的順序。

如果您現在執行示例應用程式,您將在螢幕上看到以下視窗:

帶有按鈕的 PyQt 工具欄

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

注意:當您第一次._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因為如果此小部件獲得焦點,則應用程式的鍵盤快捷鍵將無法正常工作。

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

帶有小部件的 PyQt 工具欄

此處,“編輯”工具欄顯示了一個QSpinBox物件,您的使用者可以使用該物件來設定應用程式上的字型大小或任何其他數字屬性。

自定義工具欄

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

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

所有這些屬性都有一個關聯的 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...

突出顯示的線使這裡變得神奇。現在您的使用者無法在應用程式視窗周圍移動工具欄:

PyQt 工具欄自定義

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

組織選單和工具欄選項

為了在 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...

在突出顯示的第一行中,在“檔案”選單中的“儲存”和“退出”選項之間新增一個分隔符。在第二個突出顯示的行中,新增一個分隔符,將“查詢和替換”選項與“編輯”選單中的其餘選項分開。以下是這些新增的工作原理:

帶分隔符的 PyQt 選單

您的“檔案”選單現在顯示一條水平線,將“編輯”選項與選單中的其餘選項分開。在編輯選單中還顯示,在選項的下拉選單中的最後一個分隔符。分隔符的連貫使用可以巧妙地提高選單和工具欄的清晰度,使您的 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 上下文選單策略

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

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

通過事件處理建立上下文選單

在 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()。

這將在檔案選項和編輯選項之間新增一條水平線。以下是新增此內容的上下文選單的外觀:

帶分隔符的 PyQt 上下文選單

現在,您的上下文選單包含一條水平線,可直觀地將來自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()

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

PyQt 連線訊號和插槽

如果單擊選單選項、工具欄按鈕或上下文選單選項,則應用程式視窗中央的標籤會顯示一條訊息,指示已執行的操作。此功能在學習環境之外不是很有用,但它可以讓您瞭解如何在使用者與 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您用作示例應用程式的中央小部件的物件的文字。

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

PyQt 動態建立的選單

當您的滑鼠指標懸停在開啟最近選單上時,選單會發出.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提供標準鍵盤快捷鍵。

如果您執行帶有這些新增的示例應用程式,那麼您的選單將如下所示:

PyQt 鍵盤快捷鍵

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

使用鍵盤加速器

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

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

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

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

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

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

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

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

建立選單和工具欄:最佳實踐和技巧

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

  1. 按照普遍接受的順序排列選單。例如,如果您有一個檔案選單,那麼它應該是從左到右的第一個選單。如果你有一個編輯選單,那麼它應該是第二個。幫助應該是最右邊的選單,依此類推。
  2. 使用您正在開發的應用程式型別的常用選項填充您的選單。例如,在文字編輯器中,檔案選單通常包括諸如NewOpenSaveExit 之類的選項編輯選單通常包括複製貼上剪下撤消等選項。
  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()類初始值設定項。通過這些新增,當您再次執行您的應用程式時,您將看到一個如下所示的視窗:

PyQt 狀態列

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

顯示臨時狀態訊息

狀態列的主要目的是嚮應用程式的使用者顯示狀態資訊。要在狀態列中顯示臨時狀態訊息,您需要使用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幾毫秒:

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

執行應用程式時,狀態列會顯示訊息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物件建立為例項屬性,因為需要根據使用者對當前檔案所做的更改來更新字數。

如果您使用此更新執行應用程式,那麼您將在狀態列的右側看到字數統計訊息:

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

狀態列會顯示一條訊息,通知使用者假設當前檔案中的字數。在狀態列中向使用者顯示永久資訊或其他選項的能力非常有用,可以幫助您極大地改善應用程式的使用者體驗。

向操作新增幫助提示

在建立 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選項向使用者顯示了一個簡短但描述性的幫助提示:

PyQt 幫助提示

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

通常,向 Python 選單和工具欄新增幫助提示被認為是最佳實踐。它將使您的 GUI 應用程式更易於使用者導航和學習。作為最後的練習,您可以繼續向示例應用程式的其餘操作新增幫助提示,並檢視完成後的效果。

結論

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

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

  • 以程式設計方式建立選單、工具欄和狀態列
  • 使用 PyQt操作填充選單和工具欄
  • 使用狀態列提供狀態資訊

在此過程中,您學習了一些在 GUI 應用程式中新增和使用選單、工具欄和狀態列時值得考慮的最佳程式設計實踐。

 

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

相關文章