2012-02-23 6 views
6

Ho un QListView, in cui vengono visualizzati gli oggetti utilizzando un delegato personalizzato con verniciatura personalizzata. All'interno di ciascun articolo (ad esempio ogni riga di elenco) voglio essere in grado di mostrare un paio di "collegamenti ipertestuali" su cui l'utente può fare clic e che quindi chiamerebbero alcune funzioni.Elementi cliccabili o widget figlio all'interno del delegato personalizzato Dipinto

Ho già provato a controllare la documentazione ufficiale (ad esempio Model/View Programming) e un bel po 'di google, ma non sono riuscito a capire come ottenerlo.

ho due idee, ognuno con i propri problemi:

  • ho potuto disegnare utilizzando widget figli, come un QPushButton piatta. Come posso quindi posizionare e visualizzare questi widget?
  • Potrei anche disegnarli come stringhe di testo. Come faccio a renderli cliccabili? Oppure posso acquisire eventi click sul padre QListView e in qualche modo determinare le coordinate da quelli? Potrei quindi abbinare le coordinate a questi elementi cliccabili e agire di conseguenza.

Il mio approccio iniziale era utilizzare QListWidget con .setItemWidget(), dove avevo un widget adeguato con un layout e widget figlio. Sfortunatamente questo era troppo lento quando la mia lista crebbe a centinaia o migliaia di oggetti. Ecco perché sono passato a QListView con un delegato.

risposta

1

Mi sembra di essere in una soluzione.

Posso ricevere clic sugli elementi ignorando lo .editorEvent(event, model, option, index) del delegato. Posso quindi scoprire lo event.type(), la riga selezionata da index.row() e le coordinate effettive da event.x() e event.y() (poiché, se il tipo di evento è MouseButtonRelease, l'evento è un QMouseEvent).

Da questi, penso di poter correlare le coordinate ai miei elementi sullo schermo e agire di conseguenza.

Aggiornerò questa risposta una volta che ho il codice funzionante.

EDIT

Un semplice esempio di lavoro, utilizzando 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)