PyQt connect inside for 循环与单独调用导致不同的行为
Posted
技术标签:
【中文标题】PyQt connect inside for 循环与单独调用导致不同的行为【英文标题】:PyQt connect inside for loop vs. separate calls results in different behavior 【发布时间】:2015-01-28 07:06:48 【问题描述】:我正在构建一个绘图 UI,它允许用户从加载的数据集生成多个绘图。作为其中的一部分,用户可以将标记线添加到他们的绘图中,以通过在绘图上移动这些标记线来检查 (x, y) 值。
如果标记分别添加到每个绘图(即通过 elif 代码块分别将标记添加到 Plot1、Plot2 等),则以下函数可以正常工作。但是,如果选择了“全部添加”选项,则会导致在 add_marker 函数中使用 for 循环代码块,所有标记最终都会成为列表中最后一个 plotItem (plot_objects) 的子项。
如果我在调用 add_marker 函数时在循环迭代时检查标记对象,则对象及其父对象是不同的。但是,如果我在 update_marker_vals 函数中检查父项,则标记 1 和 2 的父项对于列表中除最后一个图之外的所有图都是不正确的。
不确定这里发生了什么,但我认为这与两个 sigDragged.connect 语句有关,因为在那之前其他一切似乎都很好。
代码:
def add_marker(self):
name = self.markersPlot_dropdown.currentText()
if name == "All":
for plot_name, plt in self.plot_objects.items():
x_val = (plt.viewRange()[0][0]+plt.viewRange()[0][1])/2
marker_one = plt.addLine(x=x_val*0.5, pen=pg.mkPen('g', width=2.0), movable=True)
marker_two = plt.addLine(x=x_val*1.5, pen=pg.mkPen('c', width=2.0), movable=True)
marker_one.sigDragged.connect(lambda: self.update_marker_vals(marker_one, "Marker One"))
marker_two.sigDragged.connect(lambda: self.update_marker_vals(marker_two, "Marker Two"))
self.plot_markers[plot_name] = "Marker One": marker_one, "Marker Two:": marker_two
elif name:
plt = self.plot_objects[name]
x_val = (plt.viewRange()[0][0]+plt.viewRange()[0][1])/2
marker_one = plt.addLine(x=x_val*0.5, pen=pg.mkPen('g', width=2.0), movable=True)
marker_two = plt.addLine(x=x_val*1.5, pen=pg.mkPen('c', width=2.0), movable=True)
marker_one.sigDragged.connect(lambda: self.update_marker_vals(marker_one, "Marker One"))
marker_two.sigDragged.connect(lambda: self.update_marker_vals(marker_two, "Marker Two"))
self.plot_markers[name] = "Marker One": marker_one, "Marker Two:": marker_two
def update_marker_vals(self, marker, marker_num):
plot_item = marker.parentItem().parentItem().parentItem()
plot_name = list(self.plot_objects.keys())[list(self.plot_objects.values()).index(plot_item)]
sampling_divisor = self.selected_curve[plot_name].getData()[0][1] - \
self.selected_curve[plot_name].getData()[0][0]
index = int(marker.getXPos() / sampling_divisor)
x_val = self.selected_curve[plot_name].getData()[0][index]
y_val = self.selected_curve[plot_name].getData()[1][index]
if marker_num == "Marker One":
print(plot_name)
print("Marker One, :" + str(index))
print(x_val, y_val)
elif marker_num == "Marker Two":
print(plot_name)
print("Marker Two, :" + str(index))
print(x_val, y_val)
编辑:
附带说明一下,作为一种解决方案,我可以将此函数分成两个函数 - 一个函数创建两个标记,另一个函数从 QComboBox 获取输入并为特定绘图创建一组标记或为所有可用的图创建标记。这可行,并且是我当前的解决方案,但我仍然对上述代码的问题感到好奇。
【问题讨论】:
【参考方案1】:当您将信号连接到lambda
函数时,lambda
函数的内容会在信号发出时评估,不会在信号连接时评估。因此,您使用的变量(marker_one
和 marker_two
)始终指向在循环的最后一次迭代中创建的对象。
一个简单的解决方案是在lambda
函数的签名中明确地将marker_one
和marker_two
作为默认参数传递给同名变量:
lambda marker_one=marker_one: self.update_marker_vals(marker_one, "Marker One")
lambda marker_two=marker_two: self.update_marker_vals(marker_two, "Marker Two")
有几个与here 非常相似的问题相关的有用答案,特别是ekhumoro 的答案,如果您想了解更多信息(我对这个问题的回答也很有用,尽管 ekhumoro 的解决方案更简洁)
【讨论】:
以上是关于PyQt connect inside for 循环与单独调用导致不同的行为的主要内容,如果未能解决你的问题,请参考以下文章
AndroidStudio更新时报错:Connection Error,Temp directory inside installation
PyQt 小部件 connect() 和 disconnect()
Pyqt5 多线程错误:QObject::connect: 无法对“QTextCursor”类型的参数进行排队