PyQt 在 for 循环内部连接与单独调用会导致不同的行为 [英] PyQt connect inside for loop vs. separate calls results in different behavior

查看:37
本文介绍了PyQt 在 for 循环内部连接与单独调用会导致不同的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个绘图 UI,让用户可以从加载的数据集生成多个绘图.作为此操作的一部分,用户可以将标记线添加到他们的图中,通过在图中移动这些标记线来检查 (x, y) 值.

I'm building a plotting UI that lets a user generate multiple plots from loaded data sets. As part of this the user can add marker lines to their plots to examine (x, y) values by moving those marker lines across the plot.

如果将标记分别添加到每个图(即通过 elif 代码块分别将 add_marker 添加到 Plot1、Plot2 等),下面的函数可以正常工作.但是,如果选择了添加到全部"选项,导致在 add_marker 函数中使用 for 循环代码块,所有标记最终都会成为列表中最后一个 plotItem (plot_objects) 的子项.

The functions below work fine if the markers are added to each plot separately (i.e. add_marker to Plot1, Plot2, etc. separately via the elif block of code). However, if the "add to all" option is selected, resulting in the usage of the for loop block of code in the add_marker function all of the markers end up being children of the last plotItem in the list (plot_objects).

如果我在调用 add_marker 函数时在循环迭代时检查标记对象,则对象及其父对象是不同的.但是,如果我检查 update_marker_vals 函数中的父项,则标记 1 和 2 的父项对于除列表中的最后一个图之外的所有图都不正确.

If I check the marker objects as the loop iterates when the add_marker function is called the objects, and their parents, are distinct. However, if I check the parents in the update_marker_vals function the parent for markers 1 and 2 are incorrect for all but the last plot in the list.

不确定这里发生了什么,但我认为它与两个 sigDragged.connect 语句有关,因为在那之前其他一切似乎都很好.

Not sure what's going on here, but I assume it has something to do with the two sigDragged.connect statements, seeing as everything else seems fine before then.

代码:

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 获取输入并为特定图创建一组标记或为所有可用的图创建标记.这有效,并且是我当前的解决方案,但我仍然很好奇上述代码的问题是什么.

On a side note, as a solution I can separate this function out into two functions - one function that creates the two markers and then another function that takes the input from the QComboBox and creates one set of markers for a specific plot or creates markers for all the plots available. This works, and is my current solution, but I'm still curious as to what the issue is with the above code.

推荐答案

当您将信号连接到 lambda 函数时,lambda 函数的内容在以下情况下进行评估信号被发射,当信号被连接时.因此,您使用的变量(marker_onemarker_two)始终指向在循环的最后一次迭代中创建的对象.

When you connect a signal to a lambda function, the contents of the lambda function are evaluated when the signal is emitted, not when the signal is connected. As such, the variables you use (marker_one and marker_two) always point to the objects created in the last iteration of the loop.

一个简单的解决方案是在 lambdamarker_one 和 marker_two 作为同名变量的默认参数> 功能:

One simple solution is to explicitly pass in marker_one and marker_two as default arguments to variables of the same name, in the signature of the lambda function:

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 的解决方案更简洁)

There are several useful answers relating to a very similar problem here, specifically the answer by ekhumoro, if you would like to know more (my answer to that question my also be of use, although ekhumoro's solution is cleaner)

这篇关于PyQt 在 for 循环内部连接与单独调用会导致不同的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆