在qstandardemmodel中存储非弦值
这是MRE:
import sys, datetime
from PyQt5 import QtWidgets, QtCore, QtGui
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setMinimumSize(1000, 800)
self.main_splitter = QtWidgets.QSplitter(self)
self.main_splitter.setOrientation(QtCore.Qt.Horizontal)
self.setCentralWidget(self.main_splitter)
self.tree_view = MyTreeView(self.main_splitter)
self.right_panel = QtWidgets.QFrame(self.main_splitter)
self.right_panel.setStyleSheet("background-color: green");
class MyTreeView(QtWidgets.QTreeView):
def __init__(self, *args):
super().__init__(*args)
self.setModel(MyTreeModel())
self.setColumnWidth(1, 150)
self.header().setStretchLastSection(False)
self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
class MyTreeModel(QtGui.QStandardItemModel):
def __init__(self, *args):
super().__init__(*args)
item0_0 = QtGui.QStandardItem('blip')
item0_1 = QtGui.QStandardItem('2000-01-01')
self.invisibleRootItem().appendRow([item0_0, item0_1])
item1_0 = QtGui.QStandardItem('bubble')
item1_1 = QtGui.QStandardItem('')
self.invisibleRootItem().appendRow([item1_0, item1_1])
def setData(self, index, value, role=QtCore.Qt.EditRole):
original_value = value
# if role == QtCore.Qt.EditRole:
# if index.column() == 1:
# if value.strip() == '':
# value = None
# else:
# try:
# value = datetime.date.fromisoformat(value)
# except ValueError as e:
# print(f'**** value could not be parsed as date: |{value}| - value not changed')
# return False
return_val = super().setData(index, value, role)
if role == QtCore.Qt.EditRole:
item = self.itemFromIndex(index)
assert item.text() == original_value, f'item.text() |{item.text()}| original_value |{original_value}|'
return return_val
# def data(self, index, role=QtCore.Qt.DisplayRole):
# value = super().data(index, role)
# if role == QtCore.Qt.DisplayRole:
# if index.column() == 1:
# value = '' if value == None else str(value)
# elif role == QtCore.Qt.EditRole:
# if index.column() == 1:
# if value == '':
# value = None
# return value
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
这里的第二列是日期列:仅应接受有效的日期(或空字符串)。
如果输入注释的行,您将看到我尝试做的事情:我的想法是存储不是str
,而是dateTime.date.date.date
模型。修改setData()
也意味着我必须修改data()
(nb考虑到您最初可能会在任何编辑之前找到字符串的事实)。
这个想法是,每当用户修改日期(按第二列中F2进行编辑,输入新的有效日期,或没有日期,请按Enter),存储的值应为dateTime.dateTime.date.date
(或无
)。但是令我惊讶的是,如果我尝试执行此操作,此断言
失败:模型数据似乎已通过super()。SetData(index,value,value,crom),但是
item.text()
令人困惑地没有更改:尽管显然可以看到它 已更改。
通过评论了这些评论的线路,断言
不会失败。
这是什么解释?我发现很难相信不建议将数据存储在qstandardItemmodel
中,所以我认为我在项目的“更新”方面做错了什么。
我尝试插入以下(super()。SetData(...)
):
if role == QtCore.Qt.EditRole and index.column() == 1:
item = self.itemFromIndex(index)
item.setText(original_value)
... >触发另一个调用setData()
(带有字符串)和多个混淆editrole
和datarole
呼叫data()
代码>,实际上交付字符串值和无
值。
我还推测,代表可能在这里扮演角色...默认情况下,代表的编辑是qlineedit
,看来该代表的方法的方法setmodeldata
负责调用模型的setData
方法。
但是,通过测试item.text()
和调用和呼叫super()。setData(...)
之后的值。可以确定确实是super()
调用会更改项目中文本的调用。但是,显然,如果value
是字符串!
直到另行通知,我假设除非您在此处完全重新实现数据存储机制,否则您必须满足于仅存储字符串在QstandardItemModel
中。
Here's an MRE:
import sys, datetime
from PyQt5 import QtWidgets, QtCore, QtGui
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setMinimumSize(1000, 800)
self.main_splitter = QtWidgets.QSplitter(self)
self.main_splitter.setOrientation(QtCore.Qt.Horizontal)
self.setCentralWidget(self.main_splitter)
self.tree_view = MyTreeView(self.main_splitter)
self.right_panel = QtWidgets.QFrame(self.main_splitter)
self.right_panel.setStyleSheet("background-color: green");
class MyTreeView(QtWidgets.QTreeView):
def __init__(self, *args):
super().__init__(*args)
self.setModel(MyTreeModel())
self.setColumnWidth(1, 150)
self.header().setStretchLastSection(False)
self.header().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
class MyTreeModel(QtGui.QStandardItemModel):
def __init__(self, *args):
super().__init__(*args)
item0_0 = QtGui.QStandardItem('blip')
item0_1 = QtGui.QStandardItem('2000-01-01')
self.invisibleRootItem().appendRow([item0_0, item0_1])
item1_0 = QtGui.QStandardItem('bubble')
item1_1 = QtGui.QStandardItem('')
self.invisibleRootItem().appendRow([item1_0, item1_1])
def setData(self, index, value, role=QtCore.Qt.EditRole):
original_value = value
# if role == QtCore.Qt.EditRole:
# if index.column() == 1:
# if value.strip() == '':
# value = None
# else:
# try:
# value = datetime.date.fromisoformat(value)
# except ValueError as e:
# print(f'**** value could not be parsed as date: |{value}| - value not changed')
# return False
return_val = super().setData(index, value, role)
if role == QtCore.Qt.EditRole:
item = self.itemFromIndex(index)
assert item.text() == original_value, f'item.text() |{item.text()}| original_value |{original_value}|'
return return_val
# def data(self, index, role=QtCore.Qt.DisplayRole):
# value = super().data(index, role)
# if role == QtCore.Qt.DisplayRole:
# if index.column() == 1:
# value = '' if value == None else str(value)
# elif role == QtCore.Qt.EditRole:
# if index.column() == 1:
# if value == '':
# value = None
# return value
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The second column here is a date column: only valid dates (or empty string) should be accepted.
If you uncomment the commented-out lines you will see what I tried to do: my idea was to store not a str
but a datetime.date
in the second column of the model. Modifying setData()
also meant I had to modify data()
(NB taking account of the fact that you may find a string initially, before any edit).
The idea is that whenever the user modifies a date (press F2 to edit in the 2nd column, enter a new valid date, or no date, press Enter), the value stored should be a datetime.date
(or None
). But to my surprise if I try to do this, this assert
fails: the model data appears to have been updated OK by super().setData(index, value, role)
, but item.text()
, confusingly, has not changed: although visibly the user can see that it has changed.
With these commented-out lines commented out, the assert
does not fail.
What's the explanation for this? I find it difficult to believe that it is not recommended to store data other than strings in a QStandardItemModel
, so I presume I am doing something wrong regarding the "updating" of the item.
I tried inserting the following (after super().setData(...)
):
if role == QtCore.Qt.EditRole and index.column() == 1:
item = self.itemFromIndex(index)
item.setText(original_value)
... but this doesn't work: item.setText(...)
triggers another call to setData()
(with a string) and multiple confusing EditRole
and DataRole
calls to data()
, which in fact deliver string values and None
values.
I also surmise that the delegate may have a role to play here... by default the delegate's editor is a QLineEdit
, and it appears that the delegate's method setModelData
is responsible for calling the model's setData
method.
However, by testing the value of item.text()
both before and after calling super().setData(...)
it is possible to ascertain that it is indeed that super()
call which changes the text in the item. But only, apparently, if value
is a string!
Until further notice, I assume that unless you completely re-implement the data storage mechanism here, you have to be content with storing only strings in a QStandardItemModel
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用与DateTime.date具有相同功能的QDATE,而不是不必要的事情。
Instead of unnecessarily complicating things you could use QDate which has the same functionality as datetime.date and is handled natively by Qt.
这是对Eyllanesc的好答案的补充。我真的很想能够输入 null Date !
实际上,我不喜欢此
qdateTimeEdit
+弹出解决方案,因此我选择的只是为我的编辑器使用qlineEdit
,带有qdate
数据值。然后,一个空白字符串转换为nullqdate
。但是我首先使用了
QDateEdit
,并希望能够设置一个空日期值。这个主题有些沮丧。使用验证器可能会有一个更优雅的解决方案,但是虽然这是算力,但它似乎可以完成工作:一旦您开始编辑,按“删除”并立即结束编辑,将值设置为模型中的无。确认的消息框可能是一件好事。
* 源代码 of
setmodeldata
This is by way of a supplement to eyllanesc's great answer. I really really really want to be able to enter a null date!
In fact I'm not keen on this
QDateTimeEdit
+ popup solution, so I've chosen just to use aQLineEdit
for my editor, withQDate
data values. A blank string then translates to a nullQDate
.But I first used a
QDateEdit
, and wanted to be able to set a null date value. There is a bit of frustration out there on this subject. There may be a more elegant solution using a validator but this, hacky though it is, seemed to do the job:Pressing "Delete" once you've started editing and the editing session ends instantly, setting the value to None in the model. A message box of confirmation might be a nice thing to add.
* source code of
setModelData