Python ItemChanged信号在QTreeWidget中触发三次

Python ItemChanged信号在QTreeWidget中触发三次,python,user-interface,pyqt5,treewidget,Python,User Interface,Pyqt5,Treewidget,有人能看到是什么导致ItemChanged信号触发三次而不是一次吗 目的是: 从外部源加载数据 创建一个树小部件,其中包含与数据列对应的顶级项 勾选用户应在表格中看到的列 创建一个仅显示选定列的表 我设法修复了代码,使其忽略了方形选择(如果只选择了一些子项),并且也忽略了对子项的任何更改。但每当选择或取消选择航向时,信号仍会触发3次 import pandas as pd from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidge

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

目的是:

  • 从外部源加载数据
  • 创建一个树小部件,其中包含与数据列对应的顶级项
  • 勾选用户应在表格中看到的列
  • 创建一个仅显示选定列的表
  • 我设法修复了代码,使其忽略了方形选择(如果只选择了一些子项),并且也忽略了对子项的任何更改。但每当选择或取消选择航向时,信号仍会触发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_()
    

    这是因为您为df.columns中的name连接了
    的每个周期的信号。因为您有三列,所以信号连接三次,这意味着每次更改数据(通过检查项),函数都会被调用三次

    只需将连接置于for循环之外,您将只有一个呼叫

    
        # ...
        self.setLayout(self.horizontalLayout_2)
    
        self.tree.itemChanged.connect(self.return_checked_headers)
    
        for name in df.columns:
            # ...
    
    
    # ...
    self.setLayout(self.horizontalLayout_2)
    self.tree.itemChanged.connect(self.return\u checked\u头)
    对于df.columns中的名称:
    # ...
    
    这确实奏效了!我很难理解为什么。该函数作为属性有效地添加到树中。它未连接到表示列的widgetItem。当信号被触发时,是什么导致“for name in df.columns”被激活?