web-dev-qa-db-ja.com

PyQt-QTableView内のコンボボックスの最も簡単な実例

背景QTableView内にコンボボックスの完全な実例が見つかりません。そこで、他のいくつかのより工夫された例に基づいてこのコードを作成しました。ただし、問題は、この例では、コンボボックスを有効にする前にダブルクリックする必要があり、次にもう一度クリックしてドロップダウンする必要があることです。それはあまりユーザーフレンドリーではありません。 QTableWidgetを使用して非モデル/ビューを実行すると、最初のクリックでコンボボックスがドロップダウンします。

質問:誰かがこれを見て、QTableWidgetのように応答させるために何をする必要があるか教えてもらえますか?また、私がやっていることで不要なことがあれば、それも示してください。たとえば、アプリケーションスタイルを参照することは絶対に必要ですか?

import sys
from PyQt4 import QtGui, QtCore

rows = "ABCD"
choices = ['Apple', 'orange', 'banana']

class Delegate(QtGui.QItemDelegate):
    def __init__(self, owner, items):
        super(Delegate, self).__init__(owner)
        self.items = items
    def createEditor(self, parent, option, index):
        self.editor = QtGui.QComboBox(parent)
        self.editor.addItems(self.items)
        return self.editor
    def Paint(self, Painter, option, index):
        value = index.data(QtCore.Qt.DisplayRole).toString()
        style = QtGui.QApplication.style()
        opt = QtGui.QStyleOptionComboBox()
        opt.text = str(value)
        opt.rect = option.rect
        style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, Painter)
        QtGui.QItemDelegate.Paint(self, Painter, option, index)
    def setEditorData(self, editor, index):
        value = index.data(QtCore.Qt.DisplayRole).toString()
        num = self.items.index(value)
        editor.setCurrentIndex(num)
    def setModelData(self, editor, model, index):
        value = editor.currentText()
        model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value))
    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

class Model(QtCore.QAbstractTableModel):
    def __init__(self):
        super(Model, self).__init__()
        self.table = [[row, choices[0]] for row in rows]
    def rowCount(self, index=QtCore.QModelIndex()):
        return len(self.table)
    def columnCount(self, index=QtCore.QModelIndex()):
        return 2
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self.table[index.row()][index.column()]
    def setData(self, index, role, value):
        if role == QtCore.Qt.DisplayRole:
            self.table[index.row()][index.column()] = value

class Main(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.model = Model()
        self.table = QtGui.QTableView()
        self.table.setModel(self.model)
        self.table.setItemDelegateForColumn(1, Delegate(self, ["Apple", "orange", "banana"]))
        self.setCentralWidget(self.table)
        self.setWindowTitle('Delegate Test')
        self.show()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Main()
    app.exec_()
12
user2120303

QTableWiget.setCellWidget を使用する

import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
table = QtGui.QTableWidget(1,1)
combobox = QtGui.QComboBox()
combobox.addItem("Combobox item")
table.setCellWidget(0,0, combobox)
table.show()
app.exec()
6
Ramchandra Apte

ビューにエディターが表示されるタイミングを調整しようとしている場合は、QAbstractItemViewで定義されているように編集トリガーを変更する必要があります。デフォルトはdoubleClickでの編集ですが、あなたが求めているのは QAbstractItemView.CurrentChanged だと思います。 myView.setEditTrigger() を呼び出して設定します

1
Robot Inc

あなたはこのようなことを試すことができます。

import sys
from PyQt4 import QtGui, QtCore

rows = "ABCD"
choices = ['Apple', 'orange', 'banana']

class Delegate(QtGui.QItemDelegate):
    def __init__(self, owner, items):
        super(Delegate, self).__init__(owner)
        self.items = items
    def createEditor(self, parent, option, index):
        self.editor = QtGui.QComboBox(parent)
        self.editor.addItems(self.items)
        return self.editor
    def Paint(self, Painter, option, index):
        value = index.data(QtCore.Qt.DisplayRole).toString()
        style = QtGui.QApplication.style()
        opt = QtGui.QStyleOptionComboBox()
        opt.text = str(value)
        opt.rect = option.rect
        style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, Painter)
        QtGui.QItemDelegate.Paint(self, Painter, option, index)
    def setEditorData(self, editor, index):
        value = index.data(QtCore.Qt.DisplayRole).toString()
        num = self.items.index(value)
        editor.setCurrentIndex(num)
        if index.column() == 1: #just to be sure that we have a QCombobox
            editor.showPopup()
    def setModelData(self, editor, model, index):
        value = editor.currentText()
        model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value))
    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

class Model(QtCore.QAbstractTableModel):
    def __init__(self):
        super(Model, self).__init__()
        self.table = [[row, choices[0]] for row in rows]
    def rowCount(self, index=QtCore.QModelIndex()):
        return len(self.table)
    def columnCount(self, index=QtCore.QModelIndex()):
        return 2
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self.table[index.row()][index.column()]
    def setData(self, index, role, value):
        if role == QtCore.Qt.DisplayRole:
            self.table[index.row()][index.column()] = value
            return True
        else:
            return False

class Main(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        self.model = Model()
        self.table = QtGui.QTableView()
        self.table.setModel(self.model)
        self.table.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged) # this is the one that fits best to your request
        self.table.setItemDelegateForColumn(1, Delegate(self, ["Apple", "orange", "banana"]))
        self.setCentralWidget(self.table)
        self.setWindowTitle('Delegate Test')
        self.show()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Main()
    app.exec_()

ご覧のとおり、コードに数行追加しました。ビューは「エディション」を管理するため、エディションのトリガーを変更する必要があります。次に、デリゲートデータを設定するときに、ウィジェットからのポップアップをデリゲートに表示するように強制します。

少し前に、作成者がデリゲート(エディション、ナビゲーション、データの更新など)を「適切に」機能させるためにQAbstractItemViewをサブクラス化したブログ投稿を読みましたが、投稿が見つかりません:(

それが役に立てば幸い。

1
user20679

興味のある方は、PyQt5とPython 3。の変更点を以下に示します。主な更新は次のとおりです。

  • Python 3:super().__init__()
  • PyQt5:ほとんどのクラスはQtWidgetsにあります。この例ではQtGuiは必要ありません
  • Model.setData:入力引数の順序が次のように変更されました:index, value, role、およびTrueの代わりにNoneが返されました
  • コンボボックスchoicesとテーブルの内容がMain内で指定されるようになりました。これにより、DelegateModelがより一般的になります
from PyQt5 import QtWidgets, QtCore

class Delegate(QtWidgets.QItemDelegate):
    def __init__(self, owner, choices):
        super().__init__(owner)
        self.items = choices
    def createEditor(self, parent, option, index):
        self.editor = QtWidgets.QComboBox(parent)
        self.editor.addItems(self.items)
        return self.editor
    def Paint(self, Painter, option, index):
        value = index.data(QtCore.Qt.DisplayRole)
        style = QtWidgets.QApplication.style()
        opt = QtWidgets.QStyleOptionComboBox()
        opt.text = str(value)
        opt.rect = option.rect
        style.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt, Painter)
        QtWidgets.QItemDelegate.Paint(self, Painter, option, index)
    def setEditorData(self, editor, index):
        value = index.data(QtCore.Qt.DisplayRole)
        num = self.items.index(value)
        editor.setCurrentIndex(num)
    def setModelData(self, editor, model, index):
        value = editor.currentText()
        model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value))
    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)

class Model(QtCore.QAbstractTableModel):
    def __init__(self, table):
        super().__init__()
        self.table = table
    def rowCount(self, parent):
        return len(self.table)
    def columnCount(self, parent):
        return len(self.table[0])
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    def data(self, index, role):
        if role == QtCore.Qt.DisplayRole:
            return self.table[index.row()][index.column()]
    def setData(self, index, value, role):
        if role == QtCore.Qt.EditRole:
            self.table[index.row()][index.column()] = value
        return True

class Main(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # set combo box choices:
        choices = ['Apple', 'orange', 'banana']
        # create table data:
        table   = []
        table.append(['A', choices[0]])
        table.append(['B', choices[0]])
        table.append(['C', choices[0]])
        table.append(['D', choices[0]])
        # create table view:
        self.model     = Model(table)
        self.tableView = QtWidgets.QTableView()
        self.tableView.setModel(self.model)
        self.tableView.setItemDelegateForColumn(1, Delegate(self,choices))
        # make combo boxes editable with a single-click:
        for row in range( len(table) ):
            self.tableView.openPersistentEditor(self.model.index(row, 1))
        # initialize
        self.setCentralWidget(self.tableView)
        self.setWindowTitle('Delegate Test')
        self.show()

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main = Main()
    app.exec_()
1
ToddP

これは機能するはずです:

view = QTreeView()
model = QStandardItemModel(view)
view.setModel(model)

combobox = QComboBox()

child1 = QStandardItem('test1')
child2 = QStandardItem('test2')
child3 = QStandardItem('test3')
model.appendRow([child1, child2, child3])
a = model.index(0, 2)
view.setIndexWidget(a, combobox)
0
avasygn