<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Qt Archives | DMC, Inc.</title>
	<atom:link href="https://static.dmcinfo.com/blog/tag/qt/feed/index.xml" rel="self" type="application/rss+xml" />
	<link></link>
	<description></description>
	<lastBuildDate>Tue, 23 Dec 2025 14:49:26 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>

<image>
	<url>https://static.dmcinfo.com/wp-content/uploads/2025/04/site-icon-150x150.png</url>
	<title>Qt Archives | DMC, Inc.</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using a QAbstractListModel in QML</title>
		<link>https://static.dmcinfo.com/blog/17671/using-a-qabstractlistmodel-in-qml/</link>
		
		<dc:creator><![CDATA[Mark Locascio]]></dc:creator>
		<pubDate>Mon, 27 Mar 2023 09:36:10 +0000</pubDate>
				<category><![CDATA[Application Development]]></category>
		<category><![CDATA[PC Application Development]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Qt]]></category>
		<guid isPermaLink="false">https://static.dmcinfo.com/blog/17671/using-a-qabstractlistmodel-in-qml/</guid>

					<description><![CDATA[<p>The QAbstractListModel class provided by Qt can be used to organize data that will be presented visually as a list or table. Standardizing the interface with an abstract class like QAbstractListModel makes it easy to keep your model data completely isolated from your view (a software design principle known as &#8220;separation of concerns&#8220;). That abstraction [&#8230;]</p>
<p>The post <a href="https://static.dmcinfo.com/blog/17671/using-a-qabstractlistmodel-in-qml/">Using a QAbstractListModel in QML</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The <code><a href="https://doc.qt.io/qt-6/qabstractlistmodel.html">QAbstractListModel</a></code> class provided by Qt can be used to organize data that will be presented visually as a list or table. Standardizing the interface with an abstract class like <code>QAbstractListModel</code> makes it easy to keep your model data completely isolated from your view (a software design principle known as &#8220;<a href="https://csrc.nist.gov/glossary/term/separation_of_concerns">separation of concerns</a>&#8220;). That abstraction makes it a powerful and flexible tool, but it also makes the learning curve steep.</p>



<p class="wp-block-paragraph">The goal of this post is to provide concrete examples, explanations, and definitions of terms so you can more easily make use of the <code>QAbstractListModel</code> class. For your reference, you can see the complete <a href="https://github.com/marklocascio/qml-listmodel-example">example code on GitHub</a>.</p>



<h2 class="wp-block-heading" id="h-example-gui">Example GUI</h2>



<p class="wp-block-paragraph">Let&#8217;s say we&#8217;ve got a list of devices with which our software interacts. The data we&#8217;ve got for each device is:</p>



<ul class="wp-block-list">
<li>A human-readable name (a string)</li>



<li>A serial number (an integer)</li>



<li>Whether or not the device is currently connected (a Boolean)</li>
</ul>



<p class="wp-block-paragraph">Our example GUI will look like this:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/app.png" alt="Example GUI"/></figure>



<p class="wp-block-paragraph">Part of the appeal of Qt is that you can make extremely slick UIs. We will not be doing that here in order to keep the focus on listmodel concepts. I&#8217;ve resisted the urge to add eye candy for the sake of clarity, and I have crafted the example to make it clear how you <strong><em>could</em></strong> stylize the list if you wanted to.</p>



<p class="wp-block-paragraph">Additionally, the example uses Qt&#8217;s Python bindings (<a href="https://pypi.org/project/PySide6/">PySide6</a>). Everything here is equally applicable to C++, but again, for the sake of simplicity, it is presented as a Python application. The QML is identical in both cases.</p>



<h2 class="wp-block-heading" id="h-the-qml-description">The QML Description</h2>



<p class="wp-block-paragraph">First, we&#8217;ll describe the visualization of our list of devices in QML. The <a href="https://doc.qt.io/qt-6/qml-qtquick-listview.html">QML <code>ListView</code> class</a> is a great start. We&#8217;ll set three properties:</p>



<ul class="wp-block-list">
<li>
<p class="wp-block-paragraph"><code><span style="color:#c00000">model</span></code>: this is what we&#8217;ll use to bind the QML <code>ListView</code> to a <code>QAbstractListModel</code> class defined in C++ or Python</p>
</li>



<li><code><span style="color:#2f5496">delegate</span></code>: this is used to define how each item in the list is rendered as a QML object</li>



<li><code><span style="color:#bf8f00">highlight</span></code>: this is not necessary to use a <code>ListView</code>, but it is generally useful to visualize a selected item in the list</li>
</ul>



<h2 class="wp-block-heading" id="h-basic-example">Basic Example</h2>



<p class="wp-block-paragraph">A rough first draft of the QML might look like this (for the final version, <a href="https://github.com/marklocascio/qml-listmodel-example/blob/main/sample/main.qml">see here</a>):</p>



<p class="wp-block-paragraph"><code><span style="white-space: nowrap;">ListView {<br>
&nbsp;&nbsp;&nbsp;&nbsp;id: deviceList<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#c00000">model: controller.listmodel</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2f5496">delegate: Item {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;width: deviceList.width<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Text {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text: "Placeholder"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MouseArea {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;anchors.fill: parent<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;}</span>&nbsp;&nbsp;<span style="color:#538135">// Item delegate</span><br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bf8f00">highlight: Rectangle { color: "lightBlue" }</span><br>
}&nbsp;&nbsp;<span style="color:#538135">// ListView</span></span></code></p>



<h2 class="wp-block-heading" id="h-using-the-model-and-the-delegate">Using the Model and the Delegate</h2>



<p class="wp-block-paragraph">In my <code>main()</code> function, I <a href="https://github.com/marklocascio/qml-listmodel-example/blob/main/sample/__main__.py#L18">set a context property</a> called <code>controller</code> that refers to an instance of my <code>Controller</code> class:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>qml_app_engine = QQmlApplicationEngine()
qml_context = qml_app_engine.rootContext()
controller = Controller(parent=app)
qml_context.setContextProperty("controller", controller)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #D4D4D4">qml_app_engine = QQmlApplicationEngine()</span></span>
<span class="line"><span style="color: #D4D4D4">qml_context = qml_app_engine.rootContext()</span></span>
<span class="line"><span style="color: #D4D4D4">controller = Controller(</span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">=app)</span></span>
<span class="line"><span style="color: #D4D4D4">qml_context.setContextProperty(</span><span style="color: #CE9178">&quot;controller&quot;</span><span style="color: #D4D4D4">, controller)</span></span></code></pre></div>



<p class="wp-block-paragraph">The <code>Controller</code> class <a href="https://github.com/marklocascio/qml-listmodel-example/blob/main/sample/controller.py#L12">exposes a Qt property</a> called <code>listmodel</code>. Note that that property is declared as a <code>QObject</code> in my Python code, and that it does not need a property change signal (i.e., I use <code>constant=True</code>). In the QML above, I bind the <code>ListView</code>&#8216;s <code>model</code> property to the <code>listmodel</code> property of my <code>controller</code> object:</p>



<p class="wp-block-paragraph"><code><span style="color:#c00000">model: controller.listmodel</span></code></p>



<p class="wp-block-paragraph">The <code><span style="color:#2f5496">delegate</span></code> property of <code>ListView</code> is like a template that defines how each item in the list is rendered as a QML object. For the sake of demonstration, we&#8217;ll keep it simple here. I made it a QML <code><a href="https://doc.qt.io/qt-6/qml-qtquick-item.html">Item</a></code> that is as wide as the <code>ListView</code> itself and contains a <code><a href="https://doc.qt.io/qt-6/qml-qtquick-text.html">Text</a></code> object and a <code><a href="https://doc.qt.io/qt-6/qml-qtquick-mousearea.html">MouseArea</a></code>, but you can make it anything you like (you&#8217;ll generally make it much fancier)! For example, you might instead have something like a <code><a href="https://doc.qt.io/qt-6/qml-qtquick-layouts-rowlayout.html">RowLayout</a></code> containing a <code><a href="https://doc.qt.io/qt-6/qml-qtquick-controls2-checkbox.html">Checkbox</a></code>, an <code><a href="https://doc.qt.io/qt-6/qml-qtquick-image.html">Image</a></code>, and a <code><a href="https://doc.qt.io/qt-6/qml-qtquick-text.html">Text</a></code>. (Haven&#8217;t used layouts yet? <a href="https://static.dmcinfo.com/latest-thinking/blog/id/10393/resizing-uis-with-qml-layouts">Start here!</a>) However you want each item in your list to be visualized, you can define it in your <code><span style="color:#2f5496">delegate</span></code>. For simplicity, I often start by just rendering it all in a <code>Text</code> item. We&#8217;ll look at how to access each item of data (name, serial number, and connection status) in the next section.</p>



<p class="wp-block-paragraph">Note also that the <code>MouseArea</code> in my <code><span style="color:#2f5496">delegate</span></code> is used to select an item in the list. Each item in the list is instantiated as a <code><span style="color:#2f5496">delegate</span></code> object, so each item in the list has a <code>MouseArea</code> that can handle click events. We&#8217;ll look at this in more detail later also.</p>



<h2 class="wp-block-heading" id="h-the-qabstractlistmodel-class">The QAbstractListModel Class</h2>



<p class="wp-block-paragraph">If you are managing a large quantity of data and you want to visualize it on your QML GUI, you have a few options. For simple cases, a <a href="https://doc.qt.io/qt-6/qml-qtquick-repeater.html"><code>Repeater</code></a> can usually get the job done just fine and is conceptually very easy to grasp. However, for very large lists, <a href="https://doc.qt.io/qt-6/qml-qtquick-repeater.html#considerations-when-using-repeater">a <code>Repeater</code> is not recommended</a> because it instantiates all visual items at once. In cases where you have a lot of data, you often only want to view or update a small section of it. For these cases, QML provides the <a href="https://doc.qt.io/qt-6/qml-qtquick-listview.html"><code>ListView</code></a> object, which expects to be bound to a <a href="https://doc.qt.io/qt-6/qabstractlistmodel.html">QAbstractListModel</a> object in your C++ or Python application.</p>



<p class="wp-block-paragraph"><code>QAbstractListModel</code> is an abstract class that cannot be instantiated itself, so you need to create a new class that inherits from it and is specialized for your needs. I would first suggest reading the section of its documentation titled <a href="https://doc.qt.io/qt-6/qabstractlistmodel.html#subclassing">&#8220;Subclassing,&#8221;</a> which states that:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">When subclassing QAbstractListModel, you must provide implementations of the <code>rowCount()</code> and <code>data()</code> functions. Well behaved models also provide a <code>headerData()</code> implementation.</p>



<p class="wp-block-paragraph">If your model is used within QML and requires roles other than the default ones provided by the <code>roleNames()</code> function, you must override it.</p>



<p class="wp-block-paragraph">For editable list models, you must also provide an implementation of <code>setData()</code>&nbsp;and implement the <code>flags()</code> function so that it returns a value containing Qt::ItemIsEditable.</p>
</blockquote>



<p class="wp-block-paragraph">It&#8217;s unlikely that those few sentences made it immediately obvious what you need to do. Let&#8217;s start with what confused me most when I got started: the concept of a &#8220;role.&#8221;</p>



<h2 class="wp-block-heading" id="h-roles">Roles</h2>



<p class="wp-block-paragraph">Think about the data we&#8217;re presenting. We have a list of devices, and each device in the list has three pieces of data (name, serial number, and connection status). You might think of each device&#8217;s data as a row in a table:</p>


<table border="0" cellpadding="1" cellspacing="1">
<thead>
<tr>
<th scope="col" style="text-align: left;">Serial Number</th>
<th scope="col" style="text-align: left;">Human-readable name</th>
<th scope="col" style="text-align: left;">Connected?</th>
</tr>
</thead>
<tbody>
<tr>
<td>123</td>
<td>name1</td>
<td>No</td>
</tr>
<tr>
<td>456</td>
<td>name2</td>
<td>Yes</td>
</tr>
<tr>
<td>789</td>
<td>name3</td>
<td>No</td>
</tr>
</tbody>
</table>


<p class="wp-block-paragraph">The simplest analogy is that the &#8220;role&#8221; is the piece of data that goes in each column. You might also think of it as identifying each piece of data in each object in the list. So, we will define our &#8220;roles&#8221; as <code>name</code>, <code>serial</code>, and <code>connected</code>.</p>



<p class="wp-block-paragraph">Notice also that Qt provides a <a href="https://doc.qt.io/qt-6/qt.html#ItemDataRole-enum">built-in <code>ItemDataRole</code> enum</a>. I initially found this very confusing, because it provides roles with names like <code>Qt::DisplayRole</code> and <code>Qt::EditRole</code>, which don&#8217;t really sound like individual data items to me. The built-in roles are intended for use with built-in classes like <code>QString</code> and <code>QIcon</code>, and they don&#8217;t necessarily make sense for this particular custom class, so don&#8217;t let it throw you off. Consider though, that you might have roles (items of data in your class) that aren&#8217;t pieces of data that you&#8217;d want to render as text but are instead pieces of data that determine how the display of that data behaves (like a background color or an icon).</p>



<p class="wp-block-paragraph">Roles that you want to define yourself for your own custom class can use enum values starting with <code>Qt::UserRole</code>, which has value 0x0100 = 256.</p>



<h2 class="wp-block-heading" id="h-an-aside-on-tables">An Aside on Tables</h2>



<p class="wp-block-paragraph">It&#8217;s worth mentioning that there is indeed a <a href="https://doc.qt.io/qt-6/qabstracttablemodel.html"><code>QAbstractTableModel</code></a> class as well. As shown above, we can use the role as the &#8220;second dimension&#8221; of our one-dimensional list, making it look like a table. So, when would you use <code>QAbstract<u>Table</u>Model</code>? You might use it when you have a 2D array of objects, where each object has a set of properties that you identify as &#8220;roles.&#8221;</p>



<p class="wp-block-paragraph">What makes the most sense as a data model will depend on your specific data, and it may be confusing to think about a list in terms of &#8220;rows&#8221; if your data doesn&#8217;t really seem like a table (you may not even arrange items vertically on your UI, which makes the terminology much worse!). We&#8217;re stuck with the &#8220;row&#8221; and &#8220;column&#8221; terminology used by Qt here, but the models can be used in whatever way makes the most sense for the data you need to represent.</p>



<p class="wp-block-paragraph">In most real-life applications (as well as in the example code here), I use a 1D array with multiple roles, because I find that to be the simplest and most natural data structure. However, both <code>QAbstract<u>Table</u>Model</code> and <code>QAbstract<u>Item</u>Model</code> are available to you if you need a more complex visualization of more complex data. Once you get a handle on <code>QAbstract<u>List</u>Model</code>, the more general classes will make more sense.</p>



<h2 class="wp-block-heading" id="h-how-are-roles-used-in-qml">How are Roles Used in QML?</h2>



<p class="wp-block-paragraph">As shown above, you will use the QML <code>ListView</code>&#8216;s model property to specify an object in your C++ or Python code that inherits from <code>QAbstractListModel</code>. The <code><span style="color:#2f5496">delegate</span></code> property is then used to define the QML object that will visualize that data. In this case, each item in the list has three roles (<code>name</code>, <code>serial</code>, and <code>connected</code>), and we&#8217;ll want to access each of those data items in QML independently.</p>



<p class="wp-block-paragraph">Looking at the GUI again:</p>



<figure class="wp-block-image"><img decoding="async" src="https://static.dmcinfo.com/wp-content/uploads/2025/05/app-1.png" alt="GUI example"/></figure>



<p class="wp-block-paragraph">Each item in the list is visualized as a <code>Text</code> item where the content follows this pattern:</p>



<p class="wp-block-paragraph"><code><span style="white-space: nowrap;">[<span style="color:#00b050">index</span> of item]: [<span style="color:#00b050">name</span> role] ([<span style="color:#00b050">serial</span> role]) - [<span style="color:#00b050">connection</span> role]</span></code></p>



<p class="wp-block-paragraph">In our <span style="color:#2f5496"><code>delegate</code></span>, we can access each item of data using the name of the role:</p>



<p class="wp-block-paragraph"><span style="white-space: nowrap;"><code>ListView {<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#c00000">model: controller.listmodel</span><br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2f5496">delegate: Text {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;text: `${<span style="color:#00b050">index</span>}: ${<span style="color:#00b050">name</span>} (${<span style="color:#00b050">serial</span>}) - ${<span style="color:#00b050">connected</span> ? "OK" : "NOT FOUND"}`<br>
&nbsp;&nbsp;&nbsp;&nbsp;}</span><br>
}</code></span></p>



<p class="wp-block-paragraph">Inside the <span style="color:#2f5496"><code>delegate</code></span> object we can simply use <span style="color:#00b050"><code>index</code></span>, <span style="color:#00b050"><code>name</code></span>, <span style="color:#00b050"><code>serial</code></span> and <span style="color:#00b050"><code>connected</code></span> as if they are bound to the individual data items inside that element of the list. <span style="color:#00b050"><code>index</code></span> is provided out-of-the-box by <code>ListView</code>, but <span style="color:#00b050"><code>name</code></span>, <span style="color:#00b050"><code>serial</code></span>, and <span style="color:#00b050"><code>connected</code></span> are the <strong><em>names of roles we define ourselves</em></strong>. Within the <span style="color:#2f5496"><code>delegate</code></span> object, we can refer to those names, and our child class of <code>QAbstractListModel</code> will provide methods that QML can use to link those names to specific pieces of data.</p>



<p class="wp-block-paragraph">The <span style="color:#00b050"><code>index</code></span> value is also useful in our <code>MouseArea</code>. We added the <code>MouseArea</code> so that the user could click an item in the list and manipulate it. Since the <code>MouseArea</code> is inside the <span style="color:#2f5496"><code>delegate</code></span>, we have access to the index value. In the <code>MouseArea</code>&#8216;s signal handler <code>onClicked</code>, we will want to set <a href="https://doc.qt.io/qt-6/qml-qtquick-listview.html#currentIndex-prop">the <code>currentIndex</code> property</a> of the <code>ListView</code> to the index of the item in the list that was clicked:</p>



<p class="wp-block-paragraph"><code><span style="white-space: nowrap;">ListView {<br>
&nbsp;&nbsp;&nbsp;&nbsp;id: deviceList<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#2f5496">delegate: Item {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MouseArea {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onClicked: deviceList.currentIndex = index<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp; // MouseArea<br>
&nbsp;&nbsp;&nbsp;&nbsp;}</span>&nbsp;&nbsp;<span style="color:#538135">// Item delegate</span><br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#bf8f00">highlight: Rectangle { color: "lightBlue" }</span><br>
}&nbsp;&nbsp;<span style="color:#538135">// ListView</span></span></code></p>



<p class="wp-block-paragraph">Setting the <code>currentIndex</code> of the <code>ListView</code> enables the <code>ListView</code> to automatically animate the <span style="color:#bf8f00"><code>highlight</code></span> object that we defined. When the user clicks an item in the list, it will move the <code>Rectangle</code> to highlight the selected list item.</p>



<p class="wp-block-paragraph">As an exercise for the reader, try making the <span style="color:#2f5496"><code>delegate</code></span> more interesting. Instead of indicating the state of the connected role with just a <code>Text</code>, try using the <code>connected</code> role to set the text color of the <span style="color:#2f5496"><code>delegate</code></span>, or add an icon to each row that indicates whether or not the device is connected.</p>



<h2 class="wp-block-heading" id="h-setting-up-the-roles">Setting Up the Roles</h2>



<p class="wp-block-paragraph">Let&#8217;s circle back to this statement in the documentation:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">If your model is used within QML and requires roles other than the default ones provided by the <code>roleNames()</code> function, you must override it.</p>
</blockquote>



<p class="wp-block-paragraph">We want to use our own role names for this, so we can use names that make sense in our <span style="color:#2f5496"><code>delegate</code></span> (like <code>name</code>, <code>serial</code>, and <code>connected</code>). The mapping from integer role enum values (like <code>Qt::UserRole</code>) to strings of characters is established with the <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#roleNames"><code>QAbstractItemModel::roleNames()</code></a> method, which your custom listmodel will inherit. All classes that inherit <code>QAbstractListModel</code> need to implement this method, which returns the map from integers to byte arrays. In C++, this map is a <code>QHash&lt;int, QByteArray&gt;</code>, and in Python it is a basic <code>dict</code>. The integer is the role enum value, and the byte array is the string name used in QML to access that role in each item of the listmodel.</p>



<p class="wp-block-paragraph">I like to set up my roles by doing two things: creating an enum (starting with the value <code>Qt::UserRole</code> and incrementing from there) that enumerates my custom roles, and then creating a dictionary that maps the role enum values to byte arrays (the names used by QML to access elements of the model). In our example, I might do:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>class DeviceItemRoles(IntEnum):    
  NAME = Qt.UserRole
  SERIAL = auto()
  CONNECTED = auto()
  _role_names = {
      DeviceItemRoles.NAME: b'name',
      DeviceItemRoles.SERIAL: b'serial',
      DeviceItemRoles.CONNECTED: b'connected'
  }</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DeviceItemRoles</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">IntEnum</span><span style="color: #D4D4D4">):    </span></span>
<span class="line"><span style="color: #D4D4D4">  NAME = Qt.UserRole</span></span>
<span class="line"><span style="color: #D4D4D4">  SERIAL = auto()</span></span>
<span class="line"><span style="color: #D4D4D4">  CONNECTED = auto()</span></span>
<span class="line"><span style="color: #D4D4D4">  _role_names = {</span></span>
<span class="line"><span style="color: #D4D4D4">      DeviceItemRoles.NAME: </span><span style="color: #569CD6">b</span><span style="color: #CE9178">&apos;name&apos;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      DeviceItemRoles.SERIAL: </span><span style="color: #569CD6">b</span><span style="color: #CE9178">&apos;serial&apos;</span><span style="color: #D4D4D4">,</span></span>
<span class="line"><span style="color: #D4D4D4">      DeviceItemRoles.CONNECTED: </span><span style="color: #569CD6">b</span><span style="color: #CE9178">&apos;connected&apos;</span></span>
<span class="line"><span style="color: #D4D4D4">  }</span></span></code></pre></div>



<p class="wp-block-paragraph">Note again that in Python, the values are byte arrays (<code>b''</code>), not strings.</p>



<p class="wp-block-paragraph">With this setup, the delegate of our <code>ListView</code> can access each piece of data in each list item using the strings <code>name</code>, <code>serial</code>, and <code>connected</code>. QML knows how the role integers (from the enum) map to the names because it knows that a <code>QAbstractListModel</code> must have a <code>roleNames()</code> method, so now we just need to give it a way to access each piece of data given the list index and the role. That is the job of the <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#data"><code>QAbstractItemModel::data()</code></a> method, which we will get to shortly.</p>



<h2 class="wp-block-heading" id="h-subclassing-a-qabstractlistmodel">Subclassing a QAbstractListModel</h2>



<p class="wp-block-paragraph">Recall from the <a href="https://doc.qt.io/qt-6/qabstractlistmodel.html#subclassing">documentation</a> that subclasses of <code>QAbstractListModel</code> need to implement the <code>rowCount()</code> and <code>data()</code> methods, plus <code>roleNames()</code> if the listmodel is used in QML. We&#8217;ll cover these one-by-one, but first let&#8217;s define how we&#8217;ll store our data.</p>



<h2 class="wp-block-heading" id="h-data-storage">Data Storage</h2>



<p class="wp-block-paragraph">I find that the easiest way to store the data (for a Python application) is with a list of dictionaries, where each dictionary uses the role enum as the key for each data value. This is by no means the only way, but it is very simple and often sufficient. So, you might start developing your custom listmodel class like this:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>class DeviceListModel(QAbstractListModel):

    def __init__(self):

        super().__init__()

        self._data = []



    def add_device(self, name, serial, connected):

        new_row = {

            DeviceItemRoles.NAME: name,

            DeviceItemRoles.SERIAL: serial,

            DeviceItemRoles.CONNECTED: connected

        }



        self._data.append(new_row)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">class</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">DeviceListModel</span><span style="color: #D4D4D4">(</span><span style="color: #4EC9B0">QAbstractListModel</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">__init__</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #4EC9B0">super</span><span style="color: #D4D4D4">().</span><span style="color: #DCDCAA">__init__</span><span style="color: #D4D4D4">()</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data = []</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">add_device</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">serial</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">connected</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        new_row = {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            DeviceItemRoles.NAME: name,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            DeviceItemRoles.SERIAL: serial,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">            DeviceItemRoles.CONNECTED: connected</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        }</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data.append(new_row)</span></span></code></pre></div>



<p class="wp-block-paragraph">When we create a new listmodel, the list of data, <code>self._data</code>, is just an empty list. We can then add device data to the list with the <code>add_device()</code> method, which takes the name, serial number, and connection status, puts them in a dictionary with the appropriate role enum values as keys, and then appends that dictionary to the data list.</p>



<p class="wp-block-paragraph">Now that we&#8217;ve established how the data is stored, we can fill out the required methods.</p>



<h2 class="wp-block-heading" id="h-the-rolenames-method">The roleNames() Method</h2>



<p class="wp-block-paragraph"><code>roleNames()</code> is the easiest to implement, because it&#8217;s already done! The <code>_role_names</code> dictionary from above is exactly what <code>roleNames()</code> should return, so this one&#8217;s a no-brainer:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def roleNames(self):
    return _role_names</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">roleNames</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">):</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> _role_names</span></span></code></pre></div>



<p class="wp-block-paragraph">That&#8217;s it!</p>



<h2 class="wp-block-heading" id="h-the-rowcount-method">The rowCount() Method</h2>



<p class="wp-block-paragraph"><code>rowCount()</code> is similarly straightforward. The number of rows is just the number of elements in our <code>self._data</code> list. We don&#8217;t need to do much here either:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def rowCount(self, parent=QModelIndex()):
    return len(self._data)</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">rowCount</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">parent</span><span style="color: #D4D4D4">=QModelIndex()):</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">len</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data)</span></span></code></pre></div>



<p class="wp-block-paragraph">The only thing to address is that weird <code>parent</code> argument. What&#8217;s that about?</p>



<p class="wp-block-paragraph">It comes from the base class, <code>QAbstract<u>Item</u>Model</code>. The base class is more general. Whereas <code>QAbstract<u>List</u>Model</code> represents a one-dimensional list of items that all have the same type of elements, <code>QAbstract<u>Item</u>Model</code> can describe trees and other complex hierarchical structures. In those cases, you need to provide the index of a parent object in the tree so the <code>rowCount()</code> method can return the number of children <strong><em>of that parent</em></strong>. Once you get your bearings with the <code>QAbstract<u>List</u>Model</code>, you can dig into the <code>QAbstract<u>Item</u>Model</code>, but for now, let&#8217;s just ignore <code>parent</code>, because it doesn&#8217;t apply to a one-dimensional list. Just give it a default <code>QModelIndex</code>.</p>



<h2 class="wp-block-heading" id="h-the-data-method">The data() Method</h2>



<p class="wp-block-paragraph">Finally, we need to implement a method that will return data values when QML asks for them. <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#data">The C++ signature of this method is:</a></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">C++</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>QVariant QAbstractItemModel::data(const QModelIndex &amp;index, int role = Qt::DisplayRole) const</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #4EC9B0">QVariant</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">QAbstractItemModel</span><span style="color: #D4D4D4">::</span><span style="color: #DCDCAA">data</span><span style="color: #D4D4D4">(</span><span style="color: #569CD6">const</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">QModelIndex</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">&amp;</span><span style="color: #9CDCFE">index</span><span style="color: #D4D4D4">, </span><span style="color: #569CD6">int</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">role</span><span style="color: #D4D4D4"> = </span><span style="color: #4EC9B0">Qt</span><span style="color: #D4D4D4">::</span><span style="color: #4EC9B0">DisplayRole</span><span style="color: #D4D4D4">) </span><span style="color: #569CD6">const</span></span></code></pre></div>



<p class="wp-block-paragraph">So, our implementation of the method needs to take the index of the row we want (as a <code>QModelIndex</code> object) and the role of the individual data item we want (as an integer, like our convenient <code>DeviceItemRoles</code> enum), and it will return the data as a <code>QVariant</code>. With the PySide6 bindings, there is no <code>QVariant</code>. We can return whatever Python object we want, and if there&#8217;s no data at that index or with that role, we can just return <code>None</code>. A simple implementation in Python looks like:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def data(self, index, role):

    if role not in list(DeviceItemRoles):

        return None



    try:

        device = self._data&#91;index.row()&#93;

    except IndexError:

        return None



    if role in device:

        return device&#91;role&#93;

    return None</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">data</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">index</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">role</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> role </span><span style="color: #569CD6">not</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">list</span><span style="color: #D4D4D4">(DeviceItemRoles):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">None</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        device = </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data&#91;index.row()&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IndexError</span><span style="color: #D4D4D4">:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">None</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> role </span><span style="color: #569CD6">in</span><span style="color: #D4D4D4"> device:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> device&#91;role&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">None</span></span></code></pre></div>



<p class="wp-block-paragraph">There&#8217;s a little more meat here than in our <code>roleNames()</code> and <code>rowCount()</code> methods. First, we check that the role integer that was passed in is an item in our <code>DeviceItemRoles</code> enum. If it isn&#8217;t, then something is looking for a role we aren&#8217;t providing, so we&#8217;ll just return <code>None</code>.</p>



<p class="wp-block-paragraph">Next, we&#8217;ll try to get the index of the item in the list. Note that you can&#8217;t index the <code>self._data</code> list using the <code>index</code> argument directly. You need to call <code>index.row()</code>, which is a consequence of the fact that <code>QAbstract<u>List</u>Model</code> is a child of the more general <code>QAbstract<u>Item</u>Model</code> class, which is not necessarily a 1D list. If you look at the <a href="https://doc.qt.io/qt-6/qmodelindex.html"><code>QModelIndex</code></a> class, you&#8217;ll see that, in addition to <code>row()</code>, it also provides <code>column()</code>, as well as various other methods that only apply to more complex structures.</p>



<p class="wp-block-paragraph">Anyway, if the given index is out of bounds, then something is looking for an invalid row, and we return <code>None</code>. Beyond that, both the index and the role are ok, so we return the appropriate value by indexing the list to get a dictionary, and then looking up the value of the role key in that dictionary. Whatever data was stored there gets returned.</p>



<h2 class="wp-block-heading" id="h-updating-inserting-and-removing-data">Updating, Inserting, and Removing Data</h2>



<p class="wp-block-paragraph">What was implemented above is sufficient for a listmodel that will never change, but that&#8217;s probably in the minority of use cases. If you only have a small-ish amount of static data, it would probably be easier to use a <code>Repeater</code>. More likely, you&#8217;ll want to add data to your list, remove data, or change data at runtime, and <code>QAbstractListModel</code> is a much better fit in these situations. In order to manipulate our list contents, we need to understand a few additional concepts.</p>



<h2 class="wp-block-heading" id="h-signaling-changes-to-existing-row-data-from-the-application">Signaling Changes to Existing Row Data from the Application</h2>



<p class="wp-block-paragraph">In general, when we bind properties to QML, we provide a signal that we emit when the property changes. QML listens for that signal, and when it gets emitted, it calls the property getter to refresh the value. This is done by a <code>QAbstractListModel</code> by using the <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#dataChanged"><code>dataChanged</code> signal</a> provided by its parent, <code>QAbstract<u>Item</u>Model</code>, which specifies which elements of the model changed (in terms of rows, columns, and roles).</p>



<p class="wp-block-paragraph">In some cases, you need to emit this signal yourself. For example, we might want our listmodel class to have a method that <a href="https://github.com/marklocascio/qml-listmodel-example/blob/main/sample/device_listmodel.py#L73">sets all devices to &#8220;disconnected.&#8221;</a> That would look like:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def set_all_disconnected(self):

    for d in self._data:

        d&#91;DeviceItemRoles.CONNECTED&#93; = False

    self.dataChanged.emit(self.index(0), self.index(self.rowCount() - 1), [])</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">set_all_disconnected</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> d </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        d&#91;DeviceItemRoles.CONNECTED&#93; = </span><span style="color: #569CD6">False</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.dataChanged.emit(</span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.index(</span><span style="color: #B5CEA8">0</span><span style="color: #D4D4D4">), </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.index(</span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.rowCount() - </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4">), [])</span></span></code></pre></div>



<p class="wp-block-paragraph">In this method, we first loop over all items in the data list and set the <code>connected</code> value to <code>False</code>. Then, we only need to emit a single signal that says that all items in the list have changed (i.e., every index from 0 to <code>rowCount() - 1</code>). The empty list in the last parameter of the signal is a list of roles that changed, which can be left empty to indicate that all roles have changed. In this case, you can specify <code>[DeviceItemRoles.CONNECTED]</code> if you prefer. This only makes a difference if you have many roles.</p>



<h2 class="wp-block-heading" id="h-signaling-changes-to-the-collection-of-rows">Signaling Changes to the Collection of Rows</h2>



<p class="wp-block-paragraph">Even if you don&#8217;t <strong><em>change any existing data</em></strong>, you might <strong><em>add or remove entire rows</em></strong>, and QML will need to know what to update when that happens. In this case, we use a pair of methods, <code>beginInsertRows()</code> and <code>endInsertRows()</code>, to specify that we&#8217;re adding data (and how many rows we&#8217;re adding).</p>



<p class="wp-block-paragraph">Let&#8217;s say we want to add a new element to the list after the selected index. <a href="https://github.com/marklocascio/qml-listmodel-example/blob/main/sample/device_listmodel.py#L54">We can do that with a method like:</a></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def add_device_after_index(self, idx, name, serial, connected):

    index_of_new_device = idx + 1

    new_device = {

        DeviceItemRoles.NAME: name,

        DeviceItemRoles.SERIAL: serial,

        DeviceItemRoles.CONNECTED: connected

    }



    self.beginInsertRows(QModelIndex(), index_of_new_device, index_of_new_device)

    self._data.insert(index_of_new_device, new_device)

    self.endInsertRows()</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">add_device_after_index</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">idx</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">name</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">serial</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">connected</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    index_of_new_device = idx + </span><span style="color: #B5CEA8">1</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    new_device = {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        DeviceItemRoles.NAME: name,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        DeviceItemRoles.SERIAL: serial,</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        DeviceItemRoles.CONNECTED: connected</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    }</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.beginInsertRows(QModelIndex(), index_of_new_device, index_of_new_device)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data.insert(index_of_new_device, new_device)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.endInsertRows()</span></span></code></pre></div>



<p class="wp-block-paragraph"><code>beginInsertRows()</code> needs three things: the <code>QModelIndex</code> of the parent into which rows are inserted (for 1D listmodels that we&#8217;re talking about here, just give it a default one), the row number that <strong><em>the first new row will have after insertion</em></strong>, and the row number that <strong><em>the last new row will have after insertion</em></strong>. I&#8217;m never able to remember this, so I almost always consult the helpful diagrams in <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#beginInsertRows">the documentation for this method</a>.</p>



<p class="wp-block-paragraph">After that, we&nbsp;insert the new data into our list, and then we call <code>endInsertRows()</code>. The <code>beginInsertRows()</code> method handles emitting a signal for you (<code>rowsAboutToBeInserted</code>), and <code>endInsertRows()</code> handles emitting a different signal for you (<code>rowsInserted</code>) so you don’t have to emit any signals yourself! These signals are used to notify QML that it’s time to refresh the <code>ListView</code> with new rows, and which ones need to be updated (if the model contains large quantities of data, we obviously only want to update as few as possible).</p>



<h2 class="wp-block-heading" id="h-signaling-changes-to-existing-row-data-from-the-gui">Signaling Changes to Existing Row Data from the GUI</h2>



<p class="wp-block-paragraph">The final scenario we&#8217;ll discuss addresses the last part of the <code>QAbstractListModel</code> documentation on subclassing:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">For editable list models, you must also provide an implementation of <code>setData()</code>&nbsp;and implement the <code>flags()</code> function so that it returns a value containing <code>Qt::ItemIsEditable</code>.</p>
</blockquote>



<p class="wp-block-paragraph">As you can see above, if <strong><em>the application</em></strong> manipulates data in the <code>QAbstractListModel</code>, it simply needs to emit a signal (<code>dataChanged</code>) to notify QML that there&#8217;s something new. The <code>setData()</code> method is used when information goes the opposite direction, <strong><em>from the UI to the application</em></strong>. For example, say the delegate contains a checkbox. If the user clicks the checkbox in a particular row, QML needs to tell the <code>QAbstractListModel</code> that there is a new value for the checkbox&#8217;s role at a particular list index. It does this by calling the <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#setData"><code>setData()</code></a> method, which takes three arguments: the <code>index</code>, the new <code>value</code>, and the <code>role</code>. It will look very similar to the <code>data()</code> method above, perhaps like:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#1e1e1e"><span style="background:#c7c7c7;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#1e1e1e">Python</span></span><span role="button" tabindex="0" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>def setData(self, index, value, role):

    if role != MyRoleEnum.SOME_EDITABLE_ROLE:

        return False



    try:

        data_row = self._data_list&#91;index.row()&#93;

    except IndexError:

        return False



    data_row&#91;MyRoleEnum.SOME_EDITABLE_ROLE&#93; = value

    self.dataChanged.emit(index, index, &#91;MyRoleEnum.SOME_EDITABLE_ROLE&#93;)

    return True</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #569CD6">def</span><span style="color: #D4D4D4"> </span><span style="color: #DCDCAA">setData</span><span style="color: #D4D4D4">(</span><span style="color: #9CDCFE">self</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">index</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">value</span><span style="color: #D4D4D4">, </span><span style="color: #9CDCFE">role</span><span style="color: #D4D4D4">):</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> role != MyRoleEnum.SOME_EDITABLE_ROLE:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">False</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">try</span><span style="color: #D4D4D4">:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        data_row = </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">._data_list&#91;index.row()&#93;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">except</span><span style="color: #D4D4D4"> </span><span style="color: #4EC9B0">IndexError</span><span style="color: #D4D4D4">:</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">False</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    data_row&#91;MyRoleEnum.SOME_EDITABLE_ROLE&#93; = value</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #569CD6">self</span><span style="color: #D4D4D4">.dataChanged.emit(index, index, &#91;MyRoleEnum.SOME_EDITABLE_ROLE&#93;)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">return</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">True</span></span></code></pre></div>



<p class="wp-block-paragraph">In short, you use the <code>index</code> and <code>role</code> arguments to find the data you’re looking for in the model, you set that data to the new <code>value</code>, and then you emit <code>dataChanged</code>.</p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p class="wp-block-paragraph">The <code>QAbstract<u>List</u>Model</code> (and its base class, <code>QAbstract<u>Item</u>Model</code>) is a powerful way to present a list of data to a user interface, but the extensive abstraction can make the documentation hard to parse. A <a href="https://github.com/marklocascio/qml-listmodel-example">simple example</a> should help clarify, as well as a small number of important concepts:</p>



<ul class="wp-block-list">
<li>Many of <code>QAbstract<u>List</u>Model</code>&#8216;s methods are inherited from its base classes, and consequently involve a parent <code>QModelIndex</code> that doesn&#8217;t apply to a simple list and can be very confusing.</li>



<li>A &#8220;role&#8221; is simply a way to specify individual pieces of data in a list item.</li>



<li>Roles can be used to make a list seem like a table, and that&#8217;s fine&#8230; you can still use <code>QAbstractListModel</code>!</li>



<li>When adding items to the list or removing items from it, call the <code>beginInsertRows()</code> and <code>endInsertRows()</code> methods before making your changes, and the correct signals will be emitted for you at the right times.</li>



<li>If your application updates the model by changing data in an existing item in the list (or multiple existing items in the list), make sure you emit the <a href="https://doc.qt.io/qt-6/qabstractitemmodel.html#dataChanged"><code>dataChanged</code> signal</a> after the changes are made to notify QML that it needs to update its views.</li>



<li>If the user interacts with the QML UI and modifies data in the model, you will need to implement <code>setData()</code> to store the new information in the model object, and then you will need to emit <code>dataChanged.</code></li>
</ul>



<h2 class="wp-block-heading" id="h-building-a-qt-app">Building a Qt app?</h2>



<p class="wp-block-paragraph">I&#8217;d love to help! Give us a call or <a href="mailto:sales@localhost?subject=Let's%20build%20a%20Qt%20app!">send us an email</a> to discuss!&nbsp;</p>



<p class="wp-block-paragraph"><strong>Learn more about our&nbsp;<a href="https://static.dmcinfo.com/services/application-development">Application Development</a>&nbsp;expertise and&nbsp;<a href="https://static.dmcinfo.com/contact#get-in-touch">contact us</a>&nbsp;for your next project.</strong></p>
<p>The post <a href="https://static.dmcinfo.com/blog/17671/using-a-qabstractlistmodel-in-qml/">Using a QAbstractListModel in QML</a> appeared first on <a href="https://static.dmcinfo.com/">DMC, Inc.</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
