ItemChanged 信号在 QTreeWidget 中触发三次

ItemChanged signal fires three times in QTreeWidget

有人能看出是什么导致 ItemChanged 信号触发三次而不是一次吗?

目的是:

  1. 从外部源加载数据
  2. 使用与数据列对应的顶级项目创建一个树形小部件
  3. 勾选用户应该在 table
  4. 中看到的列
  5. 创建一个 table 仅显示所选列

我设法修复了代码,使其忽略正方形选择(如果只选择了一些子项)并且也忽略了对子项的任何更改。每次选择或取消选择航向时,信号仍会触发 3 次。

import pandas as pd 
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.Qt import Qt
import sys

df = pd.DataFrame()
column_names = ['something1', 'different1', 'nothing1']
df_2 = pd.DataFrame(columns = column_names)
df= df.append (df_2)
df.loc[len(df)] = [2, 4, 5]
df.loc[len(df)] = [6, 7, 8]
df.loc[len(df)] = [9, 10, 11]
df.loc[len(df)] = [12, 13, 14]

class My_test(QtWidgets.QFrame):
    def __init__ (self, df,*args, **kw):
        super(My_test, self).__init__(*args, **kw)

        # Import the datafrarme
        self.df = df

        self.horizontalLayout_2 = QtWidgets.QVBoxLayout()
        #Define the table
        self.table = QtWidgets.QTableWidget()
        #Define the tree
        self.tree = QtWidgets.QTreeWidget(self)
        self.tree.setHeaderLabel("Station Data")

        #Complete the Gui
        self.horizontalLayout_2.addWidget(self.table)
        self.horizontalLayout_2.addWidget(self.tree)
        self.setLayout(self.horizontalLayout_2)

        # Create the top level tree items (the same as the table headers)
        for name in df.columns:
            top_level_item_KD = QTreeWidgetItem([name])
            top_level_item_KD.setFlags(top_level_item_KD.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsTristate )
            # self.tree.itemChanged['QTreeWidgetItem*','int'].connect(self.my_func)

            #Connect the itemChanged signal to the its slot
            self.tree.itemChanged.connect(self.return_checked_headers)

            #Populate each header with the appropriate data
            for data_point in df[name]:
                child_KD = QTreeWidgetItem([str(data_point)])
                child_KD.setFlags(child_KD.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
                child_KD.setCheckState(0, Qt.Unchecked)
                top_level_item_KD.addChild(child_KD)
            self.tree.addTopLevelItem(top_level_item_KD)

    def return_checked_headers(self,item ,column_index):
        #column_index is not used in the function. It is kept in the definition for a reminder of what is the second option of the "itemChanged" signal     
        my_selected_columns = []

        #Identify how many data columns have been generated
        top_level_count = self.tree.topLevelItemCount()

        #check if change is on a top level item
        if item.parent() == None:
            #ignore the change if it is a square (value of 1)
            if item.checkState(0)!=1:
                for index in  range(self.tree.topLevelItemCount()):         
                    tree_item = self.tree.topLevelItem(index)
                    if tree_item.checkState(0) !=0:
                        my_header = tree_item.text(0)
                        my_selected_columns.append(my_header)
                self.update_table(self.df,my_selected_columns, self.table)  

    def update_table(self, df, headers, table):
        print ('you are in the updating fucntion')
        self.df = df
        self.headers = headers
        self.table = table
        viewing_df = []
        viewing_df  =self.df[self.headers]

        column_count = len(self.headers)
        row_count = len(viewing_df)

        #Update row and column numbers to reflect input data
        self.table.setRowCount(len(viewing_df.index))
        self.table.setColumnCount(len(self.headers))

        #Create the column headings
        self.table.setHorizontalHeaderLabels(self.headers)
        #Transfer data
        for row_number, row_data in enumerate(viewing_df.values):
            for column_number, datum in enumerate(row_data):
                #Convert numerical data to 1 decimal place and ensure it is converted to a string               
                if type(datum)==float or int:
                    datum= str(round(datum,1))
                self.table.setItem(row_number, column_number,QTableWidgetItem(datum))

#Run the GUI        
app = QtWidgets.QApplication (sys.argv)
my_window = My_test(df)
my_window.show()

app.exec_()

发生这种情况是因为您为 for name in df.columns 的每个周期都连接了信号。因为你有三列,信号被连接了三次,这意味着每次数据改变(通过检查项目),函数被调用三次。

只需将连接放在 for 循环之外,您将只有一个调用。


    # ...
    self.setLayout(self.horizontalLayout_2)

    <b>self.tree.itemChanged.connect(self.return_checked_headers)</b>

    for name in df.columns:
        # ...