2

我正在构建一个绘图 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 获取输入并为特定绘图创建一组标记或创建标记所有可用的地块。这可行,并且是我当前的解决方案,但我仍然对上述代码的问题感到好奇。

4

1 回答 1

3

当您将信号连接到函数时,会在发出信号时评估lambda函数的内容,而不是在连接信号时评估。因此,您使用的变量 (和) 始终指向在循环的最后一次迭代中创建的对象。lambdamarker_onemarker_two

一种简单的解决方案是在函数的签名中显式传入同名变量marker_one并作为默认参数:marker_twolambda

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")

这里有几个与非常相似的问题相关的有用答案,特别是ekhumoro的答案,如果您想了解更多信息(我对这个问题的回答也很有用,尽管 ekhumoro 的解决方案更简洁)

于 2014-11-30T05:25:37.410 回答