Support for QStandardItem proxies?
-
wrote on 27 Sept 2018, 10:02 last edited by
Some views support the display of ordinary data types (like strings) directly. But it seems that they can not work with specific custom data types by default.
Now I am looking again for possibilities to convert these custom data (according to the programming interface of the class “QStandardItem”) into a target format which is directly supported already.- Is the software design pattern “proxy” (or “adapter”) useful here?
- How will development approaches evolve around internal data structures and corresponding interfaces?
-
I guess you could use a
QIdentityProxyModel
subclass that reimplementsdata()
but I still think the delegate solution proposed here is the preferred way. Especially if you plan to make the data editablewrote on 27 Sept 2018, 11:23 last edited byI guess you could use a QIdentityProxyModel subclass …
You can choose between involved places for desired data format conversions.
- Data models
- Views
-
wrote on 27 Sept 2018, 11:34 last edited by
Views do not deal with individual item data. That's the delegate's job
-
wrote on 27 Sept 2018, 12:00 last edited by
Views do not deal with individual item data.
- They try to display something and delegate edit attempts.
- Items are connected with their data models.
-
I guess you could use a
QIdentityProxyModel
subclass that reimplementsdata()
but I still think the delegate solution proposed here is the preferred way. Especially if you plan to make the data editablewrote on 27 Sept 2018, 13:36 last edited byI have tried out to append a text by a QIdentityProxyModel subclass to a member variable of a custom data structure.
Unfortunately, the display of one view from my test program indicates that the function “QVariant::canConvert” did not provide the result which I expected here.
Would you like to clarify any affected implementation details? -
wrote on 27 Sept 2018, 14:48 last edited by
They try to display something and delegate edit attempts.
I disagree, or at least it's not 100% accurate.
Items are connected with their data models.
Anything said above actually applies to any data model (
QAbstractItemModel
subclass), regardless of the implementationthe display of one view from my test program
can you post your code?
-
They try to display something and delegate edit attempts.
I disagree, or at least it's not 100% accurate.
Items are connected with their data models.
Anything said above actually applies to any data model (
QAbstractItemModel
subclass), regardless of the implementationthe display of one view from my test program
can you post your code?
wrote on 28 Sept 2018, 11:25 last edited bycan you post your code?
- I am curious on how a code review will evolve for my test program.
- The forum software gave me the information “Uploading 100%” and “You do not have enough privileges for this action.”.
-
They try to display something and delegate edit attempts.
I disagree, or at least it's not 100% accurate.
Items are connected with their data models.
Anything said above actually applies to any data model (
QAbstractItemModel
subclass), regardless of the implementationthe display of one view from my test program
can you post your code?
wrote on 28 Sept 2018, 12:14 last edited byAnother try for a possible code review …
main.cpp:
#include <QApplication> #include <QtUiTools/QUiLoader> #include <QFile> #include <QString> #include <QWidget> #include <QListView> #include <QStandardItemModel> #include <QIdentityProxyModel> #include <QMetaType> #include <iostream> #include <stdexcept> #include <cstdio> #include <cstdlib> struct my_message { QString text; my_message(char const * s = "ABC") : text(s) { } my_message(my_message const& s) : text(s.text) { } ~my_message() { } }; Q_DECLARE_METATYPE(my_message); class my_item : public QStandardItem { public: my_item(my_message const mm) { setData(QVariant::fromValue(mm), Qt::DisplayRole); } }; class my_proxy : public QIdentityProxyModel { QVariant data(QModelIndex const & index, int role) const override { if (role != Qt::DisplayRole) return QIdentityProxyModel::data(index, role); auto x(sourceModel()->data(index)); if (x.canConvert<my_message>()) { my_message mm(x.value<my_message>()); mm.text.append("||"); return QVariant::fromValue(mm); } else { return "***"; } } }; struct my_views : public QWidget { Q_OBJECT QListView* v1; QListView* v2; public: explicit my_views(QWidget* parent = nullptr) : QWidget(parent) { // QFile f(":/form.ui"); QFile f("/home/elfring/Projekte/view-test2/form.ui"); if (!f.open(QFile::ReadOnly)) throw std::runtime_error(tr("UI file could not be opened.").toStdString()); QUiLoader l; QWidget* w = l.load(&f, this); if (!w) throw std::runtime_error(l.errorString().toStdString()); f.close(); v1 = findChild<QListView*>("V1"); if (!v1) throw std::runtime_error(tr("First view was not found.").toStdString()); v2 = findChild<QListView*>("V2"); if (!v2) throw std::runtime_error(tr("Second view was not found.").toStdString()); auto i1(new QStandardItem("abc")); auto i2(new my_item("XYZ")); auto m1(new QStandardItemModel); auto m2(new QStandardItemModel); auto mp(new my_proxy); m1->appendRow(i1); m2->appendRow(i2); mp->setSourceModel(m2); v1->setModel(m1); v2->setModel(mp); } }; #include "main.moc" int main(int argc, char** argv) { try { QApplication app(argc, argv); qRegisterMetaType<my_message>("my_message"); my_views mv; mv.show(); return app.exec(); } catch (std::bad_alloc const& b) { (void) std::fputs("out of memory\n", stderr); return EXIT_FAILURE; } catch (std::exception const& x) { (void) std::fprintf(stderr, "A kind of standard%s\n%s\n", " exception was caught.", x.what()); return EXIT_FAILURE; } catch (...) { (void) std::fprintf(stderr, "An unknown%s\n", " exception was caught."); throw; } }
CMakeLists.txt:
cmake_minimum_required(VERSION 3.1) project(view-test CXX) set(CMAKE_AUTOMOC ON) find_package(Qt5 COMPONENTS Core Widgets UiTools REQUIRED) include_directories(${Qt5Widgets_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ${Qt5UiTools_INCLUDE_DIRS}) add_executable(test1 main.cpp) target_link_libraries(test1 Qt5::Widgets Qt5::Core Qt5::UiTools)
form.ui:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>my_views</class> <widget class="QWidget" name="my_views"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>282</width> <height>228</height> </rect> </property> <property name="windowTitle"> <string>Display test</string> </property> <widget class="QListView" name="V1"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>256</width> <height>91</height> </rect> </property> <property name="uniformItemSizes"> <bool>true</bool> </property> </widget> <widget class="Line" name="L1"> <property name="geometry"> <rect> <x>10</x> <y>100</y> <width>241</width> <height>20</height> </rect> </property> <property name="lineWidth"> <number>9</number> </property> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> <widget class="QListView" name="V2"> <property name="geometry"> <rect> <x>10</x> <y>120</y> <width>256</width> <height>91</height> </rect> </property> <property name="uniformItemSizes"> <bool>true</bool> </property> </widget> </widget> <resources/> <connections/> </ui>
-
wrote on 28 Sept 2018, 12:33 last edited by
- does
if (x.canConvert<my_message>())
return false? - what is your intention in this code snippet?
my_message mm(x.value<my_message>()); mm.text.append("||"); return QVariant::fromValue(mm);
- You are leaking all 3 of the models. The view does not own the model
- does
-
- does
if (x.canConvert<my_message>())
return false? - what is your intention in this code snippet?
my_message mm(x.value<my_message>()); mm.text.append("||"); return QVariant::fromValue(mm);
- You are leaking all 3 of the models. The view does not own the model
wrote on 28 Sept 2018, 13:00 last edited bydoes
if (x.canConvert<my_message>())
return false?I get this impression after I see three asterisks in the display from my test widget on the screen.
what is your intention in this code snippet?
I am trying also to get more familiar with the provided programming interfaces around models and views.
You are leaking all 3 of the models.
I do not really need my own clean-up for this software experiment at the moment.
The view does not own the model
Thanks for your reminder.
Do you spot any other suspicious implementation details?
- does
-
- does
if (x.canConvert<my_message>())
return false? - what is your intention in this code snippet?
my_message mm(x.value<my_message>()); mm.text.append("||"); return QVariant::fromValue(mm);
- You are leaking all 3 of the models. The view does not own the model
wrote on 2 Oct 2018, 18:06 last edited bydoes `if (x.canConvert<my_message>()) return false?
I have added a test output for my local variable “x”. The programming interface “qDebug()” provides the information “QVariant(Invalid)” then so far.
- Would you like to help with finding an explanation for this software behaviour?
- How can a source model work here?
- does
-
@elfring said in Support for QStandardItem proxies?:
auto x(sourceModel()->data(index));
How should this work at all? http://doc.qt.io/qt-5/qidentityproxymodel.html#mapToSource
-
@elfring said in Support for QStandardItem proxies?:
auto x(sourceModel()->data(index));
How should this work at all? http://doc.qt.io/qt-5/qidentityproxymodel.html#mapToSource
wrote on 2 Oct 2018, 19:28 last edited byGood spot, I'm surprised it didn't just assert. I got shouted at in code review for having models that didn't assert when
index.model()!=this
@elfring replace
auto x(sourceModel()->data(index));
withauto x=QIdentityProxyModel::data(index, role);
-
@VRonin said in Support for QStandardItem proxies?:
I'm surprised it didn't just assert
Maybe because Qt was not compiled in debug mode. Or there is no assert and the new index check stuff is not yet used there - feel free to add it ;)
-
Good spot, I'm surprised it didn't just assert. I got shouted at in code review for having models that didn't assert when
index.model()!=this
@elfring replace
auto x(sourceModel()->data(index));
withauto x=QIdentityProxyModel::data(index, role);
wrote on 2 Oct 2018, 20:15 last edited byreplace
auto x(sourceModel()->data(index));
withauto x=QIdentityProxyModel::data(index, role);
Thanks for this suggestion.
- Unfortunately, I selected a questionable member function call combination before.
- The test case is working as expected together with the statement “
return mm.text;
” now.
-
Good spot, I'm surprised it didn't just assert. I got shouted at in code review for having models that didn't assert when
index.model()!=this
@elfring replace
auto x(sourceModel()->data(index));
withauto x=QIdentityProxyModel::data(index, role);
wrote on 5 Oct 2018, 10:56 last edited byGood spot, I'm surprised it didn't just assert.
- Did I try the usage of model indexes out in appropriate way for my test case?
- Do indexes need to be different for proxy and source models?
-
Good spot, I'm surprised it didn't just assert.
- Did I try the usage of model indexes out in appropriate way for my test case?
- Do indexes need to be different for proxy and source models?
wrote on 5 Oct 2018, 11:04 last edited by@elfring said in Support for QStandardItem proxies?:
Did I try the usage of model indexes out in appropriate way for my test case?
Usually you'd want a
Q_ASSERT
that uses checkIndex()Do indexes need to be different for proxy and source models?
Yes, obviously
-
@elfring said in Support for QStandardItem proxies?:
Did I try the usage of model indexes out in appropriate way for my test case?
Usually you'd want a
Q_ASSERT
that uses checkIndex()Do indexes need to be different for proxy and source models?
Yes, obviously
wrote on 5 Oct 2018, 11:53 last edited byYes, obviously
- Should the difference between indexes for proxy and source models be better described in the Qt documentation?
- How do you think about the introduction of a class like QProxyModelIndex then?
-
Yes, obviously
- Should the difference between indexes for proxy and source models be better described in the Qt documentation?
- How do you think about the introduction of a class like QProxyModelIndex then?
wrote on 5 Oct 2018, 12:29 last edited by@elfring said in Support for QStandardItem proxies?:
How do you think about the introduction of a class like QProxyModelIndex then?
QAbstractPorxyModel::mapToSource
/QAbstractPorxyModel::mapFromSource
already do everything that class would do so I see no gain in introducing itShould the difference between indexes for proxy and source models be better described in the Qt documentation?
A proxy model is still a model, the docs say "Note that it's undefined behavior to pass illegal indices to item models" so I feel it is documented already
5/27