PyQt5的使用
布局
绝对布局
直接通过QLabel指定self使标签出现在窗口上
水平盒布局QHBoxLayout
可以使用布局对象的setSpacing()方法控制控件之间的间距
设置控件的对齐方式
可以通过在addWidget中增加两个参数改变伸缩量和对齐方式 第一个参数为按钮控件,第二个参数为伸缩量,第三个为对齐方式
垂直盒布局QVBoxLayout
设置布局的伸缩量addStretch
设置布局伸缩量有两种方法,第一种:添加控件时设置 第二种:addStretch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import sysfrom PyQt5.QtWidgets import *class Stretch (QWidget ): def __init__ (self ): super (Stretch, self ).__init__() self .setWindowTitle('设置伸缩量' ) btn1 = QPushButton('按钮1' ) btn2 = QPushButton('按钮2' ) btn3 = QPushButton('按钮3' ) layout = QHBoxLayout() layout.addStretch(1 ) layout.addWidget(btn1) layout.addStretch(2 ) layout.addWidget(btn2) layout.addStretch(3 ) layout.addWidget(btn3) self .setLayout(layout) if __name__ == '__main__' : app = QApplication(sys.argv) main = Stretch() main.show() sys.exit(app.exec_())
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import sysfrom PyQt5.QtWidgets import *class Stretch (QWidget ): def __init__ (self ): super (Stretch, self ).__init__() self .setWindowTitle('设置伸缩量' ) self .resize(800 ,100 ) btn1 = QPushButton('按钮1' ) btn2 = QPushButton('按钮2' ) btn3 = QPushButton('按钮3' ) btn4 = QPushButton('按钮4' ) btn5 = QPushButton('按钮5' ) layout = QHBoxLayout() layout.addStretch(0 ) layout.addWidget(btn1) layout.addStretch(1 ) layout.addWidget(btn2) layout.addWidget(btn3) layout.addWidget(btn4) layout.addWidget(btn5) btnOK = QPushButton('确定' ) btnCancel = QPushButton('取消' ) layout.addStretch(1 ) layout.addWidget(btnOK) layout.addWidget(btnCancel) self .setLayout(layout) if __name__ == '__main__' : app = QApplication(sys.argv) main = Stretch() main.show() sys.exit(app.exec_())
让按钮永远在窗口的右下角
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtCore import Qtclass RightBottomButton (QWidget ): def __init__ (self ): super (RightBottomButton, self ).__init__() self .setWindowTitle("让按钮永远在右下角" ) self .resize(400 , 300 ) okButton = QPushButton("确定" ) cancelButton = QPushButton('取消' ) hbox = QHBoxLayout() hbox.addStretch(1 ) hbox.addWidget(okButton) hbox.addWidget(cancelButton) vbox = QVBoxLayout() btn1 = QPushButton('按钮1' ) btn2 = QPushButton('按钮2' ) btn3 = QPushButton('按钮3' ) vbox.addStretch(0 ) vbox.addWidget(btn1) vbox.addWidget(btn2) vbox.addWidget(btn3) vbox.addStretch(1 ) vbox.addLayout(hbox) self .setLayout(vbox) if __name__ == '__main__' : app = QApplication(sys.argv) main = RightBottomButton() main.show() sys.exit(app.exec_())
两个布局,一个垂直布局一个水平布局通过addStretch设置伸缩量使它们分开
栅格布局QGridLayout
用循环方式实现计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import sysfrom PyQt5.QtWidgets import *class Calc (QWidget ): def __init__ (self ): super (Calc, self ).__init__() self .setWindowTitle('栅格布局' ) grid = QGridLayout() self .setLayout(grid) names = ['Cls' , 'Back' , '' , 'Close' , '7' , '8' , '9' , '/' , '4' , '5' , '6' , '*' , '1' , '2' , '3' , '-' , '0' , '.' , '=' , '+' , ] positions = [(i, j) for i in range (5 ) for j in range (4 )] print (positions) for position, name in zip (positions, names): if name == '' : continue button = QPushButton(name) grid.addWidget(button, *position) if __name__ == '__main__' : app = QApplication(sys.argv) main = Calc() main.show() sys.exit(app.exec_())
进行表单UI设计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import sysfrom PyQt5.QtWidgets import *class GridForm (QWidget ): def __init__ (self ): super (GridForm, self ).__init__() self .setWindowTitle('栅格布局:表单设计' ) titleLabel = QLabel('标题' ) authorLabel = QLabel('作者' ) contentLabel = QLabel('内容' ) titleEdit = QLineEdit() authorEdit = QLineEdit() contentEdit = QTextEdit() grid = QGridLayout() grid.setSpacing(10 ) grid.addWidget(titleLabel, 1 , 0 ) grid.addWidget(titleEdit, 1 , 1 ) grid.addWidget(authorLabel, 2 , 0 ) grid.addWidget(authorEdit, 2 , 1 ) grid.addWidget(contentLabel, 3 , 0 ) grid.addWidget(contentEdit, 3 , 1 , 5 , 1 ) self .setLayout(grid) self .resize(350 , 300 ) if __name__ == '__main__' : app = QApplication(sys.argv) main = GridForm() main.show() sys.exit(app.exec_())
表单设计可以通过栅格布局或者表单布局创建 主要区别是一个是使用addWidget 一个是使用addRow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import sysfrom PyQt5.QtWidgets import *class FormLayout (QWidget ): def __init__ (self ): super (FormLayout, self ).__init__() self .setWindowTitle('表单布局' ) titleLabel = QLabel('标题' ) authorLabel = QLabel('作者' ) contentLabel = QLabel('内容' ) titleEdit = QLineEdit() authorEdit = QLineEdit() contentEdit = QTextEdit() formLayout = QFormLayout() formLayout.addRow(titleLabel,titleEdit) formLayout.addRow(authorLabel,authorEdit) formLayout.addRow(contentLabel,contentEdit) self .setLayout(formLayout) if __name__ == '__main__' : app = QApplication(sys.argv) main = FormLayout() main.show() sys.exit(app.exec_())
拖动控件之间的边界(QSplitter)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class Splitter (QWidget ): def __init__ (self ): super (Splitter, self ).__init__() self .initUI() def initUI (self ): hbox = QHBoxLayout() self .setWindowTitle('QSplitter 例子' ) self .setGeometry(300 , 300 , 300 , 200 ) topleft = QFrame() topleft.setFrameShape(QFrame.StyledPanel) bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) textedit = QTextEdit() splitter1.addWidget(topleft) splitter1.addWidget(textedit) splitter1.setSizes([200 , 100 ]) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self .setLayout(hbox) if __name__ == '__main__' : app = QApplication(sys.argv) main = Splitter() main.show() sys.exit(app.exec_())
信号和槽
在 Qt 中,用户和控件的每次交互过程称为一个事件,比如“用户点击按钮”是一个事件,“用户关闭窗口”也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出“按钮被点击”的信号,用户关闭窗口会发出“窗口被关闭”的信号。
Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如,按钮所在的窗口接收到“按钮被点击”的信号后,会做出“关闭自己”的响应动作;再比如输入框自己接收到“输入框被点击”的信号后,会做出“显示闪烁的光标,等待用户输入数据”的响应动作。在 Qt 中,对信号做出的响应动作就称为槽。
图 1 信号和槽
信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如,“按钮被按下”这个信号可以用 clicked() 函数表示,“窗口关闭”这个槽可以用 close() 函数表示,信号和槽机制实现“点击按钮会关闭窗口”的功能,其实就是 clicked() 函数调用 close() 函数的效果。
connect()函数实现信号和槽
connect() 是 QObject 类中的一个静态成员函数,专门用来关联指定的信号函数和槽函数。 关联某个信号函数和槽函数,需要搞清楚以下 4 个问题:
信号发送者是谁?
哪个是信号函数?
信号的接收者是谁?
哪个是接收信号的槽函数?
不同控件对应的信号
Qlabel控件(标签控件): linkHovered(滑过时触发) linkActivated(单击时触发)
QLineEdit控件(输入框控件):textChanged(文本改变时触发),editingFinished(文本输入时触发)
QPushButton控件(普通按钮控件):clicked(单击按钮时触发)
QRadioButton控件(单选按钮控件):toggled(按钮被选中时触发)
QCheckBox控件(复选框控件 ):stateChanged(按钮状态改变时触发)
QComboBox控件(下拉列表控件):currentIndexChanged(列表选择改变时触发)
QSlider控件(滑块控件):valueChanged(当滑块的值改变时触发)
QSpinBox控件(计数器控件 ):valueChanged(当计数器中的值改变时触发
QAction创建菜单栏中的菜单或者工具栏中的工具:triggered(当点击菜单时触发)
tb1 = self.addToolBar(“File”)创建的工具栏(是工具栏而不是工具):actionTriggered (当点击工具栏中的任意一个工具就会触发)
QListWidget() 扩展的列表控件 :itemClicked (当点击列表中的某一项时触发,触发时传参数是QListWidgetItem )
QListWidget() 扩展的列表控件:currentRowChanged(当改变选择的列表行时调用)
生成自定义信号pyqtSignal
通过生成pyqtSignal的实例(可自定义发送时的参数类型)(pyqtSignal是QObject中的方法因此需要在类中定义信号) 使用时需要先关联再通过emit发送参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 from PyQt5.QtCore import *class MyTypeSignal (QObject ): '''自定义信号的类''' sendmsg = pyqtSignal(object ) sendmsg1 = pyqtSignal(str , int , int ) def run (self ): '''自定义信号发送时传入的参数''' self .sendmsg.emit('Hello PyQt5' ) def run1 (self ): self .sendmsg1.emit('hello' , 3 , 4 ) class MySlot (QObject ): '''自定义槽''' def get (self, msg ): print ('信息:' + msg) def get1 (self, msg, a, b ): print (msg) print (a + b) if __name__ == '__main__' : send = MyTypeSignal() slot = MySlot() send.sendmsg.connect(slot.get) send.sendmsg1.connect(slot.get1) send.run() send.run1() send.sendmsg.disconnect(slot.get) send.run()
输出: 信息:Hello PyQt5 hello 7
为类添加多个信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from PyQt5.QtCore import *class MultiSignal (QObject ): signal1 = pyqtSignal() signal2 = pyqtSignal(int ) signal3 = pyqtSignal(int , str ) signal4 = pyqtSignal(list ) signal5 = pyqtSignal(dict ) signal6 = pyqtSignal([int , str ], [str ]) def __init__ (self ): super (MultiSignal, self ).__init__() self .signal1.connect(self .signalCall1) self .signal2.connect(self .signalCall2) self .signal3.connect(self .signalCall3) self .signal4.connect(self .signalCall4) self .signal5.connect(self .signalCall5) self .signal6[str ].connect(self .signalCall6Overload) self .signal6[int , str ].connect(self .signalCall6) self .signal1.emit() self .signal2.emit(10 ) self .signal3.emit(1 , 'hello world' ) self .signal4.emit([1 , 2 , 3 , 4 , 5 , 6 ]) self .signal5.emit({"name" : "Bill" , "age" : 30 }) self .signal6[str ].emit("test" ) self .signal6[int , str ].emit(100 , "mytest" ) def signalCall1 (self ): print ('signal1 emit' ) def signalCall2 (self, val ): print ('signal2 emit,value:' , val) def signalCall3 (self, val, text ): print ('signal3 emit.value:' , val, text) def signalCall4 (self, val ): print ('signal4 emit,value:' , val) def signalCall5 (self, val ): print ('signal5 emit,value:' , val) def signalCall6 (self, val, text ): print ('signal6 emit,value:' , val, text) def signalCall6Overload (self, val ): print ('signal6 overload emit,value:' , val) if __name__ == '__main__' : multiSignal = MultiSignal()
输出: signal1 emit signal2 emit,value: 10 signal3 emit.value: 1 hello world signal4 emit,value: [1, 2, 3, 4, 5, 6] signal5 emit,value: {‘name’: ‘Bill’, ‘age’: 30} signal6 overload emit,value: test signal6 emit,value: 100 mytest
信号和槽的N对N连接和断开连接
没什么需要讲的,就是定义的信号可以连接并发送给不同的槽,以及多个信号可以共用一个槽 断开连接上上一节已经使用过了,就是使用disconnect方法。
为窗口添加信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass WinSignal (QWidget ): button_clicked_signal = pyqtSignal() def __init__ (self ): super (WinSignal, self ).__init__() self .setWindowTitle('为窗口类增加信号' ) self .resize(300 , 100 ) btn = QPushButton('关闭窗口' , self ) btn.clicked.connect(self .btn_clicked) self .button_clicked_signal.connect(self .btn_close) def btn_clicked (self ): self .button_clicked_signal.emit() def btn_close (self ): self .close() if __name__ == '__main__' : app = QApplication(sys.argv) main = WinSignal() main.show() sys.exit(app.exec_())
点击关闭窗口后调用自定义信号所绑定的槽实现关闭窗口的功能。
多线程更新UI数据(在两个线程中传递数据)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import sysimport timefrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class BackendThread (QThread ): update_date = pyqtSignal(str ) def run (self ): while True : data = QDateTime.currentDateTime() currentTime = data.toString("yyyy-MM-dd hh:mm:ss" ) self .update_date.emit(str (currentTime)) time.sleep(1 ) class ThreadUpdateUI (QDialog ): def __init__ (self ): QDialog.__init__(self ) self .setWindowTitle('多线程更新UI数据' ) self .resize(400 , 100 ) self .input = QLineEdit(self ) self .input .resize(400 , 100 ) self .initUI() def initUI (self ): self .backend = BackendThread() self .backend.update_date.connect(self .handleDisplay) self .backend.start() def handleDisplay (self, data ): self .input .setText(data) if __name__ == '__main__' : app = QApplication(sys.argv) main = ThreadUpdateUI() main.show() sys.exit(app.exec_())
信号与槽自动连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 from PyQt5 import QtCorefrom PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButtonimport sysclass AutoSignalSlot (QWidget ): def __init__ (self ): super (AutoSignalSlot, self ).__init__() self .okButton = QPushButton('ok' , self ) self .okButton.setObjectName('okButton' ) self .okButton1 = QPushButton('cancel' , self ) self .okButton1.setObjectName('cancelButton' ) layout = QHBoxLayout() layout.addWidget(self .okButton) self .setLayout(layout) self .resize(200 , 100 ) QtCore.QMetaObject.connectSlotsByName(self ) @QtCore.pyqtSlot() def on_okButton_clicked (self ): print ('点击了ok按钮' ) @QtCore.pyqtSlot() def on_cancelButton_clicked (self ): print ('点击了cancel按钮' ) if __name__ == '__main__' : app = QApplication(sys.argv) main = AutoSignalSlot() main.show() sys.exit(app.exec_())
用Lambda表达式为槽函数传递参数
先介绍一下Lambda表达式 Lambda表达式名字叫做匿名函数,就是没有名字的函数。 目前个人理解: lambda中的冒号前面是输入参数,冒号后面是返回值。 lambda函数本身是一个函数,可以通过将lambda函数赋值给一个变量,然后就可以通过变量间接的调用lambda函数 使用介绍: fun = lambda: print(“hello world”) fun()# 不需要输入直接返回 hello world fun1 = lambda x, y: print(x, y) fun1(“a”, “b”) # 输入两个参数x,y返回(x,y) 输出: hello world a b
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from PyQt5.QtWidgets import *import sysclass LambdaSlotArg (QMainWindow ): def __init__ (self ): super (LambdaSlotArg, self ).__init__() self .setWindowTitle("使用Lambda表达式为槽函数传递参数" ) button1 = QPushButton("按钮1" ) button2 = QPushButton("按钮2" ) ok = 100 button1.clicked.connect(lambda : self .onButtonClick(10 , ok)) button2.clicked.connect(lambda : self .onButtonClick(ok, -20 )) button1.clicked.connect(lambda : QMessageBox.information(self , "结果" , "单击了button1" )) layout = QHBoxLayout() layout.addWidget(button1) layout.addWidget(button2) mainFrame = QWidget() mainFrame.setLayout(layout) self .setCentralWidget(mainFrame) def onButtonClick (self, m, n ): print ('m+n=' , m + n) QMessageBox.information(self , '结果' , str (m + n)) if __name__ == '__main__' : app = QApplication(sys.argv) main = LambdaSlotArg() main.show() sys.exit(app.exec_())
用partial对象为槽函数传递参数
partial介绍:和装饰器一样,它可以扩展函数的功能,但又不完成等价于装饰器。 使用时需要先导入partial模块 from functools import partial partial使用:类func = functools.partial(func, args, keywords) func为要增强的函数,args为元组类型数据(不需要在意名字,名字是什么无所谓,需要在意的是 ),keywords为字典类型数据(不需要在意名字,名字是什么无所谓,需要在意的是 ) args和keywords这些数据为默认传入func的数据。 举例: def add(*args): return sum(args) add_100 = partial(add, 100) print(add_100(1, 2, 3)) # 106 partial与lambda为槽函数传递参数的区别:
override(覆盖)槽函数
举例覆盖系统自带的槽函数:KeyPressEvent 按下键盘时执行事件: 这段代码的功能就是新增了两个键盘对应事件: 当按下esc键时关闭程序 当按下alt键时更改窗口标题名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from PyQt5.QtWidgets import *from PyQt5.QtCore import *import sysclass OverrideSlot (QWidget ) : def __init__ (self ): super (OverrideSlot, self ).__init__() self .setWindowTitle("Override(覆盖)槽函数" ) def keyPressEvent (self,e ) : if e.key() == Qt.Key_Escape : self .close() elif e.key() == Qt.Key_Alt : self .setWindowTitle("按下Alt键" ) if __name__ == '__main__' : app = QApplication(sys.argv) main = OverrideSlot() main.show() sys.exit(app.exec_())
多窗口交互(1):不使用信号与槽
多窗口交互介绍: 举例:在窗口1选择的内容在窗口2显示 如果不使用信号与槽那么就需要在窗口1直接调用窗口2的控件。 这种方法在编程方面更简单,但是缺点就是耦合性太强。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class DateDialog (QDialog ): """ 窗口1.显示日期 """ def __init__ (self, parent=None ): super (DateDialog, self ).__init__(parent) self .setWindowTitle("DateDialog" ) layout = QVBoxLayout(self ) self .datetime = QDateTimeEdit(self ) self .datetime.setCalendarPopup(True ) self .datetime.setDateTime(QDateTime.currentDateTime()) layout.addWidget(self .datetime) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self ) buttons.accepted.connect(self .accept) buttons.rejected.connect(self .reject) layout.addWidget(buttons) def dateTime (self ): return self .datetime.dateTime() @staticmethod def getDateTime (parent=None ): dialog = DateDialog(parent) result = dialog.exec () date = dialog.dateTime() return (date.date(), date.time(), result == QDialog.Accepted) class MultiWindow1 (QWidget ): def __init__ (self ): super (MultiWindow1, self ).__init__() self .setWindowTitle("多窗口交互(1):不使用信号与槽" ) self .lineEdit = QLineEdit(self ) self .button1 = QPushButton("弹出对话框1" ) self .button1.clicked.connect(self .onButton1Click) self .button2 = QPushButton('弹出对话框2' ) self .button2.clicked.connect(self .onButton2Click) gridLayout = QGridLayout() gridLayout.addWidget(self .lineEdit) gridLayout.addWidget(self .button1) gridLayout.addWidget(self .button2) self .setLayout(gridLayout) def onButton1Click (self ): dialog = DateDialog(self ) result = dialog.exec () date = dialog.dateTime() self .lineEdit.setText(date.date().toString()) dialog.destroy() def onButton2Click (self ): date, time, result = DateDialog.getDateTime() self .lineEdit.setText(date.toString()) if result == QDialog.Accepted: print ('点击确定按钮' ) else : print ("点击取消按钮" ) if __name__ == '__main__' : app = QApplication(sys.argv) main = MultiWindow1() main.show() sys.exit(app.exec_())
多窗口交互(2):使用信号与槽
如果一个窗口A和另一个窗口B交互,那么A尽量不要直接访问B窗口中的控件,应该访问B窗口中的信号,并指定与信号绑定的槽函数 例: 如果A直接访问B窗口的控件,一旦B窗口控件发生改变,那么A和B的代码都需要变化 如果A访问的是B中的信号,那么B中的控件发生了改变,只需要修改B中的代码即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class NewDateDialog (QDialog ): Signal_OneParameter = pyqtSignal(str ) def __init__ (self, parent=None ): super (NewDateDialog, self ).__init__(parent) self .setWindowTitle('子窗口:用来发射信号' ) layout = QVBoxLayout(self ) self .label = QLabel(self ) self .label.setText('前者发射内置信号\n后者发射自定义信号' ) self .datetime_inner = QDateTimeEdit(self ) self .datetime_inner.setCalendarPopup(True ) self .datetime_inner.setDateTime(QDateTime.currentDateTime()) self .datetime_emit = QDateTimeEdit(self ) self .datetime_emit.setCalendarPopup(True ) self .datetime_emit.setDateTime(QDateTime.currentDateTime()) layout.addWidget(self .label) layout.addWidget(self .datetime_inner) layout.addWidget(self .datetime_emit) buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self ) buttons.accepted.connect(self .accept) buttons.rejected.connect(self .reject) layout.addWidget(buttons) self .datetime_emit.dateTimeChanged.connect(self .emit_signal) def emit_signal (self ): date_str = self .datetime_emit.dateTime().toString() self .Signal_OneParameter.emit(date_str) class MultiWindow2 (QWidget ): def __init__ (self, parent=None ): super (MultiWindow2, self ).__init__(parent) self .resize(400 , 90 ) self .setWindowTitle('多窗口交互(2):使用信号与槽' ) self .open_btn = QPushButton('获取时间' ) self .lineEdit_inner = QLineEdit(self ) self .lineEdit_emit = QLineEdit(self ) self .open_btn.clicked.connect(self .openDialog) self .lineEdit_inner.setText('接收子窗口内置信号的时间' ) self .lineEdit_emit.setText('接收子窗口自定义信号的时间' ) grid = QGridLayout() grid.addWidget(self .lineEdit_inner) grid.addWidget(self .lineEdit_emit) grid.addWidget(self .open_btn) self .setLayout(grid) def openDialog (self ): dialog = NewDateDialog(self ) dialog.datetime_inner.dateTimeChanged.connect(self .deal_inner_slot) dialog.Signal_OneParameter.connect(self .deal_emit_slot) dialog.show() def deal_inner_slot (self, date ): self .lineEdit_inner.setText(date.toString()) def deal_emit_slot (self, dateStr ): self .lineEdit_emit.setText(dateStr) if __name__ == "__main__" : app = QApplication(sys.argv) form = MultiWindow2() form.show() sys.exit(app.exec_())
开发第一个基于PyQt5的桌面应用
PyQt5的类都是以Q开头的。 开发时必须使用两个类:QApplication (这个代表整个应用程序)和QWidget (这个代表应用窗口,也可以用QMainWindow ,QDialog 代替,详情在下面有讲)。这两个类都在PyQt5.QtWidget这个模块中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import sysfrom PyQt5.QtWidgets import QApplication, QWidgetif __name__ == '__main__' : app = QApplication(sys.argv) w = QWidget() w.resize(400 , 200 ) w.move(300 , 300 ) w.setWindowTitle("第一个基于PyQt5的桌面应用" ) w.show() sys.exit(app.exec_())
效果:
创建主窗口
有3种窗口 QMainWindow类生成的窗口自带菜单栏、工具栏和状态栏,中央区域还可以添加多个控件,常用来作为应用程序的主窗口 QWidget:所有的控件类都直接或者间接继承自 QWidget 类,它既可以用来制作窗口,也可以作为某个窗口上的控件。 QDialog:是对话窗口的基类,(对话窗口就是在主窗口里选择一个功能后,弹出的窗口,不关闭这个窗口是无法回到主窗口的。)没有菜单栏、工具栏、状态栏,但可以添加多个控件。 实际开发中,制作应用程序的主窗口可以用 QMainWindow 或者 QWdiget;制作一个提示信息的对话框就用 QDialog 或 QWidget;如果暂时无法决定,后续可能作为窗口,也可能作为控件,就选择 QWidget。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import sysfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom PyQt5.QtGui import QIconclass FirstMainWin (QMainWindow ): def __init__ (self ): super (FirstMainWin, self ).__init__() self .setWindowTitle("第一个主窗口应用" ) self .resize(400 , 300 ) self .status = self .statusBar() self .status.showMessage('只存在5秒的消息' , 5000 ) if __name__ == '__main__' : app = QApplication(sys.argv) app.setWindowIcon(QIcon('./images/bool.png' )) main = FirstMainWin() main.show() sys.exit(app.exec_())
效果:其中下面的标签栏只会显示5秒钟就消失了
退出应用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import sysfrom PyQt5.QtWidgets import QHBoxLayout, QMainWindow, QApplication, QPushButton, QWidgetclass QuitApplication (QMainWindow ): def __init__ (self ): super (QuitApplication, self ).__init__() self .resize(300 , 120 ) self .setWindowTitle("退出应用程序" ) self .button1 = QPushButton('退出应用程序' ) self .button1.clicked.connect(self .onClick_Button) layout = QHBoxLayout() layout.addWidget(self .button1) mainFrame = QWidget() mainFrame.setLayout(layout) self .setCentralWidget(mainFrame) def onClick_Button (self ): sender = self .sender() print (sender.text() + '按钮被按下' ) app = QApplication.instance() app.quit() if __name__ == '__main__' : app = QApplication(sys.argv) main = QuitApplication() main.show() sys.exit(app.exec_())
屏幕坐标系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import sysfrom PyQt5.QtWidgets import QHBoxLayout, QMainWindow, QApplication, QPushButton, QWidgetapp = QApplication(sys.argv) def onClicked_Button (): print ("1" ) print ("widget.x()=%d" % widget.x()) print ("widget.y()=%d" % widget.y()) print ("widget.width()=%d" % widget.width()) print ("widget.height()=%d" % widget.height()) print ("2" ) print ("widget.geometry().x() = %d" % widget.geometry().x()) print ("widget.geometry().y() = %d" % widget.geometry().y()) print ("widget.geometry().width()=%d" % widget.geometry().width()) print ("widget.geometry().height()=%d" % widget.geometry().height()) print ("3" ) print ("widget.frameGeometry().x() = %d" % widget.frameGeometry().x()) print ("widget.frameGeometry().y() = %d" % widget.frameGeometry().y()) print ("widget.frameGeometry().width()=%d" % widget.frameGeometry().width()) print ("widget.frameGeometry().height()=%d" % widget.frameGeometry().height()) widget = QWidget() btn = QPushButton(widget) btn.setText("按钮" ) btn.clicked.connect(onClicked_Button) btn.move(24 , 52 ) widget.resize(300 , 240 ) widget.move(250 , 200 ) widget.setWindowTitle("屏幕坐标系" ) widget.show() sys.exit(app.exec_())
设置窗口和应用图标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import sysfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom PyQt5.QtGui import QIconclass iconForm (QMainWindow ): def __init__ (self ): super (iconForm, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("设置窗口图标" ) self .setGeometry(300 , 300 , 250 , 250 ) self .setWindowIcon(QIcon('./images/bool.png' )) if __name__ == '__main__' : app = QApplication(sys.argv) main = iconForm() main.show() sys.exit(app.exec_())
为控件添加提示信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import sysfrom PyQt5.QtWidgets import QHBoxLayout, QMainWindow, QApplication, QPushButton, QWidget, QToolTipfrom PyQt5.QtGui import QFontclass TooltipForm (QMainWindow ): def __init__ (self ): super (TooltipForm, self ).__init__() self .initUI() def initUI (self ): QToolTip.setFont(QFont('SansSerif' , 12 )) self .setToolTip("今天是<b>星期五<\b>" ) self .setGeometry(300 , 300 , 200 , 300 ) self .setWindowTitle("显示控件提示消息" ) self .button1 = QPushButton("我的按钮" ) self .button1.setToolTip("提示:这是一个按钮" ) layout = QHBoxLayout() layout.addWidget(self .button1) mainFrame = QWidget() mainFrame.setLayout(layout) self .setCentralWidget(mainFrame) if __name__ == '__main__' : app = QApplication(sys.argv) main = TooltipForm() main.show() sys.exit(app.exec_())
效果:
QLabel控件的基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import sysfrom PyQt5.QtWidgets import QVBoxLayout, QMainWindow, QApplication, QWidget, QLabelfrom PyQt5.QtGui import QPalette, QPixmapfrom PyQt5.QtCore import Qtclass QLabelDemo (QWidget ): def __init__ (self ): super (QLabelDemo, self ).__init__() self .initUI() def initUI (self ): label1 = QLabel(self ) label2 = QLabel(self ) label3 = QLabel(self ) label4 = QLabel(self ) label1.setText("<font color=yellow>这是一个文本标签。</font>" ) label1.setAutoFillBackground(True ) palette = QPalette() palette.setColor(QPalette.Window, Qt.blue) label1.setPalette(palette) label1.setAlignment(Qt.AlignCenter) label2.setText("<a href='#'>欢迎使用Python GUI程序</a>" ) label3.setAlignment(Qt.AlignCenter) label3.setToolTip('这是一个图片标签' ) label3.setPixmap(QPixmap("./images/bool.png" )) label4.setOpenExternalLinks(True ) label4.setText("<a href='https://wallhaven.cc'>壁纸网站</a>" ) label4.setAlignment(Qt.AlignRight) label4.setToolTip("这是一个超级链接" ) vbox = QVBoxLayout() vbox.addWidget(label1) vbox.addWidget(label2) vbox.addWidget(label3) vbox.addWidget(label4) label2.linkHovered.connect(self .linkHovered) label4.linkActivated.connect(self .linkClicked) self .setLayout(vbox) self .setWindowTitle("QLabel控件演示" ) def linkHovered (self ): print ("鼠标滑动到了label2标签并触发了事件" ) def linkClicked (self ): print ("鼠标点击了label4标签并触发了事件" ) if __name__ == "__main__" : app = QApplication(sys.argv) main = QLabelDemo() main.show() sys.exit(app.exec_())
运行效果:
QLabel与伙伴控件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from PyQt5.QtWidgets import *import sysclass QlabelBuddy (QDialog ): def __init__ (self ): super (QlabelBuddy, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("QLabel与伙伴控件" ) nameLabel = QLabel('&Name' , self ) nameLineEdit = QLineEdit(self ) nameLabel.setBuddy(nameLineEdit) passwordnameLabel = QLabel('&password' , self ) passwordnameLineEdit = QLineEdit(self ) passwordnameLabel.setBuddy(passwordnameLineEdit) btnOK = QPushButton("&OK" ) btnCancel = QPushButton("&Cancel" ) mainLayout = QGridLayout(self ) mainLayout.addWidget(nameLabel, 0 , 0 ) mainLayout.addWidget(nameLineEdit, 0 , 1 , 1 , 2 ) mainLayout.addWidget(passwordnameLabel, 1 , 0 ) mainLayout.addWidget(passwordnameLineEdit, 1 , 1 , 1 , 2 ) mainLayout.addWidget(btnOK, 2 , 1 ) mainLayout.addWidget(btnCancel, 2 , 2 ) if __name__ == '__main__' : app = QApplication(sys.argv) main = QlabelBuddy() main.show() sys.exit(app.exec_())
效果:
QLIneEdit
QLineEdit控件和回显模式
QLineEdit控件上一节使用过,就是这个 生成可编辑的文字框。 EchoMode回显模式 回显模式有四种: 1.Normal 就是正常的输入后显示输出 2.NoEcho 意思是输入后什么都不显示在屏幕上,但是机器能够读取到。 3.Password 意思是输入后以符号表示输入。 4.PasswordEchoOnEdit 意思是编辑时显示正常,不编辑时显示符号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from PyQt5.QtWidgets import *import sysclass QLineEditEchoMode (QWidget ): def __init__ (self ): super (QLineEditEchoMode, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("文本输入框的回显模式" ) formLayout = QFormLayout() normalLineEdit = QLineEdit() noEchoLineEdit = QLineEdit() passworldLineEdit = QLineEdit() passwordEchoOnEditLineEdit = QLineEdit() formLayout.addRow("Normal" , normalLineEdit) formLayout.addRow("NoEcho" , noEchoLineEdit) formLayout.addRow("Passworld" , passworldLineEdit) formLayout.addRow("PasswordEchoOnEdit" , passwordEchoOnEditLineEdit) normalLineEdit.setPlaceholderText("Normal" ) noEchoLineEdit.setPlaceholderText("NoEcho" ) passworldLineEdit.setPlaceholderText("Password" ) passwordEchoOnEditLineEdit.setPlaceholderText("PasswordEchoOnEdit" ) normalLineEdit.setEchoMode(QLineEdit.Normal) noEchoLineEdit.setEchoMode(QLineEdit.NoEcho) passworldLineEdit.setEchoMode(QLineEdit.Password) passwordEchoOnEditLineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit) self .setLayout(formLayout) if __name__ == '__main__' : app = QApplication(sys.argv) main = QLineEditEchoMode() main.show() sys.exit(app.exec_())
效果: 其中passwordechoonedit是输入是为数字切换到其他框后就变成圆圈,noecho是已经输入了但是不显示在屏幕上
限制QLineEdit控件的输入(校验器)
限制举例: 只能输入整数、浮点数或满足一定条件的字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 from PyQt5.QtWidgets import *from PyQt5.QtGui import QIntValidator, QDoubleValidator, QRegExpValidatorfrom PyQt5.QtCore import QRegExpimport sysclass QLineEditValidator (QWidget ): def __init__ (self ): super (QLineEditValidator, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("校验器" ) formLayout = QFormLayout() intLineEdit = QLineEdit() doubleLineEdit = QLineEdit() validatorLineEdit = QLineEdit() formLayout.addRow("整数类型" , intLineEdit) formLayout.addRow("浮点类型" , doubleLineEdit) formLayout.addRow("数字和字母" , validatorLineEdit) intLineEdit.setPlaceholderText("整型" ) doubleLineEdit.setPlaceholderText("浮点型" ) validatorLineEdit.setPlaceholderText("字母和数字" ) intValidator = QIntValidator() intValidator.setRange(1 , 99 ) doubleValidator = QDoubleValidator() doubleValidator.setRange(-360 , 360 ) doubleValidator.setNotation(QDoubleValidator.StandardNotation) doubleValidator.setDecimals(2 ) reg = QRegExp("[a-zA-Z0-9]+$" ) validator = QRegExpValidator() validator.setRegExp(reg) intLineEdit.setValidator(intValidator) doubleLineEdit.setValidator(doubleValidator) validatorLineEdit.setValidator(validator) self .setLayout(formLayout) if __name__ == '__main__' : app = QApplication(sys.argv) main = QLineEditValidator() main.show() sys.exit(app.exec_())
使用掩码限制QLineEdit控件的输入
字符 含义 A ASCII字母字符是必须输入的(A-Z,a-z) a ASCII字母字符是允许输入的,但不是必须输入的 N ASCII字母字符是必须输入的(A-Z,a-z,0-9) n ASCII字母字符是允许输入的,但不是必须输入的 X 任何字符都是必须输入 x 任何字符都是允许输入的,但不是必须输入的 9 ASCII数字字符是必须输入的(0-9) 0 ASCII数字字符是允许输入的,但不是必须输入的 D ASCII数字字符是必须输入的(1-9) d ASCII数字字符是允许输入的,但不是必须的(1-9) # ASCII数字字符与加减字符是允许输入的,但不是必须的 H 十六进制格式字符是必须输入的(A-F,a-f,0-9) h 十六进制格式字符允许输入,但不是必须的 B 二进制格式字符是必须输入的(0,1) b 二进制格式字符是允许输入的,但不是必须的 > 所有字母字符都大写 < 所有字母字符都小写 ! 关闭大小写转换 \ 使用‘\’转义上面列出的字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import sysfrom PyQt5.QtWidgets import *class QLIneEditMask (QWidget ): def __init__ (self ): super (QLIneEditMask, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("用掩码限制QLineEdit控件的输入" ) formlayout = QFormLayout() ipLineEdit = QLineEdit() macLineEdit = QLineEdit() dateLineEdit = QLineEdit() licenseLineEdit = QLineEdit() ipLineEdit.setInputMask('000.000.000.000;_' ) macLineEdit.setInputMask('HH:HH:HH:HH:HH:HH;_' ) dateLineEdit.setInputMask('0000-00-00' ) licenseLineEdit.setInputMask('>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#' ) formlayout.addRow('数字掩码' , ipLineEdit) formlayout.addRow('Mac掩码' , macLineEdit) formlayout.addRow('日期掩码' , dateLineEdit) formlayout.addRow('许可证掩码' , licenseLineEdit) self .setLayout(formlayout) if __name__ == '__main__' : app = QApplication(sys.argv) main = QLIneEditMask() main.show() sys.exit(app.exec_())
QLineEdit控件综合案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import Qtimport sysclass QLineEditDemo (QWidget ): def __init__ (self ): super (QLineEditDemo, self ).__init__() self .initUI() def initUI (self ): edit1 = QLineEdit() edit1.setValidator(QIntValidator()) edit1.setMaxLength(4 ) edit1.setAlignment(Qt.AlignRight) edit1.setFont(QFont('Arial' , 10 )) edit2 = QLineEdit() doubleValidator = QDoubleValidator() doubleValidator.setRange(0.99 , 99 ) doubleValidator.setNotation(QDoubleValidator.StandardNotation) doubleValidator.setDecimals(2 ) edit2.setValidator(doubleValidator) edit3 = QLineEdit() edit3.setInputMask("99_9999_999999;#" ) edit4 = QLineEdit() edit4.textChanged.connect(self .textChanged) edit5 = QLineEdit() edit5.setEchoMode(QLineEdit.Password) edit5.editingFinished.connect(self .enterPress) edit6 = QLineEdit() edit6.setReadOnly(True ) formlayout = QFormLayout() formlayout.addRow("整数校验" , edit1) formlayout.addRow("浮点数校验" , edit2) formlayout.addRow("Input Mask" , edit3) formlayout.addRow("文本变化" , edit4) formlayout.addRow("密码" , edit5) formlayout.addRow("只读" , edit6) self .setLayout(formlayout) self .setWindowTitle("QLineEdit综合案例" ) def textChanged (self, text ): print ('输入的内容:' + text) def enterPress (self ): print ('已输入值' ) if __name__ == '__main__' : app = QApplication(sys.argv) main = QLineEditDemo() main.show() sys.exit(app.exec_())
使用QTextEdit控件输入多行文本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 from PyQt5.QtWidgets import *import sysclass QTextEditDemo (QWidget ): def __init__ (self ): super (QTextEditDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("QTextEdit控件演示" ) self .resize(300 , 320 ) self .textEdit = QTextEdit() buttonText = QPushButton("显示文本" ) buttonHTML = QPushButton("显示HTML" ) buttonToText = QPushButton("获取文本" ) buttonToHTML = QPushButton("获取HTML" ) layout = QVBoxLayout() layout.addWidget(self .textEdit) layout.addWidget(buttonText) layout.addWidget(buttonToText) layout.addWidget(buttonHTML) layout.addWidget(buttonToHTML) self .setLayout(layout) buttonText.clicked.connect(self .onClick_ButtonText) buttonToText.clicked.connect(self .onClick_ButtonToText) buttonHTML.clicked.connect(self .onClick_ButtonHTML) buttonToHTML.clicked.connect(self .onClick_ButtonToHTML) def onClick_ButtonText (self ): self .textEdit.setPlainText('Hello World,世界你好吗?' ) def onClick_ButtonToText (self ): print (self .textEdit.toPlainText()) def onClick_ButtonHTML (self ): self .textEdit.setHtml('<font color="blue" size="5">Hello World</font>' ) def onClick_ButtonToHTML (self ): print (self .textEdit.toHtml()) if __name__ == '__main__' : app = QApplication(sys.argv) main = QTextEditDemo() main.show() sys.exit(app.exec_())
按钮控件
按钮控件有 QPushButton 普通按钮 AToolButton 工具条按钮 QRadioButton 单选按钮 QCheckBox 复选框
使用lambda表达式,可以在连接信号与槽时,将信号自身的信息作为参数传递给槽
也可以通过sender来获得信号自身的信息(这样还不需要定义为成员变量了。) 举例: self.button1.clicked.connect(lambda: self.whichButton(self.button1))改成 button1.clicked.connect(self.whichButton) whichButton函数中通过 # 得到发送信号的对象 sender = self.sender() # sender.text为发送信号的对象的名字 print(sender.text() + ‘按钮被按下’) 这里的from PyQt5.QtCore import *好像并没有什么用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QPushButtonDemo (QDialog ): def __init__ (self ): super (QPushButtonDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("QPushButtonDemo" ) layout = QVBoxLayout() self .button1 = QPushButton('第一个按钮' ) self .button1.setText('First Button1' ) self .button1.setCheckable(True ) self .button1.toggle() self .button1.clicked.connect(self .buttonState) self .button1.clicked.connect(lambda : self .whichButton(self .button1)) layout.addWidget(self .button1) button2 = QPushButton("图像按钮" ) button2.setIcon(QIcon('./images/bool.png' )) button2.clicked.connect(lambda : self .whichButton(button2)) layout.addWidget(button2) button3 = QPushButton("不可用的按钮" ) button3.setEnabled(False ) layout.addWidget(button3) button4 = QPushButton("&MyButton" ) button4.setDefault(True ) button4.clicked.connect(lambda : self .whichButton(button4)) layout.addWidget(button4) self .setLayout(layout) self .resize(400 , 300 ) def buttonState (self ): if self .button1.isChecked(): print ('按钮1已经被选中' ) else : print ('按钮1未被选中' ) def whichButton (self, btn ): print ("被单击的按钮是<" + btn.text() + '>' ) if __name__ == '__main__' : app = QApplication(sys.argv) main = QPushButtonDemo() main.show() sys.exit(app.exec_())
单选按钮: 单选按钮需要放在一个容器里,这样它们之间才能产生联系 这里from PyQt5.QtGui import * from PyQt5.QtCore import * 也是没什么用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QRadioButtonDemo (QWidget ): def __init__ (self ): super (QRadioButtonDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("QRadioButton" ) layout = QHBoxLayout() button1 = QRadioButton('单选按钮1' ) button1.setChecked(True ) button1.toggled.connect(self .buttonState) layout.addWidget(button1) button2 = QRadioButton("单选按钮2" ) button2.toggled.connect(self .buttonState) layout.addWidget(button2) self .setLayout(layout) def buttonState (self ): radioButton = self .sender() if radioButton.isChecked() == True : print ('<' +radioButton.text()+'>被选中' ) else : print ('<' +radioButton.text()+'>被取消选中状态' ) if __name__ == '__main__' : app = QApplication(sys.argv) main = QRadioButtonDemo() main.show() sys.exit(app.exec_())
QCheckBox
QCheckBox控件有三种状态 未选中:0 半选中:1 选中:2 这三种状态可以通过checkState方法来获取到 要想拥有半选中状态需要为定义的复选框使用setTristate(True)方法.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QCheckBoxDemo (QWidget ): def __init__ (self ): super (QCheckBoxDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("复选框控件演示" ) layout = QHBoxLayout() self .checkBox1 = QCheckBox('复选框控件1' ) self .checkBox1.setChecked(True ) self .checkBox1.stateChanged.connect(lambda : self .checkBoxState(self .checkBox1)) layout.addWidget(self .checkBox1) self .checkBox2 = QCheckBox('复选框控件2' ) self .checkBox2.stateChanged.connect(lambda : self .checkBoxState(self .checkBox1)) layout.addWidget(self .checkBox2) self .checkBox3 = QCheckBox('半选中' ) self .checkBox3.setTristate(True ) self .checkBox3.setCheckState(Qt.PartiallyChecked) self .checkBox3.stateChanged.connect(lambda : self .checkBoxState(self .checkBox1)) layout.addWidget(self .checkBox3) self .setLayout(layout) def checkBoxState (self, cb ): """ 输出三个复选框的的名字加上是否被选中加上选择的状态(0,1,2) :param cb: :return: """ check1Status = self .checkBox1.text() + ',isChecked=' + str (self .checkBox1.isChecked()) + ',checkState=' + str ( self .checkBox1.checkState()) + '\n' check2Status = self .checkBox2.text() + ',isChecked=' + str (self .checkBox2.isChecked()) + ',checkState=' + str ( self .checkBox2.checkState()) + '\n' check3Status = self .checkBox3.text() + ',isChecked=' + str (self .checkBox3.isChecked()) + ',checkState=' + str ( self .checkBox3.checkState()) + '\n' print (check1Status + check2Status + check3Status) if __name__ == '__main__' : app = QApplication(sys.argv) main = QCheckBoxDemo() main.show() sys.exit(app.exec_())
下拉列表控件(QComboBox)
下拉列表属于这种 这节学习
如何将列表项添加到QComboBox控件中
如何获取选中的列表项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QCheckBoxDemo (QWidget ): def __init__ (self ): super (QCheckBoxDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("下拉列表控件演示" ) self .resize(300 , 100 ) layout = QVBoxLayout() self .label = QLabel("请选择编程语言" ) self .cb = QComboBox() self .cb.addItem('C++' ) self .cb.addItem('Python' ) self .cb.addItems(['Java' , 'C#' , 'Ruby' ]) self .cb.currentIndexChanged.connect(self .selectionChange) layout.addWidget(self .label) layout.addWidget(self .cb) self .setLayout(layout) def selectionChange (self, i ): self .label.setText(self .cb.currentText()) self .label.adjustSize() for count in range (self .cb.count()): print ('item' + str (count) + '=' + self .cb.itemText(count)) print ('current index' , i, 'selection changed' , self .cb.currentText()) if __name__ == '__main__' : app = QApplication(sys.argv) main = QCheckBoxDemo() main.show() sys.exit(app.exec_())
效果:
滑块控件(QSlider)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QSliderDemo (QWidget ): def __init__ (self ): super (QSliderDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("滑块控件演示" ) self .resize(300 , 700 ) layout = QVBoxLayout() self .label = QLabel('你好 PyQt5' ) self .label.setAlignment(Qt.AlignCenter) layout.addWidget(self .label) slider = QSlider(Qt.Horizontal) slider.setMinimum(12 ) slider.setMaximum(48 ) slider.setSingleStep(3 ) slider.setValue(18 ) slider.setTickPosition(QSlider.TicksBelow) slider.setTickInterval(6 ) slider.valueChanged.connect(self .valueChange) layout.addWidget(slider) slider1 = QSlider(Qt.Vertical) slider1.setMinimum(10 ) slider1.setMaximum(60 ) slider1.setSingleStep(5 ) slider1.setValue(30 ) slider1.setTickPosition(QSlider.TicksLeft) slider1.setTickInterval(2 ) slider1.valueChanged.connect(self .valueChange) layout.addWidget(slider1) self .setLayout(layout) def valueChange (self ): print ('当前值:%s' % self .sender().value()) size = self .sender().value() self .label.setFont(QFont('Arial' , size)) if __name__ == '__main__' : app = QApplication(sys.argv) main = QSliderDemo() main.show() sys.exit(app.exec_())
效果: 竖直滑块和水平滑块都能够更改Qlabel(你好PyQt5)的大小
计数器控件(QSpinBox)(翻译结果是选值框)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 from PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *import sysclass QSpinBoxDemo (QWidget ): def __init__ (self ): super (QSpinBoxDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle("滑块控件演示" ) self .resize(300 , 100 ) layout = QVBoxLayout() self .label = QLabel('当前值' ) self .label.setAlignment(Qt.AlignCenter) layout.addWidget(self .label) spinbox = QSpinBox() spinbox.setValue(18 ) spinbox.setRange(10 , 999 ) spinbox.setSingleStep(3 ) spinbox.valueChanged.connect(self .valueChange) layout.addWidget(spinbox) self .setLayout(layout) def valueChange (self ): self .label.setText('当前值:%s' % self .sender().value()) if __name__ == '__main__' : app = QApplication(sys.argv) main = QSpinBoxDemo() main.show() sys.exit(app.exec_())
效果:
对话框
对话框的分类:
QMessageBox 消息对话框
QColorDialog 颜色对话框
QFileDialog 文件的打开与保存
QFontDialog 设置字体的对话框
QInputDialog 获取用户输入信息的对话框
新建的对话框的类都需要继承QDialog 对话框的特点是没有菜单栏,对话框可以设置为执行时不能进行同一软件下对话框之外的操作
使用QDialog显示通用对话框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QDialogDemo (QMainWindow ): def __init__ (self ): super (QDialogDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('QDialog案例' ) self .resize(300 , 200 ) button = QPushButton(self ) button.setText('弹出对话框' ) button.move(50 , 50 ) button.clicked.connect(self .showDialog) def showDialog (self ): dialog = QDialog() button = QPushButton('确定' , dialog) button.clicked.connect(dialog.close) button.move(50 , 50 ) dialog.setWindowTitle('对话框' ) dialog.setWindowModality(Qt.ApplicationModal) dialog.exec () if __name__ == '__main__' : app = QApplication(sys.argv) main = QDialogDemo() main.show() sys.exit(app.exec_())
QMessageBox信息对话框
看这个知乎链接https://zhuanlan.zhihu.com/p/29795495 比教程详细多了 有多种不同类型的对话框
关于对话框 QMessageBox.about
错误对话框 QMessageBox.critical
警告对话框 QMessageBox.warning
提问对话框 QMessageBox.question
消息对话框 QMessageBox.information
有两点差异
显示的对话框图标可能不同
显示的按钮是不一样的(关于对话框一般显示1个按钮,其他对话框一般显示2个)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QMessageBoxDemo (QWidget ): def __init__ (self ): super (QMessageBoxDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('QDialog案例' ) self .resize(300 , 400 ) layout = QVBoxLayout() button1 = QPushButton() button1.setText('显示关于对话框' ) button1.clicked.connect(self .showDialog) button2 = QPushButton() button2.setText('显示消息对话框' ) button2.clicked.connect(self .showDialog) button3 = QPushButton() button3.setText('显示警告对话框' ) button3.clicked.connect(self .showDialog) button4 = QPushButton() button4.setText('显示错误对话框' ) button4.clicked.connect(self .showDialog) button5 = QPushButton() button5.setText('显示提问对话框' ) button5.clicked.connect(self .showDialog) layout.addWidget(button1) layout.addWidget(button2) layout.addWidget(button3) layout.addWidget(button4) layout.addWidget(button5) self .setLayout(layout) def showDialog (self ): text = self .sender().text() if text == "显示关于对话框" : reply = QMessageBox.about(self , '关于' , '这是一个关于对话框' ) print (reply == QMessageBox.Yes) elif text == "显示消息对话框" : QMessageBox.information(self , '消息' , '这是一个消息对话框' , QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) elif text == "显示警告对话框" : QMessageBox.warning(self , '警告' , '这是一个警告对话框' , QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) elif text == "显示错误对话框" : QMessageBox.critical(self , '错误' , '这是一个错误对话框' , QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) elif text == "显示提问对话框" : QMessageBox.question(self , '提问' , '这是一个提问对话框' , QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if __name__ == '__main__' : app = QApplication(sys.argv) main = QMessageBoxDemo() main.show() sys.exit(app.exec_())
输入对话框,特点是允许显示带输入的控件,例如输入列表,输入文本,输入整数(计数器)
QInputDialog.getItem 显示输入列表(QComboBox)
QInputDialog.getText 显示输入文本
QInputDialog.getInt 显示输入整数(计数器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QInputDialogDemo (QWidget ): def __init__ (self ): super (QInputDialogDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('输入对话框' ) layout = QFormLayout() button1 = QPushButton('获取列表中的选项' ) button1.clicked.connect(self .getItem) self .lineEdit1 = QLineEdit() layout.addRow(button1, self .lineEdit1) button2 = QPushButton('获取字符串' ) button2.clicked.connect(self .getText) self .lineEdit2 = QLineEdit() layout.addRow(button2, self .lineEdit2) button3 = QPushButton('获取整数' ) button3.clicked.connect(self .getInt) self .lineEdit3 = QLineEdit() layout.addRow(button3, self .lineEdit3) self .setLayout(layout) def getItem (self ): items = ('C' , 'C++' , 'Ruby' , 'Python' , 'Java' ,) item, ok = QInputDialog.getItem(self , '请选择编程语言' , '语言列表' , items) if ok and item: self .lineEdit1.setText(item) def getText (self ): text, ok = QInputDialog.getText(self , '文本输入框' , '输入姓名' ) if ok and text: self .lineEdit2.setText(text) def getInt (self ): num, ok = QInputDialog.getInt(self , '整数输入框' , '输入数字' ) if ok and num: self .lineEdit3.setText(str (num)) if __name__ == '__main__' : app = QApplication(sys.argv) main = QInputDialogDemo() main.show() sys.exit(app.exec_())
QFontDialog字体对话框
字体对话框,显示字体列表,用于进行字体的设置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QFontDialogDemo (QWidget ): def __init__ (self ): super (QFontDialogDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('Font Dialog例子' ) layout = QVBoxLayout() self .fontButton = QPushButton("选择字体" ) self .fontButton.clicked.connect(self .getFont) layout.addWidget(self .fontButton) self .fontLabel = QLabel("Hello,测试字体例子" ) layout.addWidget(self .fontLabel) self .setLayout(layout) self .resize(300 ,200 ) def getFont (self ): font, ok = QFontDialog.getFont() if ok : self .fontLabel.setFont(font) if __name__ == '__main__' : app = QApplication(sys.argv) main = QFontDialogDemo() main.show() sys.exit(app.exec_())
QColorDialog 颜色对话框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QFontDialogDemo (QWidget ): def __init__ (self ): super (QFontDialogDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('Color Dialog例子' ) layout = QVBoxLayout() self .colorButton = QPushButton('设置字体颜色' ) self .colorButton.clicked.connect(self .getColor) layout.addWidget(self .colorButton) self .colorButton1 = QPushButton('设置背景颜色' ) self .colorButton1.clicked.connect(self .getBGColor) layout.addWidget(self .colorButton1) self .colorlabel = QLabel('Hello,测试颜色例子' ) layout.addWidget(self .colorlabel) self .setLayout(layout) self .resize(300 , 200 ) def getColor (self ): color = QColorDialog.getColor() p = QPalette() p.setColor(QPalette.WindowText, color) self .colorlabel.setPalette(p) def getBGColor (self ): color = QColorDialog.getColor() p = QPalette() p.setColor(QPalette.Window, color) self .colorlabel.setAutoFillBackground(True ) self .colorlabel.setPalette(p) if __name__ == '__main__' : app = QApplication(sys.argv) main = QFontDialogDemo() main.show() sys.exit(app.exec_())
QFileDialog 文件对话框
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import *class QColorDialogDemo (QWidget ): def __init__ (self ): super (QColorDialogDemo, self ).__init__() self .initUI() def initUI (self ): layout = QVBoxLayout() self .button1 = QPushButton('加载图片' ) self .button1.clicked.connect(self .loadImage) layout.addWidget(self .button1) self .imageLabel = QLabel() layout.addWidget(self .imageLabel) self .button2 = QPushButton('加载文本文件' ) self .button2.clicked.connect(self .loadText) layout.addWidget(self .button2) self .contents = QTextEdit() layout.addWidget(self .contents) self .setWindowTitle('文件对话框演示' ) self .setLayout(layout) def loadImage (self ): frame, _ = QFileDialog.getOpenFileName(self , '打开文件' , '.' , '图像文件(*.jpg *.png)' ) self .imageLabel.setPixmap(QPixmap(frame)) def loadText (self ): dialog = QFileDialog() dialog.setFileMode(QFileDialog.AnyFile) dialog.setFilter(QDir.Files) if dialog.exec (): filenames = dialog.selectedFiles() f = open (filenames[0 ], encoding='utf-8' , mode='r' ) with f: data = f.read() self .contents.setText(data) if __name__ == '__main__' : app = QApplication(sys.argv) main = QColorDialogDemo() main.show() sys.exit(app.exec_())
绘图API
绘图API包括
文本
各种图形(直线,点,椭圆,弧,扇形,多边形等)
图像
框架: 所有的方法都是在QPainter这个类中,因此框架就是 painter = QPainter()
painter.bengin()
绘制内容
painter.end()
必须在painterEvent事件方法中绘制各种元素(当窗口放大和缩小时都需要重新绘制,窗口方法和缩小时都会自动调用painterEvent事件)
DrawText在窗口上绘制文本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import sysfrom PyQt5.QtWidgets import QApplication,QWidgetfrom PyQt5.QtGui import QPainter,QColor,QFontfrom PyQt5.QtCore import Qtclass DrawText (QWidget ) : def __init__ (self ): super (DrawText, self ).__init__() self .setWindowTitle('在窗口上绘制文本' ) self .resize(500 ,400 ) self .text = "Python从菜鸟到高手" def paintEvent (self, event ): painter = QPainter(self ) painter.begin(self ) painter.setPen(QColor(150 ,43 ,5 )) painter.setFont(QFont('SimSun' ,25 )) painter.drawText(event.rect(),Qt.AlignCenter,self .text) painter.end() if __name__ == '__main__' : app = QApplication(sys.argv) main = DrawText() main.show() sys.exit(app.exec_())
DrawPoint在窗口上绘制正弦曲线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import sys, mathfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import Qtclass DrawPoints (QWidget ): def __init__ (self ): super (DrawPoints, self ).__init__() self .resize(300 , 300 ) self .setWindowTitle("在窗口上用像素点绘制两个周期的正弦曲线" ) def paintEvent (self, event ): painter = QPainter() painter.begin(self ) painter.setPen(Qt.blue) size = self .size() for i in range (1000 ): x = int (100 * (-1 + 2.0 * i / 1000 ) + size.width() / 2.0 ) y = int (-50 * math.sin((x - size.width() / 2.0 ) * math.pi / 50 ) + size.height() / 2.0 ) painter.drawPoint(x, y) painter.end() if __name__ == '__main__' : app = QApplication(sys.argv) main = DrawPoints() main.show() sys.exit(app.exec_())
拖动和剪贴板操作
拖动: 将A控件拖入到B: 将A设置为可拖动,将B设置为可以接收其他控件的拖动 A.setDragEnabled(True) B.setAcceptDrops(True) 对于接收拖动的控件B需要两个事件 1.dragEnterEvent 将A拖到B触发 2.dropEvent 在B的区域放下A时触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import sys, mathfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class MyComboBox (QComboBox ) : def __init__ (self ): super (MyComboBox, self ).__init__() self .setAcceptDrops(True ) def dragEnterEvent (self, e ): print (e) if e.mimeData().hasText(): e.accept() else : e.ignore() def dropEvent (self, e ): self .addItem(e.mimeData().text()) class DrapDropDemo (QWidget ) : def __init__ (self ): super (DrapDropDemo, self ).__init__() formlayout = QFormLayout() formlayout.addRow(QLabel("请将左边的文本拖拽到右边的下拉列表中" )) lineEdit = QLineEdit() lineEdit.setDragEnabled(True ) combo = MyComboBox() formlayout.addRow(lineEdit,combo) self .setLayout(formlayout) self .setWindowTitle("拖拽案例" ) if __name__ == '__main__' : app = QApplication(sys.argv) main = DrapDropDemo() main.show() sys.exit(app.exec_())
效果:使用剪贴板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class ClipBoard (QDialog ): def __init__ (self ): super (ClipBoard, self ).__init__() textCopyButton = QPushButton('复制文本' ) textPasteButton = QPushButton('粘贴文本' ) htmlCopyButton = QPushButton('复制HTML' ) htmlPasteButton = QPushButton('粘贴HTML' ) imageCopyButton = QPushButton('复制图像' ) imagePasteButton = QPushButton('粘贴图像' ) self .textLabel = QLabel('默认文本' ) self .imageLabel = QLabel() self .imageLabel.setPixmap(QPixmap('./images/bool.png' )) layout = QGridLayout() layout.addWidget(textCopyButton, 0 , 0 ) layout.addWidget(imageCopyButton, 0 , 1 ) layout.addWidget(htmlCopyButton, 0 , 2 ) layout.addWidget(textPasteButton, 1 , 0 ) layout.addWidget(imagePasteButton, 1 , 1 ) layout.addWidget(htmlPasteButton, 1 , 2 ) layout.addWidget(self .textLabel, 2 , 0 , 1 , 2 ) layout.addWidget(self .imageLabel, 2 , 2 ) self .setLayout(layout) textCopyButton.clicked.connect(self .copyText) textPasteButton.clicked.connect(self .pasteText) htmlCopyButton.clicked.connect(self .copyHtml) htmlPasteButton.clicked.connect(self .pasteHtml) imageCopyButton.clicked.connect(self .copyImage) imagePasteButton.clicked.connect(self .pasteImage) self .setWindowTitle('剪贴板演示' ) def copyText (self ): clipboard = QApplication.clipboard() clipboard.setText('hello world' ) def pasteText (self ): clipboard = QApplication.clipboard() self .textLabel.setText(clipboard.text()) def copyImage (self ): clipboard = QApplication.clipboard() clipboard.setPixmap(QPixmap('../images/bool.png' )) def pasteImage (self ): clipboard = QApplication.clipboard() self .imageLabel.setPixmap(clipboard.pixmap()) def copyHtml (self ): mimeData = QMimeData() mimeData.setHtml('<b>Bold and <font color=red>Red</font></b>' ) clipboard = QApplication.clipboard() clipboard.setMimeData(mimeData) def pasteHtml (self ): clipboard = QApplication.clipboard() mimeData = clipboard.mimeData() if mimeData.hasHtml(): self .textLabel.setText(mimeData.html()) if __name__ == '__main__' : app = QApplication(sys.argv) main = ClipBoard() main.show() sys.exit(app.exec_())
** **
菜单栏、工具栏和状态栏
菜单栏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class Menu (QMainWindow ): def __init__ (self ): super (Menu, self ).__init__() bar = self .menuBar() file = bar.addMenu("文件" ) file.addAction("新建" ) save = QAction("保存" , self ) save.setShortcut("Ctrl + S" ) file.addAction(save) save.triggered.connect(self .process) quit = QAction("退出" , self ) file.addAction(quit) edit = bar.addMenu("Edit" ) edit.addAction("copy" ) edit.addAction("paste" ) self .resize(300 , 200 ) def process (self, a ): print (self .sender().text()) if __name__ == '__main__' : app = QApplication(sys.argv) main = Menu() main.show() sys.exit(app.exec_())
效果: 点击保存后会执行自定义的process函数输出“保存”
工具栏
工具栏是这样的 工具栏有三种显示方式
只显示图标
只显示文本
同时显示文本和图标
ToolButtonIconOnly 只显示图标 ToolButtonTextOnly 只显示文本 ToolButtonTextBesideIcon 文本显示在图标旁边 ToolButtonTextUnderIcon 文本显示在图标下边 ToolButtonFollowStyle 默认模式,文本作为图标的提示出现 设置显示方式: tb2.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class ToolBar (QMainWindow ): def __init__ (self ): super (ToolBar, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('工具栏例子' ) self .resize(300 , 200 ) tb1 = self .addToolBar("File" ) new = QAction(QIcon('../images/icon4.png' ), "new" , self ) tb1.addAction(new) open = QAction(QIcon('../images/icon1.png' ), "open" , self ) tb1.addAction(open ) save = QAction(QIcon('../images/icon2.png' ), "save" , self ) tb1.addAction(save) tb2 = self .addToolBar("File1" ) new1 = QAction(QIcon('../images/icon3.png' ), "新建" , self ) tb2.addAction(new1) tb2.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) tb1.actionTriggered.connect(self .toolbtnpressed) tb2.actionTriggered.connect(self .toolbtnpressed) def toolbtnpressed (self, a ): print ("按下的工具栏按钮是" , a.text()) if __name__ == '__main__' : app = QApplication(sys.argv) main = ToolBar() main.show() sys.exit(app.exec_())
状态栏
状态栏是在窗口下方用来显示状态文本信息的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class StatusBar (QMainWindow ): def __init__ (self ): super (StatusBar, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('状态栏演示' ) self .resize(300 , 200 ) bar = self .menuBar() file = bar.addMenu("File" ) file.addAction("show" ) file.triggered.connect(self .processTrigger) self .setCentralWidget(QTextEdit()) self .statusBar = QStatusBar() self .setStatusBar(self .statusBar) def processTrigger (self, q ): if q.text() == "show" : self .statusBar.showMessage(q.text() + '菜单被点击了' , 5000 ) if __name__ == '__main__' : app = QApplication(sys.argv) main = StatusBar() main.show() sys.exit(app.exec_())
表格布局
QTableView控件 显示二维表数据
显示二维表数据 MCV数据处理方法: M:Model V: Viewer C: Controller 将每个信息都分开创建再联系到一起,目的是将后端的数据和前端页面的耦合度降低,使一个数据可以被多次使用
声明表格模型,创建表格的首行标题,设置表格的数据,声明表格控件,关联表格控件与模型,最终将表格控件添加到布局中。总而言之就是根据数据创建模型,控件由模型构成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class TableView (QWidget ): def __init__ (self ): super (TableView, self ).__init__() self .setWindowTitle('QTableView表格视图控件演示' ) self .resize(500 , 300 ) self .model = QStandardItemModel(4 , 3 ) self .model.setHorizontalHeaderLabels(['id' , '姓名' , '年龄' ]) self .tableview = QTableView() self .tableview.setModel(self .model) item11 = QStandardItem('10' ) item12 = QStandardItem('雷神' ) item13 = QStandardItem('2000' ) self .model.setItem(0 , 0 , item11) self .model.setItem(0 , 1 , item12) self .model.setItem(0 , 2 , item13) item31 = QStandardItem('30' ) item32 = QStandardItem('死亡女神' ) item33 = QStandardItem('3000' ) self .model.setItem(2 , 0 , item31) self .model.setItem(2 , 1 , item32) self .model.setItem(2 , 2 , item33) layout = QVBoxLayout() layout.addWidget(self .tableview) self .setLayout(layout) if __name__ == '__main__' : app = QApplication(sys.argv) main = TableView() main.show() sys.exit(app.exec_())
QTableWidget是QTableView的子类,相比父类添加了其他方法 每一个Cell(单元格)是一个QTableWidgetItem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import sysfrom PyQt5.QtWidgets import *class TableWidgetDemo (QWidget ): def __init__ (self ): super (TableWidgetDemo, self ).__init__() self .initUI() def initUI (self ): self .setWindowTitle('QTableWidget演示' ) self .resize(430 , 230 ) layout = QVBoxLayout() tablewidget = QTableWidget() tablewidget.setRowCount(4 ) tablewidget.setColumnCount(3 ) layout.addWidget(tablewidget) tablewidget.setHorizontalHeaderLabels(['姓名' , '年龄' , '籍贯' ]) nameItem = QTableWidgetItem('小明' ) tablewidget.setItem(0 , 0 , nameItem) ageItem = QTableWidgetItem('24' ) tablewidget.setItem(0 , 1 , ageItem) jgItem = QTableWidgetItem('北京' ) tablewidget.setItem(0 , 2 , jgItem) tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers) tablewidget.setSelectionBehavior(QAbstractItemView.SelectRows) tablewidget.resizeColumnsToContents() tablewidget.resizeRowsToContents() tablewidget.verticalHeader().setVisible(False ) tablewidget.setVerticalHeaderLabels(['a' , 'b' ]) tablewidget.setShowGrid(False ) self .setLayout(layout) if __name__ == '__main__' : app = QApplication(sys.argv) main = TableWidgetDemo() main.show() sys.exit(app.exec_())
QListView控件 显示列数据
先声明列数据控件,再声明列数据模型,然后声明列数据,然后将列数据与列数据模型关联起来,然后再把列数据控件与列数据模型关联起来。最终将列数据控件添加到布局中。总而言之就是根据数据创建模型,控件由模型构成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class ListViewDemo (QWidget ): def __init__ (self ): super (ListViewDemo, self ).__init__() self .setWindowTitle('QListView 例子' ) self .resize(300 , 270 ) layout = QVBoxLayout() listview = QListView() listModel = QStringListModel() self .list = ['列表项1' , '列表项2' , '列表项3' ] listModel.setStringList(self .list ) listview.setModel(listModel) listview.clicked.connect(self .clicked) layout.addWidget(listview) self .setLayout(layout) def clicked (self, item ): QMessageBox.information(self , 'QListView' , '您选择了:' + self .list [item.row()]) if __name__ == '__main__' : app = QApplication(sys.argv) main = ListViewDemo() main.show() sys.exit(app.exec_())
QListWidget是QListView的子类 子类在父类的基础上添加了很多API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from PyQt5.QtWidgets import *import sysclass ListWidgetDemo (QMainWindow ): def __init__ (self, parent=None ): super (ListWidgetDemo, self ).__init__() self .setWindowTitle('QListWidget 例子' ) self .resize(300 , 270 ) self .listwidget = QListWidget() self .listwidget.addItem('item1' ) self .listwidget.addItem('item2' ) self .listwidget.addItem('item3' ) self .listwidget.addItem('item4' ) self .listwidget.addItem('item5' ) self .listwidget.itemClicked.connect(self .clicked) self .setCentralWidget(self .listwidget) def clicked (self, Index ): QMessageBox.information(self , 'QListWidget' , '您选择了:' + self .listwidget.item(self .listwidget.row(Index)).text()) if __name__ == '__main__' : app = QApplication(sys.argv) main = ListWidgetDemo() main.show() sys.exit(app.exec_())
容器控件
QTabWidget被继承后,可以在QTabWidget容器中添加多个tab(选项卡),然后可以为不同选项卡设置不同的窗口。 选项卡控件介绍:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import sysfrom PyQt5.QtWidgets import *class TabWidgetDemo (QTabWidget ): def __init__ (self ): super (TabWidgetDemo, self ).__init__() self .setWindowTitle("选项卡控件:QTabWidget" ) self .resize(400 , 300 ) self .tab1 = QWidget() self .tab2 = QWidget() self .tab3 = QWidget() self .addTab(self .tab1, "选项卡1" ) self .addTab(self .tab2, "选项卡2" ) self .addTab(self .tab3, "选项卡3" ) self .tab1UI() self .tab2UI() self .tab3UI() def tab1UI (self ): layout = QFormLayout() layout.addRow('姓名' , QLineEdit()) layout.addRow('地址' , QLineEdit()) self .setTabText(0 , '联系方式' ) self .tab1.setLayout(layout) def tab2UI (self ): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton('男' )) sex.addWidget(QRadioButton('女' )) layout.addRow(QLabel('性别' ), sex) layout.addRow('生日' , QLineEdit()) self .setTabText(1 , '个人详细信息' ) self .tab2.setLayout(layout) def tab3UI (self ): layout = QHBoxLayout() layout.addWidget(QLabel('科目' )) layout.addWidget(QCheckBox('物理' )) layout.addWidget(QCheckBox('高数' )) self .setTabText(2 , "教育程度" ) self .tab3.setLayout(layout) if __name__ == '__main__' : app = QApplication(sys.argv) main = TabWidgetDemo() main.show() sys.exit(app.exec_())
堆栈窗口控件就是用来存放多个窗口的容器,然后可以通过setCurrentIndex(index)方法来显示对应序号的窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import sysfrom PyQt5.QtWidgets import *class StackedExample (QWidget ): def __init__ (self ): super (StackedExample, self ).__init__() self .setGeometry(300 , 50 , 10 , 10 ) self .setWindowTitle("堆栈窗口控件:QStackedWidget" ) self .resize(400 , 300 ) self .list = QListWidget() self .list .insertItem(0 , '联系方式' ) self .list .insertItem(1 , '个人信息' ) self .list .insertItem(2 , '教育程度' ) self .stack1 = QWidget() self .stack2 = QWidget() self .stack3 = QWidget() self .tab1UI() self .tab2UI() self .tab3UI() self .stack = QStackedWidget() self .stack.addWidget(self .stack1) self .stack.addWidget(self .stack2) self .stack.addWidget(self .stack3) hbox = QHBoxLayout() hbox.addWidget(self .list ) hbox.addWidget(self .stack) self .setLayout(hbox) self .list .currentRowChanged.connect(self .display) def tab1UI (self ): layout = QFormLayout() layout.addRow('姓名' , QLineEdit()) layout.addRow('地址' , QLineEdit()) self .stack1.setLayout(layout) def tab2UI (self ): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton('男' )) sex.addWidget(QRadioButton('女' )) layout.addRow(QLabel('性别' ), sex) layout.addRow('生日' , QLineEdit()) self .stack2.setLayout(layout) def tab3UI (self ): layout = QHBoxLayout() layout.addWidget(QLabel('科目' )) layout.addWidget(QCheckBox('物理' )) layout.addWidget(QCheckBox('高数' )) self .stack3.setLayout(layout) def display (self, index ): self .stack.setCurrentIndex(index) if __name__ == '__main__' : app = QApplication(sys.argv) main = StackedExample() main.show() sys.exit(app.exec_())
停靠控件用来创建那些平时使用的软件中的可以自由拖动与固定的那些窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class DockDemo (QMainWindow ): def __init__ (self ): super (DockDemo, self ).__init__() self .setWindowTitle('停靠控件(QDockWidget)' ) self .resize(400 , 300 ) layout = QHBoxLayout() self .items = QDockWidget('Dockable' , self ) self .listWidget = QListWidget() self .listWidget.addItem('item1' ) self .listWidget.addItem('item2' ) self .listWidget.addItem('item3' ) self .items.setWidget(self .listWidget) self .setCentralWidget(QLineEdit()) self .items.setFloating(True ) self .addDockWidget(Qt.RightDockWidgetArea, self .items) if __name__ == '__main__' : app = QApplication(sys.argv) main = DockDemo() main.show() sys.exit(app.exec_())
容纳多文档窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class MultiWindows (QMainWindow ): count = 0 def __init__ (self, parent=None ): super (MultiWindows, self ).__init__(parent) self .setWindowTitle('容纳多文档的窗口' ) self .mdi = QMdiArea() self .setCentralWidget(self .mdi) bar = self .menuBar() file = bar.addMenu('File' ) file.addAction('New' ) file.addAction('cascade' ) file.addAction('Tiled' ) file.triggered.connect(self .windowacation) def windowacation (self, q ): print (q.text()) if q.text() == "New" : MultiWindows.count = MultiWindows.count + 1 sub = QMdiSubWindow() sub.setWidget(QTextEdit()) sub.setWindowTitle('子窗口' + str (MultiWindows.count)) self .mdi.addSubWindow(sub) sub.show() elif q.text() == "cascade" : self .mdi.cascadeSubWindows() elif q.text() == "Tiled" : self .mdi.tileSubWindows() if __name__ == '__main__' : app = QApplication(sys.argv) main = MultiWindows() main.show() sys.exit(app.exec_())
new时:新建窗口 cascade时: 层叠 Tiled时 平铺
通过滚动条值的变化控制其他控件状态的变化
通过滚动条值的变化控制控件位置的变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *class ScrollBar (QWidget ): def __init__ (self ): super (ScrollBar, self ).__init__() self .initUI() def initUI (self ): hbox = QHBoxLayout() self .label = QLabel('拖动滚动条去改变文字颜色' ) hbox.addWidget(self .label) self .scrollbar1 = QScrollBar() self .scrollbar1.setMaximum(255 ) self .scrollbar1.sliderMoved.connect(self .sliderMoved) self .scrollbar2 = QScrollBar() self .scrollbar2.setMaximum(255 ) self .scrollbar2.sliderMoved.connect(self .sliderMoved) self .scrollbar3 = QScrollBar() self .scrollbar3.setMaximum(255 ) self .scrollbar3.sliderMoved.connect(self .sliderMoved) self .scrollbar4 = QScrollBar() self .scrollbar4.setMaximum(255 ) self .scrollbar4.sliderMoved.connect(self .sliderMoved1) hbox.addWidget(self .scrollbar1) hbox.addWidget(self .scrollbar2) hbox.addWidget(self .scrollbar3) hbox.addWidget(self .scrollbar4) self .setGeometry(300 , 300 , 300 , 200 ) self .setLayout(hbox) self .y = self .label.pos().y() def sliderMoved (self ): print (self .scrollbar1.value(), self .scrollbar2.value(), self .scrollbar3.value()) palette = QPalette() c = QColor(self .scrollbar1.value(), self .scrollbar2.value(), self .scrollbar3.value(), 255 ) palette.setColor(QPalette.Foreground, c) self .label.setPalette(palette) def sliderMoved1 (self ): self .label.moce(self .label.x(), self .y + self .scrollbar4.value()) if __name__ == '__main__' : app = QApplication(sys.argv) main = ScrollBar() main.show() sys.exit(app.exec_())
从左到右前三个滑块分别控制rgb三通道数值(0~255),第四个滑块控制标签的y坐标
多线程与定时器
多线程的作用:对于比较耗时的任务如果使用单线程可能会造成阻塞,因此通过多线程可以使耗时的任务不影响其他任务的进行。
QTimer定时器控件
定时器控件可以用来动态显示当前时间,每一秒都在调用函数更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QListWidget, QGridLayout, QLabelfrom PyQt5.QtCore import QTimer, QDateTimeimport sysclass ShowTime (QWidget ): def __init__ (self ): super (ShowTime, self ).__init__() self .setWindowTitle('动态显示当前时间' ) self .label = QLabel('显示当前时间' ) self .startBtn = QPushButton('开始' ) self .endBtn = QPushButton('结束' ) layout = QGridLayout() self .timer = QTimer() self .timer.timeout.connect(self .showTime) layout.addWidget(self .label, 0 , 0 , 1 , 2 ) layout.addWidget(self .startBtn, 1 , 0 ) layout.addWidget(self .endBtn, 1 , 1 ) self .startBtn.clicked.connect(self .startTimer) self .endBtn.clicked.connect(self .endTimer) self .setLayout(layout) self .resize(400 , 300 ) def showTime (self ): time = QDateTime.currentDateTime() timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd" ) self .label.setText(timeDisplay) def startTimer (self ): self .timer.start(1000 ) self .startBtn.setEnabled(False ) self .endBtn.setEnabled(True ) def endTimer (self ): self .timer.stop() self .startBtn.setEnabled(True ) self .endBtn.setEnabled(False ) if __name__ == '__main__' : app = QApplication(sys.argv) main = ShowTime() main.show() sys.exit(app.exec_())
QTimer.singleShot让程序定时关闭
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *if __name__ == '__main__' : app = QApplication(sys.argv) label = QLabel('<font color=red size=140><b>Hello World,窗口在5秒后自动关闭!</b></font>' ) label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint) label.show() QTimer.singleShot(5000 , app.quit) sys.exit(app.exec_())
QThread 线程类
线程类可以实现计数器 QLCDNumber : 模拟LCD显示效果的控件 WorkThread(继承自QThread): 自定义信号,实现在不同线程中信息的交互。之前使用的都是空间变化的系统信号。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import sysfrom PyQt5.QtWidgets import *from PyQt5.QtGui import *from PyQt5.QtCore import *sec = 0 class WorkThread (QThread ): timer = pyqtSignal() end = pyqtSignal() def run (self ): while True : self .sleep(1 ) if sec == 5 : self .end.emit() self .timer.emit() class Counter (QWidget ): def __init__ (self, parent=None ): super (Counter, self ).__init__(parent) self .setWindowTitle("使用线程类(QThread)编写计数器" ) self .resize(300 , 120 ) layout = QVBoxLayout() self .lcdNumber = QLCDNumber() layout.addWidget(self .lcdNumber) button = QPushButton('开始计数' ) layout.addWidget(button) self .workThread = WorkThread() self .workThread.timer.connect(self .countTime) self .workThread.end.connect(self .end) button.clicked.connect(self .work) self .setLayout(layout) def countTime (self ): global sec sec += 1 self .lcdNumber.display(sec) def end (self ): QMessageBox.information(self ,'消息' ,'计数结束' ,QMessageBox.Ok) def work (self ): self .workThread.start() if __name__ == '__main__' : app = QApplication(sys.argv) main = Counter() main.show() sys.exit(app.exec_())
窗口
设置窗口风格
pyqt5窗口一共有三种风格 可以通过print(QStyleFactory.keys())来显示pyqt5窗口风格的种类: ‘windowsvista’, ‘Windows’, ‘Fusion’ 可以通过QApplication.setStyle(窗口风格)来设置窗口控件的风格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import sysfrom PyQt5.QtCore import *from PyQt5 import QtCorefrom PyQt5.QtWidgets import *class WindowStyle (QWidget ): def __init__ (self ): super (WindowStyle, self ).__init__() horizontalLayout = QHBoxLayout() self .styleLabel = QLabel('设置窗口风格:' ) self .styleComboBox = QComboBox() self .styleComboBox.addItems(QStyleFactory.keys()) print (QApplication.style().objectName()) index = self .styleComboBox.findText(QApplication.style().objectName(), QtCore.Qt.MatchFixedString) self .styleComboBox.setCurrentIndex(index) self .styleComboBox.activated[str ].connect(self .handleStyleChanged) horizontalLayout.addWidget(self .styleLabel) horizontalLayout.addWidget(self .styleComboBox) self .setLayout(horizontalLayout) self .resize(200 , 100 ) def handleStyleChanged (self, style ): QApplication.setStyle(style) if __name__ == '__main__' : app = QApplication(sys.argv) main = WindowStyle() main.show() sys.exit(app.exec_())
设置窗口样式 setWindowFlags
窗口样式的调整主要针对窗口边框、标题栏以及窗口本身的样式 使用setWindowFlags设置窗口样式,可以使用参数介绍: Qt.WindowMaximizeButtonHint(设置激活窗口的最大化按钮(右上角那个按钮)) Qt.WindowCloseButtonHint(设置激活窗口的关闭按钮(右上角那个按钮)) Qt.WindowMinimizeButtonHint(设置激活窗口的最小化按钮(右上角那个按钮)) Qt.WindowStaysOnTopHint(设置窗口始终在窗口最前方显示) Qt.FramelessWindowHint(设置窗口为无边框)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import sysfrom PyQt5.QtCore import *from PyQt5.QtWidgets import *class WindowPattern (QMainWindow ): def __init__ (self ): super (WindowPattern, self ).__init__() self .setWindowTitle("设置窗口的样式" ) self .setWindowFlags(Qt.WindowMaximizeButtonHint | Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self .setObjectName("MainWindow" ) self .setStyleSheet("#MainWindow{border-image:url(../images/bool.png);}" ) if __name__ == '__main__' : app = QApplication(sys.argv) main = WindowPattern() main.show() sys.exit(app.exec_())
用代码设置窗口的最大化和最小化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import sysfrom PyQt5.QtCore import *from PyQt5.QtWidgets import *class WindowMaxMin (QWidget ): def __init__ (self, parent=None ): super (WindowMaxMin, self ).__init__(parent) self .resize(300 , 400 ) self .setWindowTitle('用代码控制窗口的最大化和最小化' ) layout = QVBoxLayout() maxButton1 = QPushButton('窗口最大化1' ) maxButton1.clicked.connect(self .maximized1) maxButton2 = QPushButton('窗口最大化2' ) maxButton2.clicked.connect(self .showMaximized) minButton = QPushButton('窗口最小化' ) minButton.clicked.connect(self .showMinimized) layout.addWidget(maxButton1) layout.addWidget(maxButton2) layout.addWidget(minButton) self .setLayout(layout) def maximized1 (self ): desktop = QApplication.desktop() rect = desktop.availableGeometry() self .setGeometry(rect) if __name__ == '__main__' : app = QApplication(sys.argv) main = WindowMaxMin() main.show() sys.exit(app.exec_())