Python桌面应用开发之PyQt

news2024/11/18 14:49:04

文章目录

    • 引言:桌面应用开发三大框架介绍
    • 一、PyQT介绍
    • 二、安装
    • 三、使用教程
    • (1)基础窗口
    • (2)分区布局窗口(类似于html中div的使用)
    • (3)栅格布局窗口(类似于html中的table)
    • (4)表单布局窗口(类似于html中的form)
    • (5)事件函数与事件过滤器
    • (6)信号和槽
    • 四、实战示例
    • (1)状态栏(追踪鼠标移动轨迹)
    • (2)菜单栏
    • (3)工具栏
    • (4)对话框
    • (5)相册
    • (6)计算器
    • (7)秒表
    • (8)嵌入浏览器或其他windows应用
    • 五、图形化界面QtDesigner

引言:桌面应用开发三大框架介绍

Tkinter:优势是免安装、相对简单,缺点是功能少,无界面设计工具。
PyQT:使用率高,功能最为强大,代码可维护性和易读性高。
WxPython:介于Tkinter和PyQT之间,相当于压缩版QT。

总结:三种框架各有优劣,有时间可以全部学习,并不复杂。如果只选一种,这里推荐使用最主流、最保值、上限最高的PyQT。

一、PyQT介绍

Qt:Qt是一个跨平台的C++图形用户界面应用程序开发框架,目前已成为最强大,最受欢迎的跨平台GUI库之一。Qt不仅可以开发GUI程序,也可开发非GUI程序,比如控制台工具和服务程序。
PyQt:PyQt是Qt的Python封装,提供Qt类和函数的API。
PyQt6的官网:https://www.riverbankcomputing.co.uk/news
可以参考的中文手册:https://www.syrr.cn/news/415861.html?action=onClick

PyQt常用模块:
QtWidgets模块:包含应用程序类、窗口类、控件类和组件类
QtGui模块:包含和gui相关的功能,例如用于事件处理、图像处理、字体和颜色类等
QtCore模块:包含核心的非gui功能,例如线程、定时器、日期时间类、文件类等

二、安装

安装:pip install PyQt6
检查安装版本(进入python命令行):

from PyQt6.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
QT_VERSION_STR, PYQT_VERSION_STR

三、使用教程

(1)基础窗口

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模块:包含应用程序类、窗口类、控件类和组件类
	#构造函数
    def __init__(self): 
        super().__init__() # 调用基类的构造函数
        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) # 文本在标签内居中
        self.show() # 显示窗口

if __name__ == '__main__':
    app = QApplication(sys.argv) # 创建应用程序,接收来自命令行的参数列表
    win = MyWindow() # 创建窗口,这里初始化的时候不需要QWidget入参
    sys.exit(app.exec()) # 应用程序主循环结束后,调用sys.exit()方法清理现场

执行后结果如下:
在这里插入图片描述

(2)分区布局窗口(类似于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('分区布局')
        self.setGeometry(400, 300, 320, 160) # 设置窗位置和大小
        lab_acc = QLabel('账号:') # 实例化标签
        account = QLineEdit() #单行文本编辑框
        account.setAlignment(Qt.AlignmentFlag.AlignCenter) # 文本在标签内居中
        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) # 设置左侧拉伸因子
        hbox_btn.addWidget(btn_ok) # 添加btn_ok控件
        hbox_btn.addWidget(btn_cancel) # 添加btn_cancel控件
        hbox_btn.addStretch(1) # 设置右侧拉伸因子
        # 使用垂直布局管理器布局上面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())

执行后结果如下:
在这里插入图片描述

(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):   #创建一个5*5的数组,后面会逐一放入栅格
        keys = [
            ['(', ')', 'Back', 'Clear'],
            ['7',  '8',  '9',  '/'], 
            ['4',  '5',  '6',  '*'], 
            ['1',  '2',  '3',  '-'], 
            ['0',  '.',  '=',  '+']
        ]  
        grid = QGridLayout() # 创建网格布局管理器
        self.setLayout(grid) # 将网格布局管理器应用到窗口
        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())

执行后结果如下:
在这里插入图片描述

(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() # 创建表单布局管理器
        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:显示平台相关的密码掩码字符,而不是实际输入的字符。
        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())

执行后结果如下:
在这里插入图片描述

(5)事件函数与事件过滤器

常用的事件函数如下:
keyPressEvent(): 键盘按下事件 keyReleaseEvent(): 键盘释放事件
mouseDoubleClickEvent(): 鼠标双击事件
mouseMoveEvent(): 鼠标移动事件
mousePressEvent(): 鼠标按下事件
mouseReleaseEvent(): 鼠标释放事件
timerEvent(): 定时器事件
dragEnterEvent(): 拖拽进入当前窗口事件
dragLeaveEvent(): 拖拽离开当前窗口事件
dragMoveEvent(): 拖拽移动事件
enterEvent(): 进入窗口区域事件
leaveEvent(): 离开窗口区域事件
closeEvent(): 关闭窗口事件

示例1–事件函数:

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('事件和事件函数')
        self.setGeometry(400, 300, 320, 80)
        self.initUI() # 初始化界面
        self.show()
    
    def initUI(self):
        lab = QLabel('按Esc键关闭窗口')
        box = QHBoxLayout()
        box.addStretch(1)
        box.addWidget(lab)
        box.addStretch(1)
        self.setLayout(box)
	#重写"键盘按下事件"的事件函数,指定ESC键作为触发事件的键(如果不指定就是所有键都会触发事件)
    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())

执行后结果如下:
在这里插入图片描述
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 右侧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 数字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–事件过滤器:
(在刚才的基础上增加导入QEvent,添加eventFilter方法,并在最后执行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('事件和事件函数')
        self.setGeometry(400, 300, 320, 80)
        self.initUI() # 初始化界面
        self.show()
    
	    
    def initUI(self):
        lab = QLabel('按Esc键关闭窗口')
        box = QHBoxLayout()
        box.addStretch(1)
        box.addWidget(lab)
        box.addStretch(1)
        self.setLayout(box)
	#重写"键盘按下事件"的事件函数,指定ESC键作为触发事件的键(如果不指定就是所有键都会触发事件)
    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键无法关闭窗口

(6)信号和槽

介绍:信号(signal)和槽(slot)是Qt的核心机制,也是在PyQt编程中对象之间进行通信的机制。
在创建事件循环之后,通过建立信号和槽的连接就可以实现对象之间的通信。当信号发射(emit)时,连接的槽函数将会自动执行。
示例1–使用内置的信号和槽:

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绑定事件,点击按钮时触发
        self.close()

    def btn_hand(self):
        widget = QWidget()
        QMessageBox.information(widget, 'Pop messgae', 'OK') #触发的事件时弹出会话框


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

运行结果如下:
在这里插入图片描述

示例2–自定义信号和槽函数示例:

import sys
from PyQt6.QtCore import pyqtSignal, Qt
from PyQt6.QtWidgets import *

class WinForm(QWidget):
    # 自定义信号,不带参数
    button_clicked_signal = pyqtSignal()
 
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('自定义信号和槽函数示例')
        self.resize(300, 150)
        # 接收信号,连接到自定义槽函数
        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()     # 发射信号
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WinForm()
    win.show()
    sys.exit(app.exec())

运行结果如下:
在这里插入图片描述

示例三–结合信号和槽进行多线程操作:

import sys
from PyQt6.QtWidgets import QApplication,QMainWindow,QWidget,QProgressBar,QVBoxLayout,QPushButton
from PyQt6.QtCore import QThread,QObject,pyqtSignal,Qt
 
#线程函数 
class CountSever(QObject):
    _isrun = False #线程是否运行全局变量
    countupdate = pyqtSignal()  #自定义信号
 
    #构造函数
    def __init__(self, interval) -> None:  #-> None 表示返回的数值类型不受限制
        super().__init__()
        self.interval = interval #执行间隔,初始化的时候在构造函数中指定,如self.cs1 = CountSever(100)代表每100ms执行一次
 
    #判断单个线程是否运行
    def isrun(self,value:bool):
        self._isrun = value
 
    #线程运行函数
    def run(self):
        while True:
            pass
            while self._isrun:
                self.countupdate.emit()  #当线程运行时发射自定义信号
                QThread.msleep(self.interval) #设置线程执行间隔
 
 #进度条主界面,QMainWindow--顶层窗口类,重量级控件。
class MainWindow(QMainWindow):
    countstart = pyqtSignal(bool) #自定义信号对象
    def __init__(self) -> None: #-> None 表示返回的数值类型不受限制
        super().__init__() 
        self.init_ui()
        self.setcenter() #调用下面的居中方法
 
 
    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指定最小和最大步数
        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按钮触发下面定义的start方法,start方法会根据当前按钮发送True/Flase的信号给countstart自定义对象,然后这个True/Flase决定了isrun的结果,决定线程是否运行
        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执行一次
        #自定义信号绑定下面的事件countupdate,下面的 self.progress_1.setValue(self.progress_1.value() + 1)表示执行一次进度条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函数:给多个任务各分配一个线程去执行
        self.th1.started.connect(self.cs1.run) #QThread提供了QThread::started()(当线程开始时发射)和QThread::finished()(在线程运行结束后发射)两个信号
        self.th1.start() #线程开始执行
 
        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方法会根据当前按钮发送True/Flase的信号给countstart自定义对象,然后这个True/Flase决定了isrun的结果,决定线程是否运行
    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)  #表示执行一次进度条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())

运行结果如下:
在这里插入图片描述

四、实战示例

(1)状态栏(追踪鼠标移动轨迹)

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('状态栏')
        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() # 返回窗口状态栏
        self.mouth_info = QLabel() # 显示鼠标坐标的标签
        self.sbar.addPermanentWidget(self.mouth_info) # 将显示鼠标坐标的标签添加到状态栏
        self.sbar.addPermanentWidget(QLabel('版权所有 ')) # 将版权声明添加到状态栏
        self.sbar.showMessage('准备就绪', 3000) # 显示消息,3秒钟后消失
    
    def enterEvent(self, evt):
        """响应鼠标进入窗口事件"""
		
        #QStatusBar.showMessage(str, msecs=0):显示str消息持续msecs毫秒。如果msecs为0(默认),则消息将一直显示,直到调用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())

运行结果如下:
在这里插入图片描述

(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() # 返回窗口状态栏
        #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('&个人权限', self)
        singleAction.setStatusTip('个人权限')
        singleAction.triggered.connect(lambda : print('此处响应个人权限操作'))
        
        groupAction = QAction('&组权限', self)
        groupAction.setStatusTip('组权限')
        groupAction.triggered.connect(lambda : print('此处响应组权限操作'))
 
        mb = self.menuBar()
        fm = mb.addMenu('&文件')
        fm.addAction(openAction)
        fm.addAction(saveAction)
        fm.addSeparator()
        subMenu = fm.addMenu('权限')
        subMenu.addAction(singleAction)
        subMenu.addAction(groupAction)
        fm.addSeparator()
        fm.addAction(quitAction)

if __name__ == '__main__':
    app = QApplication(sys.argv) 
    win = MainWindow()
    sys.exit(app.exec())

运行结果如下:
在这里插入图片描述

(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() # 返回窗口状态栏
        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() # 返回窗口状态栏
        #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('&个人权限', self)
        singleAction.setStatusTip('个人权限')
        singleAction.triggered.connect(lambda : print('此处响应个人权限操作'))
        
        groupAction = QAction('&组权限', self)
        groupAction.setStatusTip('组权限')
        groupAction.triggered.connect(lambda : print('此处响应组权限操作'))
 
        mb = self.menuBar()
        
        fm = mb.addMenu('&文件')
        fm.addAction(openAction)
        fm.addAction(saveAction)
        
        fm.addSeparator() #添加分割线
        subMenu = fm.addMenu('权限')
        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('权限')
        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('&个人权限', self)
        singleAction.setStatusTip('个人权限')
        singleAction.triggered.connect(lambda : print('此处响应个人权限操作'))
        
        groupAction = QAction('&组权限', self)
        groupAction.setStatusTip('组权限')
        groupAction.triggered.connect(lambda : print('此处响应组权限操作'))
 
        mb = self.menuBar()
        
        fm = mb.addMenu('&文件')
        fm.addAction(openAction)
        fm.addAction(saveAction)
        
        fm.addSeparator() #添加分割线
        subMenu = fm.addMenu('权限')
        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('权限')
        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())

运行结果如下:
在这里插入图片描述

(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 = [
            ['通知消息', '警告消息', '错误消息', '确认消息', '关于'],
            ['颜色选择', '保存文件', '打开文件', '选择路径', '输入']
        ]
        
        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()  #在槽函数种调用该方法可以返回信号的发出者
        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, '提示', '对手认负,比赛结束。', 
                QMessageBox.StandardButton.Ok           
            )
            self.sbar.showMessage(reply.name, 2000)
        elif key == '警告消息':
            reply = QMessageBox.warning(self, '警告', '不能连续提和!', 
                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)  #把按钮的选择结果展示到左下角消息展示栏
        elif key == '关于':
            QMessageBox.about(self, '关于', '云顶之弈 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())

运行结果如下:
在这里插入图片描述

(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标签展示图片,默认从列表第一个图片,后面有根据按钮切换图片的方法
        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)就行,这里求余总数量的作用是为了能保持循环,比如第一张前面没有照片,就会跳到最后一张
            #比如第一张时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())

运行结果如下:
在这里插入图片描述

(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)
                
                #分区设置颜色 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/=外,其他的数字直接拼接到末尾

if __name__ == '__main__':
    app = QApplication(sys.argv) 
    win = MyWindow()
    sys.exit(app.exec())

运行结果如下:
在这里插入图片描述

(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:
                #信号发射(执行update_time方法)时输出时间差,因为t0只初始化一次,这个时间差就是秒表的计时时间,'%.2f'%+数字 代表保留两位小数
                self.update_time.emit('%.2f'%(time.time()-t0))  
                time.sleep(0.01)    #每0.01s执行一次 

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样式的数字
        self.lcd.setDigitCount(6)  #设置限制位数为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() # 创建计时服务,ts是自己命名的服务对象
        self.ts.update_time.connect(self.lcd.display) # 连接update_time信号到液晶显示屏的显示函数
        self.thread = QThread() # 创建线程
        self.ts.moveToThread(self.thread) # 将计时服务加到线程
        self.thread.started.connect(self.ts.run) # 将计时服务的启动方法设置为线程函数
        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())

运行结果如下:
在这里插入图片描述

(8)嵌入浏览器或其他windows应用

这里使用QAxWidget插件实现,我们要学会怎么通过注册表找到组件的uuid,才能通过uuid打开该组件。
首先打开注册表编辑器,找到HKEY_CLASSES_ROOT这一栏:
在这里插入图片描述

然后下拉找到Shell.Explorer/Shell.Explorer.1/Shell.Explorer.2可以看到这里有三个浏览器,任选其一即可,然后复制其uuid:
在这里插入图片描述

最后调用嵌入浏览器的代码示例如下:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt6.QAxContainer import QAxWidget

class MyWindow(QWidget):
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle('内嵌浏览器')
        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是进入的网址
        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())

运行结果如下:
在这里插入图片描述

五、图形化界面QtDesigner

为什么把这个放到最后呢?原因有二:
①目前还是比较推荐自己手写界面的,更灵活;
②先学基础的绘制,再看由工具转化的图形化代码比较容易看懂,也比较容易在基础上做改造
(1)安装: pip install pyqt6-tools
(2)使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/692047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跨链协议悄然升级

当前加密产业公链百家争鸣&#xff0c;群雄割据&#xff0c;每条公链都拥有自身的忠实用户。 然而&#xff0c;公链与公链之间仿佛一座座孤岛&#xff0c;无法进行无缝的交流和联系&#xff0c;仅能通过跨链桥经由在两条不同的链上运用不同处理机制来协助转移用户的资产。但&a…

【深度学习 | CNN】“深入解析卷积神经网络与反卷积:从原理到应用的全面指南” (从一维、二维、三维讲解)

🤵‍♂️ 个人主页: @AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!🐱‍🏍 🙋‍♂️声明:本人目前大学就读于大二,研究兴趣方向人工智能&硬件(虽然硬件还没开始玩…

MySQL数据库的MHA高可用集群部署及故障切换(图文详解!绝对详细!!)

目录 一、MHA概述 1、MHA简介 2、MHA 的组成 &#xff08;1&#xff09;MHA Node&#xff08;数据节点&#xff09; &#xff08;2&#xff09;MHA Manager&#xff08;管理节点&#xff09; 3、MHA 的特点 二、 搭建MySQLMHA 1、实验思路 2、修改mysql节点的主机名 3&…

JS 事件委托

JavaScript事件委托&#xff08;Event delegation&#xff09;又叫事件代理&#xff0c;是一种在父元素上监听事件&#xff0c;然后通过事件冒泡机制来处理子元素的事件的技术。通过事件委托&#xff0c;可以避免为每个子元素都绑定事件处理程序&#xff0c;提高性能并简化代码…

SC7504运算放大器(OPA)可pin对pin兼容OPA4350

SC750x 系列轨至轨 CMOS 运算放大器针对低电压单电源运行进行了优化。轨至轨输入和输出、低噪声(5nV/√Hz) 和高速运行(38MHz, 22V/μs) 使得运算放大器非常适合驱动模数 (A/D) 转换器。可pin对pin兼容OPA4350。而且也适用于手机功率放大器 (PA) 控制环路和视频处理&#xff08…

【嵌入式Qt开发入门】初识Qt——Linux下安装Qt

Qt 是什么&#xff1f; Qt 是一个跨平台的 C开发库。主要用来开发图形用户界面&#xff08;Graphical User Interface&#xff0c;简 称 GUI&#xff09;程序。 Qt 虽然经常被当做一个 GUI 库&#xff0c;用来开发图形界面应用程序&#xff0c;但这并不是 Qt 的全部&#xff1b…

Win11总是出现BitLocker恢复,想要彻底关闭它该如何操作?

win11解除bitlocker加密方法一&#xff1a; 1、首先按下键盘“WinR”打开运行(如图所示)。 2、打开运行后&#xff0c;在其中输入“control”并点击“确定”打开控制面板(如图所示)。 3、打开后&#xff0c;进入“bitlocker驱动器加密”(如图所示)。 4、随后展开被加密的磁盘&…

Pycharm报错Non-zero exit code (2)

问题现象&#xff1a; 通常我们拿到一个Python项目后&#xff0c;项目中有requirement.txt文件&#xff0c;里面有列出需要安装的三方库&#xff0c;使用pycharm直接安装这些库时&#xff0c;报错&#xff1a;Non-zero exit code (2) 解决方案&#xff1a; 第一种临时解决方案&…

模糊图片秒转高清图,分享几个免费方法!

相信大家都曾经遇到过拍摄的老旧照片放大后变得模糊不清的情况。然而&#xff0c;由于这些照片是我们自己拍摄的&#xff0c;我们也无法在网上找到并下载原始高清图像。那么&#xff0c;有没有什么方法可以修复这种模糊不清的照片呢&#xff1f;当然&#xff0c;很多人可能会说…

计算机硬件

硬盘 固态硬盘&#xff08;SSD&#xff09;拥有比机械硬盘&#xff08;HDD&#xff09;更快的读写速度。目前大多数机器使用的是SATA总线标准&#xff0c;实际最高传输约为600MB/s。而支持PCIe总线&#xff0c;NVMe协议的SSD&#xff0c;实际传输速度将超过1000MB/s。 当前采…

KDG5V-8-33C330N200-EX-H-M-U-H1-20比例方向阀控制器

与外置电子放大器一起使用&#xff0c;在智能控制系统和液压系统之间提供接口。这是一种非常实用的方法&#xff0c;用于控制执行器的方向和速度&#xff0c;同时消除了机器负载的快速加速和减速所引起的冲击。除了提高机器的性能和寿命外&#xff0c;通过将方向和流量控制能力…

【UE5 Cesium】04-Cesium for Unreal 将不同地区的倾斜摄影作为不同子关卡

上一篇&#xff1a;【UE5 Cesium】03-Cesium for Unreal 添加本地数据集 步骤 1. 新建一个空白关卡 保存新建的关卡&#xff0c;命名为“Globe” 添加地图 再添加“Cesium SunSky”和“DynamicPawn” 在大纲中选中“Globe&#xff08;编辑器&#xff09;”&#xff0c;然后勾…

深入浅出设计模式 - 享元模式

博主介绍&#xff1a; ✌博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家✌ Java知识图谱点击链接&#xff1a;体系化学习Java&#xff08;Java面试专题&#xff09; &#x1f495;&#x1f495; 感兴趣的同学可以收…

初始Git

文章目录 前言技术目标协作目标 一、提出问题二、如何解决版本控制器注意事项 三、Git安装Linux-centosLinux-ubuntu 四、Git基本操作创建Git本地仓库配置Git 总结 前言 技术目标 掌握Git企业级应用,深刻理解Git操作过程与操作原理,理解工作区,暂存区,版本库的含义.掌握Git版…

LC-1595. 连通两组点的最小成本(状态压缩DP(记忆化搜索==>动态规划))

1595. 连通两组点的最小成本 难度困难86 给你两组点&#xff0c;其中第一组中有 size1 个点&#xff0c;第二组中有 size2 个点&#xff0c;且 size1 > size2 。 任意两点间的连接成本 cost 由大小为 size1 x size2 矩阵给出&#xff0c;其中 cost[i][j] 是第一组中的点 …

FineReport学习3

冻结行列&#xff08;冻结表头&#xff09; 创建多数据源之间的关联 给单元格添加过滤条件&#xff0c;让 ds2 的「客户ID」等于 ds1 的「客户ID」&#xff0c;这样两数据集就关联起来 复杂多源报表

.NETCore项目在Windows下构建Docker镜像并本地导出分发到CentOS系统下

在Windows下使用Docker&#xff0c;我们选择Docker Desktop这个软件&#xff0c;非常方便。 Docker Desktop介绍及安装 Docker Desktop是适用于Mac、Linux或Windows环境的一键安装应用程序&#xff0c;使您能够构建和共享容器化应用程序和微服务。 它提供了一个简单的GUI&…

[数据库系统] 五、数据增删改

第一关&#xff1a;数据插入 用insert给数据库添加数据 相关知识 有关系student(sno,sname,ssex,sage,sdept)&#xff0c;属性对应含义&#xff1a;学号&#xff0c;姓名&#xff0c;性别&#xff0c;所在系。现有的部分元组如下所示 insert 向数据库表插入数据的基本格式有…

生成 ocr key 字符集 alphabet 6698个字符

生成 ocr key 字符集 alphabet import pickle as pkl#----------- 生成 ocr key 字符集 alphabet alphabet_set set() # 数据集label infofiles_label [/home/jlb/下载/rec_data_lesson_demo/train.txt, /home/jlb/下载/rec_data_lesson_demo/val.txt]# ppocr中文key infofil…

SpringBoot—热部署(Community)

配置热部署 &#x1f50e;引入依赖&#x1f50e;设置 Settings 文章介绍的是社区版 Idea 配置热部署的步骤 &#x1f50e;引入依赖 复制如下代码至 pom.xml 文件中即可 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-b…