背景: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_()
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()
ビューにエディターが表示されるタイミングを調整しようとしている場合は、QAbstractItemViewで定義されているように編集トリガーを変更する必要があります。デフォルトはdoubleClickでの編集ですが、あなたが求めているのは QAbstractItemView.CurrentChanged だと思います。 myView.setEditTrigger() を呼び出して設定します
あなたはこのようなことを試すことができます。
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をサブクラス化したブログ投稿を読みましたが、投稿が見つかりません:(
それが役に立てば幸い。
興味のある方は、PyQt5とPython 3。の変更点を以下に示します。主な更新は次のとおりです。
super().__init__()
QtWidgets
にあります。この例ではQtGui
は必要ありませんModel.setData
:入力引数の順序が次のように変更されました:index, value, role
、およびTrue
の代わりにNone
が返されましたchoices
とテーブルの内容がMain
内で指定されるようになりました。これにより、Delegate
とModel
がより一般的になります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_()
これは機能するはずです:
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)