4、PyQt5入门:Qt Designer界面设计、信号与槽机制、主窗口与布局管理
说实话,很多做电机控制的工程师,一听到「上位机界面开发」就头大。我以前也是这样,觉得写界面比写控制算法还麻烦。直到我用了PyQt5,才发现原来拖拖拽拽就能搞定一个专业的上位机。今天我就带你从零开始,把PyQt5的核心东西捋一遍。
4.1 Qt Designer:别手写界面了,拖拽它不香吗?
我刚开始学PyQt5的时候,傻乎乎地一行一行写代码布局。后来被老同事笑话了——「你写代码画界面,跟用记事本写PPT有啥区别?」他甩给我一个工具:Qt Designer。
Qt Designer是啥?说白了就是一个可视化的界面设计器。你拖一个按钮、拉一个文本框,它自动生成对应的.ui文件。然后你用PyQt5把这个.ui文件加载进来,界面就有了。
具体操作流程是这样的:
- 打开Qt Designer,选择「Main Window」模板
- 从左侧工具箱拖拽控件到画布上(比如按钮、标签、下拉框)
- 在右侧属性面板调整控件的大小、文字、颜色等
- 保存为.ui文件
那怎么在Python里用这个.ui文件呢?有两种方式:
方式一:直接加载.ui文件(我推荐新手用这个)
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication
app = QApplication([])
window = uic.loadUi('main_window.ui')
window.show()
app.exec_()
方式二:把.ui转成.py文件(项目大了建议用这个)
# 在命令行执行:
pyuic5 main_window.ui -o main_window_ui.py
# 然后在代码里导入:
from main_window_ui import Ui_MainWindow
4.2 信号与槽机制:让控件「活」起来
界面搭好了,但按钮按下去没反应,那跟一张图片有啥区别?这时候就要请出PyQt5的灵魂机制——信号与槽。
信号(Signal)就是控件发出的消息,比如「按钮被点击了」、「滑块被拖动了」。槽(Slot)就是处理这个消息的函数。你把信号和槽连接起来,控件就能「活」起来。
举个例子,你点一下「启动电机」按钮,控制台打印一条消息:
from PyQt5.QtWidgets import QPushButton, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.btn = QPushButton('启动电机', self)
# 连接信号与槽
self.btn.clicked.connect(self.on_start_motor)
def on_start_motor(self):
print('电机已启动!转速:1500 RPM')
你看,clicked就是按钮的信号,on_start_motor就是槽函数。用connect把它们连起来,就这么简单。
我在项目中遇到过一个问题:多个按钮要连接同一个槽函数,但需要区分是哪个按钮触发的。解决办法是用lambda表达式传递参数:
self.btn_start.clicked.connect(lambda: self.on_motor_control('start'))
self.btn_stop.clicked.connect(lambda: self.on_motor_control('stop'))
def on_motor_control(self, command):
if command == 'start':
print('启动电机')
elif command == 'stop':
print('停止电机')
4.3 主窗口与布局管理:别让控件「乱跑」
你想想看,如果窗口一拉大,按钮还挤在左上角,那画面多难看。布局管理就是解决这个问题的。
PyQt5提供了几种布局方式:
| 布局类型 | 特点 | 适用场景 |
|---|---|---|
| QHBoxLayout | 水平排列,控件从左到右 | 工具栏、状态栏 |
| QVBoxLayout | 垂直排列,控件从上到下 | 参数设置面板 |
| QGridLayout | 网格排列,像Excel表格 | 仪表盘、数据显示 |
| QFormLayout | 表单排列,标签+输入框 | 参数配置界面 |
我一般用QGridLayout做电机监控界面,因为可以很直观地把电压、电流、转速这些参数排成网格。举个例子:
from PyQt5.QtWidgets import QWidget, QGridLayout, QLabel, QLineEdit
class MotorMonitor(QWidget):
def __init__(self):
super().__init__()
layout = QGridLayout()
# 第一行:电压
layout.addWidget(QLabel('电压 (V):'), 0, 0)
self.voltage_edit = QLineEdit('220.0')
layout.addWidget(self.voltage_edit, 0, 1)
# 第二行:电流
layout.addWidget(QLabel('电流 (A):'), 1, 0)
self.current_edit = QLineEdit('5.0')
layout.addWidget(self.current_edit, 1, 1)
# 第三行:转速
layout.addWidget(QLabel('转速 (RPM):'), 2, 0)
self.speed_edit = QLineEdit('1500')
layout.addWidget(self.speed_edit, 2, 1)
self.setLayout(layout)
4.4 实战:做一个简单的电机控制面板
光说不练假把式。我们来做一个完整的例子:一个电机控制面板,包含启动/停止按钮、转速滑块、状态显示。
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
class MotorControlPanel(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('电机控制面板 v1.0')
self.setGeometry(100, 100, 400, 300)
# 中心控件
central = QWidget()
self.setCentralWidget(central)
# 主布局:垂直
main_layout = QVBoxLayout(central)
# 状态显示
self.status_label = QLabel('电机状态:停止')
self.status_label.setAlignment(Qt.AlignCenter)
main_layout.addWidget(self.status_label)
# 转速控制
speed_layout = QHBoxLayout()
speed_layout.addWidget(QLabel('目标转速:'))
self.speed_slider = QSlider(Qt.Horizontal)
self.speed_slider.setRange(0, 3000)
self.speed_slider.setValue(1500)
self.speed_display = QLabel('1500 RPM')
speed_layout.addWidget(self.speed_slider)
speed_layout.addWidget(self.speed_display)
main_layout.addLayout(speed_layout)
# 按钮
btn_layout = QHBoxLayout()
self.btn_start = QPushButton('启动')
self.btn_stop = QPushButton('停止')
btn_layout.addWidget(self.btn_start)
btn_layout.addWidget(self.btn_stop)
main_layout.addLayout(btn_layout)
# 连接信号
self.btn_start.clicked.connect(self.start_motor)
self.btn_stop.clicked.connect(self.stop_motor)
self.speed_slider.valueChanged.connect(self.update_speed)
def start_motor(self):
self.status_label.setText('电机状态:运行中')
self.status_label.setStyleSheet('color: green;')
def stop_motor(self):
self.status_label.setText('电机状态:停止')
self.status_label.setStyleSheet('color: red;')
def update_speed(self, value):
self.speed_display.setText(f'{value} RPM')
if __name__ == '__main__':
app = QApplication([])
window = MotorControlPanel()
window.show()
app.exec_()
好了,这一章的内容就这些。Qt Designer帮你省掉画界面的时间,信号与槽让控件有交互,布局管理让界面不乱跑。这三样东西掌握了,PyQt5你就入门了。下一章我们聊聊怎么用PyQt5做实时数据曲线显示,那才是电机监控的重头戏。