Clickable items or child widgets inside a scheduled personalized delegate

I have a QListView where I show elements using a custom delegate with custom painting. Inside each element (i.e., each line of the list) I want to show a couple of "hyperlinks" that the user could click and then call some functions.

I already tried to check the official documentation (e.g. Model / View Programming ), as well as quite a few search queries, but haven not been able to figure out how to do this.

I have two ideas, each of which has its own problems:

  • I could draw them using child widgets, for example, with a flat QPushButton. How can I place and display these widgets?
  • I could also draw them as text strings. How to make them interactive? Or can I capture click events on the parent QListView and somehow determine the coordinates of them? Then I could map the coordinates to these clickable elements and act accordingly.

My initial approach was to use a QListWidget with .setItemWidget (), where I had a corresponding widget with layouts and child widgets. Unfortunately, it was too slow when my list grew to hundreds or thousands of items. This is why I switched to QListView with a delegate.

+6
source share
1 answer

I seem to be closing the solution.

I can get clicks on elements by overriding the delegate .editorEvent(event, model, option, index) . Then I can find out event.type() by clicking the line from index.row() and the actual coordinates from event.x() and event.y() (since if the event type is MouseButtonRelease, the event is QMouseEvent).

From this, I think I can match the coordinates with my elements on the screen and act accordingly.

I will update this answer when I have working code.

EDIT

A simple working example using 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) 
+1
source

Source: https://habr.com/ru/post/909188/


All Articles