欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python桌面應用開發(fā)實戰(zhàn)之PyQt的安裝使用

 更新時間:2023年08月31日 11:23:22   作者:TTTALK  
這篇文章主要給大家介紹了關(guān)于Python桌面應用開發(fā)實戰(zhàn)之PyQt的安裝使用,PyQt是一個功能強大的Python庫,用于創(chuàng)建圖形用戶界面(GUI)應用程序,需要的朋友可以參考下

引言:桌面應用開發(fā)三大框架介紹

Tkinter:優(yōu)勢是免安裝、相對簡單,缺點是功能少,無界面設計工具。

PyQT:使用率高,功能最為強大,代碼可維護性和易讀性高。

WxPython:介于Tkinter和PyQT之間,相當于壓縮版QT。

總結(jié):三種框架各有優(yōu)劣,有時間可以全部學習,并不復雜。如果只選一種,這里推薦使用最主流、最保值、上限最高的PyQT。

一、PyQT介紹

Qt:Qt是一個跨平臺的C++圖形用戶界面應用程序開發(fā)框架,目前已成為最強大,最受歡迎的跨平臺GUI庫之一。Qt不僅可以開發(fā)GUI程序,也可開發(fā)非GUI程序,比如控制臺工具和服務程序。

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模塊:包含應用程序類、窗口類、控件類和組件類

QtGui模塊:包含和gui相關(guān)的功能,例如用于事件處理、圖像處理、字體和顏色類等

QtCore模塊:包含核心的非gui功能,例如線程、定時器、日期時間類、文件類等

二、安裝

安裝: pip install PyQt6

檢查安裝版本(進入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類派生的桌面應用程序窗口類
class MyWindow(QWidget):  #QtWidgets模塊:包含應用程序類、窗口類、控件類和組件類
	#構(gòu)造函數(shù)
    def __init__(self): 
        super().__init__() # 調(diào)用基類的構(gòu)造函數(shù)
        self.setWindowTitle('Hello World') # 設置標題
        #self.setWindowIcon(QIcon('res/qt.png')) # 可以設置圖標
        lab = QLabel('Hello World', self) # 實例化標簽
        lab.resize(320,160) # 設置標簽大小
        lab.setFont(QFont('Arial', 32, QFont.Weight.Bold)) # 設置字體字號
        lab.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本在標簽內(nèi)居中
        self.show() # 顯示窗口
if __name__ == '__main__':
    app = QApplication(sys.argv) # 創(chuàng)建應用程序,接收來自命令行的參數(shù)列表
    win = MyWindow() # 創(chuàng)建窗口,這里初始化的時候不需要QWidget入?yún)?
    sys.exit(app.exec()) # 應用程序主循環(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) # 設置窗位置和大小
        lab_acc = QLabel('賬號:') # 實例化標簽
        account = QLineEdit() #單行文本編輯框
        account.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本在標簽內(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) #將實例化標簽賬號放入
        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) # 設置左側(cè)拉伸因子
        hbox_btn.addWidget(btn_ok) # 添加btn_ok控件
        hbox_btn.addWidget(btn_cancel) # 添加btn_cancel控件
        hbox_btn.addStretch(1) # 設置右側(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)
        # 將垂直布局管理器應用到窗口
        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)格布局管理器應用到窗口
        for i in range(5):
            for j in range(4):
                button = QPushButton(keys[i][j])
                grid.addWidget(button, i, j) #將元素放入柵格,i是橫坐標,j是縱坐標
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) # 設置窗位置和大小
        form = QFormLayout() # 創(chuàng)建表單布局管理器
        form.setLabelAlignment(Qt.AlignmentFlag.AlignRight) #設置標簽右對齊(默認左對齊)
        name = QLineEdit() #單行文本編輯框
        mobile = QLineEdit()
        passwd = QLineEdit()
        addr = QLineEdit()
        form.addRow('姓名', name) #將文本放入form中
        form.addRow('移動電話', mobile)
        form.addRow('密碼', passwd)
        form.addRow('通訊地址', addr)
        name.setPlaceholderText("請輸入姓名") #設置placeholder灰體默認值
        mobile.setPlaceholderText("請輸入移動電話")
        passwd.setPlaceholderText("請輸入密碼")
        addr.setPlaceholderText("請輸入通訊地址")
        name.setEchoMode(QLineEdit.EchoMode.Normal) #EchoMode為Normal:顯示輸入的字符。這是默認值
        mobile.setEchoMode(QLineEdit.EchoMode.NoEcho) #EchoMode為NoEcho:不顯示任何東西。這可能適用于連密碼長度都應該保密的密碼。
        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)
        # 將垂直布局管理器應用到窗口
        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(): 鼠標雙擊事件
mouseMoveEvent(): 鼠標移動事件
mousePressEvent(): 鼠標按下事件
mouseReleaseEvent(): 鼠標釋放事件
timerEvent(): 定時器事件
dragEnterEvent(): 拖拽進入當前窗口事件
dragLeaveEvent(): 拖拽離開當前窗口事件
dragMoveEvent(): 拖拽移動事件
enterEvent(): 進入窗口區(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對應的鍵盤下面有對照表
            self.close()
if __name__ == '__main__':
    app = QApplication(sys.argv) 
    win = MyWindow()
    sys.exit(app.exec())

執(zhí)行后結(jié)果如下:

Qt.Key對應的鍵盤對照如下:

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ǔ)上增加導入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編程中對象之間進行通信的機制。在創(chuàng)建事件循環(huán)之后,通過建立信號和槽的連接就可以實現(xiàn)對象之間的通信。當信號發(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):        # 重寫鼠標按下事件
        super().mousePressEvent(event)
        if event.button() == Qt.MouseButton.LeftButton:     # 當鼠標左鍵單擊時
            self.button_clicked_signal.emit()     # 發(fā)射信號
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WinForm()
    win.show()
    sys.exit(app.exec())

運行結(jié)果如下:

示例三–結(jié)合信號和槽進行多線程操作:

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()  #當線程運行時發(fā)射自定義信號
                QThread.msleep(self.interval) #設置線程執(zhí)行間隔
 #進度條主界面,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("線程刷新進度條")
        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)
        #設置四個進度條
        self.progress_1 = QProgressBar(self) #ProgressBar提供了一個水平或垂直的進度條,可以使用setMinimum()和setMaximum指定最小和最大步數(shù)
        self.progress_1.setRange(0,100)
        self.main_layout.addWidget(self.progress_1) #在頁面布局中添加進度條控件
        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ù)當前按鈕發(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í)行一次進度條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ù):給多個任務各分配一個線程去執(zhí)行
        self.th1.started.connect(self.cs1.run) #QThread提供了QThread::started()(當線程開始時發(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ù)當前按鈕發(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í)行一次進度條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)欄(追蹤鼠標移動軌跡)

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)
        # 對于需要處理鼠標移動事件的部件,開啟感知鼠標移動軌跡
        lab.setMouseTracking(True)
        self.main_widget.setMouseTracking(True)
        self.setMouseTracking(True)
        self.sbar = self.statusBar() # 返回窗口狀態(tài)欄
        self.mouth_info = QLabel() # 顯示鼠標坐標的標簽
        self.sbar.addPermanentWidget(self.mouth_info) # 將顯示鼠標坐標的標簽添加到狀態(tài)欄
        self.sbar.addPermanentWidget(QLabel('版權(quán)所有 ')) # 將版權(quán)聲明添加到狀態(tài)欄
        self.sbar.showMessage('準備就緒', 3000) # 顯示消息,3秒鐘后消失
    def enterEvent(self, evt):
        """響應鼠標進入窗口事件"""
        #QStatusBar.showMessage(str, msecs=0):顯示str消息持續(xù)msecs毫秒。如果msecs為0(默認),則消息將一直顯示,直到調(diào)用clearMessage()或再次showMessage以更改消息。
        self.sbar.showMessage('鼠標進入', 3000) 
    def leaveEvent(self, evt):
        """響應鼠標離開窗口事件"""
        self.sbar.showMessage('鼠標離開', 3000)
        self.mouth_info.setText('')
    def mouseMoveEvent(self, evt):
        """響應鼠標移動事件"""
        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ù)設置圖片
        openAction = QAction('&打開', self)
        openAction.setShortcut('Ctrl+O')  #設置快捷鍵
        openAction.setStatusTip('打開文件') #設置狀態(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('此處響應個人權(quán)限操作'))
        groupAction = QAction('&組權(quán)限', self)
        groupAction.setStatusTip('組權(quán)限')
        groupAction.triggered.connect(lambda : print('此處響應組權(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) 可添加圖標圖片
        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('此處響應個人權(quán)限操作'))
        groupAction = QAction('&組權(quán)限', self)
        groupAction.setStatusTip('組權(quán)限')
        groupAction.triggered.connect(lambda : print('此處響應組權(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('此處響應個人權(quán)限操作'))
        groupAction = QAction('&組權(quán)限', self)
        groupAction.setStatusTip('組權(quán)限')
        groupAction.triggered.connect(lambda : print('此處響應組權(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 = [
            ['通知消息', '警告消息', '錯誤消息', '確認消息', '關(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):
        """響應按鍵"""
        key = self.sender().text()  #在槽函數(shù)種調(diào)用該方法可以返回信號的發(fā)出者
        self.sbar.showMessage(key, 1000)
        #QMessageBox.information/warning/critical/question/about這幾個方法的圖標不一樣
        #方法API--int QMessageBox::information(QWidget *parent, const QString &title, const QString &text, button0|button1|button2)
        #parent是父組件指針,title標題,text是文本文字,button0、1和 2是三個按鈕,每個按鈕間以|隔開。
        if key == '通知消息':
            reply = QMessageBox.information(self, '提示', '對手認負,比賽結(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 == '確認消息':
            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
        #注意這里要選三張圖片,放入當前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標簽展示圖片,默認從列表第一個圖片,后面有根據(jù)按鈕切換圖片的方法
        btn_prev = QPushButton('<')
        btn_next = QPushButton('>')
        btn_prev.clicked.connect(self.on_btn)
        btn_next.clicked.connect(self.on_btn)
        #設置邊框
        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):
        """響應按鍵"""
        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')  #默認展示
        self.lcd.setFont(QFont('Arial', 24, QFont.Weight.Bold)) #設置字體
        self.lcd.setAlignment(Qt.AlignmentFlag.AlignRight) #右對齊
        self.lcd.setStyleSheet('background-color:#000030; color:#30ff30') #設置顏色
        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ū)設置顏色 back、clear和運算字符顏色設置與其他不同
                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) #設置間隔
        box.addLayout(grid)
        self.setLayout(box)
    def on_btn(self):
        """響應按鍵"""
        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):
    """計時服務"""
    update_time = pyqtSignal(str) # 更新時間信號
    isRun = False
    def run(self):
        """啟動服務"""
        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ù)為6
        self.lcd.display('0:00') #初始值
        #設置按鈕
        self.btn = QPushButton('開始')
        self.btn.setStyleSheet('background-color:#f0d090')
        self.btn.clicked.connect(self.on_btn)
        #設置樣式
        vbox = QVBoxLayout()
        vbox.addWidget(self.lcd)
        vbox.addSpacing(5)
        vbox.addWidget(self.btn)
        self.setLayout(vbox)
        self.ts = ClockServer() # 創(chuàng)建計時服務,ts是自己命名的服務對象
        self.ts.update_time.connect(self.lcd.display) # 連接update_time信號到液晶顯示屏的顯示函數(shù)
        self.thread = QThread() # 創(chuàng)建線程
        self.ts.moveToThread(self.thread) # 將計時服務加到線程
        self.thread.started.connect(self.ts.run) # 將計時服務的啟動方法設置為線程函數(shù)
        self.thread.start() # 啟動線程
    def on_btn(self):
        """響應按鍵"""
        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應用

這里使用QAxWidget插件實現(xiàn),我們要學會怎么通過注冊表找到組件的uuid,才能通過uuid打開該組件。首先打開注冊表編輯器,找到HKEY_CLASSES_ROOT這一欄:

然后下拉找到Shell.Explorer/Shell.Explorer.1/Shell.Explorer.2可以看到這里有三個瀏覽器,任選其一即可,然后復制其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,可以當作一個窗口類使用
        #若setControl(“E:/test.doc”);直接會加載word應用打開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是進入的網(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

為什么把這個放到最后呢?原因有二:①目前還是比較推薦自己手寫界面的,更靈活;②先學基礎(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ǔ)控件

相信通過前面的學習,有不少控件大家已經(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:有標題的組合框
  • Scroll Area:自動滾動區(qū)
  • Tool Box:抽屜控件(工具箱)
  • Tab Widget:選項卡
  • Stacked Widget:控件棧??丶V伙@示棧頂?shù)目丶?,開發(fā)人員可以使用raiseWidget()函數(shù)把棧中任何其他控件移到棧頂,從而實現(xiàn)控件之間的切換。
  • Frame:框架。QFrame框架組件用來存放其他控件,也可用于裝飾,一般用來作為更加復雜容器的基礎(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è)儀表盤等等。
  • Horizontal Scroll Bar:水平卷滾條,與 QSlider 功能類似,還可以用于卷滾區(qū)域。
  • Vertical Scroll Bar:垂直卷滾條,與 QSlider 功能類似,還可以用于卷滾區(qū)域。
  • Horizontal Slider:水平滑動條,通過滑動來設置數(shù)值,可用于數(shù)值輸入。
  • Vertical Slider:垂直滑動條,通過滑動來設置數(shù)值,可用于數(shù)值輸入。
  • Key Sequence Edit:文本輸入控件。用作對快捷鍵的采集。結(jié)合其內(nèi)部的API可以實現(xiàn)對自定義快捷鍵的設置。

⑨Display Widgets:

  • Label:常用的控件,用于顯示文本,顯示html超文本,放置可點擊的超鏈接,顯示圖片,動畫等等。
  • Text Browser:帶有超文本導航的富文本瀏覽器,可以設置其readOnly屬性為false則可編輯,使用ui.textBrowse->document()->toPlainText()可以獲取里面的內(nèi)容出來。
  • Graphics Widget:是一個擴展的基礎(chǔ)項,它在 QGraphicsItem 之上提供額外的功能。 它在很多方面與 QWidget 相似,我覺得是更靈活的大畫板。
  • LCD Number:用于顯示一個LCD數(shù)字。
  • Progress Bar:一個水平或垂直進度條。
  • Horizontal Line:水平線
  • Vertical Line:垂直線。
  • OpenGL Widget:一個渲染OpenGL圖形的窗口部件。
  • QQuickWidget:用來加載qml文件,用于顯示界面。

(3)使用教程

①點擊窗口控件左側(cè),即可看到全部的窗口控件

②創(chuàng)建一個MainWindow

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

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

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

⑦打開該文件,發(fā)現(xià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)換,進入cmd,到ui文件所在的目錄下執(zhí)行:pyuic6 -o {輸出文件名} {輸入designer設計好的.ui后綴界面文件}如:pyuic6 -o test0628.py test0628.ui

⑩pyuic工具將Ui_附加到你定義的對象名稱后面,這就是您想要導入的對象,如你創(chuàng)建的是MainWindow生成的對象默認是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桌面應用開發(fā)實戰(zhàn)之PyQt的安裝使用的文章就介紹到這了,更多相關(guān)Python桌面應用PyQt內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論