Trusted Software Excellence across Desktop and Embedded
Take a glance at the areas of expertise where KDAB excels ranging from swift troubleshooting, ongoing consulting and training to multi-year, large-scale software development projects.
Find out why customers from innovative industries rely on our extensive expertise, including Medical, Biotech, Science, Renewable Energy, Transportation, Mobility, Aviation, Automation, Electronics, Agriculture and Defense.
High-quality Embedded Engineering across the Stack
To successfully develop an embedded device that meets your expectations regarding quality, budget and time to market, all parts of the project need to fit perfectly together.
Learn more about KDAB's expertise in embedded software development.
Where the capabilities of modern mobile devices or web browsers fall short, KDAB engineers help you expertly architect and build high-functioning desktop and workstation applications.
Extensible, Safety-compliant Software for the Medical Sector
Create intelligent, patient-focused medical software and devices and stay ahead with technology that adapts to your needs.
KDAB offers you expertise in developing a broad spectrum of clinical and home-healthcare devices, including but not limited to, internal imaging systems, robotic surgery devices, ventilators and non-invasive monitoring systems.
Building digital dashboards and cockpits with fluid animations and gesture-controlled touchscreens is a big challenge.
In over two decades of developing intricate UI solutions for cars, trucks, tractors, scooters, ships, airplanes and more, the KDAB team has gained market leading expertise in this realm.
Build on Advanced Expertise when creating Modern UIs
KDAB assists you in the creation of user-friendly interfaces designed specifically for industrial process control, manufacturing, and fabrication.
Our specialties encompass the custom design and development of HMIs, enabling product accessibility from embedded systems, remote desktops, and mobile devices on the move.
Legacy software is a growing but often ignored problem across all industries. KDAB helps you elevate your aging code base to meet the dynamic needs of the future.
Whether you want to migrate from an old to a modern GUI toolkit, update to a more recent version, or modernize your code base, you can rely on over 25 years of modernization experience.
KDAB offers a wide range of services to address your software needs including consulting, development, workshops and training tailored to your requirements.
Our expertise spans cross-platform desktop, embedded and 3D application development, using the proven technologies for the job.
When working with KDAB, the first-ever Qt consultancy, you benefit from a deep understanding of Qt internals, that allows us to provide effective solutions, irrespective of the depth or scale of your Qt project.
Qt Services include developing applications, building runtimes, mixing native and web technologies, solving performance issues, and porting problems.
KDAB helps create commercial, scientific or industrial desktop applications from scratch, or update its code or framework to benefit from modern features.
Discover clean, efficient solutions that precisely meet your requirements.
Boost your team's programming skills with in-depth, constantly updated, hands-on training courses delivered by active software engineers who love to teach and share their knowledge.
Our courses cover Modern C++, Qt/QML, Rust, 3D programming, Debugging, Profiling and more.
The collective expertise of KDAB's engineering team is at your disposal to help you choose the software stack for your project or master domain-specific challenges.
Our particular focus is on software technologies you use for cross-platform applications or for embedded devices.
Since 1999, KDAB has been the largest independent Qt consultancy worldwide and today is a Qt Platinum partner. Our experts can help you with any aspect of software development with Qt and QML.
KDAB specializes in Modern C++ development, with a focus on desktop applications, GUI, embedded software, and operating systems.
Our experts are industry-recognized contributors and trainers, leveraging C++'s power and relevance across these domains to deliver high-quality software solutions.
KDAB can guide you incorporating Rust into your project, from as overlapping element to your existing C++ codebase to a complete replacement of your legacy code.
Unique Expertise for Desktop and Embedded Platforms
Whether you are using Linux, Windows, MacOS, Android, iOS or real-time OS, KDAB helps you create performance optimized applications on your preferred platform.
If you are planning to create projects with Slint, a lightweight alternative to standard GUI frameworks especially on low-end hardware, you can rely on the expertise of KDAB being one of the earliest adopters and official service partner of Slint.
KDAB has deep expertise in embedded systems, which coupled with Flutter proficiency, allows us to provide comprehensive support throughout the software development lifecycle.
Our engineers are constantly contributing to the Flutter ecosystem, for example by developing flutter-pi, one of the most used embedders.
KDAB invests significant time in exploring new software technologies to maintain its position as software authority. Benefit from this research and incorporate it eventually into your own project.
Start here to browse infos on the KDAB website(s) and take advantage of useful developer resources like blogs, publications and videos about Qt, C++, Rust, 3D technologies like OpenGL and Vulkan, the KDAB developer tools and more.
The KDAB Youtube channel has become a go-to source for developers looking for high-quality tutorial and information material around software development with Qt/QML, C++, Rust and other technologies.
Click to navigate the all KDAB videos directly on this website.
In over 25 years KDAB has served hundreds of customers from various industries, many of them having become long-term customers who value our unique expertise and dedication.
Learn more about KDAB as a company, understand why we are considered a trusted partner by many and explore project examples in which we have proven to be the right supplier.
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications.
Read more about the history, the values, the team and the founder of the company.
When working with KDAB you can expect quality software and the desired business outcomes thanks to decades of experience gathered in hundreds of projects of different sizes in various industries.
Have a look at selected examples where KDAB has helped customers to succeed with their projects.
KDAB is committed to developing high-quality and high-performance software, and helping other developers deliver to the same high standards.
We create software with pride to improve your engineering and your business, making your products more resilient and maintainable with better performance.
KDAB has been the first certified Qt consulting and software development company in the world, and continues to deliver quality processes that meet or exceed the highest expectations.
In KDAB we value practical software development experience and skills higher than academic degrees. We strive to ensure equal treatment of all our employees regardless of age, ethnicity, gender, sexual orientation, nationality.
Interested? Read more about working at KDAB and how to apply for a job in software engineering or business administration.
The Qt model/view APIs are used throughout Qt -- in Qt Widgets, in Qt Quick, as well as in other non-GUI code. As I tell my students when I deliver Qt trainings: mastering the usage of model/view classes and functions is mandatory knowledge, any non-trivial Qt application is going to be data-driven, with the data coming from a model class. In this blog series I will show some of the improvements to the model/view API that KDAB developed for Qt 5.11. A small word of advice: these posts are not meant to be a general introduction to Qt's model/view (the book's margin is too narrow... but if you're looking for that, I suggest you start here) and assumes a certain knowledge of the APIs used.
Implementing a model class
Data models in Qt are implemented by QAbstractItemModel subclasses. Application developers can either choose one of the ready-to-use item-based models coming with Qt (like QStringListModel or QStandardItemModel), or can develop custom model classes. Typically the choice falls on the latter, as custom models provide the maximum flexibility (e.g. custom storage, custom update policies, etc.) and the biggest performance. In my experience with Qt, I have implemented probably hundreds of custom models. For simplicity, let's assume we are implementing a table-based model. For this use case, Qt offers the convenience QAbstractTableModel class, which is much simpler to use than the fully-fledged QAbstractItemModel. A typical table model may look like this:
First and foremost, note that this model is not storing the data; it's acting as an adaptor between the real data storage (represented by the Storage class) and the views. When used into a Qt view (for instance a QTreeView), this code works perfectly and shows us a nice table full of data, for instance like this:
Making the code more robust
The code of the class above has a few issues. The first issue is that the implementation of rowCount() and columnCount() is, generally speaking, wrong. Those functions are supposed to be callable for every model index belonging to this model, plus the root (invalid) model index; the parameter of the functions is indeed the parent index for which we're asking the row count / column count respectively. When called with the root index, the functions return the right amount of rows and columns. However, there are no rows and no columns below any of elements in the table (because it is a table). The existing implementation does not make this distinction, and happily returns a wrong amount of rows/columns below the elements themselves, instead of 0. The lesson here is that we must not ignore the parent argument, and handle it in our rowCount and columnCount overrides. Therefore, a more correct implementation would look like this:
The second issue is not strictly a bug, but still a possible cause of concern: we don't validate any of the indices passed to the model's functions. For instance, we do not check that data() receives an index which is valid (i.e. isValid() returns true), belonging to this very model (i.e. model() returns this), and pointing to an existing item (i.e. its row and column are in a valid range).
QVariant data(const QModelIndex &&index,int role)constoverride{if(role != Qt::DisplayRole)return{};// what happens here if index is not valid, or not belonging to this model, etc.?return m_data.getData(index.row(), index.column());}
I personally maintain quite a strong point of view about this issue: passing such indices is a violation of the API contract. A model should never be assumed to be able to handle illegal indices. In other words, in my (not so humble) opinion, the QAbstractItemModel API has a narrow contract. Luckily, Qt's own views and proxy models honour this practice. (However, be aware that some other bits of code, such as the old model tester from Qt Labs, does not honour it, and will pass invalid indices. I will elaborate more on this in the next blog post.) Since Qt will never pass illegal indices to a model, it's generally pointless to make QAbstractItemModel APIs have wide contracts by handling all the possible inputs to its functions; this will just add unnecessary overhead to functions which are easily hotspots in our GUI. On the other hand, there are cases in which it is desirable to have a few extra safety checks in place, in the eventuality that an illegal index gets passed to our model. This can happen in a number of ways, for instance:
in case we are developing a custom view or some other component that uses our model via the model/view API, accidentally using wrong indices;
a QModelIndex is accidentally stored across model modifications and then used to access the model (a QPersistentModelIndex should have been used instead);
the model is used in combination with one or more proxy models, which may have bugs in the mapping of the indices (from source indices to proxy indices and viceversa), resulting in the accidental passing of a proxy index to our model's functions.
In the above scenarios, a bug somewhere in the stack may cause our model's methods to be called with illegal indices. Rather than crashing or producing invalid data, it would be very useful to catch the mistakes, in order to gracefully fail and especially in order to be able to debug them. In practice all of this means that our implementation of the QAbstractItemModel functions needs some more thorough checks. For instance, we can rewrite data() like this:
QVariant data(const QModelIndex &&index,int role)constoverride{// index is validQ_ASSERT(index.isValid());// index is right below the rootQ_ASSERT(!index.parent().isValid());// index is for this modelQ_ASSERT(index.model()==this);// the row is legalQ_ASSERT(index.row()&>=0);Q_ASSERT(index.row()&<rowCount(index.parent()));// the column is legalQ_ASSERT(index.column()&>=0);Q_ASSERT(index.column()&<columnCount(index.parent()));if(role != Qt::DisplayRole)return{};return m_data.getData(index.row(), index.column());}
Instead of hard assertions, we could use soft assertions, logging, etc. and returning an empty QVariant. Also, do note that some of the checks could (and should) also be added to the rowCount() and columnCount() functions, for instance checking that if the index is valid then it indeed belongs to this model.
Introducing checkIndex
After years of developing models I've realized that I must have written some variation of the above checks countless times, in each and every function of the QAbstractItemModel API. Recently I gave the question some more thought, and I came up with a solution: centralize the above checks, so that I don't have to re-write them every time. In Qt 5.11 I have added a new function to QAbstractItemModel: QAbstractItemModel::checkIndex(). This function takes a model index to check, and an option to determine the kind of checks that should be done on the index (see the function documentation for all the details). In case of failure, the function returns false and prints some information in the qt.core.qabstractitemmodel.checkindexlogging category. This gives us the flexibility of deciding what can be done on failure, and also to extract interesting data to debug an issue. Using the brand new checkIndex() our data() reimplementation can now be simplified to this:
QVariant data(const QModelIndex &&index,int role)constoverride{// data wants a valid index; moreover, this is a table, so the index must not have a parentQ_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid | QAbstractItemModel::CheckIndexOption::ParentIsInvalid));if(role != Qt::DisplayRole)return{};return m_data.getData(index.row(), index.column());}
Again, the example has an hard assert, which means that the program will crash in case of an illegal index (forcing the developer to do something about it). On the other hand the check will disappear in a release build, so that we don't pay the price of the check at each invocation of data(). One could instead use a soft assert or just a plain if statement (as many models — unfortunately — do, including the ones coming with Qt) for customizing the outcome of the check. This is an example of the logging output we automatically get in case we pass an invalid model index, which is not accepted by data():
qt.core.qabstractitemmodel.checkindex: Index QModelIndex(-1,-1,0x0,QObject(0x0)) is not valid (expected valid)
And this is an example of the output in case we accidentally pass an index belonging to another model (which happens all the time when developing custom proxy models):
qt.core.qabstractitemmodel.checkindex: Index QModelIndex(0,0,0x0,ProxyModel(0x7ffee145b640)) is for model ProxyModel(0x7ffee145b640) which is different from this model TableModel(0x7ffee145b660)
Conclusions
I hope that this addition to QAbstractItemModel will help developers build better data models, and to quickly and effectively debug situations where the model API is being misused. In the next instalment I will talk about other improvements to the model/view framework in Qt 5.11.
About KDAB
Trusted software excellence across embedded and desktop platforms
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
CheckIndexOption usage in the examples suggested that it is an enum class. I checked the source and it is indeed an enum class. However the linked Qt documentation lists enum values as if CheckIndexOption is just an enum.
Thanks a lot Giuseppe!
I've been using Qt for many years and still get tripped up with model/view issues fairly frequently, so any improvements here will be welcome. I rely on the old model tester to help catch issues - are you looking at updating it? Or are you trying to make it obsolete with new methods like checkIndex()?
22 - May - 2018
Giuseppe D'Angelo
Hi Andy,
(not sure what happened to my previous comment, trying to repost it now).
checkIndex() and the model tester are supposed to complement each other. checkIndex() is "defensive programming" for your model (although I disagree, as I said, to me models have narrow contracts), but more importantly, it acts just at a local level -- one particular function with one particular parameter. The model tester instead can do semantic checks, spanning across multiple functions. For instance, it can check that if the model says that there are rows/columns under an item, then asking for index(0, 0, item) returns a valid index. Or, it can check that the row count after a rowsInserted matches the advertised number of rows.
Unfortunately, the existing model tester doesn't work with checkIndex(), because it violates the narrow contract and deliberately supplies invalid indices to models. But I've something to say about that — in the next blog post!
Which is the best way to update a QML a view when a model changes? What happens when the model changes in a different thread (very common situation). Thanks.
22 - May - 2018
Giuseppe D'Angelo
Hi Gianluca,
The "best" way is simply using the QAbstractItemModel APIs for triggering notifications on change (all the rows inserted / rows removed functions, dataChanged, and the like). Please refer to the model view documentation I linked above for more information.
Regarding changes from a different thread, things are more complicated: a QAbstractItemModel is a QObject and I consider it non-reentrant. So you can only touch it from one thread (and if you use from QML, that thread is the GUI thread). This implies that any change from the data from another thread require some synchronization into your model, synchronization that must be completely invisible to the "users" of the model (aka the viewS). In other words: the views in the main thread must always have a coherent vision of the model; the model must take care of doing syncronizations internally.
22 - May - 2018
jason
Instead of using all those asserts and pre-condition checks, I would think using an exception would be the right way to go. Exceptions allow you to avoid all those repeated checks (and any model will repeat them heavily) so that you don't burn cpu on what should be 99.999% correct indexes.
Another question is why/how would you ever get an invalid index? If you mention multithreading in your answer, then your asserts are useless anyway because they are not thread safe.
22 - May - 2018
Giuseppe D'Angelo
Hi Jason,
do you mean having checkIndex() throw an exception? Or having model functions (such as data(), etc.) throw exceptions?
In general, exceptions can't be used in Qt's own code at all. Moreover, Qt doesn't allow exceptions to bubble through itself, so throwing from a custom model of yours isn't doable either.
When you say "Exceptions allow you to avoid all those repeated checks" I'm not sure what you mean. The point I tried to make in the blog post is that such checks shouldn't exist in the first place, so there's nothing to do waste. However, just in case something goes wrong, it might be useful to have a way to debug the indexed passed through the models. This does not mean having wide contracts, but just a valuable debugging aid. (Or, if you prefer having wide contracts, you can have them too...). checkIndex aims to be that debugging aid, by centralizing those checks and avoiding lots of c&p code in model subclasses.
About the "how would you ever get an invalid index" this can actually happen for many many reasons, I stated some in the blog post. For instance, one can build a proxy model that does some incorrect mapping and accidentally passes a proxy index to the source model, or one can develop a custom "view" that does a similar mistake.
Hope I've clarified a few things here!
11 - Feb - 2020
Thomas L.
Hi Giuseppe,
thank you for this information. But I'm not sure how the data() method is working without using the "role" variable:
QVariant data(const QModelIndex &index, int role) const override
{
if (role != Qt::DisplayRole)
return {};
return m_data.getData(index.row(), index.column());
}
If I debug in my qml application the role variable changes while index.column() remains at zero. So how can I increase the "column"?
Thank you,
Thomas
12 - Feb - 2020
Giuseppe D'Angelo
Hi,
This fundamentally depends on what kind of view you're using. ListView, Repeater and similar views in Qt Quick only use column 0 (they're list-based views) and different roles to extract different pieces of information for each row. TableView (in Qt Quick) or QTableView/QTreeView would also be able to use extra columns.
12 - Feb - 2020
Thomas L.
Thank you. I'm using the (old) Qt Quick TableView (Qt Quick Controls 1.4) with "TableViewColumn's".
That could be the reason, why the index.column() is always 0.
Or do you know, how it is possible to "use" index.column()?
Kind Regards,
Thomas
12 - Feb - 2020
Giuseppe D'Angelo
As far as I know, QQC1's TableView also operates on list-like models, using multiple roles in column 0 (in the model) to populate the columns in the view. For that particular view, the model is still a list -- the view maps roles onto columns using the mapping defined by the TableViewCOlumn elements.
TableView in Qt Quick itself (introduced in 5.12 IIRC) is instead able to operate on actual table models.
Giuseppe D’Angelo
Senior Software Engineer
Senior Software Engineer at KDAB. Giuseppe is a long-time contributor to Qt, having used Qt and C++ since 2000, and is an Approver in the Qt Project. His contributions in Qt range from containers and regular expressions to GUI, Widgets, and OpenGL. A free software passionate and UNIX specialist, before joining KDAB, he organized conferences on opensource around Italy. He holds a BSc in Computer Science.
Our hands-on Modern C++ training courses are designed to quickly familiarize newcomers with the language. They also update professional C++ developers on the latest changes in the language and standard library introduced in recent C++ editions.
14 Comments
15 - May - 2018
cka
CheckIndexOption usage in the examples suggested that it is an enum class. I checked the source and it is indeed an enum class. However the linked Qt documentation lists enum values as if CheckIndexOption is just an enum.
15 - May - 2018
Giuseppe D'Angelo
Hi, you're right; qdoc doesn't handle enum classes yet. https://bugreports.qt.io/browse/QTBUG-66740 has been already reported to track this.
15 - May - 2018
Andy
Thanks a lot Giuseppe! I've been using Qt for many years and still get tripped up with model/view issues fairly frequently, so any improvements here will be welcome. I rely on the old model tester to help catch issues - are you looking at updating it? Or are you trying to make it obsolete with new methods like checkIndex()?
22 - May - 2018
Giuseppe D'Angelo
Hi Andy, (not sure what happened to my previous comment, trying to repost it now). checkIndex() and the model tester are supposed to complement each other. checkIndex() is "defensive programming" for your model (although I disagree, as I said, to me models have narrow contracts), but more importantly, it acts just at a local level -- one particular function with one particular parameter. The model tester instead can do semantic checks, spanning across multiple functions. For instance, it can check that if the model says that there are rows/columns under an item, then asking for index(0, 0, item) returns a valid index. Or, it can check that the row count after a rowsInserted matches the advertised number of rows. Unfortunately, the existing model tester doesn't work with checkIndex(), because it violates the narrow contract and deliberately supplies invalid indices to models. But I've something to say about that — in the next blog post!
16 - May - 2018
Tuukka Turunen
You might want to add this to the list the most important changes at: https://wiki.qt.io/New_Features_in_Qt_5.11
17 - May - 2018
Giuseppe D'Angelo
Hi Tuukka, that's done now!
21 - May - 2018
Gianluca
Which is the best way to update a QML a view when a model changes? What happens when the model changes in a different thread (very common situation). Thanks.
22 - May - 2018
Giuseppe D'Angelo
Hi Gianluca, The "best" way is simply using the QAbstractItemModel APIs for triggering notifications on change (all the rows inserted / rows removed functions, dataChanged, and the like). Please refer to the model view documentation I linked above for more information. Regarding changes from a different thread, things are more complicated: a QAbstractItemModel is a QObject and I consider it non-reentrant. So you can only touch it from one thread (and if you use from QML, that thread is the GUI thread). This implies that any change from the data from another thread require some synchronization into your model, synchronization that must be completely invisible to the "users" of the model (aka the viewS). In other words: the views in the main thread must always have a coherent vision of the model; the model must take care of doing syncronizations internally.
22 - May - 2018
jason
Instead of using all those asserts and pre-condition checks, I would think using an exception would be the right way to go. Exceptions allow you to avoid all those repeated checks (and any model will repeat them heavily) so that you don't burn cpu on what should be 99.999% correct indexes. Another question is why/how would you ever get an invalid index? If you mention multithreading in your answer, then your asserts are useless anyway because they are not thread safe.
22 - May - 2018
Giuseppe D'Angelo
Hi Jason, do you mean having
checkIndex()
throw an exception? Or having model functions (such asdata()
, etc.) throw exceptions? In general, exceptions can't be used in Qt's own code at all. Moreover, Qt doesn't allow exceptions to bubble through itself, so throwing from a custom model of yours isn't doable either. When you say "Exceptions allow you to avoid all those repeated checks" I'm not sure what you mean. The point I tried to make in the blog post is that such checks shouldn't exist in the first place, so there's nothing to do waste. However, just in case something goes wrong, it might be useful to have a way to debug the indexed passed through the models. This does not mean having wide contracts, but just a valuable debugging aid. (Or, if you prefer having wide contracts, you can have them too...). checkIndex aims to be that debugging aid, by centralizing those checks and avoiding lots of c&p code in model subclasses. About the "how would you ever get an invalid index" this can actually happen for many many reasons, I stated some in the blog post. For instance, one can build a proxy model that does some incorrect mapping and accidentally passes a proxy index to the source model, or one can develop a custom "view" that does a similar mistake. Hope I've clarified a few things here!11 - Feb - 2020
Thomas L.
Hi Giuseppe, thank you for this information. But I'm not sure how the data() method is working without using the "role" variable:
If I debug in my qml application the role variable changes while index.column() remains at zero. So how can I increase the "column"? Thank you, Thomas
12 - Feb - 2020
Giuseppe D'Angelo
Hi, This fundamentally depends on what kind of view you're using. ListView, Repeater and similar views in Qt Quick only use column 0 (they're list-based views) and different roles to extract different pieces of information for each row. TableView (in Qt Quick) or QTableView/QTreeView would also be able to use extra columns.
12 - Feb - 2020
Thomas L.
Thank you. I'm using the (old) Qt Quick TableView (Qt Quick Controls 1.4) with "TableViewColumn's". That could be the reason, why the index.column() is always 0. Or do you know, how it is possible to "use" index.column()? Kind Regards, Thomas
12 - Feb - 2020
Giuseppe D'Angelo
As far as I know, QQC1's TableView also operates on list-like models, using multiple roles in column 0 (in the model) to populate the columns in the view. For that particular view, the model is still a list -- the view maps roles onto columns using the mapping defined by the TableViewCOlumn elements.
TableView in Qt Quick itself (introduced in 5.12 IIRC) is instead able to operate on actual table models.