<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[New in Qt 6.11: QRangeModel updates and QRangeModelAdapter]]></title><description><![CDATA[<p dir="auto">When <a href="https://www.qt.io/blog/a-model-for-all-ranges" target="_blank" rel="noopener noreferrer nofollow ugc">introducing QRangeModel</a> for Qt 6.10 I wrote that we'd try to tackle some limitations in future releases. With Qt 6.11 around the corner, it's time to give an update.</p>
<h2>Model updates when properties change</h2>
<p dir="auto">For a <code>QRangeModel</code> where all items or rows are backed by instances of the same QObject type, the model can now automatically emit the <code>dataChanged()</code> signal when properties of those objects change. This provides a convenient mechanism to keep things in sync without having to go through the <code>QAbstractItemModel</code> API for such changes. Let's say our data is backed by an item type like this:</p>
<pre><code class="language-C++">class Person : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString firstName READ firstName WRITE setFirstName NOTIFY firstNameChanged)
    Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY lastNameChanged)
    Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)

public:
    explicit Person( /* ~~~ */ );

    // ~~~
Q_SIGNALS:
    // ~~~
    void ageChanged(int age);

private:
    int m_age = 0;
};
</code></pre>
<p dir="auto">QRangeModel represents a list of such objects as a table with three columns, one for each property.</p>
<pre><code class="language-C++">// backend code
QList&lt;Person *&gt; data = {
    new Person("Max", "Mustermann", 37),
    new Person("Eva", "Nordmann", 39),
    new Person("Bob", "Mountainman", 42),
};
model = new QRangeModel(&amp;data);
model-&gt;setAutoConnectPolicy(QRangeModel::AutoConnectPolicy::Full);

// frontend code
tableView = new QTableView(this);
tableView-&gt;setModel(model);
</code></pre>
<p dir="auto">By setting the <code>autoConnectPolicy</code> of QRangeModel to either <code>Full</code> or <code>OnRead</code>, future changes to properties will make the model emit <code>QAbstractItemModel::dataChanged()</code> for the corresponding index and role. This in turn updates all views.</p>
<pre><code class="language-C++">// backend code
data[0]-&gt;setAge(data[0]-&gt;age() + 1);
</code></pre>
<p dir="auto">The only requirement is that the property has a notification signal that the setter emits when the value changes.</p>
<p dir="auto">Using <code>QObject</code> instances as the data type backing a model is comparatively expensive, but this addition makes it easy to work with the data inside small models directly, without having to deal with <code>QModelIndex</code> or <code>QVariant</code>.</p>
<h2>Modify a model with QRangeModelAdapter</h2>
<p dir="auto">Making it unnecessary to deal with those <code>QAbstractItemModel</code>'isms for trivial operations is also the idea behind the biggest item-models addition in Qt 6.11: <code>QRangeModelAdapter</code> is a new template class that makes it safe and convenient to work with the data structure a <code>QRangeModel</code> operates on. Item data and row/column structure of the underlying range can be modified and accessed through the adapter without having to deal with <code>QModelIndex</code> or <code>QVariant</code>, and the adapter makes sure that the model emits signals, invalidates and updates persistent indexes, and informs views about the changes.</p>
<pre><code class="language-C++">struct Backend
{
    QList&lt;int&gt; data { 1, 2, 3, 4 };
    QRangeModelAdapter adapter(std::ref(data));

    void updateData();
};

class Frontend
{
    Frontend()
    {
        // ~~~
        listView-&gt;setModel(backend.adapter.model()); // the adapter creates and owns the model
    }
};

// ~~~
void Backend::updateData()
{
    adapter[0] = 23; // emits dataChanged()
    adapter.insertRow(0, 78); // prepends 78, calls begin/endInsertRows
    adapter.removeRows(2, 2); // removes two rows, calls begin/endRemoveRows
}
</code></pre>
<p dir="auto">If the underlying data structure is a table, then an individual item can be modified like this:</p>
<pre><code class="language-C++">void Backend::updateData()
{
    adapter.at(1, 0) = 44; // works with C++17
    adapter[0, 1] = 55; // with C++23's multidimensional subscript operator
}
</code></pre>
<p dir="auto">For tree-shaped data structures, the row can be accessed using a path of row indexes:</p>
<pre><code class="language-C++">void Backend::updateData()
{
    adapter.at({0, 1}, 1) = "zero/one:one"; // second column in the second child of the first toplevel row
}
</code></pre>
<p dir="auto">In addition to index-based access to rows and columns, <code>QRangeModelAdapter</code> provides an iterator API:</p>
<pre><code class="language-C++">void Backend::storeData() const
{
    for (const auto &amp;item : adapter)
        storage &lt;&lt; item;
}
</code></pre>
<p dir="auto">With a table, clearing all cells while maintaining the dimensions of the table could be done like this:</p>
<pre><code class="language-C++">void Backend::clearData()
{
    for (auto row : adapter) {
        for (auto item : row) {
            item = {};
        }
    }
}
</code></pre>
<p dir="auto"><code>QRangeModelAdapter</code> is in technology preview for Qt 6.11; the API is a bit unorthodox, with different semantics depending on the underlying data structure. The heavy use of C++ 17 meta programming techniques also makes the <a href="https://doc-snapshots.qt.io/qt6-6.11/qrangemodeladapter.html" target="_blank" rel="noopener noreferrer nofollow ugc">documentation</a> a bit unwieldy, which has given our qdoc developers a good reason to improve the rendering of template APIs. We'd very much like to hear your feedback to it!</p>
<h2>Customizing item access</h2>
<p dir="auto">We added a new customization point for implementing custom item access. Specialize <a href="https://doc-snapshots.qt.io/qt6-6.11/qrangemodel-itemaccess.html" target="_blank" rel="noopener noreferrer nofollow ugc"><code>QRangeModel::ItemAccess</code></a> for your type and implement static <code>readRole</code> and <code>writeRole</code> accessors to read and write role-specific values to an item:</p>
<pre><code class="language-C++">template &lt;&gt;
struct QRangeModel::ItemAccess&lt;Person&gt;
{
    static QVariant readRole(const Person &amp;item, int role)
    {
        switch (role) {
        case Qt::DisplayRole:
            return item.firstName() + " " + item.lastName();
        case Qt::UserRole:
            return item.firstName();
        case Qt::UserRole + 1:
            return item.lastName();
        case Qt::UserRole + 2:
            return item.age();
        }
        return {};
    }

    static bool writeRole(Person &amp;item, const QVariant &amp;data, int role)
    {
        bool ok = true;
        switch (role) {
        case Qt::DisplayRole:
        case Qt::EditRole: {
            const QStringList names = data.toString().split(u' ');
            if (names.size() &gt; 0)
                item.setFirstName(names.at(0));
            if (names.size() &gt; 1)
                item.setLastName(names.at(1));
            break;
        }
        case Qt::UserRole:
            item.setFirstName(data.toString());
            break;
        case Qt::UserRole + 1:
            item.setLastName(data.toString());
            break;
        case Qt::UserRole + 2:
            item.setAge(data.toInt(&amp;ok));
            break;
        default:
            ok = false;
            break;
        }

        return ok;
    }
};
</code></pre>
<p dir="auto">A specialization of <code>ItemAccess</code> takes precedence over built-in access mechanisms, and also implies that <code>QRangeModel</code> will interpret the type as a multi-role item, even if it could be treated as a multi-column row. So you can use this technique to customize and optimize access to tuple-like types, gadgets, or completely custom structs.</p>
<h2>Support for caching std::ranges</h2>
<p dir="auto">Last but not least, a minor improvement for users of <code>std::ranges</code>: <code>QRangeModel</code> no longer requires <code>std::being</code>/<code>end</code> on constant ranges, so you can use e.g. <code>std::views::filter</code> as input to your model:</p>
<pre><code class="language-C++">const QDate today = QDate::currentDate();
model = new QRangeModel(std::views::iota(today.addYears(-100), today.addYears(100))
                      | std::views::filter([](QDate date) { return date.dayOfWeek() &lt; 6; })
                       );
</code></pre>
<p dir="auto">And if <code>std::ranges</code> is already old news for you and you want to read more about bleeding-edge C++ stuff, check the <a href="https://www.qt.io/blog/c26-reflection-qrangemodel" target="_blank" rel="noopener noreferrer nofollow ugc">blog post about my hackathon project</a> using C++26 reflections to eliminate more boiler plate for custom structs.</p>
<h2>Conclusion</h2>
<p dir="auto">With Qt 6.11 we make it easier than ever to work with C++ data structures as sources of UI data. Modifying data with <code>QRangeModelAdapter</code> uses API concepts that are familiar for C++ developers, while making sure that <code>QAbstractItemModel</code> clients are informed about relevant changes. Automatically binding the <code>dataChanged()</code> to QObject properties, support for more C++20 ranges, and a new customization point round of the additions to Qt's modern item model handling for C++ developers.</p>
]]></description><link>https://forum.qt.io/topic/164323/new-in-qt-6.11-qrangemodel-updates-and-qrangemodeladapter</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Apr 2026 18:08:37 GMT</lastBuildDate><atom:link href="https://forum.qt.io/topic/164323.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 25 Feb 2026 12:00:02 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to New in Qt 6.11: QRangeModel updates and QRangeModelAdapter on Wed, 25 Feb 2026 12:42:57 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/jonb">@<bdi>JonB</bdi></a>  that is correct; our tests compile and run with a C++ 17 only toolchain. But if you use it with a newer C++ standard, then you get some support for new language features (like multi-dimensional subscripts from C++23, or std::ranges). This is possible with QRangeModel(Adapter) as the implementation is mostly inline in the headers.</p>
]]></description><link>https://forum.qt.io/post/836579</link><guid isPermaLink="true">https://forum.qt.io/post/836579</guid><dc:creator><![CDATA[Volker Hilsheimer]]></dc:creator><pubDate>Wed, 25 Feb 2026 12:42:57 GMT</pubDate></item><item><title><![CDATA[Reply to New in Qt 6.11: QRangeModel updates and QRangeModelAdapter on Wed, 25 Feb 2026 12:12:36 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/volker-hilsheimer">@<bdi>Volker-Hilsheimer</bdi></a> said in <a href="/post/836575">New in Qt 6.11: QRangeModel updates and QRangeModelAdapter</a>:</p>
<blockquote>
<p dir="auto">support for more C++20 ranges</p>
</blockquote>
<p dir="auto">Nice addition.  Reading the linked article you say there "while we don't want to require anything more modern than C++17 to be able to use QRangeModel".  To be clear: your <code>QRangeModel</code>, now and for the foreseeable future, will only <em>require</em> that I use C++17?  <strong>IF</strong> I use C++20+ I will get more support for certain types of models/ranges which I will not get if I only use C++17, so I could not use those in the backend, but I won't <em>have to</em> use C++20+ if I keep clear of models/ranges which require its features?</p>
]]></description><link>https://forum.qt.io/post/836577</link><guid isPermaLink="true">https://forum.qt.io/post/836577</guid><dc:creator><![CDATA[JonB]]></dc:creator><pubDate>Wed, 25 Feb 2026 12:12:36 GMT</pubDate></item></channel></rss>