'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这样我的解决方案可以应用。
在您的情况下,没有必要重写任何方法,因为如果某个项目已被单击,有几个信号会通知您:
-
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_())
-
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()
我正在尝试更改 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这样我的解决方案可以应用。
在您的情况下,没有必要重写任何方法,因为如果某个项目已被单击,有几个信号会通知您:
-
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_())
-
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()