2012-02-23 12 views
6

Tengo un QListView, donde se muestran los elementos usando un delegado personalizado con pintura personalizada. Dentro de cada elemento (es decir, cada fila de la lista) quiero poder mostrar un par de "hipervínculos" en los que el usuario podría hacer clic y que llamarían a algunas funciones.Elementos que se pueden hacer clic o widgets infantiles dentro del delegado pintado a mano

Ya he intentado consultar la documentación oficial (por ejemplo, Model/View Programming), así como bastante Google, pero no he podido averiguar cómo lograr esto.

Tengo dos ideas, cada uno con sus propios problemas:

  • sabía dibujar usando widgets hijos, como un QPushButton plana. ¿Cómo puedo posicionar y visualizar estos widgets?
  • También podría dibujarlos como cadenas de texto. ¿Cómo puedo hacer que puedan hacer clic? ¿O puedo capturar eventos de clic en el QListView padre y de alguna manera determinar las coordenadas de esos? Entonces podría unir las coordenadas a estos elementos seleccionables y actuar en consecuencia.

Mi enfoque inicial era utilizar QListWidget con .setItemWidget(), donde tenía un widget adecuado con un diseño y widgets secundarios. Lamentablemente, esto fue demasiado lento cuando mi lista aumentó a cientos o miles de elementos. Es por eso que cambié a QListView con un delegado.

Respuesta

1

Parece que me estoy acercando a una solución.

Puedo recibir clics en los elementos anulando el .editorEvent(event, model, option, index) del delegado. Luego puedo averiguar el event.type(), la fila clicada de index.row() y las coordenadas reales de event.x() y event.y() (ya que, si el tipo de evento es MouseButtonRelease, el evento es un evento de QMouse).

De estos, creo que puedo correlacionar las coordenadas de mis elementos en la pantalla y actuar en consecuencia.

Voy a actualizar esta respuesta una vez que tenga el código de trabajo.

EDITAR

Un simple ejemplo de trabajo, usando 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) 
Cuestiones relacionadas