如何在 QGridLayout PyQt5 上获取索引或单击元素的位置?

How can I obtain the index or the position of a clicked element on QGridLayout PyQt5?

我需要获取在 pyqt5 中动态创建的按钮的索引或位置,我有这段代码,但目前当我单击 [-] 按钮时,我得到了最后添加的按钮的位置。

import sys
from PyQt5.QtWidgets import (QLineEdit, QLabel, QGridLayout, QWidget, 
                             QPushButton, QApplication, QSpinBox)

class Window(QWidget):
    def __init__(self):
        super().__init__()

        #Creating grid
        self.grid = QGridLayout()
        self.setLayout(self.grid)

        #Creating elements
        self.spn_amount = QSpinBox(self)
        self.txt_registercode = QLineEdit(self)
        self.txt_description = QLineEdit(self)
        self.txt_cost = QLineEdit(self)
        self.txt_total = QLineEdit(self) 
        self.btn_add = QPushButton("+",self) #Button that add rows

        #adding functionality to [+] button
        self.btn_add.clicked.connect(self.getrow_add)
        
        #Adding elements to grid
        self.grid.addWidget(self.spn_amount, 0, 0)
        self.grid.addWidget(self.txt_registercode, 0, 1)
        self.grid.addWidget(self.txt_description, 0, 2)
        self.grid.addWidget(self.txt_cost, 0, 3)
        self.grid.addWidget(self.txt_total, 0, 4)
        self.grid.addWidget(self.btn_add, 0, 5)

        self.row = 0
        self.column = 0

    def getrow_add(self): #Function that get a the actual row of the button to create a new row after
        self.row = self.grid.rowCount() #Obtener el número de filas actuales en el grid
        self.column = self.grid.columnCount() #Obtiene el número de columnas actuales en el grid
        self.addtextbox()

    def getrow_del(self):
        index = self.grid.indexOf(self.btn_del_din)
        position = self.grid.getItemPosition(index)
        self.row = position[0] #Obtengo la posición de la fila
        self.column = self.grid.columnCount() #Obtiene el número de columnas actuales en el grid
        print(self.row)


    def addtextbox(self):
        
        self.lineEdits = []
            
        #Creation of dynamicall elements
        self.spn_amount_din = QSpinBox(self)
        self.txt_registercode_din = QLineEdit(self)
        self.txt_description_din = QLineEdit(self)
        self.txt_cost_din = QLineEdit(self)
        self.txt_total_din = QLineEdit(self) 
        self.btn_del_din = QPushButton("-",self) #Button that delete rows

        #Adding functionality to the [-] button
        self.btn_del_din.clicked.connect(self.getrow_del)

        #Dynamically adding elements to grid
        self.grid.addWidget(self.spn_amount_din, self.row, 0)
        self.grid.addWidget(self.txt_registercode_din, self.row, 1)
        self.grid.addWidget(self.txt_description_din, self.row, 2)
        self.grid.addWidget(self.txt_cost_din, self.row, 3)
        self.grid.addWidget(self.txt_total_din, self.row, 4)
        self.grid.addWidget(self.btn_del_din, self.row, 5)

        self.lineEdits.append('')

    def deltextbox(self):

        for i in range (1, self.column):
            self.grid.itemAtPosition(self.row, i).widget().deleteLater()
        

if __name__ == "__main__":
    application = QApplication(sys.argv)
    window = Window()
    window.setWindowTitle('Dynamically add elements')
    window.show()
    sys.exit(application.exec_())

当我点击 [-] 按钮时,我需要获取该小部件的具体位置。

Here is my GUI

例如这里我有 6 行和 6 列,如果我点击第一个按钮 [-] 我希望得到行的值为 1,列的值为 5,但是我不是从第一个按钮 [-] 而是从最后添加的第 5 行和第 5 列获得的值。

在我的代码中,我通过函数获得了它:

def getrow_del(self):
    index = self.grid.indexOf(self.btn_del_din)
    position = self.grid.getItemPosition(index)
    self.row = position[0] #Obtengo la posición de la fila
    self.column = self.grid.columnCount() #Obtiene el número de columnas actuales en el grid
    print(self.row)

您的代码的主要问题是每次创建新行时您都在不断地覆盖实例属性。

使用动态创建对象的函数时,永远不要为这些对象创建实例属性除非您特别想保留对last 个元素已创建(这不是你的情况)。

为了正确保留对这些元素的引用,必须将它们添加到作为实例属性的持久对象容器(例如列表)中。

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.grid = QGridLayout(self)
        self.items = []
        self.addRow()

    def addRow(self):
        spn_amount_din = QSpinBox()
        txt_registercode_din = QLineEdit()
        txt_description_din = QLineEdit()
        txt_cost_din = QLineEdit()
        txt_total_din = QLineEdit() 

        row = len(self.items)
        if row == 0:
            button = QPushButton('+')
            button.clicked.connect(self.addRow)
        else:
            button = QPushButton('-')
            button.clicked.connect(lambda: self.removeRow())

        row_items = (spn_amount_din, txt_registercode_din, txt_description_din, txt_cost_din, txt_total_din, button)
        self.items.insert(row, row_items)
        for column, widget in enumerate(row_items):
            self.grid.addWidget(widget, row, column)

    def removeRow(self, row=None):
        if row is None:
            button = self.sender()
            for row, widgets in enumerate(self.items):
                if button in widgets:
                    break
        widgets = self.items.pop(row)
        for widget in widgets:
            self.grid.removeWidget(widget)
            widget.deleteLater()
        self.adjustSize()

请注意,虽然 QGridLayout 提供 rowCount()columnCount(),但应谨慎使用它们,因为它们主要用于内部和基本的静态目的:行数和列数是 删除小部件时更新;这意味着如果你想实现更高级的实现(例如 插入 行或排序项目),QGridLayout 通常不是合适的选择。

更好的解决方案是使用主 QVBoxLayout 并将每一行添加为 nested QHBoxLayout,但更好的实现实际上应该使用 class 作为容器所有小部件,这使得整个概念更易于管理,并允许使用它们的属性直接访问每个行元素:

class OrderWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.spn_amount_din = QSpinBox()
        self.txt_registercode_din = QLineEdit()
        self.txt_description_din = QLineEdit()
        self.txt_cost_din = QLineEdit()
        self.txt_total_din = QLineEdit()
        self.button = QPushButton()
        
        layout = QHBoxLayout(self)
        layout.addWidget(self.spn_amount_din)
        layout.addWidget(self.txt_registercode_din)
        layout.addWidget(self.txt_description_din)
        layout.addWidget(self.txt_cost_din)
        layout.addWidget(self.txt_total_din)
        layout.addWidget(self.button)


class Window(QWidget):
    def __init__(self):
        super().__init__()
        QVBoxLayout(self) # just create the layout and set it
        self.items = []
        self.insertRow(0)

    def insertRow(self, row=None):
        if row is None:
            row = len(self.items)
        widget = OrderWidget()
        self.layout().addWidget(widget)
        self.items.insert(row, widget)
        if row == 0:
            widget.button.setText('+')
            widget.button.clicked.connect(lambda: self.insertRow())
        else:
            widget.button.setText('-')
            widget.button.clicked.connect(lambda: self.removeRow(widget))

    def removeRow(self, row):
        if isinstance(row, QWidget):
            widget = row
            row = self.items.index(widget)
        else:
            widget = self.items[row]
        self.layout().removeWidget(widget)
        widget.deleteLater()
        del self.items[row]
        self.adjustSize()