- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在 PyQt 中,我想使用 QAbstractItemModel 和 QDataWidgetMapper 将小部件映射到模型数据。对于 QLineEdit,它工作正常,但我想在 QButtonGroup(填充有多个 QRadioButton)和模型之间建立映射。因此我继承了 QGroupBox 并添加了一个自定义属性 selectedOption:
class ButtonGroupWidget(QGroupBox):
def __init__(self, parent=None):
super(ButtonGroupWidget, self).__init__(parent)
self._selectedOption = -1
self.buttonGroup = QButtonGroup()
self.layoutGroupBox = QVBoxLayout(self)
def addRadioButton(self,optionText,optionId):
print(optionText)
radioButton = QRadioButton(optionText)
radioButton.clicked.connect(self.updateOptionSelected)
self.layoutGroupBox.addWidget(radioButton)
self.buttonGroup.addButton(radioButton,optionId)
def updateOptionSelected(self):
print(self.buttonGroup.checkedId()) # for test purpose
self.selectedOption = self.buttonGroup.checkedId()
print(self._selectedOption) # for test purpose
def getSelectedOption(self):
print("get selectedOption is called")
return self._selectedOption
def setSelectedOption(self,selectedOption):
print("set selectedOption is called")
self._selectedOption = selectedOption
self.buttonGroup.button(selectedOption).setChecked(True)
selectedOption = pyqtProperty(int,getSelectedOption,setSelectedOption)
在主小部件中,我创建了这个 ButtonGroupWidget 的一个实例:
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
...
# insert a button group widget
self.buttonGroupWidget1 = ButtonGroupWidget(self)
self.buttonGroupWidget1.setTitle("Select option")
self.buttonGroupWidget1.addRadioButton("Option 1", 1)
self.buttonGroupWidget1.addRadioButton("Option 2", 2)
self.buttonGroupWidget1.addRadioButton("Option 3", 3)
...
# Create the data model and map the model to the widgets.
self._model = DataModel()
...
self._dataMapper = QDataWidgetMapper()
self._dataMapper.setModel(self._model)
...
# mapping to custom property
self._dataMapper.addMapping(self.buttonGroupWidget1,1,"selectedOption")
下面给出了完整的代码(最小的工作示例)。我的问题如下:如果模型发生变化(例如通过您在完整代码中看到的 lineEdit),将调用 setSelectedOption 方法并将 self._selectedOption 设置为当前值并更新 radioButtons。但是如果我点击另一个单选按钮,我不知道如何更新模型。
是否有 QWidget 的数据更改事件之类的东西,它会更新模型?
有没有更好的方法将 QAbstractItemModel 映射到具有多个单选按钮的 GroupBox?
完整代码(最小示例,使用 Python 3.4 和 PyQt 5.4 测试):
import sys
from PyQt5.QtWidgets import QWidget, QLineEdit, QRadioButton, QButtonGroup, QApplication, QVBoxLayout, QGroupBox, QTreeView,QDataWidgetMapper
from PyQt5.QtCore import QAbstractItemModel,QModelIndex,Qt,pyqtProperty
"""Base class to provide some nodes fro a tree
At the moment each node contains two members: name and option"""
class Node(object):
def __init__(self,name,parent=None):
self._name = name
self._children = []
self._parent = parent
self._option = 2
if parent is not None:
parent.addChild(self)
def name(self):
return self._name
def setName(self, name):
self._name = name
def option(self):
return self._option
def setOption(self,option):
self._option = option
def addChild(self,child):
self._children.append(child)
def insertChild(self, position, child):
if position < 0 or position > len(self._children):
return False
self._children.insert(position, child)
child._parent = self
return True
def removeChild(self, position):
if position < 0 or position > len(self._children):
return False
child = self._children.pop(position)
child._parent = None
return True
def child(self,row):
return self._children[row]
def childCount(self):
return len(self._children)
def parent(self):
return self._parent
def row(self):
if self._parent is not None:
return self._parent._children.index(self)
def __repr__(self):
return self.log()
class ButtonGroupWidget(QGroupBox):
def __init__(self, parent=None):
super(ButtonGroupWidget, self).__init__(parent)
self._selectedOption = -1
self.buttonGroup = QButtonGroup()
self.layoutGroupBox = QVBoxLayout(self)
def addRadioButton(self,optionText,optionId):
print(optionText)
radioButton = QRadioButton(optionText)
radioButton.clicked.connect(self.updateOptionSelected)
self.layoutGroupBox.addWidget(radioButton)
self.buttonGroup.addButton(radioButton,optionId)
def updateOptionSelected(self):
print(self.buttonGroup.checkedId()) # for test purpose
self.selectedOption = self.buttonGroup.checkedId()
print(self._selectedOption) # for test purpose
def getSelectedOption(self):
print("get selectedOption is called")
return self._selectedOption
def setSelectedOption(self,selectedOption):
print("set selectedOption is called")
self._selectedOption = selectedOption
self.buttonGroup.button(selectedOption).setChecked(True)
selectedOption = pyqtProperty(int,getSelectedOption,setSelectedOption)
class DataModel(QAbstractItemModel):
def __init__(self, parent=None):
super(DataModel, self).__init__(parent)
self._rootNode = Node("Root Node")
childNode1 = Node("Child 1",self._rootNode)
childNode2 = Node("Child 2",self._rootNode)
childNode3 = Node("Child 3",self._rootNode)
def __eq__(self, other):
return self.__dict__ == other.__dict__
def isNull(self):
nullObject = DataModel()
if self.__eq__(nullObject):
return True
else:
return False
def rowCount(self, parent):
if not parent.isValid():
parentNode = self._rootNode
else:
parentNode = parent.internalPointer()
return parentNode.childCount()
def columnCount(self, parent):
return 1
def data(self,index,role):
if not index.isValid():
return None
node = index.internalPointer()
if role == Qt.DisplayRole or role == Qt.EditRole:
if index.column() == 0:
return node.name()
if index.column() == 1:
return node.option()
def setData(self,index,value, role=Qt.EditRole):
if index.isValid():
node = index.internalPointer()
if role == Qt.EditRole:
if index.column() == 0:
node.setName(value)
if index.column() == 1:
node.setOption(value)
self.dataChanged.emit(index,index)
return True
return False
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole:
if section == 0:
return "Select Child"
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
def parent(self, index):
node = index.internalPointer()
parentNode = node.parent()
if parentNode == self._rootNode:
return QModelIndex()
return self.createIndex(parentNode.row(), 0, parentNode)
def index(self, row, column, parent):
if not parent.isValid():
parentNode = self._rootNode
else:
parentNode = parent.internalPointer()
childItem = parentNode.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QModelIndex()
def getNode(self, index):
if index.isValid():
node = index.internalPointer()
if node:
return node
return self._rootNode
class MainWidget(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
# define tree view
self.treeView = QTreeView(self)
# insert line edit
self.lineEdit1 = QLineEdit(self)
self.lineEdit2 = QLineEdit(self)
# insert a button group widget
self.buttonGroupWidget1 = ButtonGroupWidget(self)
self.buttonGroupWidget1.setTitle("Select option")
self.buttonGroupWidget1.addRadioButton("Option 1", 1)
self.buttonGroupWidget1.addRadioButton("Option 2", 2)
self.buttonGroupWidget1.addRadioButton("Option 3", 3)
layoutMain = QVBoxLayout(self)
layoutMain.addWidget(self.treeView)
layoutMain.addWidget(self.lineEdit1)
layoutMain.addWidget(self.lineEdit2)
layoutMain.addWidget(self.buttonGroupWidget1)
# Create the data model and map the model to the widgets.
self._model = DataModel()
self.treeView.setModel(self._model)
self._dataMapper = QDataWidgetMapper()
self._dataMapper.setModel(self._model)
# the mapping works fine for line edits and combo boxes
self._dataMapper.addMapping(self.lineEdit1, 0)
self._dataMapper.addMapping(self.lineEdit2, 1)
# mapping to custom property
self._dataMapper.addMapping(self.buttonGroupWidget1,1,"selectedOption")
self.treeView.selectionModel().currentChanged.connect(self.setSelection)
def setSelection(self, current):
parent = current.parent()
self._dataMapper.setRootIndex(parent)
self._dataMapper.setCurrentModelIndex(current)
def main():
app = QApplication(sys.argv)
form = MainWidget()
form.show()
app.exec_()
main()
最佳答案
模型将在单选按钮选项更改时更新,但前提是按下回车或回车。
这样做的原因是,数据映射器使用一个项目委托(delegate)来通知模型的更改,并且这个项目委托(delegate)在每个映射的小部件上安装一个事件过滤器。但是事件过滤器只监控按键和焦点变化,不监控鼠标点击,而且在任何情况下,它都不能接收来自子部件的事件。
绕过此限制的一种稍微老套的方法是在单击单选按钮时模拟适当的按键操作:
def updateOptionSelected(self):
self.selectedOption = self.buttonGroup.checkedId()
QApplication.postEvent(
self, QKeyEvent(QEvent.KeyPress, Qt.Key_Enter, Qt.NoModifier))
关于python - PyQt:自定义属性的 QDataWidgetMapper 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30966487/
我创建了一个 sqldatabase 并用一些测试数据填充它。我正在使用 QDataWidgetMapper,我认为我已经正确连接了,因为我可以使用以下代码读取测试记录: databaseMa
我有一个包含多个列的 TreeView 。我使用 QDataWidgetMapper 将每一列与侧边栏上的几个小部件之一连接起来。可以通过双击 TreeView 中的单元格或使用侧边栏上的小部件来更改
我想使用 QDataWidgetMapper 将小部件与 sqlite 表中的数据链接起来。我找到的用于指定数据行的方法似乎只有在一次按顺序遍历行时才有效:setCurrentIndex、toFirs
我正在使用 QDataWidgetMapper 来显示模型中的值。我将其提交策略设置为 ManualSubmit,这样用户就不会不小心输入错误的值。但我也想警告用户未提交的更改,如果他/她在没有保存的
mapper = QtGui.QDataWidgetMapper() mapper.setModel(my_table_model) mapper.addMapping(widgetA, 0) #ma
我有一个 QTableView,它有一列带有 True/False 值。要更改此列中的值,我使用 QDataWidgetMapper 复选框。 我希望在单击复选框后立即更改值。通常在复选框失去焦点后进
我正在使用 QDataWidgetMapper 将数据映射到 QLineEdit 并且它工作正常。当我用来将数据映射到 QLabel 时,它不会在标签中显示任何数据。我尝试通过以下方式进行操作: QD
因此,我使用 QDataWidgetMapper 将 QSqlQueryModel 中的值映射到界面中的小部件。这工作得很好,每次更新或刷新我的模型时,小部件也会更新......太棒了! 但是假设我有
我对 QT 框架的某些部分有疑问。我正在使用 QT 5.0.2,目前正在 Windows 上进行开发。 在我的应用程序中,我有一个使用 QSqlRelationalTableModel 设置的 Tab
我有几个 QLineEdits,每个都通过自己的 QDataWidgetMapper 连接到一个 QStandardItemModel,因此它们都反射(reflect)相同的值。 如果用户在一个 QL
是否可以使用 QDataWidgetMapper 插入到 SQL 数据库中? 到目前为止,我使用映射器查看和更新但不添加新记录。本质上,我需要以某种方式从关联到 QDataWidgetMapper
我正在尝试使用 QDataWidgetmapper 更新数据库中的一行,但我的问题是当尝试调用更新函数时 row 不是全局变量,并且我尝试在调用 Qdialog 的同一函数中使用它输入整数。我无法让它
在 PyQt 中,我想使用 QAbstractItemModel 和 QDataWidgetMapper 将小部件映射到模型数据。对于 QLineEdit,它工作正常,但我想在 QButtonGrou
我有 QSqlTableModel 和一些表,我们假设它是一个 model->setTable("Person"); 我还有 QDataWidgetMapper,它将一些小部件(lineedits 等
我目前使用 QDataWidgetMapper 像这样映射我的日历小部件(使用 PySide): self.mapper.addMapping(self.ui.calendar, 2, "select
我正在编写一个 Symbian 小应用程序,但在使用 QDataWidgetMapper 时遇到了问题。这是代码: void Widget::bindToData(){ databaseMan
我正在尝试映射 QAbstractTableModel 中的数据使用 QDataWidgetMapper 到自定义 View 。映射器工作正常,但映射的数据不会根据模型的变化自动更新。我需要手动更改
我有一个包含三个字段的表单,我试图用模型中的值填充这些字段。下面是我的头文件和 .cpp 文件中的代码: myForm.h 中的声明 private: Ui::MyForm *ui;
我正在尝试使用委托(delegate)来自定义使用 QDataWidgetMapper 时模型中数据的显示方式。 我有两种不同版本的小部件,一种是仅查看(数据显示在 QLabels 中),另一种用于编
我想根据 this forum thread 将单选按钮映射到 QDataWidgetMapper .我不确定如何连接提到的代表。谁能解释一下? 我已经有了包含单选按钮的 .ui 文件,其中包括 QL
我是一名优秀的程序员,十分优秀!