2016-12-18 9 views
1

Я реализовал следующий делегат, чтобы предоставить выпадающее имя в QTableView. Вариант использования заключается в замене столбца (ключа), который обычно не имеет смысла для пользователя (например, числовой идентификатор) с текстовым эквивалентом.Как создать combo-box QItemDelegate

Сниппет ниже работ (в том числе для сохранения правильного значения), но у него есть три вопроса:

  1. Он отображает исходное значение, вместо текста эквивалент.
  2. Выбор строк в QTableView предоставляет все столбцы, но не тот, у кого есть этот делегат.
  3. В идеале я хотел бы, чтобы выпадающее поле появлялось как таковое, без необходимости нажимать на него, чтобы узнать, что это одно.

Примечание: Ключ может представлять собой любую строку (не обязательно целое число). Типичным примером может служить страна (значение «Франция» соответствует ключу «FR»).

class ComboDelegate(QtGui.QItemDelegate): 
    """ 
    A delegate that places a QComboBox in every 
    cell of the column to which it is being applied 
    """ 

    def __init__(self, parent, value_data): 
     "Value_data is a list of tuples: (item, label)" 
     QtGui.QItemDelegate.__init__(self, parent) 
     self.value_data = value_data 

    @property 
    def items(self): 
     "The list of items for display" 
     return [item[0] for item in self.value_data] 

    @property 
    def labels(self): 
     "The list of labels for display" 
     return [item[1] for item in self.value_data] 

    def item(self, label): 
     "Get the item from a label" 
     try: 
      index = self.labels.index(label) 
     except ValueError: 
      pass 
     print("Value no: &%s" % index) 
     return self.items[index] 

    def createEditor(self, parent, option, index): 
     "Create the editor (called each time)" 

     combo = QtGui.QComboBox(parent) 
     for duplet in self.value_data: 
      # the duplet is label, item 
      item, label = duplet 
      combo.addItem(label) 

     combo.currentIndexChanged.connect(self.currentIndexChanged) 
     return combo 

    def setEditorData(self, editor, index): 
     editor.blockSignals(True) 
     editor.setCurrentIndex(index.row()) 
     editor.blockSignals(False) 

    def setModelData(self, editor, model, index): 
     "This is the data stored into the field" 
     print("Current text: %s" % editor.currentText()) 
     model.setData(index, self.item(editor.currentText())) 

    def currentIndexChanged(self): 
     self.commitData.emit(self.sender()) 

ответ

1

Первая проблема может быть наиболее легко решить с помощью модели, то есть он может предоставить текст для определенного значения при запросе на DisplayRole и по-прежнему обеспечивают численное значение с помощью EditRole.

Для отображения выпадающего есть два варианта

  1. при использовании делегата, перезаписать метод paint(), чтобы нарисовать выпадающий, например, делегируя текущему стилю виджетов точно так же, как QComboBox сам

  2. вместо делегата установить индексный виджет. см QAbstractItemView::setIndexWidget()

1

Добавить {your table view}.openPersistentEditor({your QModelIndex}) Это мое решение:

import sys 
from PySide import QtGui, QtCore 


class ComboBoxDelegate(QtGui.QItemDelegate): 
    def __init__(self, parent=None): 
     super(ComboBoxDelegate, self).__init__(parent) 
     self.items = [] 

    def setItems(self, items): 
     self.items = items 

    def createEditor(self, widget, option, index): 
     editor = QtGui.QComboBox(widget) 
     editor.addItems(self.items) 
     return editor 

    def setEditorData(self, editor, index): 
     value = index.model().data(index, QtCore.Qt.EditRole) 
     if value: 
      editor.setCurrentIndex(int(value)) 

    def setModelData(self, editor, model, index): 
     model.setData(index, editor.currentIndex(), QtCore.Qt.EditRole) 

    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

    def paint(self, painter, option, index): 
     text = self.items[index.row()] 
     option.text = text 
     QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ItemViewItem, option, painter) 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    column = 0 
    model = QtGui.QStandardItemModel(4, 2) 
    tableview = QtGui.QTableView() 
    tableview.setModel(model) 
    delegate = ComboBoxDelegate() 
    delegate.setItems([str(x) for x in range(10)]) 
    tableview.setItemDelegateForColumn(column, delegate) 

    for row in range(4): 
     for col in range(2): 
      index = model.index(row, col, QtCore.QModelIndex()) 
      value = (row + 1)*(col + 1) 
      model.setData(index, value) 

    for i in range(model.rowCount()): 
     tableview.openPersistentEditor(model.index(i, column)) 
    tableview.show() 
    sys.exit(app.exec_()) 

enter image description here

enter image description here

Строка помещается, так как я в предыдущем примере я использую str(), Я покажу вам еще один пример, показывающий страны.

import sys 
from PySide import QtGui, QtCore 


class ComboBoxDelegate(QtGui.QItemDelegate): 
    def __init__(self, parent=None): 
     super(ComboBoxDelegate, self).__init__(parent) 
     self.items = [] 

    def setItems(self, items): 
     self.items = items 

    def createEditor(self, widget, option, index): 
     editor = QtGui.QComboBox(widget) 
     editor.addItems(self.items) 
     return editor 

    def setEditorData(self, editor, index): 
     value = index.model().data(index, QtCore.Qt.EditRole) 
     if value: 
      editor.setCurrentIndex(int(value)) 

    def setModelData(self, editor, model, index): 
     model.setData(index, editor.currentIndex(), QtCore.Qt.EditRole) 

    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

    def paint(self, painter, option, index): 
     text = self.items[index.row()] 
     option.text = text 
     QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_ItemViewItem, option, painter) 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    column = 0 
    model = QtGui.QStandardItemModel(4, 2) 
    tableview = QtGui.QTableView() 
    tableview.setModel(model) 
    delegate = ComboBoxDelegate() 
    delegate.setItems([QtCore.QLocale.countryToString(QtCore.QLocale.Country(locale)) for locale in range(QtCore.QLocale.Afghanistan, QtCore.QLocale.Zulu+ 1)]) 
    tableview.setItemDelegateForColumn(column, delegate) 

    for row in range(4): 
     for col in range(2): 
      index = model.index(row, col, QtCore.QModelIndex()) 
      value = (row + 1)*(col + 1) 
      model.setData(index, value) 

    for i in range(model.rowCount()): 
     tableview.openPersistentEditor(model.index(i, column)) 
    tableview.show() 
    sys.exit(app.exec_()) 

enter image description here enter image description here

+0

спасибо: это ясно и элегантно! Я забыл упомянуть, что ключ может быть любой строкой, а не только целым числом (обычно «FR» => «Франция», «IT» => «Италия» и т. Д. – fralau

+0

@fralau обновить мое решение – eyllanesc

+0

Еще раз спасибо! Если значение, возвращаемое как строка (IT для Италии и т. д.), будет лучшим для вас? – fralau

Смежные вопросы