Python桌面應(yīng)用開發(fā)實戰(zhàn)之PyQt的安裝使用
引言:桌面應(yīng)用開發(fā)三大框架介紹
Tkinter:優(yōu)勢是免安裝、相對簡單,缺點是功能少,無界面設(shè)計工具。
PyQT:使用率高,功能最為強大,代碼可維護(hù)性和易讀性高。
WxPython:介于Tkinter和PyQT之間,相當(dāng)于壓縮版QT。
總結(jié):三種框架各有優(yōu)劣,有時間可以全部學(xué)習(xí),并不復(fù)雜。如果只選一種,這里推薦使用最主流、最保值、上限最高的PyQT。
一、PyQT介紹
Qt:Qt是一個跨平臺的C++圖形用戶界面應(yīng)用程序開發(fā)框架,目前已成為最強大,最受歡迎的跨平臺GUI庫之一。Qt不僅可以開發(fā)GUI程序,也可開發(fā)非GUI程序,比如控制臺工具和服務(wù)程序。
PyQt:PyQt是Qt的Python封裝,提供Qt類和函數(shù)的API。
PyQt6的官網(wǎng):https://www.riverbankcomputing.co.uk/news
可以參考的中文手冊:https://www.syrr.cn/news/415861.html?action=onClick
PyQt常用模塊:
QtWidgets模塊:包含應(yīng)用程序類、窗口類、控件類和組件類
QtGui模塊:包含和gui相關(guān)的功能,例如用于事件處理、圖像處理、字體和顏色類等
QtCore模塊:包含核心的非gui功能,例如線程、定時器、日期時間類、文件類等
二、安裝
安裝: pip install PyQt6
檢查安裝版本(進(jìn)入python命令行):
from PyQt6.QtCore import QT_VERSION_STR, PYQT_VERSION_STR QT_VERSION_STR, PYQT_VERSION_STR
三、使用教程
(1)基礎(chǔ)窗口
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
from PyQt6.QtGui import QIcon, QFont
from PyQt6.QtCore import Qt
#從QWidget類派生的桌面應(yīng)用程序窗口類
class MyWindow(QWidget): #QtWidgets模塊:包含應(yīng)用程序類、窗口類、控件類和組件類
#構(gòu)造函數(shù)
def __init__(self):
super().__init__() # 調(diào)用基類的構(gòu)造函數(shù)
self.setWindowTitle('Hello World') # 設(shè)置標(biāo)題
#self.setWindowIcon(QIcon('res/qt.png')) # 可以設(shè)置圖標(biāo)
lab = QLabel('Hello World', self) # 實例化標(biāo)簽
lab.resize(320,160) # 設(shè)置標(biāo)簽大小
lab.setFont(QFont('Arial', 32, QFont.Weight.Bold)) # 設(shè)置字體字號
lab.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本在標(biāo)簽內(nèi)居中
self.show() # 顯示窗口
if __name__ == '__main__':
app = QApplication(sys.argv) # 創(chuàng)建應(yīng)用程序,接收來自命令行的參數(shù)列表
win = MyWindow() # 創(chuàng)建窗口,這里初始化的時候不需要QWidget入?yún)?
sys.exit(app.exec()) # 應(yīng)用程序主循環(huán)結(jié)束后,調(diào)用sys.exit()方法清理現(xiàn)場執(zhí)行后結(jié)果如下:

(2)分區(qū)布局窗口(類似于html中div的使用)
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QHBoxLayout, QVBoxLayout
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('分區(qū)布局')
self.setGeometry(400, 300, 320, 160) # 設(shè)置窗位置和大小
lab_acc = QLabel('賬號:') # 實例化標(biāo)簽
account = QLineEdit() #單行文本編輯框
account.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本在標(biāo)簽內(nèi)居中
lab_pw = QLabel('密碼:')
passwd = QLineEdit()
passwd.setAlignment(Qt.AlignmentFlag.AlignCenter)
passwd.setEchoMode(QLineEdit.EchoMode.Password) # 不顯示密碼
btn_ok = QPushButton('確定') #按鈕
btn_cancel = QPushButton('取消')
# 使用水平布局管理器布局lab_acc控件和account控件,左右留白10像素
hbox_acc = QHBoxLayout() #水平布局管理器
hbox_acc.addSpacing(10) #水平布局間隔
hbox_acc.addWidget(lab_acc) #將實例化標(biāo)簽賬號放入
hbox_acc.addWidget(account) #將#單行文本編輯框放入
hbox_acc.addSpacing(10)
# 使用水平布局管理器布局lab_pw控件和passwd控件,左右留白10像素
hbox_pw = QHBoxLayout() #垂直布局管理器
hbox_pw.addSpacing(10)
hbox_pw.addWidget(lab_pw)
hbox_pw.addWidget(passwd)
hbox_pw.addSpacing(10)
# 使用水平布局管理器布局btn_ok控件和btn_cancel控件
hbox_btn = QHBoxLayout() # 水平布局管理器
hbox_btn.addStretch(5) # 設(shè)置左側(cè)拉伸因子
hbox_btn.addWidget(btn_ok) # 添加btn_ok控件
hbox_btn.addWidget(btn_cancel) # 添加btn_cancel控件
hbox_btn.addStretch(1) # 設(shè)置右側(cè)拉伸因子
# 使用垂直布局管理器布局上面3個水平布局管理器
vbox = QVBoxLayout()
vbox.addSpacing(10)
vbox.addLayout(hbox_acc)
vbox.addSpacing(5)
vbox.addLayout(hbox_pw)
vbox.addStretch(1)
vbox.addLayout(hbox_btn)
vbox.addSpacing(10)
# 將垂直布局管理器應(yīng)用到窗口
self.setLayout(vbox)
self.show() # 顯示窗口
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())執(zhí)行后結(jié)果如下:

(3)柵格布局窗口(類似于html中的table)
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout
from PyQt6.QtGui import QIcon
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('柵格布局')
self.initUI() # 初始化界面
self.show() # 顯示窗口
def initUI(self): #創(chuàng)建一個5*5的數(shù)組,后面會逐一放入柵格
keys = [
['(', ')', 'Back', 'Clear'],
['7', '8', '9', '/'],
['4', '5', '6', '*'],
['1', '2', '3', '-'],
['0', '.', '=', '+']
]
grid = QGridLayout() # 創(chuàng)建網(wǎng)格布局管理器
self.setLayout(grid) # 將網(wǎng)格布局管理器應(yīng)用到窗口
for i in range(5):
for j in range(4):
button = QPushButton(keys[i][j])
grid.addWidget(button, i, j) #將元素放入柵格,i是橫坐標(biāo),j是縱坐標(biāo)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())執(zhí)行后結(jié)果如下:

(4)表單布局窗口(類似于html中的form)
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QFormLayout
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('表單布局')
self.setGeometry(400, 300, 320, 200) # 設(shè)置窗位置和大小
form = QFormLayout() # 創(chuàng)建表單布局管理器
form.setLabelAlignment(Qt.AlignmentFlag.AlignRight) #設(shè)置標(biāo)簽右對齊(默認(rèn)左對齊)
name = QLineEdit() #單行文本編輯框
mobile = QLineEdit()
passwd = QLineEdit()
addr = QLineEdit()
form.addRow('姓名', name) #將文本放入form中
form.addRow('移動電話', mobile)
form.addRow('密碼', passwd)
form.addRow('通訊地址', addr)
name.setPlaceholderText("請輸入姓名") #設(shè)置placeholder灰體默認(rèn)值
mobile.setPlaceholderText("請輸入移動電話")
passwd.setPlaceholderText("請輸入密碼")
addr.setPlaceholderText("請輸入通訊地址")
name.setEchoMode(QLineEdit.EchoMode.Normal) #EchoMode為Normal:顯示輸入的字符。這是默認(rèn)值
mobile.setEchoMode(QLineEdit.EchoMode.NoEcho) #EchoMode為NoEcho:不顯示任何東西。這可能適用于連密碼長度都應(yīng)該保密的密碼。
passwd.setEchoMode(QLineEdit.EchoMode.Password) #EchoMode為Password:顯示平臺相關(guān)的密碼掩碼字符,而不是實際輸入的字符。
addr.setEchoMode(QLineEdit.EchoMode.PasswordEchoOnEdit) #EchoMode為PasswordEchoOnEdit:在編輯時顯示輸入的字符,否則顯示與密碼相同的字符。
btn_ok = QPushButton('確定')
vbox = QVBoxLayout() #垂直布局管理器布局
vbox.addSpacing(10)
vbox.addLayout(form)
vbox.addStretch(1)
vbox.addWidget(btn_ok, alignment=Qt.AlignmentFlag.AlignCenter)
vbox.addSpacing(10)
# 將垂直布局管理器應(yīng)用到窗口
self.setLayout(vbox)
self.show() # 顯示窗口
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())執(zhí)行后結(jié)果如下:

(5)事件函數(shù)與事件過濾器
常用的事件函數(shù)如下:
keyPressEvent(): 鍵盤按下事件 keyReleaseEvent(): 鍵盤釋放事件
mouseDoubleClickEvent(): 鼠標(biāo)雙擊事件
mouseMoveEvent(): 鼠標(biāo)移動事件
mousePressEvent(): 鼠標(biāo)按下事件
mouseReleaseEvent(): 鼠標(biāo)釋放事件
timerEvent(): 定時器事件
dragEnterEvent(): 拖拽進(jìn)入當(dāng)前窗口事件
dragLeaveEvent(): 拖拽離開當(dāng)前窗口事件
dragMoveEvent(): 拖拽移動事件
enterEvent(): 進(jìn)入窗口區(qū)域事件
leaveEvent(): 離開窗口區(qū)域事件
closeEvent(): 關(guān)閉窗口事件
示例1–事件函數(shù):
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout
from PyQt6.QtCore import Qt
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('事件和事件函數(shù)')
self.setGeometry(400, 300, 320, 80)
self.initUI() # 初始化界面
self.show()
def initUI(self):
lab = QLabel('按Esc鍵關(guān)閉窗口')
box = QHBoxLayout()
box.addStretch(1)
box.addWidget(lab)
box.addStretch(1)
self.setLayout(box)
#重寫"鍵盤按下事件"的事件函數(shù),指定ESC鍵作為觸發(fā)事件的鍵(如果不指定就是所有鍵都會觸發(fā)事件)
def keyPressEvent(self, evt):
if evt.key() == Qt.Key.Key_Escape.value: #Qt.Key對應(yīng)的鍵盤下面有對照表
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())執(zhí)行后結(jié)果如下:

Qt.Key對應(yīng)的鍵盤對照如下:
Qt::Key_Escape 0x01000000 Esc鍵
Qt::Key_Tab 0x01000001 Tab鍵 Qt::Key_Backtab 0x01000002 Tab補全鍵
Qt::Key_Backspace 0x01000003 退格鍵 Qt::Key_Return 0x01000004 Return鍵
Qt::Key_Enter 0x01000005 回車鍵 Qt::Key_Insert 0x01000006 Insert鍵
Qt::Key_Delete 0x01000007 Delete鍵 Qt::Key_Pause 0x01000008 暫停鍵
Qt::Key_Print 0x01000009 截圖鍵 Qt::Key_SysReq 0x0100000a PrtSc
Qt::Key_Clear 0x0100000b 清除鍵 Qt::Key_Home 0x01000010 Home鍵
Qt::Key_End 0x01000011 End鍵 Qt::Key_Left 0x01000012 ←
Qt::Key_Up 0x01000013 ↑ Qt::Key_Right 0x01000014 →
Qt::Key_Down 0x01000015 ↓ Qt::Key_PageUp 0x01000016 上頁
Qt::Key_PageDown 0x01000017 下頁 Qt::Key_Shift 0x01000020 Shift鍵
Qt::Key_Control 0x01000021 Ctrl鍵 Qt::Key_Alt 0x01000023 Alt鍵
Qt::Key_AltGr 0x01001103 右側(cè)Alt Qt::Key_CapsLock 0x01000024 大寫鍵
Qt::Key_NumLock 0x01000025 NumLock Qt::Key_ScrollLock 0x01000026 滾動鎖定
Qt::Key_F1 0x01000030 F1~F12 Qt::Key_F2 0x01000031
Qt::Key_F3 0x01000032 Qt::Key_F4 0x01000033 Qt::Key_F5 0x01000034
Qt::Key_F6 0x01000035 Qt::Key_F7 0x01000036 Qt::Key_F8 0x01000037
Qt::Key_F9 0x01000038 Qt::Key_F10 0x01000039
Qt::Key_F11 0x0100003a Qt::Key_F12 0x0100003b
Qt::Key_Menu 0x01000055 菜單鍵 Qt::Key_Help 0x01000058 Help鍵
Qt::Key_Space 0x20 空格鍵 Qt::Key_Exclam 0x21 ! Qt::Key_QuoteDbl 0x22 引用
Qt::Key_NumberSign 0x23 # Qt::Key_Dollar 0x24 $ Qt::Key_Percent 0x25 %
Qt::Key_Ampersand 0x26 & Qt::Key_Apostrophe 0x27 分詞符" ’ "
Qt::Key_ParenLeft 0x28 ( Qt::Key_ParenRight 0x29 )
Qt::Key_Asterisk 0x2a * Qt::Key_Plus 0x2b + Qt::Key_Comma 0x2c ,
Qt::Key_Minus 0x2d - Qt::Key_Period 0x2e 。 Qt::Key_Slash 0x2f /
Qt::Key_0 0x30 數(shù)字0~9 Qt::Key_1 0x31 Qt::Key_2 0x32 Qt::Key_3 0x33
Qt::Key_4 0x34 Qt::Key_5 0x35 Qt::Key_6 0x36 Qt::Key_7 0x37
Qt::Key_8 0x38 Qt::Key_9 0x39 Qt::Key_Colon 0x3a :
Qt::Key_Semicolon 0x3b ; Qt::Key_Less 0x3c < Qt::Key_Equal 0x3d 等于
Qt::Key_Greater 0x3e > Qt::Key_Question 0x3f ? Qt::Key_At 0x40 @
Qt::Key_A 0x41 字母鍵 Qt::Key_B 0x42 Qt::Key_C 0x43 Qt::Key_D 0x44
Qt::Key_E 0x45 Qt::Key_F 0x46 Qt::Key_G 0x47 Qt::Key_H 0x48
Qt::Key_I 0x49 Qt::Key_J 0x4a Qt::Key_K 0x4b Qt::Key_L 0x4c
Qt::Key_M 0x4d Qt::Key_N 0x4e Qt::Key_O 0x4f Qt::Key_P 0x50
Qt::Key_Q 0x51 Qt::Key_R 0x52 Qt::Key_S 0x53 Qt::Key_T 0x54
Qt::Key_U 0x55 Qt::Key_V 0x56 Qt::Key_W 0x57 Qt::Key_X 0x58
Qt::Key_Y 0x59 Qt::Key_Z 0x5a Qt::Key_BracketLeft 0x5b [
Qt::Key_Backslash 0x5c \ Qt::Key_BracketRight 0x5d ]
Qt::Key_AsciiCircum 0x5e ^ Qt::Key_Underscore 0x5f _
Qt::Key_QuoteLeft 0x60 “ Qt::Key_BraceLeft 0x7b { Qt::Key_Bar 0x7c |
Qt::Key_BraceRight 0x7d } Qt::Key_AsciiTilde 0x7e ~
Qt::Key_nobreakspace 0x0a0 不換行空格 Qt::Key_exclamdown 0x0a1 !
示例2–事件過濾器:
(在剛才的基礎(chǔ)上增加導(dǎo)入QEvent,添加eventFilter方法,并在最后執(zhí)行installEventFilter方法)
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout
from PyQt6.QtCore import Qt, QEvent
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('事件和事件函數(shù)')
self.setGeometry(400, 300, 320, 80)
self.initUI() # 初始化界面
self.show()
def initUI(self):
lab = QLabel('按Esc鍵關(guān)閉窗口')
box = QHBoxLayout()
box.addStretch(1)
box.addWidget(lab)
box.addStretch(1)
self.setLayout(box)
#重寫"鍵盤按下事件"的事件函數(shù),指定ESC鍵作為觸發(fā)事件的鍵(如果不指定就是所有鍵都會觸發(fā)事件)
def keyPressEvent(self, evt):
if evt.key() == Qt.Key.Key_Escape.value:
self.close()
#事件過濾方法
def eventFilter(self, objwatched, evt):
if evt.type() == QEvent.Type.KeyPress.value:
print('忽略按鍵事件')
return True
return super().eventFilter(objwatched, evt)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
app.installEventFilter(win) #安裝本對象的事件過濾器
sys.exit(app.exec())此時按Esc鍵無法關(guān)閉窗口
(6)信號和槽
介紹:信號(signal)和槽(slot)是Qt的核心機制,也是在PyQt編程中對象之間進(jìn)行通信的機制。在創(chuàng)建事件循環(huán)之后,通過建立信號和槽的連接就可以實現(xiàn)對象之間的通信。當(dāng)信號發(fā)射(emit)時,連接的槽函數(shù)將會自動執(zhí)行。
示例1–使用內(nèi)置的信號和槽:
import sys
from PyQt6.QtWidgets import QPushButton, QMessageBox, QApplication, QWidget
class Window(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('按鈕事件')
self.resize(300, 200)
self.btn = QPushButton('按鈕', self)
self.init_ui()
def init_ui(self):
self.btn.resize(100, 30)
self.btn.move(100, 50) #按鈕的位置
self.btn.clicked.connect(self.btn_hand) #使用connect綁定事件,點擊按鈕時觸發(fā)
self.close()
def btn_hand(self):
widget = QWidget()
QMessageBox.information(widget, 'Pop messgae', 'OK') #觸發(fā)的事件時彈出會話框
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())運行結(jié)果如下:

示例2–自定義信號和槽函數(shù)示例:
import sys
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtWidgets import *
class WinForm(QWidget):
# 自定義信號,不帶參數(shù)
button_clicked_signal = pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('自定義信號和槽函數(shù)示例')
self.resize(300, 150)
# 接收信號,連接到自定義槽函數(shù)
self.button_clicked_signal.connect(self.pop_message)
def pop_message(self):
QMessageBox.information(self, 'Pop messgae', 'OK')
def mousePressEvent(self, event): # 重寫鼠標(biāo)按下事件
super().mousePressEvent(event)
if event.button() == Qt.MouseButton.LeftButton: # 當(dāng)鼠標(biāo)左鍵單擊時
self.button_clicked_signal.emit() # 發(fā)射信號
if __name__ == '__main__':
app = QApplication(sys.argv)
win = WinForm()
win.show()
sys.exit(app.exec())運行結(jié)果如下:

示例三–結(jié)合信號和槽進(jìn)行多線程操作:
import sys
from PyQt6.QtWidgets import QApplication,QMainWindow,QWidget,QProgressBar,QVBoxLayout,QPushButton
from PyQt6.QtCore import QThread,QObject,pyqtSignal,Qt
#線程函數(shù)
class CountSever(QObject):
_isrun = False #線程是否運行全局變量
countupdate = pyqtSignal() #自定義信號
#構(gòu)造函數(shù)
def __init__(self, interval) -> None: #-> None 表示返回的數(shù)值類型不受限制
super().__init__()
self.interval = interval #執(zhí)行間隔,初始化的時候在構(gòu)造函數(shù)中指定,如self.cs1 = CountSever(100)代表每100ms執(zhí)行一次
#判斷單個線程是否運行
def isrun(self,value:bool):
self._isrun = value
#線程運行函數(shù)
def run(self):
while True:
pass
while self._isrun:
self.countupdate.emit() #當(dāng)線程運行時發(fā)射自定義信號
QThread.msleep(self.interval) #設(shè)置線程執(zhí)行間隔
#進(jìn)度條主界面,QMainWindow--頂層窗口類,重量級控件。
class MainWindow(QMainWindow):
countstart = pyqtSignal(bool) #自定義信號對象
def __init__(self) -> None: #-> None 表示返回的數(shù)值類型不受限制
super().__init__()
self.init_ui()
self.setcenter() #調(diào)用下面的居中方法
def init_ui(self):
self.setWindowTitle("線程刷新進(jìn)度條")
self.resize(400, 300)
self.main_widget = QWidget()
self.setCentralWidget(self.main_widget) #居中展示
self.main_layout = QVBoxLayout() ##垂直布局管理器布局
self.main_layout.setAlignment(Qt.AlignmentFlag.AlignHCenter)
self.main_widget.setLayout(self.main_layout)
#設(shè)置四個進(jìn)度條
self.progress_1 = QProgressBar(self) #ProgressBar提供了一個水平或垂直的進(jìn)度條,可以使用setMinimum()和setMaximum指定最小和最大步數(shù)
self.progress_1.setRange(0,100)
self.main_layout.addWidget(self.progress_1) #在頁面布局中添加進(jìn)度條控件
self.progress_2 = QProgressBar(self)
self.progress_2.setRange(0,100)
self.main_layout.addWidget(self.progress_2)
self.main_layout.addStretch(1)
self.progress_3 = QProgressBar(self)
self.progress_3.setRange(0, 100)
self.main_layout.addWidget(self.progress_3)
self.progress_4 = QProgressBar(self)
self.progress_4.setRange(0, 100)
self.main_layout.addWidget(self.progress_4)
self.btn_start = QPushButton("Start")
self.btn_start.setFixedSize(120,30)
#點擊start按鈕觸發(fā)下面定義的start方法,start方法會根據(jù)當(dāng)前按鈕發(fā)送True/Flase的信號給countstart自定義對象,然后這個True/Flase決定了isrun的結(jié)果,決定線程是否運行
self.btn_start.clicked.connect(self.start)
self.main_layout.addWidget(self.btn_start) #將開始按鈕放入布局中
self.main_layout.setAlignment(self.btn_start,Qt.AlignmentFlag.AlignCenter)
# thread
self.cs1 = CountSever(100) #每100ms執(zhí)行一次
#自定義信號綁定下面的事件countupdate,下面的 self.progress_1.setValue(self.progress_1.value() + 1)表示執(zhí)行一次進(jìn)度條progress_1的值加一,range值是0-100,加到100便會停止線程
self.cs1.countupdate.connect(self.countupdate)
self.countstart.connect(self.cs1.isrun) #自定義信號綁定下面的事件:判斷線程是否在運行
self.th1 = QThread()
self.cs1.moveToThread(self.th1) #moveToThread函數(shù):給多個任務(wù)各分配一個線程去執(zhí)行
self.th1.started.connect(self.cs1.run) #QThread提供了QThread::started()(當(dāng)線程開始時發(fā)射)和QThread::finished()(在線程運行結(jié)束后發(fā)射)兩個信號
self.th1.start() #線程開始執(zhí)行
self.cs2 = CountSever(150)
self.cs2.countupdate.connect(self.countupdate)
self.countstart.connect(self.cs2.isrun)
self.th2 = QThread()
self.cs2.moveToThread(self.th2)
self.th2.started.connect(self.cs2.run)
self.th2.start()
self.cs3 = CountSever(1000)
self.cs3.countupdate.connect(self.countupdate)
self.countstart.connect(self.cs3.isrun)
self.th3 = QThread()
self.cs3.moveToThread(self.th3)
self.th3.started.connect(self.cs3.run)
self.th3.start()
self.cs4 = CountSever(1500)
self.cs4.countupdate.connect(self.countupdate)
self.countstart.connect(self.cs4.isrun)
self.th4 = QThread()
self.cs4.moveToThread(self.th4)
self.th4.started.connect(self.cs4.run)
self.th4.start()
def setcenter(self): #界面居中顯示
win_rect = self.frameGeometry()
screen_center = self.screen().availableGeometry().center()
win_rect.moveCenter(screen_center)
self.move(win_rect.topLeft())
#start方法會根據(jù)當(dāng)前按鈕發(fā)送True/Flase的信號給countstart自定義對象,然后這個True/Flase決定了isrun的結(jié)果,決定線程是否運行
def start(self):
if self.btn_start.text() == "Start":
self.countstart.emit(True)
self.btn_start.setText("Pause")
elif self.btn_start.text() == "Pause":
self.countstart.emit(False)
self.btn_start.setText("Start")
def countupdate(self):
if self.sender() == self.cs1:
self.progress_1.setValue(self.progress_1.value() + 1) #表示執(zhí)行一次進(jìn)度條progress_1的值加一,range值是0-100,加到100便會停止線程
elif self.sender() == self.cs2:
self.progress_2.setValue(self.progress_2.value() + 1)
elif self.sender() == self.cs3:
self.progress_3.setValue(self.progress_3.value() + 1)
elif self.sender() == self.cs4:
self.progress_4.setValue(self.progress_4.value() + 1)
if __name__ == "__main__":
""" 主程序運行 """
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.show()
sys.exit(app.exec())運行結(jié)果如下:

四、實戰(zhàn)示例
(1)狀態(tài)欄(追蹤鼠標(biāo)移動軌跡)
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QHBoxLayout
from PyQt6.QtGui import QIcon, QPixmap
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('狀態(tài)欄')
self.initUI() # 初始化界面
self.center() # 窗口在屏幕上居中
self.show() # 顯示窗口
def center(self):
win_rect = self.frameGeometry() # 窗口矩形(QRect類)
scr_center = self.screen().availableGeometry().center() # 屏幕中心
win_rect.moveCenter(scr_center) # 窗口矩形中心移動到屏幕中心
self.move(win_rect.topLeft()) # 移動窗口和窗口矩形重合
def initUI(self):
self.resize(400, 300)
lab = QLabel()
box = QHBoxLayout()
box.addWidget(lab)
self.main_widget = QWidget()
self.main_widget.setLayout(box)
self.setCentralWidget(self.main_widget)
# 對于需要處理鼠標(biāo)移動事件的部件,開啟感知鼠標(biāo)移動軌跡
lab.setMouseTracking(True)
self.main_widget.setMouseTracking(True)
self.setMouseTracking(True)
self.sbar = self.statusBar() # 返回窗口狀態(tài)欄
self.mouth_info = QLabel() # 顯示鼠標(biāo)坐標(biāo)的標(biāo)簽
self.sbar.addPermanentWidget(self.mouth_info) # 將顯示鼠標(biāo)坐標(biāo)的標(biāo)簽添加到狀態(tài)欄
self.sbar.addPermanentWidget(QLabel('版權(quán)所有 ')) # 將版權(quán)聲明添加到狀態(tài)欄
self.sbar.showMessage('準(zhǔn)備就緒', 3000) # 顯示消息,3秒鐘后消失
def enterEvent(self, evt):
"""響應(yīng)鼠標(biāo)進(jìn)入窗口事件"""
#QStatusBar.showMessage(str, msecs=0):顯示str消息持續(xù)msecs毫秒。如果msecs為0(默認(rèn)),則消息將一直顯示,直到調(diào)用clearMessage()或再次showMessage以更改消息。
self.sbar.showMessage('鼠標(biāo)進(jìn)入', 3000)
def leaveEvent(self, evt):
"""響應(yīng)鼠標(biāo)離開窗口事件"""
self.sbar.showMessage('鼠標(biāo)離開', 3000)
self.mouth_info.setText('')
def mouseMoveEvent(self, evt):
"""響應(yīng)鼠標(biāo)移動事件"""
pos = evt.position()
self.mouth_info.setText('x=%d, y=%d '%(pos.x(), pos.y()))
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())運行結(jié)果如下:

(2)菜單欄
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QIcon, QAction
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('菜單欄')
self.resize(250, 150)
self.initUI() # 初始化界面
self.center() # 窗口在屏幕上居中
self.show() # 顯示窗口
def center(self):
win_rect = self.frameGeometry() # 窗口矩形(QRect類)
scr_center = self.screen().availableGeometry().center() # 屏幕中心
win_rect.moveCenter(scr_center) # 窗口矩形中心移動到屏幕中心
self.move(win_rect.topLeft()) # 移動窗口和窗口矩形重合
def initUI(self):
self.sbar = self.statusBar() # 返回窗口狀態(tài)欄
#openAction = QAction(QIcon('res/open_mso.png'), '&打開', self) 可以在第一個參數(shù)設(shè)置圖片
openAction = QAction('&打開', self)
openAction.setShortcut('Ctrl+O') #設(shè)置快捷鍵
openAction.setStatusTip('打開文件') #設(shè)置狀態(tài)提示文字
openAction.triggered.connect(lambda : print('此處彈出打開文件的對話框'))
saveAction = QAction('&保存', self)
saveAction.setShortcut('Ctrl+S')
saveAction.setStatusTip('保存文件')
saveAction.triggered.connect(lambda : print('此處彈出保存文件的對話框'))
quitAction = QAction('&退出', self)
quitAction.setShortcut('Ctrl+Q')
quitAction.setStatusTip('退出程序')
quitAction.triggered.connect(self.close)
singleAction = QAction('&個人權(quán)限', self)
singleAction.setStatusTip('個人權(quán)限')
singleAction.triggered.connect(lambda : print('此處響應(yīng)個人權(quán)限操作'))
groupAction = QAction('&組權(quán)限', self)
groupAction.setStatusTip('組權(quán)限')
groupAction.triggered.connect(lambda : print('此處響應(yīng)組權(quán)限操作'))
mb = self.menuBar()
fm = mb.addMenu('&文件')
fm.addAction(openAction)
fm.addAction(saveAction)
fm.addSeparator()
subMenu = fm.addMenu('權(quán)限')
subMenu.addAction(singleAction)
subMenu.addAction(groupAction)
fm.addSeparator()
fm.addAction(quitAction)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())運行結(jié)果如下:

(3)工具欄
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QToolBar
from PyQt6.QtGui import QIcon, QAction
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('工具欄')
self.resize(400, 300)
self.initUI() # 初始化界面
self.center() # 窗口在屏幕上居中
self.show() # 顯示窗口
def center(self):
win_rect = self.frameGeometry() # 窗口矩形(QRect類)
scr_center = self.screen().availableGeometry().center() # 屏幕中心
win_rect.moveCenter(scr_center) # 窗口矩形中心移動到屏幕中心
self.move(win_rect.topLeft()) # 移動窗口和窗口矩形重合
def initUI(self):
self.sbar = self.statusBar() # 返回窗口狀態(tài)欄
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QToolBar
from PyQt6.QtGui import QIcon, QAction
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('工具欄')
self.resize(400, 300)
self.initUI() # 初始化界面
self.center() # 窗口在屏幕上居中
self.show() # 顯示窗口
def center(self):
win_rect = self.frameGeometry() # 窗口矩形(QRect類)
scr_center = self.screen().availableGeometry().center() # 屏幕中心
win_rect.moveCenter(scr_center) # 窗口矩形中心移動到屏幕中心
self.move(win_rect.topLeft()) # 移動窗口和窗口矩形重合
def initUI(self):
self.sbar = self.statusBar() # 返回窗口狀態(tài)欄
#openAction = QAction(QIcon('res/open_mso.png'), '&打開', self) 可添加圖標(biāo)圖片
openAction = QAction('&打開', self)
openAction.setShortcut('Ctrl+O')
openAction.setStatusTip('打開文件')
openAction.triggered.connect(lambda : print('此處彈出打開文件的對話框'))
saveAction = QAction('&保存', self)
saveAction.setShortcut('Ctrl+S')
saveAction.setStatusTip('保存文件')
saveAction.triggered.connect(lambda : print('此處彈出保存文件的對話框'))
quitAction = QAction('&退出', self)
quitAction.setShortcut('Ctrl+Q')
quitAction.setStatusTip('退出程序')
quitAction.triggered.connect(self.close)
singleAction = QAction('&個人權(quán)限', self)
singleAction.setStatusTip('個人權(quán)限')
singleAction.triggered.connect(lambda : print('此處響應(yīng)個人權(quán)限操作'))
groupAction = QAction('&組權(quán)限', self)
groupAction.setStatusTip('組權(quán)限')
groupAction.triggered.connect(lambda : print('此處響應(yīng)組權(quán)限操作'))
mb = self.menuBar()
fm = mb.addMenu('&文件')
fm.addAction(openAction)
fm.addAction(saveAction)
fm.addSeparator() #添加分割線
subMenu = fm.addMenu('權(quán)限')
subMenu.addAction(singleAction)
subMenu.addAction(groupAction)
fm.addSeparator()
fm.addAction(quitAction)
tb = self.addToolBar('文件')
tb.addAction(openAction)
tb.addAction(saveAction)
tb = self.addToolBar('退出')
tb.addAction(quitAction)
tb = QToolBar(self)
tb.setObjectName('權(quán)限')
self.addToolBar(Qt.ToolBarArea.RightToolBarArea, tb)
tb.addAction(singleAction)
tb.addAction(groupAction)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())
openAction = QAction('&打開', self)
openAction.setShortcut('Ctrl+O')
openAction.setStatusTip('打開文件')
openAction.triggered.connect(lambda : print('此處彈出打開文件的對話框'))
saveAction = QAction('&保存', self)
saveAction.setShortcut('Ctrl+S')
saveAction.setStatusTip('保存文件')
saveAction.triggered.connect(lambda : print('此處彈出保存文件的對話框'))
quitAction = QAction('&退出', self)
quitAction.setShortcut('Ctrl+Q')
quitAction.setStatusTip('退出程序')
quitAction.triggered.connect(self.close)
singleAction = QAction('&個人權(quán)限', self)
singleAction.setStatusTip('個人權(quán)限')
singleAction.triggered.connect(lambda : print('此處響應(yīng)個人權(quán)限操作'))
groupAction = QAction('&組權(quán)限', self)
groupAction.setStatusTip('組權(quán)限')
groupAction.triggered.connect(lambda : print('此處響應(yīng)組權(quán)限操作'))
mb = self.menuBar()
fm = mb.addMenu('&文件')
fm.addAction(openAction)
fm.addAction(saveAction)
fm.addSeparator() #添加分割線
subMenu = fm.addMenu('權(quán)限')
subMenu.addAction(singleAction)
subMenu.addAction(groupAction)
fm.addSeparator()
fm.addAction(quitAction)
tb = self.addToolBar('文件')
tb.addAction(openAction)
tb.addAction(saveAction)
tb = self.addToolBar('退出')
tb.addAction(quitAction)
tb = QToolBar(self)
tb.setObjectName('權(quán)限')
self.addToolBar(Qt.ToolBarArea.RightToolBarArea, tb)
tb.addAction(singleAction)
tb.addAction(groupAction)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())運行結(jié)果如下:

(4)對話框
import sys, os
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QGridLayout, QMessageBox, QInputDialog, QColorDialog, QFileDialog
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('對話框')
self.initUI()
self.show()
def initUI(self):
grid = QGridLayout()
btns = [
['通知消息', '警告消息', '錯誤消息', '確認(rèn)消息', '關(guān)于'],
['顏色選擇', '保存文件', '打開文件', '選擇路徑', '輸入']
]
for i in (0, 1):
for j in range(5):
btn = QPushButton(btns[i][j])
btn.clicked.connect(self.on_button)
grid.addWidget(btn, i, j)
self.main_widget = QWidget()
self.main_widget.setLayout(grid)
self.setCentralWidget(self.main_widget)
self.sbar = self.statusBar()
self.sbar.showMessage('Ready', 5000)
def on_button(self):
"""響應(yīng)按鍵"""
key = self.sender().text() #在槽函數(shù)種調(diào)用該方法可以返回信號的發(fā)出者
self.sbar.showMessage(key, 1000)
#QMessageBox.information/warning/critical/question/about這幾個方法的圖標(biāo)不一樣
#方法API--int QMessageBox::information(QWidget *parent, const QString &title, const QString &text, button0|button1|button2)
#parent是父組件指針,title標(biāo)題,text是文本文字,button0、1和 2是三個按鈕,每個按鈕間以|隔開。
if key == '通知消息':
reply = QMessageBox.information(self, '提示', '對手認(rèn)負(fù),比賽結(jié)束。',
QMessageBox.StandardButton.Ok
)
self.sbar.showMessage(reply.name, 2000)
elif key == '警告消息':
reply = QMessageBox.warning(self, '警告', '不能連續(xù)提和!',
QMessageBox.StandardButton.Ok
)
self.sbar.showMessage(reply.name, 2000)
elif key == '錯誤消息':
reply = QMessageBox.critical(self, '錯誤', '著法錯誤!',
QMessageBox.StandardButton.Retry|QMessageBox.StandardButton.Ignore|QMessageBox.StandardButton.Abort|QMessageBox.StandardButton.Cancel
)
self.sbar.showMessage(reply.name, 2000)
elif key == '確認(rèn)消息':
reply = QMessageBox.question(self, '請選擇', '對手提和,接受嗎?',
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel
)
self.sbar.showMessage(reply.name, 2000) #把按鈕的選擇結(jié)果展示到左下角消息展示欄
elif key == '關(guān)于':
QMessageBox.about(self, '關(guān)于', '云頂之弈 S9垃圾版本')
elif key == '顏色選擇':
color = QColorDialog.getColor()
if color.isValid():
self.sbar.showMessage(color.name(), 2000)
elif key == '保存文件':
dase_dir = os.getcwd()
file_type = 'Python Files (*.py);;Text Files (*.txt);;All Files (*)' #選擇需要保存的文件格式:python或者txt
fname, fext = QFileDialog.getSaveFileName(self, '保存文件', directory=dase_dir, filter=file_type)
if fname:
self.sbar.showMessage(fname, 2000)
elif key == '打開文件':
dase_dir = os.getcwd()
file_type = 'Python Files (*.py);;Text Files (*.txt);;All Files (*)' #選擇需要保存的文件格式:python或者txt
fname = QFileDialog.getOpenFileName(self, '選擇文件', directory=dase_dir, filter=file_type)
if fname[0]:
self.sbar.showMessage(fname[0], 2000)
elif key == '選擇路徑':
dase_dir = os.getcwd()
folder = QFileDialog.getExistingDirectory(self, '選擇文件夾', directory=dase_dir)
self.sbar.showMessage(folder, 2000)
elif key == '輸入':
text, ok = QInputDialog.getText(self, '輸入對話框', '請輸入您的房間號碼:')
if ok:
self.sbar.showMessage(text, 2000)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())運行結(jié)果如下:

(5)相冊
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QHBoxLayout, QVBoxLayout
from PyQt6.QtGui import QIcon, QPixmap
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('相冊')
self.initUI()
self.show()
self.center()
def center(self):
"""窗口在屏幕上居中"""
win_rect = self.frameGeometry()
scr_center = self.screen().availableGeometry().center()
win_rect.moveCenter(scr_center)
self.move(win_rect.topLeft())
def initUI(self):
self.curr = 0
#注意這里要選三張圖片,放入當(dāng)前pyhon腳本所在的文件夾的res目錄下,我這里之前放之前的截圖了
self.photos = ('D:/tools/python/srcipts2023/res/1.png', 'D:/tools/python/srcipts2023/res/2.png', 'D:/tools/python/srcipts2023/res/3.png')
self.lab = QLabel()
self.lab.setPixmap(QPixmap(self.photos[self.curr])) #用label標(biāo)簽展示圖片,默認(rèn)從列表第一個圖片,后面有根據(jù)按鈕切換圖片的方法
btn_prev = QPushButton('<')
btn_next = QPushButton('>')
btn_prev.clicked.connect(self.on_btn)
btn_next.clicked.connect(self.on_btn)
#設(shè)置邊框
hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(btn_prev)
hbox.addSpacing(50)
hbox.addWidget(btn_next)
hbox.addStretch(1)
vbox = QVBoxLayout()
vbox.addWidget(self.lab)
vbox.addLayout(hbox)
self.setLayout(vbox)
def on_btn(self):
"""響應(yīng)按鍵"""
key = self.sender().text()
if key == '<':
#點擊'<'按鈕時,取上一條圖片,一般來說按理來說(self.curr-1)就行,這里求余總數(shù)量的作用是為了能保持循環(huán),比如第一張前面沒有照片,就會跳到最后一張
#比如第一張時self.curr=0,(self.curr-1)%len(self.photos)=-1%3=2,此時跳到最后一張
self.curr = (self.curr-1)%len(self.photos)
else:
self.curr = (self.curr+1)%len(self.photos)
self.lab.setPixmap(QPixmap(self.photos[self.curr]))
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())運行結(jié)果如下:

(6)計算器
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QGridLayout, QVBoxLayout
from PyQt6.QtGui import QIcon, QFont
from PyQt6.QtCore import Qt
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('計算器')
self.initUI()
self.show()
self.center()
def center(self):
"""窗口在屏幕上居中"""
win_rect = self.frameGeometry()
scr_center = self.screen().availableGeometry().center()
win_rect.moveCenter(scr_center)
self.move(win_rect.topLeft())
def initUI(self):
"""初始化界面"""
#lcd:液晶顯示屏(QLCDNumber)
self.lcd = QLabel('0') #默認(rèn)展示
self.lcd.setFont(QFont('Arial', 24, QFont.Weight.Bold)) #設(shè)置字體
self.lcd.setAlignment(Qt.AlignmentFlag.AlignRight) #右對齊
self.lcd.setStyleSheet('background-color:#000030; color:#30ff30') #設(shè)置顏色
keys = [
['(', ')', 'Back', 'Clear'],
['7', '8', '9', '/'],
['4', '5', '6', '*'],
['1', '2', '3', '-'],
['0', '.', '=', '+']
]
grid = QGridLayout()
box = QVBoxLayout()
for i in range(5):
for j in range(4):
btn = QPushButton(keys[i][j])
btn.clicked.connect(self.on_btn)
#分區(qū)設(shè)置顏色 back、clear和運算字符顏色設(shè)置與其他不同
if i == 0 and j in (2, 3):
btn.setStyleSheet('background-color:#f0e0d0')
elif i > 0 and j == 3:
btn.setStyleSheet('background-color:#a0f0e0')
elif i == 4 and j == 2:
btn.setStyleSheet('background-color:#f0e0a0')
else:
btn.setStyleSheet('background-color:#d9e4f1')
grid.addWidget(btn, i, j)
box.addWidget(self.lcd)
box.addSpacing(10) #設(shè)置間隔
box.addLayout(grid)
self.setLayout(box)
def on_btn(self):
"""響應(yīng)按鍵"""
if self.lcd.text() == 'Error':
self.lcd.setText('')
key = self.sender().text()
if key == 'Clear':
self.lcd.setText('')
elif key == 'Back':
self.lcd.setText(self.lcd.text()[:-1]) #回到上一步
elif key == '=':
try:
result = str(eval(self.lcd.text()))
except:
result = 'Error'
self.lcd.setText(result)
else:
self.lcd.setText(self.lcd.text() + key) #除了計算符號和back/clear/=外,其他的數(shù)字直接拼接到末尾
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())運行結(jié)果如下:

(7)秒表
import sys, time
from PyQt6.QtWidgets import QApplication, QWidget, QLCDNumber, QPushButton, QVBoxLayout
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import QObject, pyqtSignal, QThread
class ClockServer(QObject):
"""計時服務(wù)"""
update_time = pyqtSignal(str) # 更新時間信號
isRun = False
def run(self):
"""啟動服務(wù)"""
while True:
t0 = time.time()
while self.isRun:
#信號發(fā)射(執(zhí)行update_time方法)時輸出時間差,因為t0只初始化一次,這個時間差就是秒表的計時時間,'%.2f'%+數(shù)字 代表保留兩位小數(shù)
self.update_time.emit('%.2f'%(time.time()-t0))
time.sleep(0.01) #每0.01s執(zhí)行一次
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('秒表')
self.setGeometry(400, 300, 240, 140)
self.initUI()
self.show()
def initUI(self):
self.lcd = QLCDNumber() #QLCDNumber:展示LCD樣式的數(shù)字
self.lcd.setDigitCount(6) #設(shè)置限制位數(shù)為6
self.lcd.display('0:00') #初始值
#設(shè)置按鈕
self.btn = QPushButton('開始')
self.btn.setStyleSheet('background-color:#f0d090')
self.btn.clicked.connect(self.on_btn)
#設(shè)置樣式
vbox = QVBoxLayout()
vbox.addWidget(self.lcd)
vbox.addSpacing(5)
vbox.addWidget(self.btn)
self.setLayout(vbox)
self.ts = ClockServer() # 創(chuàng)建計時服務(wù),ts是自己命名的服務(wù)對象
self.ts.update_time.connect(self.lcd.display) # 連接update_time信號到液晶顯示屏的顯示函數(shù)
self.thread = QThread() # 創(chuàng)建線程
self.ts.moveToThread(self.thread) # 將計時服務(wù)加到線程
self.thread.started.connect(self.ts.run) # 將計時服務(wù)的啟動方法設(shè)置為線程函數(shù)
self.thread.start() # 啟動線程
def on_btn(self):
"""響應(yīng)按鍵"""
if self.btn.text() == '開始':
self.ts.isRun = True
self.btn.setText('停止')
else:
self.ts.isRun = False
self.btn.setText('開始')
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())運行結(jié)果如下:

(8)嵌入瀏覽器或其他windows應(yīng)用
這里使用QAxWidget插件實現(xiàn),我們要學(xué)會怎么通過注冊表找到組件的uuid,才能通過uuid打開該組件。首先打開注冊表編輯器,找到HKEY_CLASSES_ROOT這一欄:

然后下拉找到Shell.Explorer/Shell.Explorer.1/Shell.Explorer.2可以看到這里有三個瀏覽器,任選其一即可,然后復(fù)制其uuid:

最后調(diào)用嵌入瀏覽器的代碼示例如下:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt6.QAxContainer import QAxWidget
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('內(nèi)嵌瀏覽器')
self.setFixedSize(960, 640)
widget = QAxWidget(self) #QAxWidget類是一個包裝ActiveX控件的QWidget,可以當(dāng)作一個窗口類使用
#若setControl(“E:/test.doc”);直接會加載word應(yīng)用打開doc文檔。
#此處的{8856F961-340A-11D0-A96B-00C04FD705A2}是Microsoft Web Browser控件的UUID,代表打開瀏覽器。
#UUID來源于注冊表HKEY_CLASSES_ROOT\Shell.Explorer.1\CLSID
widget.setControl("{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}")
widget.dynamicCall('Navigate(const QString&)', 'https://cn.bing.com') #"Navigate(const QString&)"這是固定寫法,后面的https://cn.bing.com是進(jìn)入的網(wǎng)址
box = QVBoxLayout(self)
box.addWidget(widget )
self.center()
self.show()
def center(self):
"""窗口在屏幕上居中"""
win_rect = self.frameGeometry()
scr_center = self.screen().availableGeometry().center()
win_rect.moveCenter(scr_center)
self.move(win_rect.topLeft())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
sys.exit(app.exec())運行結(jié)果如下:

5.圖形化界面Qt Designer
為什么把這個放到最后呢?原因有二:①目前還是比較推薦自己手寫界面的,更靈活;②先學(xué)基礎(chǔ)的繪制,再看由工具轉(zhuǎn)化的圖形化代碼比較容易看懂,也比較容易在基礎(chǔ)上做改造
(1)安裝
pip install pyqt6-tools pip install pyside6
pyside6使用國內(nèi)的鏡像安裝源: pip install pyside6 -i https://pypi.douban.com/simple/
安裝完成后直接打開即可,pyside6路徑為:你的python安裝目錄\Lib\site-packages\PySide6\designer.exe
官網(wǎng)手冊:https://doc.qt.io/qt-5/qtdesigner-manual.html
(2)基礎(chǔ)控件
相信通過前面的學(xué)習(xí),有不少控件大家已經(jīng)比較熟悉了
①Layouts:
- Vertical Layout:垂直布局
- Horizontal Layout:水平布局
- Gird Layout:柵格布局
- FormLayout:表單布局
②Spacers:
- Horizontal Spacer:水平彈簧
- Vertical Spacer:垂直彈簧
③Buttons:
- Push Button:常用按鈕
- Tool Button:工具按鈕
- Radio Button:單選框(按鈕)
- Check Box:多選框
- Command Link Button:命令連接按鈕
- Dialog Button Box:按鈕盒
④Item View(Model-Based):
- List View:列表視圖
- Tree View:樹視圖
- Table View:表格視圖
- Column View:列視圖
⑤Item Widgets(Item-Based):
- List Widget:列表部件
- Tree Widget:樹部件
- Table Widget:表格部件
⑥Containers:
- Group Box:有標(biāo)題的組合框
- Scroll Area:自動滾動區(qū)
- Tool Box:抽屜控件(工具箱)
- Tab Widget:選項卡
- Stacked Widget:控件棧。控件棧只顯示棧頂?shù)目丶?,開發(fā)人員可以使用raiseWidget()函數(shù)把棧中任何其他控件移到棧頂,從而實現(xiàn)控件之間的切換。
- Frame:框架。QFrame框架組件用來存放其他控件,也可用于裝飾,一般用來作為更加復(fù)雜容器的基礎(chǔ),也可以用在form中作為占用控件。
- Widget:QWidget類是所有用戶界面對象的基類,QWidget組件在創(chuàng)建時是不可見的,可以包含子控件,在刪除Widget時,子控件也一起刪除。
- MDI Area:MDI窗口顯示區(qū)。多文檔界面,主要適用于完成一項工作時需要用到多個文件,主要適用于所有工作沒有太多文件參與的情況。
- Dock Widget:??看翱凇?梢宰鳛橐粋€頂層窗口漂浮在桌面,主要作為輔助窗體出現(xiàn)在界面中,可以在很多IDE中看到??看绑w。
- QAxWidget:是一個包裝ActiveX控件的QWidget
⑦Input Widgets:
- Line Edit:單行文本編輯框
- Text Edit:多行文本編輯框
- Plain Text Edit:多行文本編輯器,用于顯示和編輯多行簡單文本(樣式同上)
- Spin Box:整數(shù)調(diào)節(jié)按鈕
⑧Double Spin Box:
- Time Edit:提供了一個部件,用于編輯時間
- Data Edit:供了一個部件,用于編輯日期
- Date/Time Edit:QDateTime類提供的一個部件,用于編輯日期和時間。
- Dial:旋轉(zhuǎn)儀表盤。應(yīng)用于萬能遙控的溫度、聲音的控制、以及其他工業(yè)儀表盤等等。
- Horizontal Scroll Bar:水平卷滾條,與 QSlider 功能類似,還可以用于卷滾區(qū)域。
- Vertical Scroll Bar:垂直卷滾條,與 QSlider 功能類似,還可以用于卷滾區(qū)域。
- Horizontal Slider:水平滑動條,通過滑動來設(shè)置數(shù)值,可用于數(shù)值輸入。
- Vertical Slider:垂直滑動條,通過滑動來設(shè)置數(shù)值,可用于數(shù)值輸入。
- Key Sequence Edit:文本輸入控件。用作對快捷鍵的采集。結(jié)合其內(nèi)部的API可以實現(xiàn)對自定義快捷鍵的設(shè)置。
⑨Display Widgets:
- Label:常用的控件,用于顯示文本,顯示html超文本,放置可點擊的超鏈接,顯示圖片,動畫等等。
- Text Browser:帶有超文本導(dǎo)航的富文本瀏覽器,可以設(shè)置其readOnly屬性為false則可編輯,使用ui.textBrowse->document()->toPlainText()可以獲取里面的內(nèi)容出來。
- Graphics Widget:是一個擴展的基礎(chǔ)項,它在 QGraphicsItem 之上提供額外的功能。 它在很多方面與 QWidget 相似,我覺得是更靈活的大畫板。
- LCD Number:用于顯示一個LCD數(shù)字。
- Progress Bar:一個水平或垂直進(jìn)度條。
- Horizontal Line:水平線
- Vertical Line:垂直線。
- OpenGL Widget:一個渲染OpenGL圖形的窗口部件。
- QQuickWidget:用來加載qml文件,用于顯示界面。
(3)使用教程
①點擊窗口控件左側(cè),即可看到全部的窗口控件

②創(chuàng)建一個MainWindow

③拖入一個控件,如表單布局FormLayout。

④雙擊表單,彈出表單布局行。⑤填入標(biāo)簽文字,然后確定,即可得到一行表單,我這里添加了三行表單。

⑥保存現(xiàn)在的布局:Ctrl+S,即可保存該布局文件

⑦打開該文件,發(fā)現(xiàn)是一個標(biāo)準(zhǔn)的xml文件。

⑧使用生成的.ui文件–使用uic.loadUi
import sys
from PyQt6 import QtWidgets, uic
app = QtWidgets.QApplication(sys.argv)
window = uic.loadUi("D:/tools/python/srcipts2023/test0628.ui")
window.show()
app.exec()⑨文件轉(zhuǎn)換,進(jìn)入cmd,到ui文件所在的目錄下執(zhí)行:pyuic6 -o {輸出文件名} {輸入designer設(shè)計好的.ui后綴界面文件}如:pyuic6 -o test0628.py test0628.ui
⑩pyuic工具將Ui_附加到你定義的對象名稱后面,這就是您想要導(dǎo)入的對象,如你創(chuàng)建的是MainWindow生成的對象默認(rèn)是Ui_MainWindow。
也可以直接查看使用生成的.py文件,發(fā)現(xiàn)里面的class對象名稱就是Ui_MainWindow。

通過自定義對象MyUi繼承Ui_MainWindow類實現(xiàn)調(diào)用(為了實現(xiàn)初始化方法),最終代碼實現(xiàn)如下所示:
import sys
from PyQt6 import QtWidgets, uic
from test0628 import Ui_MainWindow
class MyUi(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MyUi, self).__init__(*args, **kwargs)
self.setupUi(self)
app = QtWidgets.QApplication(sys.argv)
window = MyUi()
window.show()
app.exec()總結(jié)
到此這篇關(guān)于Python桌面應(yīng)用開發(fā)實戰(zhàn)之PyQt的安裝使用的文章就介紹到這了,更多相關(guān)Python桌面應(yīng)用PyQt內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python graphlib庫輕松創(chuàng)建操作分析圖形對象
Python中的graphlib庫是一個功能強大且易于使用的工具,graphlib提供了許多功能,可以幫助您創(chuàng)建、操作和分析圖形對象,本文將介紹graphlib庫的主要用法,并提供一些示例代碼和輸出來幫助您入門2024-01-01
Python pydotplus安裝及可視化圖形創(chuàng)建教程
這篇文章主要為大家介紹了Python pydotplus安裝及可視化圖形創(chuàng)建教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
python列表推導(dǎo)和生成器表達(dá)式知識點總結(jié)
在本篇文章里小編給大家整理的是關(guān)于python列表推導(dǎo)和生成器表達(dá)式的相關(guān)知識點內(nèi)容,需要的朋友們可以參考下。2020-01-01
Python編程使用matplotlib挑鉆石seaborn畫圖入門教程
這篇文章主要為大家介紹了Python編程中使用matplotlib繪圖包來挑出完美的鉆石,本篇是seaborn包畫圖使用入門篇,有需要的朋友可以借鑒參考下2021-10-10
如何使用Python的xml.etree.ElementTree模塊解析和操作 XML 數(shù)據(jù)
xml.etree.ElementTree是Python標(biāo)準(zhǔn)庫中用于解析和操作XML數(shù)據(jù)的模塊,無需安裝,支持解析、創(chuàng)建、修改和查詢XML數(shù)據(jù),本文介紹如何使用Python的xml.etree.ElementTree模塊解析和操作 XML 數(shù)據(jù),感興趣的朋友跟隨小編一起看看吧2025-01-01
詳解Python并發(fā)編程之創(chuàng)建多線程的幾種方法
這篇文章主要介紹了詳解Python并發(fā)編程之創(chuàng)建多線程的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
python讀取查看npz/npy文件數(shù)據(jù)以及數(shù)據(jù)完全顯示方法實例
前兩天從在GitHub下載了一個代碼,其中的數(shù)據(jù)集是.npz結(jié)尾的文件,之前沒有見過不知道如何處理,下面這篇文章主要給大家介紹了關(guān)于python讀取查看npz/npy文件數(shù)據(jù)以及數(shù)據(jù)完全顯示方法的相關(guān)資料,需要的朋友可以參考下2022-04-04

