PyQt中如何实现QDialog与主窗口间的信号/变量传递
PyQt QDialog与主窗口交互传值绘图解决方案
1. 功能具体实现方法
核心问题是子弹窗Dialog00d0和主窗口MainWidget没有建立合法的通信链路,且你错误地尝试在主窗口访问子弹窗内部的下拉框控件,同时信号绑定用了错误的字符串写法导致按钮点击无响应。
采用PyQt标准的自定义信号方案实现,耦合度最低,符合Qt设计规范,步骤如下:
- 第一步:给
Dialog00d0添加自定义信号,点击确认按钮时发射,携带下拉框选中的数据集名称 - 第二步:主窗口创建弹窗实例时,将弹窗的自定义信号绑定到主窗口的
createGraph槽函数 - 第三步:修改
createGraph方法,增加入参接收传过来的数据集名称,不再直接访问子弹窗的控件
修改后的完整代码片段:
首先引入信号依赖:
from PyQt5.QtCore import pyqtSignal
修改Dialog00d0类:
class Dialog00d0(QDialog): # 自定义字符串类型信号,用于传递选中的绘图数据类型 selected_data = pyqtSignal(str) def __init__(self, parent=None): super().__init__(parent) self.layout = QVBoxLayout() hlay = QHBoxLayout() self.setLayout(self.layout) self.setWindowTitle("Create Graph") label = QLabel("Data Type") self.combobox00d0 = QComboBox() self.combobox00d0.addItems([ "Steering Angle", "Latitudinal Acceleration", "Longitudinal Acceleration", "Combined Acceleration" ]) self.BTNCreateGraph = QPushButton("Create Graph") self.BTNCancel = QPushButton("Cancel") hlay.addWidget(self.BTNCreateGraph) hlay.addWidget(self.BTNCancel) self.layout.addWidget(label) self.layout.addWidget(self.combobox00d0) self.layout.addLayout(hlay) # 修正原代码错误的字符串绑定写法,直接传入方法对象 self.BTNCreateGraph.clicked.connect(self.on_confirm) self.BTNCancel.clicked.connect(self.close) def on_confirm(self): # 读取选中值,发射信号后关闭弹窗 selected_type = self.combobox00d0.currentText() self.selected_data.emit(selected_type) self.accept()
修改主窗口中弹窗调用的逻辑:
def onSelectionChanged(self, index): self.selectionPath = self.sender().model().filePath(index) self.selectionFilename = self.selectionPath.split("/")[-1] IDList = ("ID 00d0","ID 00d1","ID 00d3","ID 00d4","ID 0140","ID 0141","ID 0360","ID 0361") if self.selectionFilename in IDList: if self.selectionFilename == "ID 00d0": # 传入self作为parent,由Qt自动管理弹窗生命周期 editDialog = Dialog00d0(self) # 绑定弹窗信号到主窗口绘图函数 editDialog.selected_data.connect(self.createGraph) editDialog.exec_()
修改主窗口createGraph方法,增加入参接收选中值:
def createGraph(self, selected_data_type): self.graphcheck = 1 self.setCentralWidget(self.scroll_area) if self.selectionFilename == "ID 00d0": self.df00d0 = pd.read_table(self.selectionPath, header=None , delim_whitespace=True, dtype=object) self.df00d0.columns = ['Timestamp','ID',"B0","B1","B2","B3","B4","B5","B6","B7"] self.df00d0.dropna(inplace=True) self.SA = np.array([], dtype=float) self.LatAcc = np.array([], dtype=float) self.LonAcc = np.array([], dtype=float) self.ComAcc = np.array([], dtype=float) self.Time00d0 = np.array([], dtype=float) self.Timestamp00d0 = np.array([], dtype=float) # 时间戳处理逻辑保留,后续优化部分会给出更高效的写法 for item in self.df00d0['Timestamp']: self.Time00d0 = np.append(self.Time00d0, datetime.fromtimestamp(float(item)).strftime("%H:%M:%S.%f")[:-4]) self.Timestamp00d0 = np.append(self.Timestamp00d0, float(item)) # 用传入的selected_data_type替代原代码访问弹窗combobox的逻辑 if selected_data_type == "Steering Angle": SA_ = (((self.df00d0['B1']) + (self.df00d0['B0'])).apply(int, base=16) * 0.1) for item in SA_: if item > 6000: self.SA = np.append(self.SA, round((item - 6553.6), 1)) else: self.SA = np.append(self.SA, round(item)) y_value = self.SA # 其余数据类型的判断分支同理,全部使用selected_data_type做判断即可
2. PyQt程序规范结构设计建议
- 所有QWidget派生类初始化必须传入
parent参数,依托Qt的parent-child机制自动回收对象内存,避免内存泄漏 - 跨窗口/跨类交互优先使用自定义信号,禁止在子窗口中直接持有主窗口实例调用主窗口方法,避免强耦合
- UI逻辑与业务逻辑拆分:文件读取、CAN数据解析这类纯计算逻辑单独抽成工具函数/数据处理类,窗口类只负责控件渲染、信号绑定、交互响应
- 常量统一管理:文件路径、ID列表、不同ID对应的可绘图数据集这类固定值,单独放在配置段或常量类中,不要散落在各个业务函数里
- 弹窗交互统一判断返回值:可以通过
if editDialog.exec_() == QDialog.Accepted:判断用户是点击确认还是关闭/取消,避免无效逻辑执行
3. 现有代码效率优化建议
- 禁止在循环中使用
np.append:numpy数组是定长结构,每次append都会重新开辟内存、复制全量数据,文件数据量大时性能会极差。所有循环append的逻辑都可以替换为pandas向量化操作,速度可提升数十到上百倍:
时间戳处理可直接改写为:
转向角计算可直接改写为:self.Timestamp00d0 = self.df00d0['Timestamp'].astype(float).values self.Time00d0 = pd.to_datetime(self.Timestamp00d0, unit='s').dt.strftime("%H:%M:%S.%f").str[:-4].valuesSA_ = ((self.df00d0['B1'] + self.df00d0['B0']).apply(int, base=16) * 0.1) self.SA = np.where(SA_ > 6000, (SA_ - 6553.6).round(1), SA_.round()).values - 删除冗余判断:
self.graphcheck = 1之后马上判断if self.graphcheck == 1属于无效代码,直接删除即可 - 读取文本文件时指定
usecols参数,只加载需要用到的列,减少内存占用 - 大数据量绘图时,pyqtgraph可以启用
setDownsampling自动降采样,避免几十万甚至上百万个点渲染造成界面卡顿
内容的提问来源于stack exchange,提问作者Stephane Simard
相关产品推荐
相关产品推荐

