PyQt5 快速指南



PyQt5 - 簡介

PyQt 是一個 GUI 控制元件工具包。它是Qt 的 Python 介面,Qt 是一個最強大和流行的跨平臺 GUI 庫之一。PyQt 由 RiverBank Computing Ltd. 開發。最新版本的 PyQt 可從其官方網站下載 - riverbankcomputing.com

PyQt API 是一組包含大量類和函式的模組。QtCore 模組包含用於處理檔案和目錄等的非 GUI 功能,而QtGui 模組包含所有圖形控制元件。此外,還有用於處理 XML (QtXml)、SVG (QtSvg) 和 SQL (QtSql) 等的模組。

以下是常用模組的列表:

  • QtCore - 其他模組使用的核心非 GUI 類

  • QtGui - 圖形使用者介面元件

  • QtMultimedia - 用於低級別多媒體程式設計的類

  • QtNetwork - 用於網路程式設計的類

  • QtOpenGL - OpenGL 支援類

  • QtScript - 用於評估 Qt 指令碼的類

  • QtSql - 使用 SQL 進行資料庫整合的類

  • QtSvg - 用於顯示 SVG 檔案內容的類

  • QtWebKit - 用於渲染和編輯 HTML 的類

  • QtXml - 用於處理 XML 的類

  • QtWidgets - 用於建立經典桌面式 UI 的類

  • QtDesigner - 用於擴充套件 Qt Designer 的類

支援環境

PyQt 相容所有流行的作業系統,包括 Windows、Linux 和 Mac OS。它具有雙重許可,可在 GPL 和商業許可下使用。最新穩定版本為PyQt5-5.13.2。

Windows

提供與 Python 3.5 或更高版本相容的 32 位或 64 位架構的輪子。推薦的安裝方法是使用PIP實用程式:

pip3 install PyQt5

要安裝諸如 Qt Designer 之類的開發工具以支援 PyQt5 輪子,以下是命令:

pip3 install pyqt5-tools

您也可以從原始碼在 Linux/macOS 上構建 PyQt5 www.riverbankcomputing.com/static/Downloads/PyQt5

PyQt5 - 最新動態

PyQt5 API 不自動相容早期版本。因此,涉及 PyQt4 模組的 Python 程式碼應透過進行相關更改手動升級。本章列出了 PyQt4 和 PyQt5 之間的主要區別。

PyQt5 不支援早於 v2.6 的 Python 版本。

PyQt5 不支援 QObject 類的 connect() 方法來連線訊號和槽。因此,用法不再能實現:

QObject.connect(widget, QtCore.SIGNAL(‘signalname’), slot_function)

僅定義以下語法:

widget.signal.connect(slot_function)

早期 QtGui 模組中定義的類已分佈在QtGui、QtPrintSupportQtWidgets模組中。

在新 QFileDialog 類中,getOpenFileNameAndFilter() 方法被getOpenFileName()替換,getOpenFileNamesAndFilter()getOpenFileNames()替換,getSaveFileNameAndFilter()getSaveFileName()替換。這些方法的舊簽名也已更改。

PyQt5 沒有規定定義從多個 Qt 類子類化的類。

pyuic5 實用程式(用於從 Designer 的 XML 檔案生成 Python 程式碼)不支援 --pyqt3-wrapper 標誌。

pyrcc5 不支援 -py2 和 -py3 標誌。pyrcc5 的輸出與所有 Python v2.6 及更高版本相容。

PyQt5 始終自動呼叫sip.setdestroyonexit()並呼叫其擁有的所有包裝例項的 C++ 解構函式。

PyQt5 - Hello World

使用 PyQt 建立簡單的 GUI 應用程式涉及以下步驟:

  • 從 PyQt5 包匯入 QtCore、QtGui 和 QtWidgets 模組。

  • 建立 QApplication 類的應用程式物件。

  • QWidget 物件建立一個頂級視窗。在其中新增 QLabel 物件。

  • 將標籤的標題設定為“hello world”。

  • 使用 setGeometry() 方法定義視窗的大小和位置。

  • 透過app.exec_()方法進入應用程式的主迴圈。

以下是使用 PyQt 執行 Hello World 程式的程式碼:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QLabel(w)
   b.setText("Hello World!")
   w.setGeometry(100,100,200,50)
   b.move(50,20)
   w.setWindowTitle("PyQt5")
   w.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   window()

上述程式碼產生以下輸出:

Hello World

也可以開發上述程式碼的面向物件解決方案。

  • 從 PyQt5 包匯入 QtCore、QtGui 和 QtWidgets 模組。

  • 建立 QApplication 類的應用程式物件。

  • 基於 QWidget 類宣告視窗類

  • 新增 QLabel 物件並將標籤的標題設定為“hello world”。

  • 使用 setGeometry() 方法定義視窗的大小和位置。

  • 透過app.exec_()方法進入應用程式的主迴圈。

以下是面向物件解決方案的完整程式碼:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class window(QWidget):
   def __init__(self, parent = None):
      super(window, self).__init__(parent)
      self.resize(200,50)
      self.setWindowTitle("PyQt5")
      self.label = QLabel(self)
      self.label.setText("Hello World")
      font = QFont()
      font.setFamily("Arial")
      font.setPointSize(16)
      self.label.setFont(font)
      self.label.move(50,20)
def main():
   app = QApplication(sys.argv)
   ex = window()
   ex.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   main()
Hello Worlds

PyQt5 - 主要類

PyQt API 是一個大型的類和方法集合。這些類在 20 多個模組中定義。

以下是一些常用模組:

序號 模組和描述
1

QtCore

其他模組使用的核心非 GUI 類

2

QtGui

圖形使用者介面元件

3

QtMultimedia

用於低級別多媒體程式設計的類

4

QtNetwork

用於網路程式設計的類

5

QtOpenGL

OpenGL 支援類

6

QtScript

用於評估 Qt 指令碼的類

7

QtSql

使用 SQL 進行資料庫整合的類

8

QtSvg

用於顯示 SVG 檔案內容的類

9

QtWebKit

用於渲染和編輯 HTML 的類

10

QtXml

用於處理 XML 的類

11

QtWidgets

用於建立經典桌面式 UI 的類。

12

QtDesigner

用於擴充套件 Qt Designer 的類

13

QtAssistant

支援線上幫助

PyQt5 開發工具是用於 Qt 開發的實用程式集合。以下是一些此類實用程式的選擇列表:

序號 工具名稱和描述
1

assistant

Qt Assistant 文件工具

2

pyqt5designer

Qt Designer GUI 佈局工具

3

linguist

Qt Linguist 翻譯工具

4

lrelease

將 ts 檔案編譯成 qm 檔案

5

pylupdate5

提取翻譯字串並生成或更新 ts 檔案

6

qmake

Qt 軟體構建工具

7

pyqt5qmlscene

QML 檔案檢視器

8

pyqmlviewer

QML 檔案檢視器

9

pyrcc5

Qt 資原始檔編譯器

10

pyuic5

用於從 ui 檔案生成程式碼的 Qt 使用者介面編譯器

11

pyqmltestrunner

在 QML 程式碼上執行單元測試

12

qdbus

列出 D-Bus 服務的命令列工具

13

QDoc

軟體專案的文件生成器。

14

Qhelpgenerator

生成和檢視 Qt 幫助檔案。

15

qmlimportscanner

解析並報告 QML 匯入

PyQt API 包含 400 多個類。QObject 類位於類層次結構的頂部。它是所有 Qt 物件的基類。此外,QPaintDevice 類是所有可以繪製的物件的基類。

QApplication 類管理 GUI 應用程式的主要設定和控制流程。它包含主事件迴圈,在該迴圈中處理和分派由視窗元素和其他來源生成的事件。它還處理系統範圍和應用程式範圍的設定。

QWidget 類派生自 QObject 和 QPaintDevice 類,是所有使用者介面物件的基類。QDialogQFrame 類也派生自 QWidget 類。它們有自己的子類系統。

以下是一些常用控制元件的選擇列表

序號 控制元件和描述
1

QLabel

用於顯示文字或影像

2

QLineEdit

允許使用者輸入一行文字

3

QTextEdit

允許使用者輸入多行文字

4

QPushButton

一個命令按鈕來呼叫動作

5

QRadioButton

能夠從多個選項中選擇一個

6

QCheckBox

能夠選擇多個選項

7

QSpinBox

能夠增加/減少整數值

8

QScrollBar

能夠訪問超出顯示光圈的控制元件內容

9

QSlider

能夠線性地更改繫結值。

10

QComboBox

提供一個下拉列表供選擇

11

QMenuBar

包含 QMenu 物件的水平條

12

QStatusBar

通常位於 QMainWindow 的底部,提供狀態資訊。

13

QToolBar

通常位於 QMainWindow 的頂部或浮動。包含操作按鈕

14

QListView

在 ListMode 或 IconMode 中提供一個可選擇的專案列表

15

QPixmap

用於在 QLabel 或 QPushButton 物件上顯示的螢幕外影像表示

16

QDialog

模態或非模態視窗,可以向父視窗返回資訊

典型的基於 GUI 的應用程式的頂級視窗是由QMainWindow控制元件物件建立的。上面列出的一些控制元件佔據其指定位置在這個主視窗中,而其他控制元件則使用各種佈局管理器放置在中央控制元件區域中。

下圖顯示了 QMainWindow 框架:

QMainWindow

PyQt5 - 使用 Qt Designer

PyQt 安裝程式附帶一個名為Qt Designer的 GUI 構建器工具。使用其簡單的拖放介面,可以快速構建 GUI 介面而無需編寫程式碼。然而,它不是像 Visual Studio 這樣的 IDE。因此,Qt Designer 沒有除錯和構建應用程式的功能。

啟動 Qt Designer 應用程式,它是開發工具的一部分,安裝在虛擬環境的 scripts 資料夾中。

Virtual Environment

透過選擇“檔案”→“新建”選單開始設計 GUI 介面。

New Menu

然後,您可以將所需的控制元件從左側窗格的控制元件框中拖放到表單上。您還可以為放在表單上的控制元件的屬性賦值。

Widget

設計的表單儲存為 demo.ui。此 ui 檔案包含設計中控制元件及其屬性的 XML 表示。此設計透過使用 pyuic5 命令列實用程式轉換為 Python 等效項。此實用程式是 Qt 工具包 uic 模組的包裝器。pyuic5 的用法如下:

pyuic5 -x demo.ui -o demo.py

在上述命令中,-x 開關向生成的 Python 指令碼(來自 XML)新增少量附加程式碼,以便它成為一個自執行的獨立應用程式。

if __name__ == "__main__":
   import sys
   app = QtGui.QApplication(sys.argv)
   Dialog = QtGui.QDialog()
   ui = Ui_Dialog()
   ui.setupUi(Dialog)
   Dialog.show()
   sys.exit(app.exec_())

執行生成的 Python 指令碼將顯示以下對話方塊:

python demo.py
Dialog Box

使用者可以在輸入欄位中輸入資料,但是點選“新增”按鈕不會產生任何操作,因為它沒有與任何函式關聯。對使用者生成的響應做出反應被稱為**事件處理**。

PyQt5 - 訊號與槽

與以順序方式執行的控制檯模式應用程式不同,基於 GUI 的應用程式是事件驅動的。函式或方法是響應使用者操作(例如單擊按鈕、從集合中選擇專案或滑鼠單擊等,稱為**事件**)而執行的。

用於構建 GUI 介面的小部件充當此類事件的來源。每個從 QObject 類派生的 PyQt 小部件都設計為響應一個或多個事件發出**“訊號”**。訊號本身不執行任何操作。相反,它“連線”到一個**“槽”**。槽可以是任何**可呼叫的 Python 函式**。

使用 Qt Designer 的訊號/槽編輯器

首先設計一個帶有 LineEdit 控制元件和 PushButton 的簡單窗體。

Slot Editor

如果按下按鈕,希望文字框的內容被清除。QLineEdit 小部件為此目的提供了一個 clear() 方法。因此,按鈕的**clicked**訊號需要連線到文字框的**clear()**方法。

首先,從“編輯”選單中選擇“編輯訊號/槽”(或按 F4)。然後用滑鼠突出顯示按鈕並將游標拖動到文字框。

Cursor

釋放滑鼠後,將顯示一個對話方塊,顯示按鈕的訊號和小部件的方法。選擇 clicked 訊號和 clear() 方法。

Clear Method

右下角的訊號/槽編輯器視窗將顯示結果。

Editor Window

儲存 ui 檔案,並根據以下程式碼所示從 ui 檔案構建和生成 Python 程式碼。

pyuic5 -x signalslot.ui -o signalslot.py

生成的 Python 程式碼將透過以下語句顯示訊號和槽之間的連線。

self.pushButton.clicked.connect(self.lineEdit.clear)

執行 signalslot.py,並在 LineEdit 中輸入一些文字。如果按下按鈕,文字將被清除。

構建訊號-槽連線

無需使用 Designer,您可以透過以下語法直接建立訊號-槽連線。

widget.signal.connect(slot_function)

假設單擊按鈕時要呼叫一個函式。這裡,clicked 訊號需要連線到一個可呼叫函式。可以使用以下任何一種技術來實現。

button.clicked.connect(slot_function)

示例

在下面的示例中,兩個 QPushButton 物件(b1 和 b2)被新增到 QDialog 視窗中。我們希望在分別單擊 b1 和 b2 時呼叫函式 b1_clicked() 和 b2_clicked()。

當單擊 b1 時,clicked() 訊號連線到 b1_clicked() 函式。

b1.clicked.connect(b1_clicked())

當單擊 b2 時,clicked() 訊號連線到 b2_clicked() 函式。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QDialog()
   b1 = QPushButton(win)
   b1.setText("Button1")
   b1.move(50,20)
   b1.clicked.connect(b1_clicked)
   
   b2 = QPushButton(win)
   b2.setText("Button2")
   b2.move(50,50)
   b2.clicked.connect(b2_clicked)
   
   win.setGeometry(100,100,200,100)

   win.setWindowTitle("PyQt5")
   win.show()
   sys.exit(app.exec_())

def b1_clicked():
   print ("Button 1 clicked")

def b2_clicked():
   print ("Button 2 clicked")

if __name__ == '__main__':
   window()

上述程式碼產生以下輸出:

PushButton

輸出

Button 1 clicked
Button 2 clicked

PyQt5 - 佈局管理

可以透過指定以畫素為單位測量的絕對座標,將 GUI 小部件放置在容器視窗內。座標相對於 setGeometry() 方法定義的視窗尺寸。

setGeometry() 語法

QWidget.setGeometry(xpos, ypos, width, height)

在下面的程式碼片段中,尺寸為 300x200 畫素的頂級視窗顯示在顯示器上的 (10, 10) 位置。

import sys
from PyQt4 import QtGui

def window():
   app = QtGui.QApplication(sys.argv)
   w = QtGui.QWidget()
	
   b = QtGui.QPushButton(w)
   b.setText("Hello World!")
   b.move(50,20)
	
   w.setGeometry(10,10,300,200)
   w.setWindowTitle(“PyQt”)
   w.show()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   window()

一個**PushButton**小部件新增到視窗中,並放置在視窗左上角位置向右 50 畫素,向下 20 畫素的位置。

然而,這種絕對定位並不合適,原因如下:

  • 即使調整視窗大小,小部件的位置也不會改變。

  • 在具有不同解析度的不同顯示裝置上,外觀可能不一致。

  • 佈局的修改很困難,因為它可能需要重新設計整個窗體。

Original and Resized Window

PyQt API 提供佈局類,用於更優雅地管理容器內小部件的位置。佈局管理器相對於絕對定位的優點是:

  • 視窗內的小部件會自動調整大小。

  • 確保在具有不同解析度的顯示裝置上外觀一致。

  • 可以動態新增或刪除小部件,而無需重新設計。

Qt 工具包定義了各種可以與 Qt Designer 實用程式一起使用的佈局。

Display Class

以下是我們將在這章中逐一討論的類的列表。

序號 類和描述
1 QBoxLayout

QBoxLayout 類垂直或水平排列小部件。它的派生類是 QVBoxLayout(用於垂直排列小部件)和 QHBoxLayout(用於水平排列小部件)。

2 QGridLayout

GridLayout 類物件以網格形式呈現,單元格按行和列排列。該類包含 addWidget() 方法。可以透過指定單元格的行數和列數來新增任何小部件。

3 QFormLayout

QFormLayout 是一種建立兩列窗體的便捷方法,其中每一行都包含一個與標籤關聯的輸入欄位。按照慣例,左列包含標籤,右列包含輸入欄位。

PyQt5 - 基本控制元件

以下是我們將在這章中逐一討論的小部件列表。

序號 控制元件和描述
1 QLabel

QLabel 物件充當佔位符,用於顯示不可編輯的文字或影像,或動畫 GIF 電影。它也可以用作其他小部件的助記鍵。

2 QLineEdit

QLineEdit 物件是最常用的輸入欄位。它提供一個框,可以在其中輸入一行文字。為了輸入多行文字,需要 QTextEdit 物件。

3 QPushButton

在 PyQt API 中,QPushButton 類物件呈現一個按鈕,單擊該按鈕可以程式設計呼叫某個函式。

4 QRadioButton

QRadioButton 類物件呈現一個帶有文字標籤的可選擇按鈕。使用者可以選擇窗體上顯示的多個選項之一。此類派生自 QAbstractButton 類。

5 QCheckBox

當將 QCheckBox 物件新增到父視窗時,文字標籤前會出現一個矩形框。與 QRadioButton 一樣,它也是一個可選擇按鈕。

6 QComboBox

QComboBox 物件呈現一個下拉列表,供使用者從中選擇專案。它在窗體上佔據最小的螢幕空間,只需顯示當前選擇的專案即可。

7 QSpinBox

QSpinBox 物件為使用者提供一個文字框,該文字框顯示一個整數,其右側帶有向上/向下按鈕。

8 QSlider 小部件和訊號

QSlider 類物件為使用者提供一個凹槽,可以在其上移動手柄。它是控制有界值的經典小部件。

9 QMenuBar、QMenu 和 QAction

QMainWindow 物件標題欄正下方的水平 QMenuBar 用於顯示 QMenu 物件。

10 QToolBar

QToolBar 小部件是一個可移動的面板,包含文字按鈕、帶圖示的按鈕或其他小部件。

11 QInputDialog

這是一個預配置的對話方塊,帶有一個文字欄位和兩個按鈕,“確定”和“取消”。使用者單擊“確定”按鈕或按 Enter 鍵後,父視窗將收集文字框中的輸入。

12 QFontDialog

另一個常用的對話方塊,字型選擇器小部件是 QDialog 類的視覺外觀。此對話方塊的結果是一個 Qfont 物件,父視窗可以使用該物件。

13 QFileDialog

此小部件是一個檔案選擇器對話方塊。它使使用者能夠瀏覽檔案系統並選擇要開啟或儲存的檔案。可以透過靜態函式或在對話方塊物件上呼叫 exec_() 函式來呼叫該對話方塊。

14 QTab

如果窗體有太多欄位無法同時顯示,則可以將它們排列在選項卡式小部件的每個選項卡下放置的不同頁面中。QTabWidget 提供一個選項卡欄和一個頁面區域。

15 QStacked

QStackedWidget 的功能類似於 QTabWidget。它還有助於有效利用視窗的客戶區。

16 QSplitter

這是另一個高階佈局管理器,它允許透過拖動它們之間的邊界來動態更改子小部件的大小。Splitter 控制元件提供一個可以拖動以調整控制元件大小的手柄。

17 QDock

可停靠視窗是一個子視窗,可以保持浮動狀態,也可以附加到主視窗的指定位置。QMainWindow 類的主視窗物件有一個為可停靠視窗保留的區域。

18 QStatusBar

QMainWindow 物件在底部保留一個水平條作為狀態列。它用於顯示永久性或上下文狀態資訊。

19 QList

QListWidget 類是一個基於專案的介面,用於向列表中新增或刪除專案。列表中的每個專案都是一個 QListWidgetItem 物件。ListWidget 可以設定為多選。

20 QScrollBar

捲軸控制元件使使用者能夠訪問位於可視區域之外的文件部分。它提供當前位置的視覺指示器。

21 QCalendar

QCalendar 小部件是一個有用的日期選擇器控制元件。它提供基於月份的檢視。使用者可以使用滑鼠或鍵盤選擇日期,預設日期為今天的日期。

PyQt5 - QDialog 類

**QDialog** 小部件呈現一個頂級視窗,主要用於收集使用者的響應。它可以配置為**模態**(它會阻止其父視窗)或**非模態**(可以繞過對話方塊視窗)。

PyQt API 有許多預配置的對話方塊小部件,例如 InputDialog、FileDialog、FontDialog 等。

示例

在下面的示例中,對話方塊視窗的**WindowModality**屬性決定它是模態還是非模態。可以將對話方塊上的任何一個按鈕設定為預設按鈕。當用戶按下 Escape 鍵時,對話方塊將被**QDialog.reject()**方法丟棄。

頂級 QWidget 視窗上的 PushButton 單擊後會產生一個對話方塊視窗。對話方塊框的標題欄上沒有最小化和最大化控制元件。

使用者無法將此對話方塊框置於後臺,因為它的 WindowModality 設定為**ApplicationModal**。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   btn = QPushButton(w)
   btn.setText("Hello World!")
   btn.move(100,50)
   btn.clicked.connect(showdialog)
   w.setWindowTitle("PyQt Dialog demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   dlg = QDialog()
   b1 = QPushButton("ok",dlg)
   b1.move(50,50)
   dlg.setWindowTitle("Dialog") 9. PyQt5 — QDialog Class
   dlg.setWindowModality(Qt.ApplicationModal)
   dlg.exec_()

if __name__ == '__main__':
   window()

上面的程式碼產生以下輸出。單擊主視窗中的按鈕,對話方塊彈出。

QDialog Class Output

PyQt5 - QMessageBox

**QMessageBox** 是一個常用的模態對話方塊,用於顯示一些資訊訊息,並可以選擇要求使用者透過單擊其上的任何一個標準按鈕來響應。每個標準按鈕都有一個預定義的標題、一個角色並返回一個預定義的十六進位制數字。

與 QMessageBox 類關聯的重要方法和列舉在以下表格中給出:

序號 方法和描述
1

setIcon()

顯示與訊息嚴重性相對應的預定義圖示

  • 提問
  • 資訊
  • 警告
  • 嚴重錯誤
2

setText()

設定要顯示的主要訊息的文字

3

setInformativeText()

顯示附加資訊

4

setDetailText()

對話方塊顯示“詳細資訊”按鈕。單擊它後,將顯示此文字

5

setTitle()

顯示對話方塊的自定義標題

6

setStandardButtons()

要顯示的標準按鈕列表。每個按鈕都與

QMessageBox.Ok 0x00000400

QMessageBox.Open 0x00002000

QMessageBox.Save 0x00000800

QMessageBox.Cancel 0x00400000

QMessageBox.Close 0x00200000

QMessageBox.Yes 0x00004000

QMessageBox.No 0x00010000

QMessageBox.Abort 0x00040000

QMessageBox.Retry 0x00080000

QMessageBox.Ignore 0x00100000

7

setDefaultButton()

將按鈕設定為預設按鈕。如果按下 Enter 鍵,它將發出 clicked 訊號

8

setEscapeButton()

將按鈕設定為在按下 Escape 鍵時視為已單擊

示例

在下面的示例中,頂級視窗上按鈕的 clicked 訊號,連線的函式顯示 messagebox 對話方塊。

msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("This is a message box")
msg.setInformativeText("This is additional information")
msg.setWindowTitle("MessageBox demo")
msg.setDetailedText("The details are as follows:")

setStandardButton() 函式顯示所需的按鈕。

msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

buttonClicked() 訊號連線到一個槽函式,該函式識別訊號源的標題。

msg.buttonClicked.connect(msgbtn)

示例的完整程式碼如下:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QPushButton(w)
   b.setText("Show message!")
   
   b.move(100,50)
   b.clicked.connect(showdialog)
   w.setWindowTitle("PyQt MessageBox demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   msg = QMessageBox()
   msg.setIcon(QMessageBox.Information)
   
   msg.setText("This is a message box")
   msg.setInformativeText("This is additional information")
   msg.setWindowTitle("MessageBox demo")
   msg.setDetailedText("The details are as follows:")
   msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
   msg.buttonClicked.connect(msgbtn)

   retval = msg.exec_()

def msgbtn(i):
   print ("Button pressed is:",i.text())

if __name__ == '__main__':
   window()

以上程式碼產生以下輸出。單擊主視窗的按鈕時,將彈出訊息框:

QMessageBox Output

如果單擊訊息框上的“確定”或“取消”按鈕,則會在控制檯中產生以下輸出:

Button pressed is: OK
Button pressed is: Cancel

PyQt5 - 多文件介面

典型的GUI應用程式可能有多個視窗。選項卡式和小部件允許一次啟用一個視窗。但是,很多時候這種方法可能不太有用,因為其他視窗的檢視被隱藏了。

同時顯示多個視窗的一種方法是將它們建立為獨立視窗。這稱為SDI **(單文件介面)**。這需要更多的記憶體資源,因為每個視窗可能都有自己的菜單系統、工具欄等。

MDI **(多文件介面)**應用程式消耗的記憶體資源較少。子視窗在主容器內相互關聯地排列。容器小部件稱為 **QMdiArea**。

QMdiArea 小部件通常佔據 QMainWindow 物件的中心小部件。此區域中的子視窗是 **QMdiSubWindow** 類的例項。可以將任何 QWidget 設定為 subWindow 物件的內部小部件。MDI 區域中的子視窗可以以級聯或平鋪方式排列。

下表列出了 QMdiArea 類和 QMdiSubWindow 類的重要方法:

序號 方法和描述
1

addSubWindow()

在 MDI 區域中新增小部件作為新的子視窗

2

removeSubWindow()

刪除作為子視窗內部小部件的小部件

3

setActiveSubWindow()

啟用子視窗

4

cascadeSubWindows()

以級聯方式排列 MDiArea 中的子視窗

5

tileSubWindows()

以平鋪方式排列 MDiArea 中的子視窗

6

closeActiveSubWindow()

關閉活動子視窗

7

subWindowList()

返回 MDI 區域中的子視窗列表

8

setWidget()

將 QWidget 設定為 QMdiSubwindow 例項的內部小部件

QMdiArea 物件發出 subWindowActivated() 訊號,而 windowStateChanged() 訊號由 QMdisubWindow 物件發出。

示例

在以下示例中,包含 QMainWindow 的頂級視窗具有選單和 MdiArea。

self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")

file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")

選單的 Triggered() 訊號連線到 windowaction() 函式。

file.triggered[QAction].connect(self.windowaction)

選單的新操作在 MDI 區域中新增一個子視窗,其標題帶有增量編號。

MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()

選單的級聯和平鋪按鈕分別以級聯和平鋪方式排列當前顯示的子視窗。

完整程式碼如下:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):
   count = 0

   def __init__(self, parent = None):
      super(MainWindow, self).__init__(parent)
      self.mdi = QMdiArea()
      self.setCentralWidget(self.mdi)
      bar = self.menuBar()

      file = bar.addMenu("File")
      file.addAction("New")
      file.addAction("cascade")
      file.addAction("Tiled")
      file.triggered[QAction].connect(self.windowaction)
      self.setWindowTitle("MDI demo")

   def windowaction(self, q):
      print ("triggered")
   
      if q.text() == "New":
         MainWindow.count = MainWindow.count+1
         sub = QMdiSubWindow()
         sub.setWidget(QTextEdit())
         sub.setWindowTitle("subwindow"+str(MainWindow.count))
         self.mdi.addSubWindow(sub)
         sub.show()

      if q.text() == "cascade":
         self.mdi.cascadeSubWindows()

      if q.text() == "Tiled":
         self.mdi.tileSubWindows()

def main():
   app = QApplication(sys.argv)
   ex = MainWindow()
   ex.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

執行以上程式碼,以級聯和平鋪形式顯示三個視窗:

Multiple Document Interface Output1

Multiple Document Interface Output2

Multiple Document Interface Output3

PyQt5 - 拖放

**拖放** 功能對於使用者來說非常直觀。它存在於許多桌面應用程式中,使用者可以在其中將物件從一個視窗複製或移動到另一個視窗。

基於 MIME 的拖放資料傳輸基於 **QDrag** 類。**QMimeData** 物件將其資料與其對應的 MIME 型別關聯。它儲存在剪貼簿中,然後用於拖放過程中。

以下 QMimeData 類函式允許方便地檢測和使用 MIME 型別。

測試器 獲取器 設定器 MIME 型別
hasText() text() setText() text/plain
hasHtml() html() setHtml() text/html
hasUrls() urls() setUrls() text/uri-list
hasImage() imageData() setImageData() image/*
hasColor() colorData() setColorData() application/x-color

許多 QWidget 物件支援拖放操作。允許拖動其資料的物件已設定 setDragEnabled(),必須將其設定為 true。另一方面,小部件應該響應拖放事件以便儲存拖入它們的資料。

  • **DragEnterEvent** 提供一個事件,該事件在拖動操作進入目標小部件時傳送到目標小部件。

  • **DragMoveEvent** 用於拖放操作正在進行時。

  • **DragLeaveEvent** 在拖放操作離開小部件時生成。

  • 另一方面,**DropEvent** 在放下操作完成後發生。可以根據條件接受或拒絕事件的建議操作。

示例

在以下程式碼中,**DragEnterEvent** 驗證事件的 MIME 資料是否包含文字。如果是,則接受事件的建議操作,並將文字作為新專案新增到 ComboBox 中。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class combo(QComboBox):
   def __init__(self, title, parent):
      super(combo, self).__init__( parent)
      self.setAcceptDrops(True)

   def dragEnterEvent(self, e):
      print (e)

      if e.mimeData().hasText():
         e.accept()
      else:
         e.ignore()

   def dropEvent(self, e):
      self.addItem(e.mimeData().text())

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      lo = QFormLayout()
      lo.addRow(QLabel("Type some text in textbox and drag it into combo box"))
   
      edit = QLineEdit()
      edit.setDragEnabled(True)
      com = combo("Button", self)
      lo.addRow(edit,com)
      self.setLayout(lo)
      self.setWindowTitle('Simple drag and drop')
def main():
   app = QApplication(sys.argv)
   ex = Example()
   ex.show()
   app.exec_()

if __name__ == '__main__':
   main()

上述程式碼產生以下輸出:

Drag and Drop Output

PyQt5 - 資料庫處理

PyQt5 庫包含 **QtSql** 模組。它是一個詳盡的類系統,用於與許多基於 SQL 的資料庫通訊。它的 **QSqlDatabase** 透過連線物件提供訪問許可權。以下是當前可用的 SQL 驅動程式列表:

序號 驅動程式型別和說明
1

QDB2

IBM DB2

2

QIBASE

Borland InterBase 驅動程式

3

QMYSQL

MySQL 驅動程式

4

QOCI

Oracle 呼叫介面驅動程式

5

QODBC

ODBC 驅動程式(包括 Microsoft SQL Server)

6

QPSQL

PostgreSQL 驅動程式

7

QSQLITE

SQLite 3 版或更高版本

8

QSQLITE2

SQLite 2 版

示例

在本節中,使用靜態方法建立與 SQLite 資料庫的連線:

db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sports.db')

QSqlDatabase 類的其他方法如下:

序號 方法和描述
1

setDatabaseName()

設定要與其建立連線的資料庫的名稱

2

setHostName()

設定安裝資料庫的主機的名稱

3

setUserName()

指定連線的使用者名稱

4

setPassword()

設定連線物件的密碼(如有)

5

commit()

提交事務,如果成功則返回 true

6

rollback()

回滾資料庫事務

7

close()

關閉連線

**QSqlQuery** 類具有執行和操作 SQL 命令的功能。可以執行 DDL 和 DML 型別的 SQL 查詢。第一步是使用以下語句建立 SQlite 資料庫:

db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sportsdatabase.db')

接下來,使用 **QSqlQuery()** 方法獲取 Query 物件,並呼叫其最重要的方法 exec_(),該方法將包含要執行的 SQL 語句的字串作為引數。

query = QtSql.QSqlQuery()
query.exec_("create table sportsmen(id int primary key, " "firstname varchar(20), lastname varchar(20))")

以下指令碼建立了一個 SQLite 資料庫 sports.db,其中包含一個填充了五個記錄的 sportsperson 表。

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def createDB():
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')

   if not db.open():
      msg = QMessageBox()
      msg.setIcon(QMessageBox.Critical)
      msg.setText("Error in Database Creation")
      retval = msg.exec_()
      return False
   query = QSqlQuery()

   query.exec_("create table sportsmen(
      id int primary key, ""firstname varchar(20), lastname varchar(20))")

   query.exec_("insert into sportsmen values(101, 'Roger', 'Federer')")
   query.exec_("insert into sportsmen values(102, 'Christiano', 'Ronaldo')")
   query.exec_("insert into sportsmen values(103, 'Ussain', 'Bolt')")
   query.exec_("insert into sportsmen values(104, 'Sachin', 'Tendulkar')")
   query.exec_("insert into sportsmen values(105, 'Saina', 'Nehwal')")
   return True

if __name__ == '__main__':
   app = QApplication(sys.argv)
   createDB()

要確認 SQLite 資料庫已建立,並在其中的 sportsmen 表中添加了上述記錄,請使用名為 **SQLiteStudio** 的 SQLite GUI 實用程式。

Database Handling

PyQt 中的 **QSqlTableModel** 類是一個高階介面,它提供可編輯的資料模型,用於讀取和寫入單個表中的記錄。此模型用於填充 **QTableView** 物件。它為使用者提供了一個可滾動和可編輯的檢視,可以將其放在任何頂級視窗上。

QSqlTableModel 物件的宣告方式如下:

model = QtSql.QSqlTableModel()

其編輯策略可以設定為以下任何一種:

QSqlTableModel.OnFieldChange 所有更改將立即應用
QSqlTableModel.OnRowChange 當用戶選擇不同的行時,將應用更改
QSqlTableModel.OnManualSubmit 所有更改都將被快取,直到呼叫 submitAll() 或 revertAll() 為止

示例

在以下示例中,sportsperson 表用作模型,策略設定為:

model.setTable('sportsmen') 
model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
   model.select()

QTableView 類是 PyQt 中 Model/View 框架的一部分。QTableView 物件的建立方式如下:

view = QtGui.QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view

此 QTableView 物件和兩個 QPushButton 小部件被新增到頂級 QDialog 視窗。add 按鈕的 clicked() 訊號連線到 addrow(),該函式對模型表執行 insertRow()。

button.clicked.connect(addrow)
def addrow():
   print model.rowCount()
   ret = model.insertRows(model.rowCount(), 1)
   print ret

與 delete 按鈕關聯的槽執行一個 lambda 函式,該函式刪除使用者選擇的行。

btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))

完整程式碼如下:

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def initializeModel(model):
   model.setTable('sportsmen')
   model.setEditStrategy(QSqlTableModel.OnFieldChange)
   model.select()
   model.setHeaderData(0, Qt.Horizontal, "ID")
   model.setHeaderData(1, Qt.Horizontal, "First name")
   model.setHeaderData(2, Qt.Horizontal, "Last name")

def createView(title, model):
   view = QTableView()
   view.setModel(model)
   view.setWindowTitle(title)
   return view

def addrow():
   print (model.rowCount())
   ret = model.insertRows(model.rowCount(), 1)
   print (ret)

def findrow(i):
   delrow = i.row()

if __name__ == '__main__':
   app = QApplication(sys.argv)
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')
   model = QSqlTableModel()
   delrow = -1
   initializeModel(model)

   view1 = createView("Table Model (View 1)", model)
   view1.clicked.connect(findrow)

   dlg = QDialog()
   layout = QVBoxLayout()
   layout.addWidget(view1)

   button = QPushButton("Add a row")
   button.clicked.connect(addrow)
   layout.addWidget(button)

   btn1 = QPushButton("del a row")
   btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
   layout.addWidget(btn1)

   dlg.setLayout(layout)
   dlg.setWindowTitle("Database Demo")
   dlg.show()
   sys.exit(app.exec_())

上述程式碼產生以下輸出:

Database Handling Output

嘗試新增和刪除一些記錄,然後返回到 SQLiteStudio 以確認事務。

PyQt5 - 繪圖 API

PyQt 中的所有 **QWidget** 類都是從 QPaintDevice 類派生的。**QPaintDevice** 是二維空間的抽象,可以使用 QPainter 在其上繪製。繪圖裝置的尺寸以畫素為單位測量,從左上角開始。

**QPainter** 類在小部件和其他可繪製裝置(如印表機)上執行低階繪圖。通常,它用於小部件的繪圖事件中。每當小部件的外觀更新時,就會發生 **QPaintEvent**。

透過呼叫 **begin()** 方法啟用繪圖器,而 **end()** 方法則停用它。在這兩者之間,透過以下表格中列出的適當方法繪製所需的圖案。

序號 方法和描述
1

begin()

開始在目標裝置上繪圖

2

drawArc()

在起始角度和結束角度之間繪製一條弧線

3

drawEllipse()

在矩形內繪製一個橢圓

4

drawLine()

繪製一條線,指定端點座標

5

drawPixmap()

從影像檔案中提取 pixmap,並將其顯示在指定位置

6

drwaPolygon()

使用座標陣列繪製多邊形

7

drawRect()

繪製一個矩形,從左上角座標開始,具有給定的寬度和高度

8

drawText()

在給定座標處顯示文字

9

fillRect()

使用 QColor 引數填充矩形

10

setBrush()

設定用於繪圖的畫筆樣式

11

setPen()

設定用於繪圖的筆的顏色、大小和樣式

示例

在以下程式碼中,使用了 PyQt 的各種繪圖方法。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()
      self.initUI()

   def initUI(self):
      self.text = "hello world"
      self.setGeometry(100,100, 400,300)
      self.setWindowTitle('Draw Demo')
      self.show()

   def paintEvent(self, event):
      qp = QPainter()
      qp.begin(self)
      qp.setPen(QColor(Qt.red))
      qp.setFont(QFont('Arial', 20))
      qp.drawText(10,50, "hello Python")
      qp.setPen(QColor(Qt.blue))
      qp.drawLine(10,100,100,100)
      qp.drawRect(10,150,150,100)
      qp.setPen(QColor(Qt.yellow))
      qp.drawEllipse(100,50,100,50)
      qp.drawPixmap(220,10,QPixmap("pythonlogo.png"))
      qp.fillRect(20,175,130,70,QBrush(Qt.SolidPattern))
      qp.end()

def main():
   app = QApplication(sys.argv)
   ex = Example()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

上述程式碼產生以下輸出:

Database Handling Outputs

PyQt5 - BrushStyle 常量

在本節中,我們將學習畫筆樣式常量。

畫筆樣式常量

以下是畫筆樣式常量:

Qt.NoBrush 無畫筆圖案
Qt.SolidPattern 均勻顏色
Qt.Dense1Pattern 極其密集的畫筆圖案
Qt.HorPattern 水平線
Qt.VerPattern 垂直線
Qt.CrossPattern 交叉水平線和垂直線
Qt.BDiagPattern 向後對角線
Qt.FDiagPattern 向前對角線
Qt.DiagCrossPattern 交叉對角線

預定義的 QColor 樣式

以下是預定義的 QColor 樣式:

Qt.NoBrush 無畫筆圖案
Qt.SolidPattern 均勻顏色
Qt.Dense1Pattern 極其密集的畫筆圖案
Qt.HorPattern 水平線
Qt.VerPattern 垂直線
Qt.CrossPattern 交叉水平線和垂直線
Qt.BDiagPattern 向後對角線
Qt.FDiagPattern 向前對角線
Qt.DiagCrossPattern 交叉對角線

預定義的 QColor 物件

以下是預定義的 QColor 物件:

Qt.white
Qt.black
Qt.red
Qt.darkRed
Qt.green
Qt.darkGreen
Qt.blue
Qt.cyan
Qt.magenta
Qt.yellow
Qt.darkYellow
Qt.gray

PyQt5 - QClipboard

**QClipboard** 類提供對系統範圍的剪貼簿的訪問,該剪貼簿提供了一種簡單的機制,可以在應用程式之間複製和貼上資料。它的作用類似於 **QDrag** 類,並使用類似的資料型別。

QApplication 類具有一個靜態方法 **clipboard()**,它返回對剪貼簿物件的引用。任何型別的 MimeData 都可以複製到剪貼簿或從剪貼簿貼上。

以下是常用剪貼簿類方法:

序號 方法和描述
1

clear()

清除剪貼簿內容

2

setImage()

將 QImage 複製到剪貼簿

3

setMimeData()

將 MIME 資料設定到剪貼簿

4

setPixmap()

將 Pixmap 物件複製到剪貼簿

5

setText()

將 QString 複製到剪貼簿

6

text()

從剪貼簿檢索文字

與剪貼簿物件關聯的訊號是:

序號 方法和說明
1

dataChanged()

每當剪貼簿資料更改時

示例

在以下示例中,兩個 TextEdit 物件和兩個 Pushbuttons 被新增到頂級視窗。

首先,例項化剪貼簿物件。textedit 物件的 Copy() 方法將資料複製到系統剪貼簿。單擊“貼上”按鈕時,它會獲取剪貼簿資料並將其貼上到另一個 textedit 物件中。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      hbox = QVBoxLayout()
      self.edit1=QTextEdit()
      hbox.addWidget(self.edit1)
      self.btn1=QPushButton("Copy")
      hbox.addWidget(self.btn1)
      self.edit2=QTextEdit()
      self.btn2=QPushButton("Paste")
      hbox.addWidget(self.edit2)
      hbox.addWidget(self.btn2)
      self.btn1.clicked.connect(self.copytext)
      self.btn2.clicked.connect(self.pastetext)
      self.setLayout(hbox)
      
      self.setGeometry(300, 300, 300, 200)
      self.setWindowTitle('Clipboard')
      self.show()
      
   def copytext(self):

      #clipboard.setText(self.edit1.copy())
      self.edit1.copy()
      print (clipboard.text())

      msg=QMessageBox()
      msg.setText(clipboard.text()+" copied on clipboard")
      msg.exec_()

   def pastetext(self):
      self.edit2.setText(clipboard.text())

app = QApplication(sys.argv)
clipboard=app.clipboard()
ex = Example()
ex.setWindowTitle("clipboard Example")
sys.exit(app.exec_())

上述程式碼產生以下輸出:

QClipboard

PyQt5 - QPixmap 類

QPixmap 類提供影像的螢幕外表示。它可以用作 QPaintDevice 物件,也可以載入到另一個小部件中,通常是標籤或按鈕。

Qt API 還有另一個類似的類QImage,它針對 I/O 和其他畫素操作進行了最佳化。另一方面,Pixmap 針對螢幕顯示進行了最佳化。這兩種格式可以相互轉換。

可以讀取到 QPixmap 物件中的影像檔案型別如下:

BMP Windows 點陣圖
GIF 圖形交換格式(可選)
JPG 聯合影像專家組
JPEG 聯合影像專家組
PNG 行動式網路圖形
PBM 行動式點陣圖
PGM 行動式灰度圖
PPM 行動式畫素圖
XBM X11 點陣圖
XPM X11 畫素圖

以下方法可用於處理 QPixmap 物件:

序號 方法和描述
1

copy()

從 QRect 物件複製畫素圖資料

2

fromImage()

將 QImage 物件轉換為 QPixmap

3

grabWidget()

從給定的小部件建立畫素圖

4

grabWindow()

建立視窗中資料的畫素圖

5

load()

載入影像檔案作為畫素圖

6

save()

將 QPixmap 物件儲存為檔案

7

toImage()

將 QPixmap 轉換為 QImage

QPixmap 最常見的用途是在標籤/按鈕上顯示影像。

示例

以下示例演示了使用setPixmap()方法在 QLabel 上顯示影像。

完整程式碼如下:

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   l1 = QLabel()
   l1.setPixmap(QPixmap("python.png"))

   vbox = QVBoxLayout()
   vbox.addWidget(l1)
   win.setLayout(vbox)
   win.setWindowTitle("QPixmap Demo")
   win.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   window()

上述程式碼產生以下輸出:

QPixmap Class
廣告
© . All rights reserved.