代码选自 张少娴老师 的 《Python量化交易从入门到实战》
重写按钮的关闭事件 closeEvent
核心就是重写父类QWidget
的closeEvent
方法
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QMessageBox
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 在窗口上创建一个按钮对象
qbtn = QPushButton('关闭', self)
# 将按钮对象的click事件连接到窗口的关闭方法
qbtn.clicked.connect(self.close)
# 指定按钮的位置
qbtn.move(50, 50)
# 设定窗口的位置和大小
self.setGeometry(300, 300, 320, 160)
self.setWindowTitle('请单击关闭按钮')
self.show()
def closeEvent(self, event):
reply = QMessageBox.question(self, '提示信息',
'确认要关闭窗口?',
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
布局
绝对布局
强行用move
控制位置,不推荐这么做,页面兼容性很差
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn1 = QPushButton('功能1', self)
qbtn1.move(50, 50)
qbtn2 = QPushButton('功能2', self)
qbtn2.move(100, 100)
qbtn3 = QPushButton('功能3', self)
qbtn3.move(150, 150)
self.setGeometry(300, 300, 280, 170)
self.setWindowTitle('绝对定位')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
盒布局
addStretch
表示“塞入弹簧”,用来控制盒布局的周围距离(塞的特多距离特大)
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 创建两个按钮对象
okButton = QPushButton("确认")
cancelButton = QPushButton("取消")
hbox = QHBoxLayout() # 创建一个水平盒布局对象hbox
hbox.addStretch(4)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
hbox.addStretch(1)
vbox = QVBoxLayout() # 创建一个垂直盒布局对象vbox
vbox.addStretch(1)
vbox.addLayout(hbox) # 弹簧把hbox压到了最下面
self.setLayout(vbox) # 将vbox设置为窗口的主布局对象
self.setGeometry(300, 300, 360, 150)
self.setWindowTitle('盒布局')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
网络布局
import sys
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QApplication
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout() # 创建一个网格布局grid,并将其设为窗口的主布局
self.setLayout(grid)
names = ['Cls', 'Bck', '', 'Close', # 创建20个元素的字符串列表
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+']
positions = [(i, j) for i in range(5) for j in range(4)] # 创建20个元素的元组列表
for position, name in zip(positions, names): # 循环取每个坐标和按钮名称
if name == '': # 空字符串则什么都不做
continue
button = QPushButton(name)
print(*position)
grid.addWidget(button, *position)
self.move(300, 160)
self.setWindowTitle('计算器')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
状态栏、菜单栏、子菜单、勾选菜单、右键菜单
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QMenu
from PyQt5.QtGui import QIcon
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 行为相关的代码
# 创建一个行为对象
exitAction = QAction(QIcon('exit.png'), '退出(&Q)', self)
# 设置行为的快捷键
exitAction.setShortcut('Ctrl+Q')
# 设置行为的状态栏提示文本
exitAction.setStatusTip('退出应用程序。')
# 将该行为作关联到窗口的关闭事件
exitAction.triggered.connect(self.close)
# 菜单栏相关的代码
# 创建一个菜单栏
menubar = self.menuBar()
# 在菜单栏中添加一个菜单
fileMenu = menubar.addMenu('文件(&F)')
# 创建两个行为和一个菜单,并将两个行为添加到菜单
impTextAct = QAction('文本文件', self)
impPictAct = QAction('图形文件', self)
impMenu = QMenu('导入', self)
impMenu.addAction(impTextAct)
impMenu.addAction(impPictAct)
fileMenu.addMenu(impMenu) # 将子菜单添加到父菜单
fileMenu.addSeparator() # 在菜单中加入一条分隔线
fileMenu.addAction(exitAction)
# 将行为添加到菜单
fileMenu.addAction(exitAction)
# ①创建一个带勾选功能的行为
viewStatAct = QAction('显示状态栏', self, checkable=True)
viewStatAct.setStatusTip('状态栏显示开关。')
viewStatAct.setChecked(True)
viewStatAct.triggered.connect(self.toggleMenu)
# ②创建一个新的菜单,并添加到菜单栏当中
viewMenu = menubar.addMenu('视图(&V)')
viewMenu.addAction(viewStatAct)
self.statusBar().showMessage('就绪')
self.setGeometry(300, 300, 360, 160)
self.setWindowTitle('主窗口')
self.show()
def toggleMenu(self, state):
"""③行为“显示状态栏”的处理函数"""
statusbar = self.statusBar()
if state:
statusbar.show()
else:
statusbar.hide()
def contextMenuEvent(self, event):
cmenu = QMenu(self)
func1Act = cmenu.addAction("功能1")
func2Act = cmenu.addAction("功能2")
quitAct = cmenu.addAction("退出")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
if action == quitAct:
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
信号与槽
对象1.信号.connect(对象2.槽函数)
点击按钮显示窗口
import sys
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QMessageBox
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
btn1 = QPushButton("按钮1", self)
btn1.move(30, 50)
btn1.clicked.connect(self.showMsg)
btn2 = QPushButton("按钮2", self)
btn2.move(150, 50)
btn2.clicked.connect(self.showMsg) # btn2与btn1连接到相同的槽函数
self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('信号与槽')
self.show()
def showMsg(self):
sender = self.sender() # 获取信号是由哪个控件发出的,可以获取到btn1或btn2
QMessageBox.information(self, '提示信息', f'{sender.text()}被按下。')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
重写keyPressEvent - Esc关闭窗口
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QApplication
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 360, 130) # (pos_x, pos_y, width, height)
self.setWindowTitle('按Esc键关闭窗口')
self.show()
# 重写了键盘事件处理器
def keyPressEvent(self, e):
if e.key() == Qt.Key_Escape:
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
内置槽函数 - 滚动条控制LCD
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QLCDNumber, QSlider, QVBoxLayout, QApplication
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 创建一个QLCDNumber控件,QLCDNumber用于显示一个带有仿真显示屏效果的数字
lcd = QLCDNumber(self)
# 创建一个QSlider控件,QSlider提供了一个水平或垂直滑动条
sld = QSlider(Qt.Horizontal, self)
vbox = QVBoxLayout()
vbox.addWidget(lcd)
vbox.addWidget(sld)
self.setLayout(vbox)
# 将滑动条的valueChanged信号与LCD的display槽函数连接
sld.valueChanged.connect(lcd.display)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('LCD显示')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
sys.exit(app.exec_())
自定义信号
自定义信号方法一:自定义信号类继承QObject
import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication
class MySignal(QObject): # 自定义信号需要继承QObject
sigClose = pyqtSignal()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.sig = MySignal():
self.sig.sigClose.connect(self.close) # 将sig的sigClose信号与窗口的close()槽函数连接
self.setGeometry(300, 300, 320, 150)
self.setWindowTitle('单击鼠标关闭')
self.show()
# 重写mousePressEvent事件处理器,该处理器在鼠标按下时触发
def mousePressEvent(self, event):
self.sig.sigClose.emit() # 将sig的sigClose信号发出,会调用与之连接的close()槽函数
# self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow ()
sys.exit(app.exec_())
自定义信号方法二:直接在MainWindow
类中定义信号属性,不需要专门定义一个类
import sys
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWindow(QMainWindow):
# 直接在MainWindow类中定义信号属性,不需要专门定义一个类
sigClose = pyqtSignal()
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 将sigClose信号与窗口的close()槽函数连接
self.sigClose.connect(self.close)
self.setGeometry(300, 300, 320, 150)
self.setWindowTitle('单击鼠标关闭')
self.show()
def mousePressEvent(self, event):
self.sigClose.emit()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow ()
sys.exit(app.exec_())
事件对象、重写mouseMoveEvent
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QLabel
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# QLabel控件用于显示文本
self.label = QLabel("x: 0, y: 0 ", self)
self.label.move(10, 10)
# 鼠标指针移动可能会触发鼠标移动事件,该事件如果开启会被频繁触发,默认是不开启的
self.setMouseTracking(True)
self.setGeometry(300, 300, 350, 200)
self.setWindowTitle('事件对象')
self.show()
def mouseMoveEvent(self