Кликабельные элементы или дочерние виджеты внутри нарисованного пользователем делегата - PullRequest
6 голосов
/ 23 февраля 2012

У меня есть QListView, где я отображаю элементы, используя пользовательский делегат с пользовательской окраской.В каждом элементе (то есть в каждой строке списка) я хочу иметь возможность показать пару «гиперссылок», по которым пользователь мог бы щелкнуть и которые затем вызвали бы некоторые функции.

Я уже пытался проверитьофициальная документация (например, Программирование модели / вида ), а также довольно много гуглят, но я не смог выяснить, как это сделать.

У меня есть две идеи, каждаяс их собственными проблемами:

  • Я мог бы нарисовать их, используя дочерние виджеты, такие как плоский QPushButton.Как мне затем расположить и отобразить эти виджеты?
  • Я также мог бы нарисовать их в виде текстовых строк.Как мне сделать их кликабельными?Или я могу зафиксировать события щелчка в родительском QListView и как-то определить координаты из них?Затем я мог бы сопоставить координаты с этими интерактивными элементами и действовать соответствующим образом.

Мой первоначальный подход состоял в том, чтобы использовать QListWidget с .setItemWidget (), где у меня был правильный виджет с макетом и дочерние виджеты.К сожалению, это было слишком медленно, когда мой список вырос до сотен или тысяч пунктов.Вот почему я перешел на QListView с делегатом.

1 Ответ

2 голосов
/ 24 февраля 2012

Кажется, я подхожу к решению.

Я могу получать клики по элементам, переопределяя делегат .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)
...