自定义绘制的委托中的可点击元素或子部件

9
我有一个QListView,使用自定义代理和绘画来显示项目。在每个项目(即每个列表行)中,我希望能够显示几个“超链接”,用户可以单击这些链接并调用一些函数。
我已经尝试查阅官方文档(例如Model/View Programming)以及进行了大量的谷歌搜索,但是还没有找出如何实现这一点。
我有两个想法,每个都有自己的问题:
- 我可以使用子小部件(例如平面QPushButton)来绘制它们。那么我应该如何定位和显示这些小部件? - 我也可以将它们绘制为文本字符串。那么我应该如何使它们可点击?或者我可以在父级QListView上捕获单击事件,并从中确定坐标吗?然后我可以将坐标与这些可点击的元素相匹配,并相应地采取行动。
我的初始方法是使用QListWidget和.setItemWidget(),其中我有一个具有布局和子小部件的适当小部件。不幸的是,当我的列表增长到数百或数千项时,这样做太慢了。这就是为什么我改为使用带有委托的QListView的原因。
1个回答

3
我似乎正在接近一个解决方案。
通过覆盖委托的.editorEvent(event, model, option, index)方法,我可以接收元素上的点击事件。然后,我可以从event.type()获取事件类型,从index.row()获取点击的行,从event.x()和event.y()获取实际坐标(因为如果事件类型是MouseButtonRelease,则事件是QMouseEvent)。
通过这些信息,我认为我可以将坐标与屏幕上的元素对应,并相应地采取行动。
一旦我有可用的代码,我会更新这个答案。
编辑:
一个简单的工作示例,使用PySide:
class MyModel(QtGui.QStandardItemModel):
  def __init__(self):
    super(MyModel, self).__init__()
    for i in range(10): self.appendRow(QtGui.QStandardItem("Row %d" % i))

class MyDelegate(QtGui.QStyledItemDelegate):
  def __init__(self, parent=None):
    super(MyDelegate, self).__init__(parent)
    self.links = {}

  def makeLinkFunc(self, row, text):
    def linkFunc(): print("Clicked on %s in row %d" % (text, row))
    return linkFunc

  def paint(self, painter, option, index):
    painter.save()
    textHeight  = QtGui.QFontMetrics(painter.font()).height()

    painter.drawText(option.rect.x()+2, option.rect.y()+2+textHeight, index.data())

    rowLinks = {}
    for i in range(3):
      text = "Link %d" % (3-i)
      linkWidth = QtGui.QFontMetrics(font).width(text)
      x = option.rect.right() - (i+1) * (linkWidth + 10)
      painter.drawText(x, y, text)
      rect = QtCore.QRect(x, y - textHeight, linkWidth, textHeight)
      rowLinks[rect] = self.makeLinkFunc(index.row(), text)

    self.links[index.row()] = rowLinks
    painter.restore()

  def sizeHint(self, option, index):
    hint = super().sizeHint(option, index)
    hint.setHeight(30)
    return hint

  def editorEvent(self, event, model, option, index):
    if event.type() == QtCore.QEvent.MouseButtonRelease:
      for rect, link in self.links[index.row()].items():
        if rect.contains(event.pos()):
          link()
          return True
    return False

listmodel = MyModel()
listview = QtGui.QListView()
listview.setModel(listmodel)
listview.setItemDelegate(MyDelegate(parent=listview))
listview.setSelectionMode(QtGui.QAbstractItemView.NoSelection)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接