PyQt4 - 使用 QItemDelegate 在 QListView 中显示小部件
PyQt4 - Using a QItemDelegate to display widget in a QListView
我想要一个 QListView
来显示自定义小部件。我想最好的方法是 QItemDelegate
。不幸的是,我不太明白如何正确地对其进行子类化以及如何实现 paint()
方法,这似乎是最重要的方法。我找不到任何有关使用委托创建另一个小部件的信息。
我已经尝试在没有委托的情况下实现类似的东西,但效果不是很好,因为 QListView
不应该显示小部件。
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class Model(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(QtCore.QAbstractListModel, self).__init__(parent)
self._widgets = []
def headerData(self, section, orientation, role):
""" Returns header for columns """
return "Header"
def rowCount(self, parentIndex=QtCore.QModelIndex()):
""" Returns number of interfaces """
return len(self._widgets)
def data(self, index, role):
""" Returns the data to be displayed """
if role == QtCore.Qt.DisplayRole:
row = index.row()
return self._widgets[row]
def insertRow(self, widget, parentIndex=QtCore.QModelIndex()):
""" Inserts a row into the model """
self.beginInsertRows(parentIndex, 0, 1)
self._widgets.append(widget)
self.endInsertRows()
class Widget(QtGui.QWidget):
def __init__(self, parent=None, name="None"):
super(QtGui.QWidget, self).__init__(parent)
self.layout = QtGui.QHBoxLayout()
self.setLayout(self.layout)
self.checkbox = QtGui.QCheckBox()
self.button = QtGui.QPushButton(self)
self.label = QtGui.QLabel(self)
self.label.setText(name)
self.layout.addWidget(self.checkbox)
self.layout.addWidget(self.button)
self.layout.addWidget(self.label)
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(QtGui.QMainWindow, self).__init__(parent)
self.view = QtGui.QListView(self)
self.model = Model()
self.view.setModel(self.model)
self.setCentralWidget(self.view)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.show()
app = QtGui.QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
那么,我需要如何实现委托才能执行我想要的操作?
这是一个 QTableWidget
的示例,每行都有一个按钮和文本。我定义了一个 add_item
方法来一次添加一整行:插入一个新行,在第 0 列中放置一个按钮,在第 1 列中放置一个常规项目。
import sys
from PyQt4 import QtGui,QtCore
class myTable(QtGui.QTableWidget):
def __init__(self,parent=None):
super(myTable,self).__init__(parent)
self.setColumnCount(2)
def add_item(self,name):
#new row
row=self.rowCount()
self.insertRow(row)
#button in column 0
button=QtGui.QPushButton(name)
button.setProperty("name",name)
button.clicked.connect(self.on_click)
self.setCellWidget(row,0,button)
#text in column 1
self.setItem(row,1,QtGui.QTableWidgetItem(name))
def on_click(self):
# find the item with the same name to get the row
text=self.sender().property("name")
item=self.findItems(text,QtCore.Qt.MatchExactly)[0]
print("Button click at row:",item.row())
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
widget = myTable()
widget.add_item("kitten")
widget.add_item("unicorn")
widget.show()
sys.exit(app.exec_())
好处:如何知道用户点击了哪个按钮?按钮没有一行 属性,但是我们可以在实例化按钮时创建一行,如下所示:
button.setProperty("row",row)
问题是,如果您对 table 进行排序或删除一行,行号将不再匹配。所以我们改为设置 "name" 属性,与第 1 列中项目的文本相同。然后我们可以使用 findItems
来获取行(参见 on_click
)。
我想要一个 QListView
来显示自定义小部件。我想最好的方法是 QItemDelegate
。不幸的是,我不太明白如何正确地对其进行子类化以及如何实现 paint()
方法,这似乎是最重要的方法。我找不到任何有关使用委托创建另一个小部件的信息。
我已经尝试在没有委托的情况下实现类似的东西,但效果不是很好,因为 QListView
不应该显示小部件。
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class Model(QtCore.QAbstractListModel):
def __init__(self, parent=None):
super(QtCore.QAbstractListModel, self).__init__(parent)
self._widgets = []
def headerData(self, section, orientation, role):
""" Returns header for columns """
return "Header"
def rowCount(self, parentIndex=QtCore.QModelIndex()):
""" Returns number of interfaces """
return len(self._widgets)
def data(self, index, role):
""" Returns the data to be displayed """
if role == QtCore.Qt.DisplayRole:
row = index.row()
return self._widgets[row]
def insertRow(self, widget, parentIndex=QtCore.QModelIndex()):
""" Inserts a row into the model """
self.beginInsertRows(parentIndex, 0, 1)
self._widgets.append(widget)
self.endInsertRows()
class Widget(QtGui.QWidget):
def __init__(self, parent=None, name="None"):
super(QtGui.QWidget, self).__init__(parent)
self.layout = QtGui.QHBoxLayout()
self.setLayout(self.layout)
self.checkbox = QtGui.QCheckBox()
self.button = QtGui.QPushButton(self)
self.label = QtGui.QLabel(self)
self.label.setText(name)
self.layout.addWidget(self.checkbox)
self.layout.addWidget(self.button)
self.layout.addWidget(self.label)
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(QtGui.QMainWindow, self).__init__(parent)
self.view = QtGui.QListView(self)
self.model = Model()
self.view.setModel(self.model)
self.setCentralWidget(self.view)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.model.insertRow(
widget=Widget(self)
)
self.show()
app = QtGui.QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
那么,我需要如何实现委托才能执行我想要的操作?
这是一个 QTableWidget
的示例,每行都有一个按钮和文本。我定义了一个 add_item
方法来一次添加一整行:插入一个新行,在第 0 列中放置一个按钮,在第 1 列中放置一个常规项目。
import sys
from PyQt4 import QtGui,QtCore
class myTable(QtGui.QTableWidget):
def __init__(self,parent=None):
super(myTable,self).__init__(parent)
self.setColumnCount(2)
def add_item(self,name):
#new row
row=self.rowCount()
self.insertRow(row)
#button in column 0
button=QtGui.QPushButton(name)
button.setProperty("name",name)
button.clicked.connect(self.on_click)
self.setCellWidget(row,0,button)
#text in column 1
self.setItem(row,1,QtGui.QTableWidgetItem(name))
def on_click(self):
# find the item with the same name to get the row
text=self.sender().property("name")
item=self.findItems(text,QtCore.Qt.MatchExactly)[0]
print("Button click at row:",item.row())
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
widget = myTable()
widget.add_item("kitten")
widget.add_item("unicorn")
widget.show()
sys.exit(app.exec_())
好处:如何知道用户点击了哪个按钮?按钮没有一行 属性,但是我们可以在实例化按钮时创建一行,如下所示:
button.setProperty("row",row)
问题是,如果您对 table 进行排序或删除一行,行号将不再匹配。所以我们改为设置 "name" 属性,与第 1 列中项目的文本相同。然后我们可以使用 findItems
来获取行(参见 on_click
)。