下载PyQt5

  • pip install PyQt5

下载designer

  • pip install PyQt5-tools

使用Qtdesigner

  • 将生产的ui文件转py文件,使用命令pyuic5 xx.ui -o xx.py
  • 此时只自动生成了ui界面的代码,需要自己写主程序调用你的界面类,并且需要自己编写界面的类并注册UI的类
  • from PyQt5 import uic
    • 使用uic的loadUi()方法读取designer设计的ui文件,就可以不必ui文件转py文件这一部。
  • 主程序入口:调用你的Qt窗口,然后show()出来,然后退出
if __name__ == '__main__':app = QApplication(sys.argv)window = MyMainWindow()window.show()sys.exit(app.exec_())
  • 设计的主窗体类:
class MyMainWindow(QMainWindow):def __init__(self):super().__init__()uipath = os.path.join(os.path.dirname(__file__), 'window.ui')  # 获取designer的ui文件的路径拼接uic.loadUi(uipath, self)  # 读取designer设计的ui文件

布局

  • 绝对定位

    • obj.move()
  • 布局类
    • 表格布局QGridLayout

QtSql

  • 引入库

    • from PyQt5.QtSql import QSqlDatabase, QSqlQuery
  • 连接数据库
    • 创建数据库连接并打开
    • 这里是连接SqlServer的例子
    server = '100.88.16.2'
    dbname = '市本级'
    username = 'xx'
    password = 'xx'
    db = QSqlDatabase.addDatabase('QODBC')
    db.setDatabaseName(f'Driver={{Sql Server}};Server={server};Database={dbname};Uid={username};Pwd={password}')  # f-String中如果有{dsfd}的正常字符串就再用一个{}来包裹
    db.open()
    
  • 执行sql语句
    query = QSqlQuery()
    query.exec("Select name From sys.databases")query = QSqlQueryModel()
    query.setQuery("xxxxx")# 上述两种方式都可以执行sql语句,不过最好分开执行,一次执行多条sql语句会出错
    
  • 获取查询结果
    • 使用QSqlQueryModel对象的属性与方法来获取结果集
    model.columnCount() # 获取总列数
    model.rowCount() # 获取总行数
    model.index(x,y) # 获取一个结果集的位置索引对象,只是一个索引对象,还不是数据
    model.data(indexObj)  # 根据索引对象来取得数据,这里的索引对象就是上面的结果
    
    • model对象不会一次获取所有数据
    while model.canFetchMore():  # model不会一次读取所有,需要获取到所有记录model.fetchMore()  # 获取多一点的记录
    
  • 关联tableView控件
    • 需要先建立model对象,再将tableView与model相关联起来
    from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
    # 先建立跟tableView关联的模型类,该类执行sql语句
    qqm = QSqlQueryModel()
    qqm.setQuery('select * from alltables')
    # 在窗体主类的tableView对象中设置该model,使用setModel方法
    self.tableView_3.setModel(qqm)  # tableView设置了setModel后控件自动渲染结果
    

QtSql数据源切换remove问题

  • 在切换数据源时需要执行removeDatabase方法,该方法如果要正常运行,需要关闭与该数据库相关的所有对象

    def DisConnectDb(self):self.tableView.setModel(None)if hasattr(self, 'model'):if self.model:self.model = Noneif hasattr(self, 'db'):if self.db:name = self.db.connectionName()QSqlDatabase.database(name).close()self.db = NoneQSqlDatabase.removeDatabase(name)
    
  • 总之需要把相关联的所有引用给关闭

PyQt5事件与信号

1. 在事件模型中有三个参与者:

  • 事件源:事件源是状态发生变化的对象
  • 事件(对象):事件(对象)封装了事件源中状态的变动
  • 事件接收者:事件源对象将事件处理的工作交给事件接收者
  • PyQt5有一个独特的signal&slot(信号槽)机制来处理事件。信号槽用于对象间的通信。signal在某一特定事件发生时被触发,slot可以是任何callable对象。当signal触发时会调用与之相连的slot。

2. Signals & slots

// 窗体中初始化
// valueChanged信号,lcd.display是槽sld.valueChanged.connect(lcd.display)
  • 重写事件处理器

    • KeyPressEvent(self,e) 按键事件

      # KeyPressEvent事件处理窗口中的按键事件,事件处理器def keyPressEvent(self, e):if e.key() == Qt.Key_Escape:self.close()if e.key() == Qt.Key_A:print('你按了a或A')if e.key() == Qt.Key_F1:print('你按了F1')
      
  • 自定义信号

自定义信号与槽的使用,是指在发射信号时,不使用窗口控件的函数,而是使用自定义的函数,(简单的说就是使用pyqtsSignal类实例发射信号),之所以要使用自定义的信号与槽,是因为通过内置函数发射信号有自身的缺陷,首先,内置函数只包含一些常用地信号,有些信号发射找不到对应的内置函数,其次在特定的情况下,才能发射此信号,如按钮的点击事件,最后,内置函数传递的参数是特定的,不可以自定义,使用自定义的信号与槽函数则没有这些缺陷
在pyqt5中,自定义信号与槽的适用很灵活,比如因为业务需要,在程序中的某些地方需要发射一个信号,传递多种数据,然后在槽函数接受这些数据,这样就可以很灵活的实现一些业务逻辑

  • 自定义信号的一般流程如下

    • 定义信号
    • 定义槽函数
    • 连接信号与槽
    • 发射信号

    //导入相关类
    from PyQt5.QtCore import pyqtSignal, QObject
    //新建一个类来自定义信号
    class Communicate(QObject):
    closeApp = pyqtSignal() //自定义一个closeApp的信号
    //向窗体类中的信号绑定槽
    self.c.closeApp.connect(self.close) # 为自定义信号绑定槽

    //重写鼠标点击事件的事件处理器
    def mousePressEvent(self, event):
    print(‘触发鼠标点击事件’)
    self.c.closeApp.emit() //触发closeApp信号的事件

  • 自定义的信号需要定义在QObject类下

  • emit()触发信号,信号再触发绑定槽的方法,也就是emit->connet的槽方法

  • 如果信号无参数,但是槽函数需要接受某些参数:

    • 第一种:lamdba表达式
    • 第二种:使用functools中的partial函数
    //单击信号关联槽函数,利用Lanbda表达式传递一个参数
    button1.clicked.connect(lambda :self.onButtonClick(1))
    button2.clicked.connect(lambda :self.onButtonClick(2))
    

PyQt5的状态栏

  • 可用于显示程序的当前状态
  • self.statusBar().showMessage(f'正在连接{server}的{dbname}........')

QTimer控件

如果在应用程序中周期性地进行某项操作,比如周期性的检测主机的cpu值,则需要用到QTimer定时器,QTimer类提供了重复和单次的定时器,要使用定时器,需要先创建一个QTimer实例,将其Timeout信号连接到槽函数,并调用start(),然后,定时器,会以恒定的间隔发出timeout信号

self.timer = QTimer()  # 定义定时器
self.timer.setInterval(500)  # 设置时间间隔毫秒
self.timer.start()  # 开始定时器
self.timer.timeout.connect(self.status)  # 为定时器超时连接一个槽def status(self):pass

PyQt5的Dialog会话框控件

  • 普通的dialog

    • 这个QInputDialog是一个弹出的会话框,getText函数获取输入的值与点击的按钮值,text为输入值,ok为点击的按钮值;getText的参数,第一个为对话框标题,第二个为提示消息
    def showDialog(self):# 下面这一句是重点text, ok = QInputDialog.getText(self, 'Input Dialog','Enter your name:')if ok:self.le.setText(text)
    
  • 选择文件的dialog
    • fname = QFileDialog.getOpenFileName(self, 'Open file')返回的是一个元组,该元组的信息为选择的文件路径和文件的筛选方式,所以我们通过返回值的第一个元素来取到文件路径
    def showDialog(self):# 下面这一句是重点fname = QFileDialog.getOpenFileName(self, 'Open file')if fname[0]:f = open(fname[0], 'r')with f:data = f.read()self.textEdit.setText(data)
    
  • 选择文件夹dialog
    • QFileDialog.getExistingDirectory(self, '选择文件夹', './') # 第三个参数为打开时所处的路径,返回选择的文件夹路径
    def showFileDialog(self):dic = QFileDialog.getExistingDirectory(self, '选择文件夹', './')  # 第三个参数为打开时所处的路径,返回选择的文件夹路径return dic
    

分离UI主线程与工作线程

  • PyQt提供了一个QThread类来处理线程问题
  • 创建一个线程类重写其run函数,来实现以往单线程的功能
  • 主程序中设置槽,槽调用的函数中实例化你的线程类并就绪start该线程
# threads.py
from PyQt5.QtCore import QThread
import timeclass SleepQThread(QThread):def __init__(self, *args, **kwargs):super().__init__()def run(self):time.sleep(10)print('sleep thread is going.....')# main.py
from PyQt5.QtWidgets import QApplication, QWidget
from sleep import Ui_Form
from threads import SleepQThread
import time
import sysclass MyWidget(QWidget, Ui_Form):def __init__(self, *args, **kwargs):super().__init__()self.setupUi(self)self.pushButton.clicked.connect(self.sleep)def sleep(self):self.sleepthread = SleepQThread() # 需要赋给类中的变量self.sleepthread.start()if __name__ == '__main__':app = QApplication(sys.argv)widget = MyWidget()widget.show()sys.exit(app.exec_())
  • 高级用法,涉及主线程与子线程之间的数据传输
# thread.py
from PyQt5.QtCore import QThread, pyqtSignal
import timeclass SleepQThread(QThread):# 自定义信号finalSignal = pyqtSignal(list)  # list为该信号的返回值,返回一个list对象def __init__(self, *args, **kwargs):super().__init__()self.args = args  # 通过初始化该线程类来传入数据到子线程中def run(self):time.sleep(10)print('sleep thread is going.....')self.finalSignal.emit([self.args])  # 信号触发,并传list对象参给connect的槽函数的第一个参数 ,此处便是子线程传数据给主线程# main.py
from PyQt5.QtWidgets import QApplication, QWidget
from sleep import Ui_Form
from threads import SleepQThread
import time
import sysclass MyWidget(QWidget, Ui_Form):def __init__(self, *args, **kwargs):super().__init__()self.setupUi(self)self.pushButton.clicked.connect(self.sleep)def sleep(self):self.pushButton.setDisabled(True)self.sleepthread = SleepQThread(int(1), int(2))  self.sleepthread.finalSignal.connect(self.sleepEnd)  # 线程中的自定义信号绑定槽self.sleepthread.start()def sleepEnd(self, fromfinalsignal):  # fromfinalsigal参数是来源于信号的emit的参数print('End')print(fromfinalsignal)self.pushButton.setDisabled(False)if __name__ == '__main__':app = QApplication(sys.argv)widget = MyWidget()widget.show()sys.exit(app.exec_())

Pyinstaller打包的时候

  • ui文件需要转化为类并装载的写法,使用Pyinstaller打包才ok不然会出错
  • Pyinstaller打包PyQt5程序时,出现Hidden import的错误,此时通过修改命令,忽略某个不需要的包的导入即可;Pyinstaller -F -w xxx.py --hidden-import PyQt5.sip
  • 如果打包的程序需要读取配置文件,就将配置文件复制到dist的程序下,通过创建快捷方式来使用程序
  • 打包的时候程序中如果使用了图片,在开发时是可以看见的,打包后就看不见,其实就是ui生成的py文件中寻找图片的路径改变了,个人做法是将需要用到的图片放到打包后的dist文件夹下,并修改ui生成的py文件中相关图片路径(./xxx.ico)
  • 如果要修改软件的图标,在生成的.spec文件的最后一个小括号内加icon='xxx.ico',然后执行pyinstaller xxx.spec,这里图片的文件名不能是中文,且是ico后缀的图片。

自适应布局

  • 需要利用布局来实现,整个窗体的外围设置一种布局,该布局可以自适应窗口,往里同样需要如此。
  • 先拖几个控件上去,在designer中右键布局,使布局自动适应。

comboBox使用

// comboBox中的选择变更时触发的信号
self.comboBox_1.currentIndexChanged.connect(self.getKm)
// 为一个comboBox添加内容
self.comboBox_3.addItems(['先入先出','后入先出']) # 为ComboBox添加选项,且该list内的元素必须为str类型
// 获取当前comboBox选择项的文本内容
com_name = self.comboBox_1.currentText()
// 清空一个comboBox的值
self.comboBox_2.clear()

QTableWidget使用

  • 设置每一行数据的双击事件self.tableWidget.doubleClicked.connect(self.yourchoice)
  • 设置总的列数,来控制表格表头的数量self.tableWidget.setColumnCount(len(result))
  • 设置表头self.tableWidget.setHorizontalHeaderLabels([i[1] for i in result])
  • 设置总的行数,来控制表格总的记录数self.tableWidget.setRowCount(len(result))
  • 往一个单元格中填充内容
    item = QTableWidgetItem(str(j[1]))  // 单元格中的内容需要时QTableWidgetItem类型的对象,且该对象的内容只能是str类型的
    self.tableWidget.setItem(i[0], j[0], item) // 前两个参数是单元格对应的位置
    
  • 根据表名与sql来实现内容的显示:
    def displayData(self, sql):self.cursor.execute(sql)# 根据执行的sql语句获取表头信息labels = [x[0] for x in self.cursor.description]  # cursor.description可以获取每个字段的描述self.tableWidget.setColumnCount(len(labels))self.tableWidget.setHorizontalHeaderLabels(labels)# 获取sql语句执行结果result = self.cursor.fetchall()self.tableWidget.setRowCount(len(result))self.statusBar().showMessage(f'当前页记录数:{len(result)}条')for i in enumerate(result):for j in enumerate(i[1]):item = QTableWidgetItem(str(j[1]))self.tableWidget.setItem(i[0], j[0], item)
  • 获取选中的记录one = [i.text() for i in self.tableWidget.selectedItems()]
  • 清空该空间中的所有内容self.tableWidget.clear()
  • 获取tablewidget中的内容self.tableWidget.item(row_index, column_index).text()

QTreeWidget使用

  • 类似于QTableWidget控件的使用
self.treeWidget.clear()  # 清空treewidget
self.treeWidget.setColumnCount(1)  # 设置列数
self.treeWidget.setHeaderLabels(['方法'])  # 设置表头
m1 = QTreeWidgetItem(self.treeWidget)  # 创建该控件的子节点
m2 = QTreeWidgetItem(self.treeWidget)
m3 = QTreeWidgetItem(self.treeWidget)
m1.setText(0, filename[0])  # 为m1这个节点0列设置内容
m2.setText(0, filename[1])
m3.setText(0, filename[2])item = self.treeWidget.currentItem()  # 获取当前选择的tree节点self.treeWidget.doubleClicked.connect(self.clickTheTree)  # 双击事件
self.treeWidget.clicked.connect(self.clickTheTree)  # 单击事件

设置字体颜色

from PyQt5.QtGui import QPalette
from PyQt5.QtCore import Qtpe = QPalette()
pe.setColor(QPalette.WindowText, Qt.red)  # 设置文本颜色
self.label_11.setPalette(pe)  # 应用于label

Python PyQt5相关推荐

  1. python PyQt5 QMainWindow类(Qt主窗口框架,主窗口提供了用于构建应用程序用户界面的框架)

    https://doc.qt.io/qtforpython/PySide2/QtWidgets/QMainWindow.html?highlight=qmainwindow#PySide2.QtWid ...

  2. python PyQt5 sender(是发出信号的对象)、receiver(接收信号的对象)、slot(插槽)(是对信号做出反应的方法)

    sender是发出信号的对象.receiver是接收信号的对象.slot(插槽)是对信号做出反应的方法. 参考文章:python PyQt5中文教程☞[第五节]PyQt5事件和信号

  3. python PyQt5 QtWidgets.QAbstractSlider.valueChanged()

    https://doc.qt.io/qtforpython/PySide2/QtWidgets/QAbstractSlider.html?highlight=valuechanged#PySide2. ...

  4. python PyQt5 QtWidgets.QWidget.setLayout()(将布局中的小部件重新父级化,以将窗口作为父级)

    https://doc.qt.io/qtforpython/PySide2/QtWidgets/QWidget.html?highlight=setlayout#PySide2.QtWidgets.P ...

  5. python PyQt5 QLabel()(可以用来显示文字、图片或作为放置一些控件提示信息的容器)

    QLabel对象作为一个占位符可以显示不可编辑的文本或者图片,也可以放一个gif动画,还可以作为其他控件的一个提示标记(如QComboBox下拉列表框.组合下拉框?): 该标签可以放纯文本,链接或者富 ...

  6. python PyQt5教程

    引用文章1:python PyQt5 教程 参考文章2:PyQt5 python官方教程 Qt for Python pyqt5-基础 PyQt5是一套来自Digia的Qt5应用框架和Python的粘 ...

  7. python PyQt5 QColor()函数

    示例: # -*- coding: utf-8 -*- """ @File : test.py @Time : 2020/3/30 17:49 @Author : Don ...

  8. Python+PyQt5实现灭霸响指

    之前在GitHub有趣分享:Thanos(灭霸命令)中分享了有趣的"灭霸命令",本博文使用Python+PyQt5实现灭霸响指,实现过程较简单,上效果图~ GUI实现代码如下: # ...

  9. Python PYQT5中用Label控件显示以numpy表示的灰度图像

    Python PYQT5中用Label控件显示以numpy表示的图像 rgb_img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) # 灰度转为RGB q_img = ...

  10. 基于Python pyqt5的随机抽号机源代码 ,可设置抽号器的人数及刷新间隔

    基于Python pyqt5的随机抽号机源代码 ,可设置抽号器的人数及刷新间隔,直接运行main.py即可 完整代码下载地址: pyqt5的随机抽号机源代码 main.py import sys fr ...

最新文章

  1. oracle数据库再深入(四)
  2. vim 撤销上一步操作_Linux笔记(4):vim入门
  3. 女生学python可以做什么_学 Python 都用来干嘛的?
  4. 典型数据中心能耗分析,空调系统选择很重要,想节能可以这样设计
  5. domino从Excel导入数据
  6. 获取Access中的所有用户表(例子)
  7. 为什么说CLR是类型安全的
  8. UVA10284 POJ2512 Chessboard in FEN【国际象棋】
  9. linux无线adb,linux 无法连接adb 设备
  10. python求圆的面积pta_任意给定一个正实数,设计一个算法求以这个数为半径的圆的面积...
  11. Servlet技术详解
  12. 基于PHP+MySQL的个人网页设计与实现
  13. java求三角形的面积_java编程中求三角形面积怎么写?
  14. Kettle【实践 01】Linux环境下使用Azkaban定时调用Kettle的KJB或KTR脚本实现自动化数据处理(完整流程实例分享:包含sql+ktr+shell+flow相关文件云资源)
  15. 6000字总结动态内存管理
  16. MFC DLL 不能正确调用的问题 + AFX_MANAGE_STATE(AfxGetStaticModuleState());
  17. Android 仿淘宝京东等我的订单界面及任意列表拓展
  18. 7.7.4 积分卡管理系统示例
  19. 利用Event实现WinUI层与Bussiness层 跨层间动态提示
  20. 怀旧服一区和五区服务器位置,魔兽怀旧服战场分组怎么看?怀旧服战场分组一区五区怎么分的?...

热门文章

  1. aes在tomcat解密中文乱码,在控制台解密中文不是乱码
  2. 将折旧表分配至公司代码时提示公司代码分录不完全解决方案
  3. 【 云原生 | kubernetes 】- tekton构建CI/CD流水线(二)
  4. Lect2 线性分类
  5. 运动模糊运动拖影果冻效应分析
  6. 聊一聊 C# 后台GC 到底是怎么回事?
  7. 移动WEB各种布局开发笔记
  8. RED5的API介紹-4
  9. 【NLP】⚠️学不会打我! 半小时学会基本操作 2⚠️词向量模型简介
  10. 移动端表格 横向纵向自适应