如何扩展默认不支持模型的Qt Widgets
How to extend Qt Widgets that do not have model support by default
CustomMenu
class 继承自 QMenu
。它的自定义 setData()
方法接受一个参数并将其设置为 class 变量 model
。我这样做是因为 QToolButton
、QToolMenu
和 QAction
不支持 model/view 框架。据我所知,除了 QList-QTable-QTree Views and Trees
,只有 QComboBox
支持 model
。
所以问题是:是否可以扩展其他 non-model widgets
的功能,以便它们也可以用作 driven-by-model
小部件?
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomMenu(QMenu):
def __init__(self):
super(CustomMenu, self).__init__()
self.model=None
def setModel(self, model):
self.model=model
self.pupulate()
def pupulate(self):
for item in self.model.items:
self.addAction(item)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, QModelIndex):
return len(self.items)
def columnCount(self, QModelIndex):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
toolButton.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))
menu=CustomMenu()
menu.setModel(tablemodel)
toolButton.setMenu(menu)
layout.addWidget(toolButton)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
稍后编辑:尝试实现 QDataWidgetMapper():
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomMenuButton(QWidget):
def __init__(self, parent):
super(CustomMenuButton, self).__init__(parent)
self.dataMapper=QDataWidgetMapper()
layout=QVBoxLayout()
self.setLayout(layout)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
self.menu=QMenu(toolButton)
toolButton.setMenu(self.menu)
def setModel(self, model):
self.dataMapper.setModel(model)
for row in range(model.rowCount()):
action=self.menu.addAction('Item')
self.dataMapper.addMapping(action, row)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent=QModelIndex()):
return len(self.items)
def columnCount(self, parent=QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
self.dataChanged.emit(index, index)
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
menuButton=CustomMenuButton(self)
layout.addWidget(menuButton)
menuButton.setModel(tablemodel)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
编辑 2:定义了 class CustomAction(QAction) with dataChanged = pyqtSignal(QModelIndex,QModelIndex)...
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomAction(QAction):
dataChanged = pyqtSignal(QModelIndex,QModelIndex)
def __init__(self, name, parent):
super(CustomAction, self).__init__(name, parent)
class CustomMenuButton(QWidget):
def __init__(self, parent):
super(CustomMenuButton, self).__init__(parent)
self.dataMapper=QDataWidgetMapper()
layout=QVBoxLayout()
self.setLayout(layout)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
self.menu=QMenu(toolButton)
toolButton.setMenu(self.menu)
def setModel(self, model):
self.dataMapper.setModel(model)
for row in range(model.rowCount()):
index=model.index(row,0)
itemName=model.data(index, Qt.DisplayRole).toPyObject()
actn=CustomAction(itemName, self.menu)
self.menu.addAction(actn)
self.dataMapper.addMapping(actn, row)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent=QModelIndex()):
return len(self.items)
def columnCount(self, parent=QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
self.dataChanged.emit(index, index)
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
menuButton=CustomMenuButton(self)
layout.addWidget(menuButton)
menuButton.setModel(tablemodel)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
这就是QDataWidgetMapper class was designed for. The following blog has a great tutorial covering exactly how to implement it: http://www.yasinuludag.com/blog/?p=98
编辑:我应该补充一点,QDataWidgetMapper
与 QWidget
及其子 类 一起使用,因此 QAction
不适用。对于不是 QWidget
或其子 类 的 类,您可能必须实现自己的自定义模型视图绑定。
CustomMenu
class 继承自 QMenu
。它的自定义 setData()
方法接受一个参数并将其设置为 class 变量 model
。我这样做是因为 QToolButton
、QToolMenu
和 QAction
不支持 model/view 框架。据我所知,除了 QList-QTable-QTree Views and Trees
,只有 QComboBox
支持 model
。
所以问题是:是否可以扩展其他 non-model widgets
的功能,以便它们也可以用作 driven-by-model
小部件?
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomMenu(QMenu):
def __init__(self):
super(CustomMenu, self).__init__()
self.model=None
def setModel(self, model):
self.model=model
self.pupulate()
def pupulate(self):
for item in self.model.items:
self.addAction(item)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, QModelIndex):
return len(self.items)
def columnCount(self, QModelIndex):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
toolButton.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))
menu=CustomMenu()
menu.setModel(tablemodel)
toolButton.setMenu(menu)
layout.addWidget(toolButton)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
稍后编辑:尝试实现 QDataWidgetMapper():
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomMenuButton(QWidget):
def __init__(self, parent):
super(CustomMenuButton, self).__init__(parent)
self.dataMapper=QDataWidgetMapper()
layout=QVBoxLayout()
self.setLayout(layout)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
self.menu=QMenu(toolButton)
toolButton.setMenu(self.menu)
def setModel(self, model):
self.dataMapper.setModel(model)
for row in range(model.rowCount()):
action=self.menu.addAction('Item')
self.dataMapper.addMapping(action, row)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent=QModelIndex()):
return len(self.items)
def columnCount(self, parent=QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
self.dataChanged.emit(index, index)
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
menuButton=CustomMenuButton(self)
layout.addWidget(menuButton)
menuButton.setModel(tablemodel)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
编辑 2:定义了 class CustomAction(QAction) with dataChanged = pyqtSignal(QModelIndex,QModelIndex)...
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys, os
class CustomAction(QAction):
dataChanged = pyqtSignal(QModelIndex,QModelIndex)
def __init__(self, name, parent):
super(CustomAction, self).__init__(name, parent)
class CustomMenuButton(QWidget):
def __init__(self, parent):
super(CustomMenuButton, self).__init__(parent)
self.dataMapper=QDataWidgetMapper()
layout=QVBoxLayout()
self.setLayout(layout)
toolButton=QToolButton(self)
toolButton.setText('Tool Button')
toolButton.setPopupMode(QToolButton.InstantPopup)
self.menu=QMenu(toolButton)
toolButton.setMenu(self.menu)
def setModel(self, model):
self.dataMapper.setModel(model)
for row in range(model.rowCount()):
index=model.index(row,0)
itemName=model.data(index, Qt.DisplayRole).toPyObject()
actn=CustomAction(itemName, self.menu)
self.menu.addAction(actn)
self.dataMapper.addMapping(actn, row)
class Model(QAbstractTableModel):
def __init__(self, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.items = ['Row0_Column0','Row1_Column0','Row2_Column0']
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def rowCount(self, parent=QModelIndex()):
return len(self.items)
def columnCount(self, parent=QModelIndex()):
return 1
def data(self, index, role):
if not index.isValid(): return QVariant()
if role == Qt.DisplayRole:
return QVariant(self.items[index.row()])
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
if role == Qt.EditRole:
self.items[index.row()]=value
self.dataChanged.emit(index, index)
return True
return False
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
layout=QVBoxLayout(self)
self.setLayout(layout)
tablemodel=Model(self)
tableView=QTableView()
tableView.horizontalHeader().setStretchLastSection(True)
tableView.setModel(tablemodel)
layout.addWidget(tableView)
combo=QComboBox()
combo.setModel(tablemodel)
layout.addWidget(combo)
menuButton=CustomMenuButton(self)
layout.addWidget(menuButton)
menuButton.setModel(tablemodel)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
这就是QDataWidgetMapper class was designed for. The following blog has a great tutorial covering exactly how to implement it: http://www.yasinuludag.com/blog/?p=98
编辑:我应该补充一点,QDataWidgetMapper
与 QWidget
及其子 类 一起使用,因此 QAction
不适用。对于不是 QWidget
或其子 类 的 类,您可能必须实现自己的自定义模型视图绑定。