'Table' 对象没有属性 'tableWidget' PyQt5

'Table' object has no attribute 'tableWidget' PyQt5

我正在尝试更改 QTableWidget 鼠标按下事件方法,以根据用户是右键单击还是左键单击对单元格项目执行不同的操作。当我左键单击 self.tableWidget 中的一个单元格时出现以下错误:

AttributeError: 'Table' object has no attribute 'tableWidget' (line 114 [commented below])

下面是我的代码:

from PyQt5 import QtCore, QtGui, QtWidgets
from WordSearch import WordSearch as ws

ws = ws()


class Table(QtWidgets.QTableWidget): #overwriting QTableWidgets to allow for right click events
    def __init__(self, *args, **kwargs):
        QtWidgets.QTableWidget.__init__(self, *args, **kwargs)

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            item = self.itemAt(event.pos())
            print (item.row(), item.column()) #FOR DEBUGGUNG
            Ui_MainWindow.leftClickLetter(self, item.row(), item.column())

        elif event.button() == QtCore.Qt.RightButton:
            print("RIGHT CLICK!") #FOR DEBUGGING
        QtWidgets.QTableWidget.mousePressEvent(self, event)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
         .....

         self.generate.clicked.connect(self.generateTable)

         .....

    def generateTable(self):

        self.tableWidget = Table(self.centralwidget)
        self.tableWidget.setObjectName("tableWidget")

        self.tableWidget.setColumnCount(int(self.size.text()))
        self.tableWidget.setRowCount(int(self.size.text()))

        self.tableWidget.show()

    def leftClickLetter(self, row, col): 
        item = self.tableWidget.item(row, col) #Line 114
        item.setBackground(QtGui.QColor(216,191,216))
        if (row, col) not in self.coordsToCheck:
            self.coordsToCheck.append((row,col))

        self.tableWidget.clearSelection()

我删除了一些我认为不相关的代码,但请告诉我是否应该添加它。 generateTable() 总是在 leftClickLetter() 之前调用,所以 self.tableWidget 应该是 Table.

类型的正确变量名

解释:

要理解这个问题,应该分析下面的例子:

class A:
    def foo(self, arg1, arg2):
        print(self)


class B:
    pass


b = B()
A.foo(b, "2", 3)

输出:

<__main__.B object at 0x7fb364501070>

如您所见,对象"self" 不是指"A" 实例,而是指传递给该方法的第一个参数,为什么会出现这个问题?好吧,因为你正试图通过 class 使用一个方法,但你必须使用这样的实例:

b = B()
a = A()
a.foo(b, "2")

输出:

<__main__.A object at 0x7fd3139a4f40>

这里我们看到"self"指的是class"A"的对象。

以上是由于对 OOP 知之甚少而导致的错误,因此我的建议是查看您关于该主题的笔记。

解决方案:

注意:首先不建议修改Qt Designer生成的class,必须还原class这样我的解决方案可以应用。

在您的情况下,没有必要重写任何方法,因为如果某个项目已被单击,有几个信号会通知您:

  • itemClicked

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            # ..
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setupUi(self)
            self.generate.clicked.connect(self.generate_table)
            self.coordsToCheck = []
            self.tables = []
    
        def generate_table(self):
    
            try:
                size = int(self.size.text())
            except ValueError as e:
                print("error", e)
            else:
                tableWidget = QtWidgets.QTableWidget()
                tableWidget.setColumnCount(size)
                tableWidget.setRowCount(size)
                tableWidget.show()
                tableWidget.itemClicked.connect(self.on_item_clicked)
                self.tables.append(tableWidget)
    
        @QtCore.pyqtSlot("QTableWidgetItem*")
        def on_item_clicked(self, it):
            row, col = it.row(), it.column()
            it.setBackground(QtGui.QColor(216, 191, 216))
            if (row, col) not in self.coordsToCheck:
                self.coordsToCheck.append((row, col))
            it.tableWidget().clearSelection()
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    
  • clicked

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            # ...
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setupUi(self)
            self.generate.clicked.connect(self.generate_table)
            self.coordsToCheck = []
            self.tables = []
    
        def generate_table(self):
    
            try:
                size = int(self.size.text())
            except ValueError as e:
                print("error", e)
            else:
                tableWidget = QtWidgets.QTableWidget()
                tableWidget.setColumnCount(size)
                tableWidget.setRowCount(size)
                tableWidget.show()
                tableWidget.clicked.connect(self.on_clicked)
                self.tables.append(tableWidget)
    
        @QtCore.pyqtSlot(QtCore.QModelIndex)
        def on_clicked(self, index):
            tableWidget = self.sender()
            row, col = index.row(), index.column()
            tableWidget.model().setData(
                index, QtGui.QColor(216, 191, 216), QtCore.Qt.BackgroundRole
            )
            if (row, col) not in self.coordsToCheck:
                self.coordsToCheck.append((row, col))
            tableWidget.clearSelection()
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    

更新:

如果要检测右键单击,则必须创建信号而不是直接调用方法:

class TableWidget(QtWidgets.QTableWidget):
    rightClicked = QtCore.pyqtSignal(QtCore.QModelIndex)

    def mouseReleaseEvent(self, event):
        super().mouseReleaseEvent(event)
        if event.button() == QtCore.Qt.RightButton:
            self.rightClicked.emit(self.indexAt(event.pos()))
def generate_table(self):
    try:
        size = int(self.size.text())
    except ValueError as e:
        print("error", e)
    else:
        tableWidget = TableWidget(size, size)
        tableWidget.show()
        tableWidget.clicked.connect(self.on_left_clicked)
        tableWidget.rightClicked.connect(self.on_right_clicked)
        self.tables.append(tableWidget)

@QtCore.pyqtSlot(QtCore.QModelIndex)
def on_left_clicked(self, index):
    self.change_color(self.sender(), index, QtGui.QColor(216, 191, 216))

@QtCore.pyqtSlot(QtCore.QModelIndex)
def on_right_clicked(self, index):
    self.change_color(self.sender(), index, None)

def change_color(self, view, index, color):
    if not isinstance(view, QtWidgets.QAbstractItemView):
        return
    model = view.model()
    if model is None:
        return
    model.setData(index, color, QtCore.Qt.BackgroundRole)
    view.clearSelection()