<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>KDAB</title><description>Global software consultancy specialising in Qt, C++, Rust, Slint and Embedded Linux. Consulting, development, training and open-source tools since 1999.</description><link>https://www.kdab.com/</link><language>en-gb</language><item><title>Bind QML Values across an Arbitrary Number of Elements</title><link>https://www.kdab.com/bind-qml-values-across-an-arbitrary-number-of-elements/</link><guid isPermaLink="true">https://www.kdab.com/bind-qml-values-across-an-arbitrary-number-of-elements/</guid><description>&lt;p data-block-key=&quot;rlqes&quot;&gt;Synchronize properties across dynamically instantiated QML elements, using a C++ singleton that acts as a message broker and recursive signal-slot connections. This design enables flexible and scalable value synchronization across components, with minimal coupling between UI and logic.&lt;/p&gt;</description><pubDate>Thu, 19 Mar 2026 08:26:39 GMT</pubDate><content:encoded>&lt;h1&gt;Bind QML Values across an Arbitrary Number of Elements&lt;/h1&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;gg3t3&quot;&gt;A while back I was writing a program that could instantiate an arbitrary number of windows containing controls synchronized across them. How a control would be synchronized would depend on a condition that determined which window instances would be linked to other instances. There are a few ways this could be implemented. In this entry I&apos;ll share my approach, in which I used a singleton C++ class serving as a message broker to bind properties across window instances.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-50 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Properties bound across multiple instances of a window_1_QML_Blog_Javier&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Properties_bound_across_multiple_instances_of_a.original.jpg&quot; class=&quot;Properties bound across multiple instances of a window_1_QML_Blog_Javier&quot; alt=&quot;Properties bound across multiple instances of a window_1_QML_Blog_Javier&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;gjgxd&quot;&gt;Properties bound across multiple instances of a window&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;the-app:-display-to-light-panels&quot; data-block-key=&quot;4wd6v&quot;&gt;The App: Display to Light Panels&lt;/h2&gt;&lt;p data-block-key=&quot;770kf&quot;&gt;The software I wrote this for is a small app that allows you to have many windows open, all synchronized to display a single color on a per-monitor basis. The idea behind this is for users to adjust the light that comes off their monitors and use it to illuminate their faces when recording a video or taking pictures. By having individual windows be synchronized, users can continue to interact with the computer through their displays (rather inconveniently), while simultaneously using them to illuminate themselves.&lt;/p&gt;&lt;p data-block-key=&quot;clvra&quot;&gt;This is, by no means, a replacement for a proper recording setup. Some of you will know that a light source placed in front of the subject can serve as either a nice &quot;fill light&quot; or a &quot;scary spotlight&quot;, depending on the height and size of the source. Therefore, this should be complemented with other sources of light; ideally ambient light and a top light, to achieve a nice look. If the app seems useful to you, there&apos;s a link to it at the end of this article. That&apos;s enough gaffer speak for today. Let&apos;s talk about the code.&lt;/p&gt;&lt;h2 id=&quot;the-code&quot; data-block-key=&quot;4ug9g&quot;&gt;The Code&lt;/h2&gt;&lt;p data-block-key=&quot;6u7bp&quot;&gt;When writing code, one of my main concerns is always long-term maintainability. For that reason, I prefer to connect different parts of code in explicit, and easy to follow ways. One of such ways is passing values through a hierarchy of components; that is generally easy to track and produces well performing code. However, that approach can become unviable when connecting dynamically instantiated items to other dynamically instantiated items. A better solution in this instance is to use signals and slots to interconnect the items via a message broker class, done in C++. Each item would have a model or backend class in C++ and those classes would have the message broker in common. Lastly, the properties would be exposed to QML through &lt;code&gt;Q_PROPERTY&lt;/code&gt; and updated via your control&apos;s signal handlers.&lt;/p&gt;&lt;h2 id=&quot;message-broker-singleton&quot; data-block-key=&quot;01urs&quot;&gt;Message Broker Singleton&lt;/h2&gt;&lt;p data-block-key=&quot;fa272&quot;&gt;The message broker needs to be a singleton. That way there&apos;s only one instance of the broker in memory and all instantiated objects interface with the same broker. Our message broker only needs to provide the signals that will be used for routing properties. The actual connections that the routing involves are to be done from the outside. As such, a broker class would look like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// internalmessagebroker.hpp
// Singleton broker class contains signals that serve as pipes
// for different parts of a program to communicate with each other.

#pragma once

#include &amp;lt;QObject&amp;gt;

class InternalMessageBroker : public QObject
{
    Q_OBJECT

// Hide regular constructor
private:
    InternalMessageBroker() = default;

public:
    // Disable copy constructor
    InternalMessageBroker(const InternalMessageBroker&amp;amp; obj) = delete;
    InternalMessageBroker&amp;amp; operator=(InternalMessageBroker const&amp;amp;) = delete;
    static std::shared_ptr&amp;lt;InternalMessageBroker&amp;gt; instance()
    {
        static std::shared_ptr&amp;lt;InternalMessageBroker&amp;gt; sharedPtr{new InternalMessageBroker};
        return sharedPtr;
    }

// This is where all the signals would go
signals:
    void broadcastAPropertyChange(int value, bool broadcast);
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;connecting-properties&quot; data-block-key=&quot;qnyhk&quot;&gt;Connecting Properties&lt;/h2&gt;&lt;p data-block-key=&quot;57h0&quot;&gt;Then we have the class or classes that would connect the properties together. On my Display Panels app, all controls and visual features come from QML, meaning I only have to concern myself with interconnecting the properties. To that end, I&apos;ve created a class based on &lt;code&gt;QObject&lt;/code&gt; and instantiated it within the delegate of a QML Instantiator. This class is only for managing property data, so I refer to it as a model class, called &lt;code&gt;PropertiesModel&lt;/code&gt;:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-qml  line-numbers &quot;&gt;// Main.qml
// Here are 3 windows, each with a PropertiesModel,
// that allows them all to share a binding to aProperty
// across all window instantiatons.

import QtQuick
import QtQuick.Window
import QtQuick.Layouts
import QtQuick.Controls

import com.kdab.example

Item {
    Instantiator {
        model: 3
        delegate: Window {
            PropertiesModel {
                id: propertiesModel
                aProperty: 1
            }
            ColumnLayout {
                anchors.fill: parent
                Text {
                    text: propertiesModel.aProperty
                }
                Slider {
                    id: hueSlider
                    value: propertiesModel.aProperty
                    Layout.fillWidth: true
                    onMoved: {
                        propertiesModel.aProperty = value;
                    }
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;669ti&quot;&gt;Each property of our class is to be declared using a &lt;code&gt;Q_PROPERTY&lt;/code&gt; macro with a getter, a setter, and a notifier. The getter and the notifier have nothing out of the ordinary...&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// An ordinary getter
int PropertiesModel::aProperty()
{
    return m_aProperty;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;




&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// An ordinary notifier, form propertiesmodel.h
signals:
    void aPropertyChanged();&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;669ti&quot;&gt;However, the setter must be able to distinguish between when its call is the product of a user interaction and when it comes from the message broker. We accomplish this by having the setter accept a boolean argument (broadcast) that will be used to determine whether the value being set should be sent through the message broker or notified back to QML for the UI to be updated. When a setter is first called, the value being set should be broadcasted and only on its way back should the UI be updated.&lt;/p&gt;&lt;p data-block-key=&quot;7krnb&quot;&gt;There are a few ways we could make sure that the value is always broadcasted first. We could set broadcast to true by default, or have two setter functions: a private one taking in both the value and broadcast arguments and a public one that only takes-in the value and calls the private function with broadcast set to true. Another option is to have broadcast be an enum with only two possible values. That would produce more readable code, however, I didn&apos;t worry about that in my code because broadcast is only to be used on calls to the private setter.&lt;/p&gt;&lt;p data-block-key=&quot;2ij84&quot;&gt;Upon the private setter being called by the public setter, it will emit the broker&apos;s broadcast signal and that signal will in turn call the calling private setter for a second time (as well as the private setters of all other instances of &lt;code&gt;PropertiesModel&lt;/code&gt;; those being called for the first time). When the private setter calls the broker that calls back to the private setter, it also passes broadcast set to false. All other instances will then evaluate the value of broadcast to be false determining that the UIs should be updated and preventing an infinite loop.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// Private setter implementation for a property that&amp;#x27;s being broadcasted
void PropertiesModel::setAProperty(const int value, const bool broadcast)
{
    if (broadcast)
        emit m_broker.get()-&amp;gt;broadcastAPropertyChange(value, false);
    else if (m_currentScreen == screenName) {
        m_aProperty = value;
        emit screenSaturationChanged();
    }
}

// Publicly exposed setter prevents the broadcast argument from being
// specified by other callers
void PropertiesModel::setAProperty(const int value)
{
    // Always broadcast properties not being set by the message broker
    setAProperty(value, true);
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;669ti&quot;&gt;To complete this loop as described, we need to connect the signal from the broker to the private setter of the &lt;code&gt;PropertiesModel&lt;/code&gt; class whenever a new copy is instantiated. The best place to accomplish that is from the class&apos; constructor, like so:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// The constructor is used to connect signals from the broker to setter properties
PropertiesModel::PropertiesModel(QObject* parent)
    : QObject { parent }
{
    m_mb = InternalMessageBroker::instance();
    // Connections take place after the class has been instantiated
    // and its QML properties parsed.
    QTimer::singleShot(0, this, [this] () {
        connect(m_mb.get(), &amp;amp;InternalMessageBroker::aPropertyChange,
        this, &amp;amp;ScreenModel::setAProperty);
    });
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;qtimer-to-delay-initialization&quot; data-block-key=&quot;f44wk&quot;&gt;QTimer to Delay Initialization&lt;/h2&gt;&lt;p data-block-key=&quot;7r9tu&quot;&gt;If you&apos;ve been reading the blocks of code that accompany this article, you may be wondering &quot;Why is there a &lt;code&gt;singleShot&lt;/code&gt; &lt;code&gt;QTimer&lt;/code&gt; there?&quot; When the &lt;code&gt;PropertiesModel&lt;/code&gt; class is instantiated via QML, any connected properties that have values assigned from QML code will trigger the &lt;code&gt;Q_PROPERTY&lt;/code&gt;&apos;s setter function. This will happen once per instantiation. If the broker were connected, it would broadcast the value set to all currently instantiated instances every single time that a new instance is added. To prevent that, we must not make the connection to the broker until after a class has been fully initialized. A single shot timer can be used to accomplish that; setting its delay to 0 will ensure that it is run immediately after all properties have been evaluated.&lt;/p&gt;&lt;p data-block-key=&quot;dlka2&quot;&gt;In the end, this is what the &lt;code&gt;PropertyMode&lt;/code&gt;l header would look like:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// propertiesmodel.h
#pragma once

#include &amp;quot;internalmessagebroker.hpp&amp;quot;

#include &amp;lt;QQmlEngine&amp;gt;

class PropertiesModel : public QObject {
    Q_OBJECT
    QML_ELEMENT

    Q_PROPERTY(int aProperty READ aProperty WRITE setAProperty NOTIFY aPropertyChanged FINAL)
public:
    explicit PropertiesModel(QObject* parent = nullptr);

    int aProperty();
    void setAProperty(const int value);

signals:
    void aPropertyChanged();

private: 
    void setAProperty(const int value, const bool broadcast);

    std::shared_ptr&amp;lt;InternalMessageBroker&amp;gt; m_mb;
    int m_aProperty;
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;conditional-propagation&quot; data-block-key=&quot;0xkmg&quot;&gt;Conditional propagation&lt;/h2&gt;&lt;p data-block-key=&quot;aoaf7&quot;&gt;If a condition must be met for the propagated value to result in an update, then, in addition to &lt;i&gt;value&lt;/i&gt; and &lt;i&gt;broadcast&lt;/i&gt;, you should also broadcast any other values that are required to for such condition to be met. Pass those as arguments to the setter&apos;s and the broker&apos;s signal. Condition validation would then take place within the base case of the private setter. Here&apos;s a commented snippet of what that looks like on the Display to Light Panels app that this article was based on:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// In the original code what here I named broadcast used to be named spread.
void ScreenModel::setScreenHue(const int hue, const bool spread=true, const QString &amp;amp;screenName=&amp;quot;s&amp;quot;)
{
    if (spread)
        emit m_mb.get()-&amp;gt;spreadHueChange(hue, false, m_currentScreen);
    // The incoming value is only accepted if screenName matches the screen
    // that the window is at and discarded otherwise.
    else if (m_currentScreen == screenName) {
        m_screens[m_currentScreen].hue = hue;
        emit screenHueChanged();
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;




&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-50 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Properties bound across instances of a window_2_QML_Blog_Javier&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Properties_bound_across_instances_of_a_window.original.jpg&quot; class=&quot;Properties bound across instances of a window_2_QML_Blog_Javier&quot; alt=&quot;Properties bound across instances of a window_2_QML_Blog_Javier&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;gjgxd&quot;&gt;Properties bound across instances of a window&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;real-world-example&quot; data-block-key=&quot;fgh11&quot;&gt;Real World Example&lt;/h2&gt;&lt;p data-block-key=&quot;cbkgp&quot;&gt;For a real world application, you can read the code for Display to Light Panels, the app that inspired this article, at: &lt;a href=&quot;https://github.com/Cuperino/Display-to-Light-Panels&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://github.com/Cuperino/Display-to-Light-Panels&lt;/a&gt;&lt;/p&gt;&lt;p data-block-key=&quot;82jef&quot;&gt;If you need help solving architecture problems, such as this one, reach out to us and we will gladly find ways in which we can help.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/bind-qml-values-across-an-arbitrary-number-of-elements/&quot;&gt;Bind QML Values across an Arbitrary Number of Elements&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>c++</category><category>desktop</category><category>qml</category><category>qt</category><category>ux/ui</category></item><item><title>Automating Repetitive GUI Interactions in Embedded Development with Spix</title><link>https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/</link><guid isPermaLink="true">https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/</guid><description>&lt;p data-block-key=&quot;k9ick&quot;&gt;This blog post showcases Spix, a small but useful library for automating GUI-interaction in your Qt/QML-based applications. Just sending clicks or entering text to checking properties, Spix offers basic automated interaction. Combining the automated screenshot function with computer vision, you can even perform simple optical checks with Spix.&lt;/p&gt;</description><pubDate>Thu, 19 Feb 2026 08:18:12 GMT</pubDate><content:encoded>&lt;h1&gt;Automating Repetitive GUI Interactions in Embedded Development with Spix&lt;/h1&gt;
&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot;&gt;
        &lt;div class=&quot;image-variable-size-image&quot;&gt;
            &lt;img src=&quot;https://www.kdab.com/documents/2023-07-05-18-08-38-small_1.gif&quot; alt=&quot;2023-07-05-18-08-38-small_Blog_Christoph_Spix&quot;&gt;
        &lt;/div&gt;

        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;r7hie&quot;&gt;As Embedded Software Developers, we all know the pain: you make a code change, rebuild your project, restart the application - and then spend precious seconds repeating the same five clicks just to reach the screen you want to test. Add a login dialog on top of it, and suddenly those seconds turn into minutes. Multiply that by a hundred iterations per day, and it’s clear: this workflow is frustrating, error-prone, and a waste of valuable development time.&lt;/p&gt;&lt;p data-block-key=&quot;5kds4&quot;&gt;In this article, we’ll look at how to automate these repetitive steps using &lt;a href=&quot;https://github.com/faaxm/spix&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Spix&lt;/a&gt;, an open-source tool for GUI automation in Qt/QML applications. We’ll cover setup, usage scenarios, and how Spix can be integrated into your workflow to save hours of clicking, typing, and waiting.&lt;/p&gt;&lt;h2 id=&quot;the-problem:-click-fatigue-in-gui-testing&quot; data-block-key=&quot;ght5m&quot;&gt;The Problem: Click Fatigue in GUI Testing&lt;/h2&gt;&lt;p data-block-key=&quot;djqar&quot;&gt;Imagine this:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;1tiuj&quot;&gt;You start your application.&lt;/li&gt;&lt;li data-block-key=&quot;4ths2&quot;&gt;The login screen appears.&lt;/li&gt;&lt;li data-block-key=&quot;dii9m&quot;&gt;You enter your username and password.&lt;/li&gt;&lt;li data-block-key=&quot;d80kp&quot;&gt;You click &quot;Login&quot;.&lt;/li&gt;&lt;li data-block-key=&quot;78ntm&quot;&gt;Only then do you finally reach the UI where you can verify whether your code changes worked.&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;9hpm3&quot;&gt;This is fine the first few times - but if you’re doing it 100+ times a day, it becomes a serious bottleneck. While features like &lt;b&gt;hot reload&lt;/b&gt; can help in some cases, they aren’t always applicable - especially when structural changes are involved or when you must work with &quot;real&quot; production data.&lt;/p&gt;&lt;p data-block-key=&quot;1mabg&quot;&gt;So, what’s the alternative?&lt;/p&gt;&lt;h2 id=&quot;the-solution:-automating-gui-input-with-spix&quot; data-block-key=&quot;3ymr9&quot;&gt;The Solution: Automating GUI Input with Spix&lt;/h2&gt;&lt;p data-block-key=&quot;5e5pv&quot;&gt;&lt;a href=&quot;https://github.com/faaxm/spix&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Spix&lt;/a&gt; allows you to control your Qt/QML applications programmatically. Using scripts (typically Python), you can automatically:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;76u3q&quot;&gt;Insert text into input fields&lt;/li&gt;&lt;li data-block-key=&quot;eajkm&quot;&gt;Click buttons&lt;/li&gt;&lt;li data-block-key=&quot;699mb&quot;&gt;Wait for UI elements to appear&lt;/li&gt;&lt;li data-block-key=&quot;c7j6r&quot;&gt;Take and compare screenshots&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;e3mi6&quot;&gt;This means you can automate login steps, set up UI states consistently, and even extend your CI pipeline with &lt;b&gt;visual testing&lt;/b&gt;. Unlike manual hot reload tweaks or hardcoding start screens, Spix provides an &lt;b&gt;external, scriptable solution&lt;/b&gt; without altering your application logic.&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;setting-up-spix-in-your-project&quot; data-block-key=&quot;awzjs&quot;&gt;Setting up Spix in Your Project&lt;/h2&gt;&lt;p data-block-key=&quot;bu5nk&quot;&gt;Getting Spix integrated requires a few straightforward steps:&lt;/p&gt;&lt;h3 id=&quot;1.-add-spix-as-a-dependency&quot; data-block-key=&quot;pp4qw&quot;&gt;1. &lt;b&gt;Add Spix as a dependency&lt;/b&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li data-block-key=&quot;cs1gu&quot;&gt;Typically done via a Git submodule into your project’s third-party folder.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-bash  line-numbers &quot;&gt;git submodule add 3rdparty/spix git@github.com:faaxm/spix.git&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;2.-register-spix-in-cmake&quot; data-block-key=&quot;swc4s&quot;&gt;2.&lt;b&gt; Register Spix in CMake&lt;/b&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li data-block-key=&quot;78qpm&quot;&gt;Update your &lt;code&gt;CMakeLists.txt&lt;/code&gt; with a &lt;code&gt;find_package(Spix REQUIRED)&lt;/code&gt; call.&lt;/li&gt;&lt;li data-block-key=&quot;5ec9b&quot;&gt;Because of CMake quirks, you may also need to manually specify the path to Spix’s CMake modules.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cmake  line-numbers &quot;&gt;LIST(APPEND CMAKE_MODULE_PATH /home/christoph/KDAB/spix/cmake/modules)
find_package(Spix REQUIRED)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;3.-link-against-spix&quot; data-block-key=&quot;m3xad&quot;&gt;3.&lt;b&gt; Link against Spix&lt;/b&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li data-block-key=&quot;7cv8c&quot;&gt;Add &lt;code&gt;Spix&lt;/code&gt; to your &lt;code&gt;target_link_libraries&lt;/code&gt; call.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cmake  line-numbers &quot;&gt;target_link_libraries(myApp
  PRIVATE Qt6::Core
          Qt6::Quick 
          Qt6::SerialPort 
          Spix::Spix
)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;4.-initialize-spix-in-your-application&quot; data-block-key=&quot;odvmk&quot;&gt;4.&lt;b&gt; Initialize Spix in your application&lt;/b&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li data-block-key=&quot;1q365&quot;&gt;Include Spix headers in &lt;code&gt;main.cpp&lt;/code&gt;.&lt;/li&gt;&lt;li data-block-key=&quot;d95bc&quot;&gt;Add some lines of boilerplate code:&lt;ul&gt;&lt;li data-block-key=&quot;2ljlr&quot;&gt;Include the 2 Spix Headers (AnyRPCServer for Communication and QtQmlBot)&lt;/li&gt;&lt;li data-block-key=&quot;b2ora&quot;&gt;Start the Spix RPC server.&lt;/li&gt;&lt;li data-block-key=&quot;d3th0&quot;&gt;Create a &lt;code&gt;Spix::QtQmlBot&lt;/code&gt;.&lt;/li&gt;&lt;li data-block-key=&quot;7rom3&quot;&gt;Run the test server on a specified port (e.g. &lt;code&gt;9000&lt;/code&gt;).&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;#include &amp;lt;Spix/AnyRpcServer.h&amp;gt;
#include &amp;lt;Spix/QtQmlBot.h&amp;gt;
[...]

//Start the actual Runner/Server
spix::AnyRpcServer server;
auto bot = new spix::QtQmlBot();
bot-&amp;gt;runTestServer(server);&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;idubt&quot;&gt;At this point, your application is &quot;Spix-enabled&quot;. You can verify this by checking for the open port (e.g. &lt;code&gt;localhost:9000&lt;/code&gt;).&lt;/p&gt;&lt;/div&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;p&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;or7ol&quot;&gt;Spix can be a Security Risk: Make sure to not expose Spix in any production environment, maybe only enable it for your Debug-builds.&lt;/p&gt;&lt;/div&gt;&lt;/p&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;where-spix-shines&quot; data-block-key=&quot;c0rsv&quot;&gt;Where Spix Shines&lt;/h2&gt;&lt;p data-block-key=&quot;5fkof&quot;&gt;Once the setup is done, Spix can be used to automate repetitive tasks. Let’s look at two particularly useful examples:&lt;/p&gt;&lt;h3 id=&quot;1.-automating-logins-with-a-python-script&quot; data-block-key=&quot;0n0mj&quot;&gt;1. Automating Logins with a Python Script&lt;/h3&gt;&lt;p data-block-key=&quot;38fq4&quot;&gt;Instead of typing your credentials and clicking &quot;Login&quot; manually, you can write a simple Python script that:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;fvros&quot;&gt;Connects to the Spix server on &lt;code&gt;localhost:9000&lt;/code&gt;&lt;/li&gt;&lt;li data-block-key=&quot;f286n&quot;&gt;Inputs text into the &lt;code&gt;userField&lt;/code&gt; and &lt;code&gt;passwordField&lt;/code&gt;&lt;/li&gt;&lt;li data-block-key=&quot;9ft5u&quot;&gt;Clicks the &quot;Login&quot; button (Items marked with &quot;Quotes&quot; are literal That-Specific-Text-Identifiers for Spix)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-python  line-numbers &quot;&gt;import xmlrpc.client

session = xmlrpc.client.ServerProxy(&amp;#x27;http://localhost:9000&amp;#x27;)

session.inputText(&amp;#x27;mainWindow/userField&amp;#x27;, &amp;#x27;christoph&amp;#x27;)
session.inputText(&amp;#x27;mainWindow/passwordField&amp;#x27;, &amp;#x27;secret&amp;#x27;) 
session.mouseClick(&amp;#x27;mainWindow/&amp;quot;Login&amp;quot;&amp;#x27;)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;6qw4v&quot;&gt;When executed, this script takes care of the entire login flow - no typing, no clicking, no wasted time. Better yet, you can check the script into your repository, so your whole team can reuse it.&lt;/p&gt;&lt;p data-block-key=&quot;f3qad&quot;&gt;For Development, Integration in Qt-Creator can be achieved with a Custom startup executable, that also starts this python script.&lt;/p&gt;&lt;/div&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;p&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;yoeyx&quot;&gt;In a CI environment, this approach is particularly powerful, since you can ensure every test run starts from a clean state without relying on manual navigation.&lt;/p&gt;&lt;/div&gt;&lt;/p&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;2.-screenshot-comparison&quot; data-block-key=&quot;fzpkt&quot;&gt;2. Screenshot Comparison&lt;/h3&gt;&lt;p data-block-key=&quot;bf9dk&quot;&gt;Beyond input automation, Spix also supports &lt;b&gt;taking screenshots&lt;/b&gt;. Combined with Python libraries like OpenCV or &lt;code&gt;scikit-image&lt;/code&gt;, this opens up interesting possibilities for testing.&lt;/p&gt;&lt;h4 id=&quot;example-1:-full-screen-comparison&quot; data-block-key=&quot;ovfo0&quot;&gt;Example 1: Full-screen comparison&lt;/h4&gt;&lt;p data-block-key=&quot;4n3v3&quot;&gt;Take a screenshot of the main window and store it first:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-python  line-numbers &quot;&gt;import xmlrpc.client

session = xmlrpc.client.ServerProxy(&amp;#x27;http://localhost:9000&amp;#x27;)

[...]
session.takeScreenshot(&amp;#x27;mainWindow&amp;#x27;, &amp;#x27;/tmp/screenshot.png&amp;#x27;)k&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;6qw4v&quot;&gt;Now we can compare it with a reference image:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-python  line-numbers &quot;&gt;from skimage import io
from skimage.metrics import structural_similarity as ssim

screenshot1 = io.imread(&amp;#x27;/tmp/reference.png&amp;#x27;, as_gray=True)
screenshot2 = io.imread(&amp;#x27;/tmp/screenshot.png&amp;#x27;, as_gray=True)

ssim_index = ssim(screenshot1, screenshot2, data_range=screenshot1.max() - screenshot1.min())

threshold = 0.95

if ssim_index == 1.0: 
    print(&amp;quot;The screenshots are a perfect match&amp;quot;)
elif ssim_index &amp;gt;= threshold:
    print(&amp;quot;The screenshots are similar, similarity: &amp;quot; + str(ssim_index * 100) + &amp;quot;%&amp;quot;)
else:
    print(&amp;quot;The screenshots are not similar at all, similarity: &amp;quot; + str(ssim_index * 100) + &amp;quot;%&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;6qw4v&quot;&gt;This is useful for catching unexpected regressions in visual layout.&lt;/p&gt;&lt;h4 id=&quot;example-2:-finding-differences-in-the-same-ui&quot; data-block-key=&quot;0zrg1&quot;&gt;Example 2: Finding differences in the same UI&lt;/h4&gt;&lt;p data-block-key=&quot;fsbra&quot;&gt;Use OpenCV to highlight pixel-level differences between two screenshots—for instance, missing or misaligned elements:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-python  line-numbers &quot;&gt;import cv2

image1 = cv2.imread(&amp;#x27;/tmp/reference.png&amp;#x27;)
image2 = cv2.imread(&amp;#x27;/tmp/screenshot.png&amp;#x27;)

diff = cv2.absdiff(image1, image2)

# Convert the difference image to grayscale
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)

# Threshold the grayscale image to get a binary image
_, thresh = cv2.threshold(gray, 30, 255, cv2.THRESH_BINARY)

contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image1, contours, -1, (0, 0, 255), 2)

cv2.imshow(&amp;#x27;Difference Image&amp;#x27;, image1)
cv2.waitKey(0)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;6qw4v&quot;&gt;This form of &lt;b&gt;visual regression testing&lt;/b&gt; can be integrated into your CI system. If the UI changes unintentionally, Spix can detect it and trigger an alert.&lt;/p&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;1024-637_Blog_Christoph_Spix&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/1024-637_1.original.png&quot; class=&quot;1024-637_Blog_Christoph_Spix&quot; alt=&quot;1024-637_Blog_Christoph_Spix&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;2759c&quot;&gt;Defective Image&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;1024-639_Blog_Christoph_Spix&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/1024-639_1.original.png&quot; class=&quot;1024-639_Blog_Christoph_Spix&quot; alt=&quot;1024-639_Blog_Christoph_Spix&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;2759c&quot;&gt;The script marked the defective parts of the image compared to the should-be image.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;recap&quot; data-block-key=&quot;j3bi4&quot;&gt;Recap&lt;/h2&gt;&lt;p data-block-key=&quot;398cv&quot;&gt;&lt;a href=&quot;https://github.com/faaxm/spix&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Spix&lt;/a&gt; is not a full-blown GUI testing framework like Squish, but it fills a useful niche for embedded developers who want to:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;30u8&quot;&gt;Save time on repetitive input (like logins).&lt;/li&gt;&lt;li data-block-key=&quot;2l6p7&quot;&gt;Share reproducible setup scripts with colleagues.&lt;/li&gt;&lt;li data-block-key=&quot;ba5ar&quot;&gt;Perform lightweight visual regression testing in CI.&lt;/li&gt;&lt;li data-block-key=&quot;3s1sr&quot;&gt;Interact with their applications on embedded devices remotely.&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;9as1q&quot;&gt;While there are limitations (e.g. manual wait times, lack of deep synchronization with UI states), Spix provides a powerful and flexible way to automate everyday development tasks - without having to alter your application logic.&lt;/p&gt;&lt;p data-block-key=&quot;8pqgh&quot;&gt;If you’re tired of clicking the same buttons all day, give Spix a try. It might just save you hours of time and frustration in your embedded development workflow.&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/WTYl4wHL0NI?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;GUI Automation and Testing with Spix&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;


&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/&quot;&gt;Automating Repetitive GUI Interactions in Embedded Development with Spix&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>python</category><category>qt</category><category>tools</category></item><item><title>AI Coding with Qt: Qt AI Assistant for Qt Creator</title><link>https://www.kdab.com/ai-coding-with-qt-qt-ai-assistant-for-qt-creator/</link><guid isPermaLink="true">https://www.kdab.com/ai-coding-with-qt-qt-ai-assistant-for-qt-creator/</guid><description>&lt;p data-block-key=&quot;bxmpy&quot;&gt;The integration of artificial intelligence into software development environments has rapidly evolved, and Qt Creator is no exception. With the introduction of the &lt;a href=&quot;https://www.qt.io/product/ai-assistant&quot;&gt;Qt AI Assistant&lt;/a&gt; by Qt Company, developers working with Qt Creator now have access to AI models through the IDE. This post provides an introduction to the Qt Creator plugin.&lt;/p&gt;&lt;p data-block-key=&quot;ek5fc&quot;&gt;This is part 1 of an ongoing series about AI coding with Qt.&lt;/p&gt;</description><pubDate>Wed, 20 Aug 2025 06:38:08 GMT</pubDate><content:encoded>&lt;h1&gt;AI Coding with Qt: Qt AI Assistant for Qt Creator&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;bny45&quot;&gt;The integration of artificial intelligence into software development environments has rapidly evolved, and &lt;a href=&quot;https://www.qt.io/product/development-tools&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Qt Creator&lt;/a&gt; is no exception. With the introduction of the &lt;a href=&quot;https://www.qt.io/product/ai-assistant&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Qt AI Assistant&lt;/a&gt; by Qt Company, developers working with Qt Creator now have access to AI models through the IDE. This post provides an introduction to the Qt Creator plugin.&lt;/p&gt;&lt;p data-block-key=&quot;5115r&quot;&gt;This is part 1 of an ongoing series about AI coding with Qt.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;what-is-qt-ai-assistant&quot; data-block-key=&quot;3zkpk&quot;&gt;What is Qt AI Assistant?&lt;/h2&gt;&lt;p data-block-key=&quot;83kcj&quot;&gt;Qt AI Assistant is a commercial plugin for Qt Creator to bring current AI models to the IDE. Features provided by the plugin include&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;ct7hf&quot;&gt;&lt;b&gt;Code completion&lt;/b&gt; for multiple languages (QML, C++, Python, Bash, etc.)&lt;/li&gt;&lt;li data-block-key=&quot;1jvkm&quot;&gt;&lt;b&gt;Contextual chat&lt;/b&gt; with your codebase, enabling explanations, code generation and code review&lt;/li&gt;&lt;li data-block-key=&quot;dothc&quot;&gt;&lt;b&gt;Automated test case generation&lt;/b&gt;, particularly tailored for QML and Qt-specific workflows&lt;/li&gt;&lt;li data-block-key=&quot;cp2eb&quot;&gt;&lt;b&gt;Model choice&lt;/b&gt; based on languages (QML vs other languages) and task (chat vs code completion)&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;1scob&quot;&gt;This is a step up from the existing GitHub Copilot support in Qt Creator that was focused on code completion only.&lt;/p&gt;&lt;p data-block-key=&quot;7tlr6&quot;&gt;Completing Qt AI Assistant is a publicly available &lt;a href=&quot;https://huggingface.co/QtGroup/models?sort=alphabetical&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;set of models&lt;/a&gt; by Qt Group. The models are based on CodeLlama and &lt;a href=&quot;https://www.qt.io/blog/codellama-13b-qml-released-on-hugging-face&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;are fine-tuned for usage with Qt 6 QML&lt;/a&gt;. They are not included with the plugin but need to be set up manually using Ollama.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;setting-up-qt-ai-assistant&quot; data-block-key=&quot;t77w3&quot;&gt;Setting Up Qt AI Assistant&lt;/h2&gt;&lt;p data-block-key=&quot;6brmo&quot;&gt;The setup process for Qt AI Assistant is more involved than some other AI coding tools. The plugin is currently available as part of the commercial Qt distribution. Installation requires enabling the appropriate extension repository within Qt Creator and activating the plugin. Once installed, configuration is necessary to connect the plugin to a large language model (LLM) provider.&lt;/p&gt;&lt;p data-block-key=&quot;2nia0&quot;&gt;Supported LLMs include OpenAI (ChatGPT), Anthropic (Claude), Google (Gemini), and self-hosted models via Ollama. For OpenAI integration, developers must use the OpenAI developer platform to generate an API key, which is different from having an account for ChatGPT. This API key is then entered into the plugin’s settings within Qt Creator. Other models require similar setup using URLs and credentials, depending on the provider or the self-hosting method.&lt;/p&gt;&lt;p data-block-key=&quot;98vld&quot;&gt;More information is in this video linked at the bottom of this blog post.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;features-in-practice&quot; data-block-key=&quot;4xcwd&quot;&gt;Features in Practice&lt;/h2&gt;&lt;h3 id=&quot;code-completion-and-chat&quot; data-block-key=&quot;a8t56&quot;&gt;Code Completion and Chat&lt;/h3&gt;&lt;p data-block-key=&quot;4j0eg&quot;&gt;The plugin distinguishes between code completion suggestions as you type and prompt-based interactions, such as asking for code explanations or generating new code. For QML, a specialized Code Llama 13B QML model can be used. For other languages general purpose models are employed.&lt;/p&gt;&lt;p data-block-key=&quot;5ct2d&quot;&gt;The chat interface allows developers to highlight code and request explanations or modifications. For example, selecting a block of QML or C++ and asking the assistant to &quot;explain the selected code&quot; yields a detailed, context-aware explanation.&lt;/p&gt;&lt;h3 id=&quot;test-case-generation&quot; data-block-key=&quot;qcuzr&quot;&gt;Test Case Generation&lt;/h3&gt;&lt;p data-block-key=&quot;17t5j&quot;&gt;A notable feature is the ability to generate test cases from selected QML code. While the generated tests may require manual refinement, this automation can accelerate the initial setup of unit tests and reduce repetitive work. The plugin’s approach is to copy relevant code into the test, which may not always result in optimal reuse, but provides a useful starting point.&lt;/p&gt;&lt;h3 id=&quot;model-choice&quot; data-block-key=&quot;38yl5&quot;&gt;Model Choice&lt;/h3&gt;&lt;p data-block-key=&quot;9uc8u&quot;&gt;Developers can choose between different LLMs to use for the chat and review vs the code completion scenario. For QML model choice is separate, and offers including the fine-tuned models provided by Qt Company. This flexibility extends to hosting options, supporting both cloud and local deployments, depending on organizational needs and privacy considerations.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;further-resources&quot; data-block-key=&quot;1d93u&quot;&gt;Further Resources&lt;/h2&gt;&lt;p data-block-key=&quot;1urcf&quot;&gt;For a detailed walkthrough and live demonstrations, watch the following episodes of &quot;The Curious Developer&quot; series:&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/Dg_1XHfvnis?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;What is the Qt AI Assistant (and how does it work)?&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;










&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/63T7b6v0sGU?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Setting up the Qt AI Assistant Plugin in Qt Creator&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;bny45&quot;&gt;Additionally, the official Qt AI Assistant product page provides up-to-date information on features and availability: &lt;a href=&quot;https://www.qt.io/product/ai-assistant&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://www.qt.io/product/ai-assistant&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;outlook&quot; data-block-key=&quot;vsxlk&quot;&gt;Outlook&lt;/h2&gt;&lt;p data-block-key=&quot;23ukb&quot;&gt;Future posts in this series will consider alternative coding tools useful for Qt and will bring the newest developments of the tools we mention here.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/ai-coding-with-qt-qt-ai-assistant-for-qt-creator/&quot;&gt;AI Coding with Qt: Qt AI Assistant for Qt Creator&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Jan Marker</dc:creator><category>bestpractices</category><category>qt</category></item><item><title>Using the Qt Logger in Rust with CXX-Qt</title><link>https://www.kdab.com/using-the-qt-logger-in-rust-with-cxx-qt/</link><guid isPermaLink="true">https://www.kdab.com/using-the-qt-logger-in-rust-with-cxx-qt/</guid><description>&lt;p data-block-key=&quot;4s2kq&quot;&gt;In CXX-Qt 0.8.0, Rust applications now have a way to forward structured log events from the tracing crate to the Qt logging system. This enables unified logging output across Rust and Qt, enabling consistent formatting, better filtering, and easier integration with tools like GammaRay. By leveraging qt_message_output and QMessageLogContext, developers can bridge Rust&apos;s log metadata with Qt&apos;s categorized logging infrastructure.&lt;/p&gt;</description><pubDate>Fri, 08 Aug 2025 07:29:00 GMT</pubDate><content:encoded>&lt;h1&gt;Using the Qt Logger in Rust with CXX-Qt&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;For projects incorporating Rust and Qt, a minor but important problem can arise: too many sources of log messages. In the usual case, one of these is from Rust (and crate dependencies) and another is from Qt. Our Rust and Qt solution, &lt;a href=&quot;https://github.com/KDAB/cxx-qt&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;CXX-Qt&lt;/a&gt;, exposes a new API to help with this in the upcoming 0.8.0 release.&lt;/p&gt;&lt;p data-block-key=&quot;7o1pl&quot;&gt;There are several benefits to ensuring your log messages go through one logger. It makes it easier to redirect said messages into a file, there&apos;s less configuration required for end users, and it makes consistent formatting easier.&lt;/p&gt;&lt;p data-block-key=&quot;btqkg&quot;&gt;Qt has its own logging infrastructure, and their suggested way to print messages in Qt applications. It has a category system, rules for filtering which messages you want to see, custom formatting and so on. Applications like &lt;a href=&quot;https://www.kdab.com/software-technologies/developer-tools/gammaray/&quot;&gt;GammaRay&lt;/a&gt; can also display messages from Qt, and configure which categories are emitted.&lt;/p&gt;&lt;p data-block-key=&quot;7hmj7&quot;&gt;One of the more popular logging libraries in Rust is called &lt;a href=&quot;https://crates.io/crates/tracing&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;tracing&lt;/a&gt;, and we&apos;re going to show how you can redirect messages from it to the Qt logger. The integration can work for any other logging crate too, including your own custom solution.&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;getting-started&quot; data-block-key=&quot;dw7z4&quot;&gt;Getting started&lt;/h2&gt;&lt;p data-block-key=&quot;5fhh1&quot;&gt;Before we start splicing the two log streams, let&apos;s quickly go over sending a Qt log message in Rust. Assuming you already have a CXX-Qt application (and if you don&apos;t, you can &lt;a href=&quot;https://kdab.github.io/cxx-qt/book/getting-started/index.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;follow our book&lt;/a&gt;, construct a message log context with &lt;a href=&quot;https://doc.qt.io/qt-6/qmessagelogcontext.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QMessageLogContext&lt;/a&gt;:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;let file = CString::new(&amp;quot;main.rs&amp;quot;).unwrap();  
let function = CString::new(&amp;quot;main&amp;quot;).unwrap();  
let category = CString::new(&amp;quot;lib&amp;quot;).unwrap();  
  
let context = QMessageLogContext::new(&amp;amp;file, 0, &amp;amp;function, &amp;amp;category);&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;You can specify the filename, the line number, the function name and even a category. We have to use &lt;a href=&quot;https://doc.rust-lang.org/std/ffi/struct.CString.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;&lt;code&gt;CString&lt;/code&gt;&lt;/a&gt; here because &lt;code&gt;QMessageLogContext&lt;/code&gt; in C++ uses &lt;code&gt;const char*&lt;/code&gt;, not &lt;code&gt;QString&lt;/code&gt;.&lt;/p&gt;&lt;p data-block-key=&quot;6jn6e&quot;&gt;Note that there isn&apos;t a way to get the name of the currently calling function out of the box in Rust, but there are alternative solutions if you want that information.&lt;/p&gt;&lt;p data-block-key=&quot;4faai&quot;&gt;Now that we have a context, we can send a message to the Qt logger. We can do this using the unfortunately undocumented &lt;code&gt;qt_message_output&lt;/code&gt; function. This sends a message to &lt;a href=&quot;https://doc.qt.io/qt-6/qtlogging.html#qInstallMessageHandler&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;the currently installed message handler&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;h2&gt;&lt;/h2&gt;
&lt;p&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;qczu6&quot;&gt;Note that CXX-Qt currently doesn&apos;t have Rust bindings to install a custom one.&lt;/p&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;aqd91&quot;&gt;The default message handler goes to the standard output and error streams. This function takes a &lt;code&gt;QtMsgType&lt;/code&gt;, the context we just created, and a QString message:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;qt_message_output(  
    QtMsgType::QtInfoMsg,  
    &amp;amp;context,  
    &amp;amp;QString::from(&amp;quot;This is an informational message...&amp;quot;),  
);&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;And voilà:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-plain  line-numbers &quot;&gt;lib: This is an informational message...&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;But that looks pretty plain, and we can&apos;t see any of our context! Most information available in the Qt logger isn&apos;t shown by default, but &lt;a href=&quot;https://doc.qt.io/qt-6/qtlogging.html#qSetMessagePattern&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;we can modify it by using the&lt;/a&gt; &lt;code&gt;QT_MESSAGE_PATTERN&lt;/code&gt;&lt;a href=&quot;https://doc.qt.io/qt-6/qtlogging.html#qSetMessagePattern&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt; environment variable&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;aqd91&quot;&gt;I used the comprehensive example given in the linked documentation, but it&apos;s useful for showcasing the context:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-plain  line-numbers &quot;&gt;export QT_MESSAGE_PATTERN=&amp;quot;[%{time yyyyMMdd h:mm:ss.zzz ttt} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{file}:%{line} - %{message}&amp;quot;&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;




&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-plain  line-numbers &quot;&gt;[20250314 8:56:45.033 EDT I] main.rs:0 - This is an informational message...&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;Now that we have sent our first Qt log message from Rust, let&apos;s up the ante and integrate the tracing crate.&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;integrating-with-tracing&quot; data-block-key=&quot;upct5&quot;&gt;Integrating with Tracing&lt;/h2&gt;&lt;p data-block-key=&quot;c129c&quot;&gt;To redirect events from tracing, we have to add a subscriber that forwards events to Qt. This basically means anything that uses tracing (e.g. your application, another crate) will be picked up.&lt;/p&gt;&lt;p data-block-key=&quot;ckajo&quot;&gt;As a side effect of tracing&apos;s flexibility, we also have to create our own &lt;a href=&quot;https://docs.rs/tracing/latest/tracing/field/trait.Visit.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Visitor&lt;/a&gt;. This is necessary because tracing records structured data, and we need to flatten said data to a string.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;use std::fmt::Write; // needed for write_fmt

struct StringVisitor&amp;lt;&amp;#x27;a&amp;gt; {
    string: &amp;amp;&amp;#x27;a mut String,
}

impl tracing::field::Visit for StringVisitor&amp;lt;&amp;#x27;_&amp;gt; {
    fn record_debug(&amp;amp;mut self, field: &amp;amp;tracing::field::Field, value: &amp;amp;dyn std::fmt::Debug) {
        write!(self.string, &amp;quot;{} = {:?} &amp;quot;, field.name(), value).unwrap();
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;And now for the custom layer that will catch the events, and send them to Qt:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;pub struct QtSubscriber {}

impl&amp;lt;S&amp;gt; tracing_subscriber::Layer&amp;lt;S&amp;gt; for QtSubscriber
    where
        S: tracing::Subscriber,
{
    fn on_event(
        &amp;amp;self,
        event: &amp;amp;tracing::Event&amp;lt;&amp;#x27;_&amp;gt;,
        _ctx: tracing_subscriber::layer::Context&amp;lt;&amp;#x27;_, S&amp;gt;,
    ) {
        let mut buffer: String = String::new();
        let mut visitor = StringVisitor {
            string: &amp;amp;mut buffer
        };
        event.record(&amp;amp;mut visitor);

        let msg_type = match *event.metadata().level() {
            tracing::Level::ERROR =&amp;gt; QtMsgType::QtCriticalMsg,
            tracing::Level::WARN =&amp;gt; QtMsgType::QtWarningMsg,
            tracing::Level::INFO =&amp;gt; QtMsgType::QtInfoMsg,
            tracing::Level::DEBUG =&amp;gt; QtMsgType::QtDebugMsg,
            tracing::Level::TRACE =&amp;gt; QtMsgType::QtDebugMsg
        };

        let file = if let Some(file) = event.metadata().file() {
            CString::new(file).unwrap()
        } else {
            CString::default()
        };

        let line = if let Some(line) = event.metadata().line() {
            line as i32
        } else {
            0
        };
        
        let function = CString::default();  
        let category = CString::new(&amp;quot;lib&amp;quot;).unwrap();  

        let context = QMessageLogContext::new(&amp;amp;file, line, &amp;amp;function, &amp;amp;category);  

        qt_message_output(msg_type, &amp;amp;context, &amp;amp;QString::from(buffer));
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;And finally, we have to register our new layer with the registry:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;use tracing_subscriber::layer::SubscriberExt; // needed for with
use tracing_subscriber::util::SubscriberInitExt; // needed for init

tracing_subscriber::registry().with(QtSubscriber{}).init();&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;Afterwards, try sending a message using &lt;code&gt;tracing::info!&lt;/code&gt; and see if it works:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-rust  line-numbers &quot;&gt;tracing::info!(&amp;quot;This is an informational message... from tracing!&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;Using a more comprehensive &lt;code&gt;QT_MESSAGE_PATTERN&lt;/code&gt;, you should get a log message from Qt. Note that &quot;message&quot; is written here, as that&apos;s the default field in tracing:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-plain  line-numbers &quot;&gt;[20250320 10:41:40.617 EDT I] examples/cargo_without_cmake/src/main.rs:104 - message = This is an informational message...&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;m2vlq&quot;&gt;These new bindings in CXX-Qt should be useful to application developers who want to adopt the best logging crates in Rust, while ensuring their messages are forwarded to Qt. If you want to redirect Qt log messages to Rust, CXX-Qt doesn&apos;t have a way to install custom message handlers yet.&lt;/p&gt;&lt;p data-block-key=&quot;fc4qr&quot;&gt;See our &lt;a href=&quot;https://github.com/KDABLabs/qt-rust-logging&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;KDABLabs repository&lt;/a&gt; for complete examples of the snippets shown here.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/using-the-qt-logger-in-rust-with-cxx-qt/&quot;&gt;Using the Qt Logger in Rust with CXX-Qt&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>c++</category><category>open source</category><category>qt</category><category>rust</category></item><item><title>Display Widget Windows in Qt Quick Applications</title><link>https://www.kdab.com/display-widget-windows-in-qt-quick-applications/</link><guid isPermaLink="true">https://www.kdab.com/display-widget-windows-in-qt-quick-applications/</guid><description>&lt;p data-block-key=&quot;t1v3d&quot;&gt;This tutorial shows how to display Qt Widget windows in a Qt Quick application, combining the flexibility of both frameworks. Learn how to manage integration through C++, expose widget properties and signals to QML, and build multi-window UIs for desktop or embedded platforms from real world examples.&lt;/p&gt;</description><pubDate>Thu, 12 Jun 2025 08:28:00 GMT</pubDate><content:encoded>&lt;h1&gt;Display Widget Windows in Qt Quick Applications&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;3t908&quot;&gt;Developing an application for desktop or embedded platforms often means choosing between Qt Widgets and Qt Quick to develop the UI. There are pros and cons to each. Qt, being the flexible framework that it is, lets you combine these in various ways. How you should integrate these APIs will depend on what you&apos;re trying to achieve. In this entry I will show you how to display Qt Widget windows on an application written primarily using Qt Quick.&lt;/p&gt;&lt;h2 id=&quot;why-show-a-qt-widget-window-in-a-qt-quick-app&quot; anchor=&quot;why-show-a-qt-widget-window-in-a-qt-quick-app&quot; data-block-key=&quot;1r7qi&quot;&gt;Why Show a Qt Widget Window in a Qt Quick App&lt;/h2&gt;&lt;p data-block-key=&quot;f52p6&quot;&gt;Qt Quick is great for software that puts emphasis on visual language. A graphics pipeline, based around the Qt Quick Scene Graph, will efficiently render your UI using the GPU. This means UI elements can be drawn, decorated, and animated efficiently as long as you pick the right tools (e.g. &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-shadereffect.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Shaders&lt;/a&gt;, &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-animator.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Animators&lt;/a&gt;, and Qt&apos;s &lt;a href=&quot;https://doc.qt.io/qt-6/qtquick-shapes-qmlmodule.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Shapes API&lt;/a&gt; instead of its implementation of &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-canvas.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;HTML&apos;s Canvas&lt;/a&gt;).&lt;/p&gt;&lt;p data-block-key=&quot;85at8&quot;&gt;From the Scene Graph also stem some of Quick&apos;s weaknesses. UI elements that in other applications would extend outside of the application&apos;s window, such as tool tips and the &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-controls-combobox.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;ComboBox&lt;/a&gt; control, can only be rendered inside of Qt Quick windows. When you see other app&apos;s tooltips and dropdowns extend beyond the window, those items are being rendered onto a separate windows; one without window decorations (a.k.a. borderless windows). Rendering everything on the same window helps ensure your app will be compatible with systems that can only display a single window at a time, such as &lt;a href=&quot;https://www.kdab.com/software-technologies/platforms/android/&quot;&gt;Android&lt;/a&gt; and &lt;a href=&quot;https://www.kdab.com/software-technologies/platforms/macos-ios/&quot;&gt;iOS&lt;/a&gt;, but it could result in wasted space if your app targets PC desktop environments.&lt;/p&gt;&lt;/div&gt;
&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot;&gt;
        &lt;div class=&quot;image-variable-size-image&quot;&gt;
            &lt;img src=&quot;https://www.kdab.com/documents/Blog_WidgetWindows_Javier_2.gif&quot; alt=&quot;Blog_WidgetWindows_Javier_2&quot;&gt;
        &lt;/div&gt;

        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;gq88d&quot;&gt;An animation shows a small window with QML&apos;s and Widget&apos;s ComboBoxes opening for comparison purposes&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;3t908&quot;&gt;QML ComboBox is confined to the Qt Quick window while the Widgets ComboBox extends beyond the window&lt;/p&gt;&lt;p data-block-key=&quot;9hqfu&quot;&gt;Qt lets us combine Widgets and Quick in a few ways. The most common approach is to embed a Qt Quick view into your Widgets app, using &lt;a href=&quot;https://doc.qt.io/qt-6/qquickwidget.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QQuickWidget&lt;/a&gt;. That approach is fitting for applications that primarily use Widgets. Another option is to render Widgets inside a Qt Quick component, by rendering it through a &lt;a href=&quot;https://doc.qt.io/qt-6/qquickpainteditem.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QQuickPaintedItem&lt;/a&gt;. However, this component will be limited to the same window confines as the rest of the items in your Quick window and it won&apos;t benefit from Scene Graph rendering optimizations, meaning you get the worst of both worlds.&lt;/p&gt;&lt;p data-block-key=&quot;d5l46&quot;&gt;A third solution is to open widget windows from your Qt Quick apps. This has none of the aforementioned drawbacks, however, the approach has a couple of drawback of its own. First, the app would need to be run from a multi-window per screen capable environment. Second, widget windows are not parentable to Qt Quick windows; meaning certain window z-stack related features, such as setting window modality to Qt::WindowModal, won&apos;t have effect on the triggering window when a Widget is opened from Qt Quick. You can work around that by setting modality to Qt::ApplicationModal instead, if you&apos;re okay with blocking all other windows for modality.&lt;/p&gt;&lt;p data-block-key=&quot;7drhk&quot;&gt;Displaying Widget windows in Qt Quick applications has been useful to me in the past, and is something I haven&apos;t seen documented anywhere, hence this tutorial.&lt;/p&gt;&lt;h2 id=&quot;how-to-show-a-qt-widget-window-in-a-qt-quick-app&quot; anchor=&quot;how-to-show-a-qt-widget-window-in-a-qt-quick-app&quot; data-block-key=&quot;3mjgr&quot;&gt;How to Show a Qt Widget Window in a Qt Quick App&lt;/h2&gt;&lt;h3 id=&quot;architecture-big-picture&quot; anchor=&quot;architecture-big-picture&quot; data-block-key=&quot;ffi7l&quot;&gt;Architecture Big Picture&lt;/h3&gt;&lt;p data-block-key=&quot;dgfr4&quot;&gt;Displaying a Qt Widget window from Qt Quick is simpler than it seems. You&apos;ll need two classes:&lt;/p&gt;&lt;ol&gt;&lt;li data-block-key=&quot;2uhcu&quot;&gt;The class that represents the widget window.&lt;/li&gt;&lt;li data-block-key=&quot;ft4rj&quot;&gt;A class to interface from QML, that hosts and instantiates the window.&lt;/li&gt;&lt;/ol&gt;&lt;p data-block-key=&quot;em8h2&quot;&gt;You might be tempted to forgo the interface class and instantiate the widget directly. However, this would result in a crash. We&apos;ll display the widget window by running &lt;code&gt;Widget::show&lt;/code&gt; from the interface class.&lt;/p&gt;&lt;h3 id=&quot;update-cmakeliststxt&quot; anchor=&quot;update-cmakeliststxt&quot; data-block-key=&quot;apkch&quot;&gt;Update &lt;code&gt;CMakeLists.txt&lt;/code&gt;&lt;/h3&gt;&lt;p data-block-key=&quot;fld25&quot;&gt;In addition to those classes, you&apos;ll also need to make sure that your app links to both &lt;code&gt;Qt::Quick&lt;/code&gt; and &lt;code&gt;Qt::Widgets&lt;/code&gt; libraries. Here&apos;s what that looks like for a CMake project&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cmake  line-numbers &quot;&gt;// Locate libraries
find_package(Qt6 6.5 REQUIRED COMPONENTS
    Quick
    Widgets)

// Link build target to libraries
target_link_libraries(${TARGET_NAME} PRIVATE
    Qt6::Quick
    Qt6::Widgets)

// Replace ${TARGET_NAME} with the name of your target executable&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;update-maincpp&quot; anchor=&quot;update-maincpp&quot; data-block-key=&quot;pmb8e&quot;&gt;Update &lt;code&gt;main.cpp&lt;/code&gt;&lt;/h3&gt;&lt;p data-block-key=&quot;e4hbq&quot;&gt;In addition to that, in &lt;code&gt;main.cpp&lt;/code&gt; you&apos;ll need to use &lt;a href=&quot;https://doc.qt.io/qt-6/qapplication.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QApplication&lt;/a&gt; in place of &lt;a href=&quot;https://doc.qt.io/qt-6/qguiapplication.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QGuiApplication&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;QApplication app(argc, argv);&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;the-interface-layer&quot; anchor=&quot;the-interface-layer&quot; data-block-key=&quot;pmb8e&quot;&gt;The Interface Layer&lt;/h2&gt;&lt;p data-block-key=&quot;2b6fi&quot;&gt;Prepare the interface layer as you would any C++ based Quick component. By this I mean: derive from &lt;code&gt;QObject&lt;/code&gt;, and use the &lt;code&gt;Q_OBJECT&lt;/code&gt; and &lt;code&gt;QML_ELEMENT&lt;/code&gt; macros to make your class available from QML.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.h
#pragma once
class WidgetFormHandler : public QObject
{
    Q_OBJECT
    QML_ELEMENT

public:
    explicit WidgetFormHandler(QObject *parent = nullptr);
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;




&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.cpp

WidgetFormHandler::WidgetFormHandler(QObject *parent)
    : QObject(parent)
{
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;instantiating-the-widgets-window&quot; anchor=&quot;instantiating-the-widgets-window&quot; data-block-key=&quot;pmb8e&quot;&gt;Instantiating the Widgets Window&lt;/h3&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.h
#pragma once
class WidgetsForm;
class WidgetFormHandler : public QObject
{
    Q_OBJECT
    QML_ELEMENT

public:
    explicit WidgetFormHandler(QObject *parent = nullptr);
~WidgetFormHandler();

private:
    std::unique_ptr&amp;lt;WidgetsForm&amp;gt; m_window;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;Use &lt;code&gt;std::make_unique&lt;/code&gt; in the constructor to initialize the unique pointer to m_window.&lt;/p&gt;&lt;p data-block-key=&quot;2t6ha&quot;&gt;Define the instantiating class&apos; destructor to ensure the pointers are de-alocated, thus preventing memory leaks. If you stick to using smart pointers, C++ will do all the work for you; simply use the default destructor, like I do here. Make sure to define it outside of the class&apos; header; some compilers have trouble dealing with the destructor when it&apos;s defined inside the header.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.cpp
#include &amp;quot;widgetFormHandler.h&amp;quot;

WidgetFormHandler::WidgetFormHandler(QObject *parent)
    : QObject(parent)
    , m_window(std::make_unique&amp;lt;WidgetsForm&amp;gt;())
{
    // ...
}

WidgetFormHandler::~WidgetFormHandler() = default;&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;make-properties-available-to-qml&quot; anchor=&quot;make-properties-available-to-qml&quot; data-block-key=&quot;pmb8e&quot;&gt;Make Properties Available to QML&lt;/h3&gt;&lt;p data-block-key=&quot;1jlj5&quot;&gt;Now we want to make properties from the widget available in QML. How we do this will depend on the property and on whether we will manipulate the property&apos;s value from both directions or only from one side only and update on the other.&lt;/p&gt;&lt;p data-block-key=&quot;3n9k8&quot;&gt;Let&apos;s look at a bi-directional example in which we add the ability to control the visible state of the widget window from QML. We&apos;ll add a property called &quot;visible&quot; to the C++ interface so that it matches the visible that we get from Qt Quick windows in QML. Declare the property using &lt;code&gt;Q_PROPERTY&lt;/code&gt;. Use READ and WRITE functions to control the window&apos;s state.&lt;/p&gt;&lt;p data-block-key=&quot;60vsu&quot;&gt;Here&apos;s what that would look like:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.h
#pragma once
class WidgetsForm;

class WidgetFormHandler : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)

public:
    explicit WidgetFormHandler(QObject *parent = nullptr);    
~WidgetFormHandler();
    const bool isVisible();    
    void setVisible(bool);

signals:
    void visibleChanged();

private:
    std::unique_ptr&amp;lt;WidgetsForm&amp;gt; m_window;
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;




&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.cpp
#include &amp;quot;widgetFormHandler.h&amp;quot;

#include &amp;quot;widgetForm.h&amp;quot;

WidgetFormHandler::WidgetFormHandler(QObject *parent)
    : QObject(parent)
    , m_window(std::make_unique&amp;lt;WidgetsForm&amp;gt;())
{
    // Hide window by default
    m_window-&amp;gt;setVisible(false);
}
WidgetFormHandler::~WidgetFormHandler() = default;
const bool WidgetFormHandler::isVisible()
{
    return m_window-&amp;gt;isVisible();
}
void WidgetFormHandler::setVisible(bool visible)
{
    m_window-&amp;gt;setVisible(visible);
    emit visibleChanged();
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;To make this bi-directional, set NOTIFY to a signal that allows the property to be updated in QML after it being emitted and emit the signal where applicable. We emit it from setVisible in this class, however if &lt;code&gt;QWidget&lt;/code&gt; had a signal that emitted when its visible state changed, I would also make a connection between that signal and that of our handler’s &lt;code&gt;visibleChanged&lt;/code&gt;. However, that isn’t the case, so we have to make sure to emit it ourselves.&lt;/p&gt;&lt;h3 id=&quot;make-signals-available-to-qml&quot; anchor=&quot;make-signals-available-to-qml&quot; data-block-key=&quot;33a87&quot;&gt;Make Signals Available to QML&lt;/h3&gt;&lt;p data-block-key=&quot;3fl8o&quot;&gt;Develop the widget window as you would any other widget. If you use UI forms, go to the header file and create a signal for each action that you wish to relay over to QML.&lt;/p&gt;&lt;p data-block-key=&quot;63uem&quot;&gt;In this example we&apos;ll relay a button press from the UI file, so we&apos;ll create a button named pushButton in our ui file:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_WidgetWindows_Javier_buttonname&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_WidgetWindows_Javier_buttonname.original.png&quot; class=&quot;Blog_WidgetWindows_Javier_buttonname&quot; alt=&quot;Blog_WidgetWindows_Javier_buttonname&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;y6oae&quot;&gt;Qt Designer shows UI file with a button named pushButton, in camel case.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;Now add a &lt;code&gt;buttonClicked&lt;/code&gt; signal to our header:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetsForm.h
#pragma once
#include &amp;lt;QWidget&amp;gt;

namespace Ui
{
    class WidgetsForm;
}

class WidgetsForm : public QWidget
{
    Q_OBJECT
public:
    explicit WidgetsForm(QWidget *parent = nullptr);
    ~WidgetsForm();
signals:
    void buttonClicked();
    // Signal to expose button click from Widgets window
private:
    std::unique_ptr&amp;lt;Ui::WidgetsForm&amp;gt; ui;
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;Once again, we use a unique pointer, this time to hold the ui object. This is better than what Qt Creator templates give us because it means C++ handles the memory management for us and we can avoid the need for a delete statement in the destructor.&lt;/p&gt;&lt;p data-block-key=&quot;2cecg&quot;&gt;In the window&apos;s constructor, we make a connection between the UI&apos;s button&apos;s signal and the one that we&apos;ve created to relay the signal for exposure.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetsForm.cpp
#include &amp;quot;widgetsform.h&amp;quot;
#include &amp;quot;ui_widgetsform.h&amp;quot;

WidgetsForm::WidgetsForm(QWidget *parent)
    : QWidget(parent)
    , ui(std::make_unique&amp;lt;Ui::WidgetsForm&amp;gt;())
{
    ui-&amp;gt;setupUi(this);
    // Expose click
    connect(ui-&amp;gt;pushButton, &amp;amp;QPushButton::clicked, this, &amp;amp;WidgetsForm::buttonClicked);
}

WidgetsForm::~WidgetsForm() = default;&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;Before we connect the exposed signal to the QML interface, we need another signal on the interface to expose our event over to QML. Here I add &lt;code&gt;qmlSignalEmitter&lt;/code&gt; signal for that purpose:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.h
[..]
signals:
    void visibleChanged();
    void qmlSignalEmitter();  // Signal to relay button press to QML
[..]&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;To complete all the connections, go to the interface layer’s constructor and make a connection between your window class’ signal and that of the interface layer. This would look as follows:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;// widgetFormHandler.cpp
[..]
WidgetFormHandler::WidgetFormHandler(QObject *parent)
    : QObject(parent)
    , m_window(std::make_unique&amp;lt;WidgetsForm&amp;gt;())
{
    QObject::connect(m_window, &amp;amp;WidgetsForm::buttonClicked, this,
    &amp;amp;WidgetFormHandler::qmlSignalEmitter);
}
[..]&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;By connecting one emitter to another emitter we keep each classes&apos; concerns separate and reduce the amount of boilerplate code, making our code easier to maintain.&lt;/p&gt;&lt;p data-block-key=&quot;8k7f&quot;&gt;Over at the QML, we connect to &lt;code&gt;qmlSignalEmitter&lt;/code&gt; using the on prefix. It would look like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-qml  line-numbers &quot;&gt;import NameOfAppQmlModule  // Should match qt_add_qml_module&amp;#x27;s URI on CMake

WidgetFormHandler {
    id: fontWidgetsForm

    visible: true  // Make the Widgets window visible from QML

    onQmlSignalEmitter: () =&amp;gt; {
        console.log(&amp;quot;Button pressed in widgets&amp;quot;)  // Log QPushButton&amp;#x27;s click event from QML
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;final-product&quot; anchor=&quot;final-product&quot; data-block-key=&quot;pmb8e&quot;&gt;Final Product&lt;/h2&gt;&lt;p data-block-key=&quot;4g3ps&quot;&gt;I&apos;ve prepared a demo app where you can see this technique in action. The demo displays text that bounces around the screen like an old DVD player&apos;s logo would. You change the text and font through two identical forms, one implemented in QML and the other done in Widgets. The code presented in this tutorial comes from that demo app.&lt;/p&gt;&lt;p data-block-key=&quot;8h2g9&quot;&gt;Example code: &lt;a href=&quot;https://github.com/KDABLabs/kdabtv/tree/master/Blog-projects/Widget-window-in-Qt-Quick-app&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://github.com/KDABLabs/kdabtv/tree/master/Blog-projects/Widget-window-in-Qt-Quick-app&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 75.0%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;150&quot; src=&quot;https://www.youtube.com/embed/IGGBhsFESR4?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Widget in QML app, bouncy window&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;



&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;adugx&quot;&gt;The moving text should work on all desktop systems except for Wayland sessions on Linux. That is because I&apos;m animating the window&apos;s absolute position (which is restricted in Wayland for security reasons) rather than the contents inside a window. This has the benefit of not obstructing other applications, since the moving window that contains the text would capture mouse inputs if clicked, preventing those from reaching the application behind it.&lt;/p&gt;&lt;h2 id=&quot;real-world-use-case&quot; anchor=&quot;real-world-use-case&quot; data-block-key=&quot;b42di&quot;&gt;Real World Use Case&lt;/h2&gt;&lt;p data-block-key=&quot;ce8fj&quot;&gt;The first time I employed this technique was in my FOSS project, QPrompt. I use it there to provide a custom font dialog that doubles as a text preview. Having a custom dialog gives me full control over formatting options presented to users, and for this app we only needed a preview for large text and a combo box to choose among system fonts. QPrompt is also open source, you can find the source code relevant to this technique here: &lt;a href=&quot;https://github.com/Cuperino/QPrompt-Teleprompter/blob/main/src/systemfontchooserdialog.h&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://github.com/Cuperino/QPrompt-Teleprompter/blob/main/src/systemfontchooserdialog.h&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_WidgetWindows_Javier_image-2-1024x634&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_WidgetWindows_Javier_image-2-1024x634.original.png&quot; class=&quot;Blog_WidgetWindows_Javier_image-2-1024x634&quot; alt=&quot;Blog_WidgetWindows_Javier_image-2-1024x634&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-end&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pmb8e&quot;&gt;Thank you for reading. I hope you’ll find this useful. A big thank you to David Faure for suggesting the use of C++ unique pointers as well as reviewing the code along with Renato and my team.&lt;/p&gt;&lt;p data-block-key=&quot;cutk4&quot;&gt;If there are other techniques that you’d like for us to try or showcase, let us know.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/display-widget-windows-in-qt-quick-applications/&quot;&gt;Display Widget Windows in Qt Quick Applications&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>c++</category><category>design</category><category>desktop</category><category>embedded</category><category>qml</category><category>qt</category><category>ux/ui</category></item><item><title>Integrate QML Window&apos;s Background with the System&apos;s Color Palette</title><link>https://www.kdab.com/integrate-qml-windows-background-with-the-systems-color-palette/</link><guid isPermaLink="true">https://www.kdab.com/integrate-qml-windows-background-with-the-systems-color-palette/</guid><description>&lt;p data-block-key=&quot;xeanb&quot;&gt;Qt Quick apps can show a white flash during window resizing due to frame lag. This happens when the window’s background doesn’t match the system theme. Use SystemPalette to set a theme-aware background color, ensuring smooth, consistent visuals across platforms.&lt;/p&gt;</description><pubDate>Thu, 24 Apr 2025 06:43:49 GMT</pubDate><content:encoded>&lt;h1&gt;Integrate QML Window&apos;s Background with the System&apos;s Color Palette&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;4stax&quot;&gt;As a person who enjoys responsive designs, I like to resize apps and see how quickly the UI updates after the resize. If you&amp;#x27;re making an app with Qt Quick, you&amp;#x27;ll sometimes find that, as the window size increases, the UI will lag behind for one or more frames, revealing a white background on two of the window&amp;#x27;s edges, that usually looks out of place on desktop applications.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Resizing_Javier_Thumbnail-For-a-Correct-Background-Color-When-Resizing-1&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_Resizing_Javier_Thumbnail-For-a-Correct-Ba.original.jpg&quot; class=&quot;Blog_Resizing_Javier_Thumbnail-For-a-Correct-Background-Color-When-Resizing-1&quot; alt=&quot;Blog_Resizing_Javier_Thumbnail-For-a-Correct-Background-Color-When-Resizing-1&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;8lg2j&quot;&gt;Thumbnail: A window with a white border where there should be a background color.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;why-is-the-color-background-revealed-when-the-window-size-is-increased&quot; anchor=&quot;why-is-the-color-background-revealed-when-the-window-size-is-increased&quot; data-block-key=&quot;4stax&quot;&gt;Why is the color background revealed when the window size is increased?&lt;/h2&gt;&lt;p data-block-key=&quot;b9f0h&quot;&gt;This issue stems from the fact that Qt Quick windows will render a background color, white by default, before the position of elements is updated by the scene graph, which lags at least one frame behind the resize because it uses a frame buffer. If the default background is white, that means the QML window itself is not aware of your application&amp;#x27;s theme and that is intentional; after all, only desktop apps need to be aware of the background color used by native applications.&lt;/p&gt;&lt;p data-block-key=&quot;ca9kv&quot;&gt;Qt Quick Controls, however, are theme aware, and that may include your platform&amp;#x27;s theme. This is why, when you make an app for Windows, if you set a Label against the application&amp;#x27;s default white background, it will look just fine. But when that app is moved to macOS or a Linux distribution with a dark theme, the label&amp;#x27;s text will be drawn with a light color to match that theme, and that will make it nearly impossible to read against the default white background.&lt;/p&gt;&lt;p data-block-key=&quot;bb2gp&quot;&gt;One solution for that issue is to place these components against a control that extends through a large area, such as a &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-controls-pane.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Pane&lt;/a&gt;. Qt Quick Controls&amp;#x27; theme awareness will ensure the right background color is used. However, controls are only drawn within the window, so when the window is resized, its true background color will seep through -- and that&amp;#x27;s the issue with which we&amp;#x27;re concerned. The correct solution is to set the window&amp;#x27;s background to the system&amp;#x27;s or the theme&amp;#x27;s background color, which will make the frame buffer&amp;#x27;s lag far less noticeable during resizing.&lt;/p&gt;&lt;h2 id=&quot;how-to-make-qt-quick-window-backgrounds-aware-of-your-systems-theme&quot; anchor=&quot;how-to-make-qt-quick-window-backgrounds-aware-of-your-systems-theme&quot; data-block-key=&quot;36p78&quot;&gt;How to Make Qt Quick Window Backgrounds Aware of Your System&amp;#x27;s Theme&lt;/h2&gt;&lt;p data-block-key=&quot;77ueb&quot;&gt;Setting a background color is as simple as assigning a value to the &amp;quot;color&amp;quot; property of the window, like so:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-qml  line-numbers &quot;&gt;Window {
    color: &amp;quot;lightblue&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;4stax&quot;&gt;To have it match the background color of native apps, use QML&amp;#x27;s &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-systempalette.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;SystemPallete&lt;/a&gt; type, as follows:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-qml  line-numbers &quot;&gt;import QtQuick
Window {
    color: systemPalette.window
    SystemPalette {
        id: systemPalette
    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;4stax&quot;&gt;Here you can find the various &lt;a href=&quot;https://doc.qt.io/qt-6/qtquickcontrols-styles.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;default styles used by Qt Quick for each supported platform&lt;/a&gt;. By making use of SystemPalette, the appropriate background color for the current platform will be chosen.&lt;/p&gt;&lt;p data-block-key=&quot;cp681&quot;&gt;It is important to note that, using SystemPalette, the background color will be chosen based on the current platform and not on which QML style has actually been applied, which may differ if your app makes use of a fixed style for all platforms.&lt;/p&gt;&lt;/div&gt;

&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot;&gt;
        &lt;div class=&quot;image-variable-size-image&quot;&gt;
            &lt;img src=&quot;https://www.kdab.com/documents/Blog_Resizing_Javier_1-ezgif.com-optimize.gif&quot; alt=&quot;Blog_Resizing_Javier_1-ezgif.com-optimize&quot;&gt;
        &lt;/div&gt;

        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;0y5ec&quot;&gt;Animation of a window resizing, letting the white background seep through a corner.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot;&gt;
        &lt;div class=&quot;image-variable-size-image&quot;&gt;
            &lt;img src=&quot;https://www.kdab.com/documents/Blog_Resizing_Javier_2-ezgif.com-optimize.gif&quot; alt=&quot;Blog_Resizing_Javier_2-ezgif.com-optimize&quot;&gt;
        &lt;/div&gt;

        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;0y5ec&quot;&gt;Animation of a window resizing. The background color is consistent with the theme at all times.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;platform-style-vs-fixed-style&quot; anchor=&quot;platform-style-vs-fixed-style&quot; data-block-key=&quot;4stax&quot;&gt;Platform Style vs. Fixed Style&lt;/h2&gt;&lt;p data-block-key=&quot;3lmtp&quot;&gt;As an alternative to following the platform&amp;#x27;s theme, you could provide a uniform experience for all platforms by enforcing one style for all. There are minor performance advantages to having a fixed style for all systems, but these only tend to matter on low-end embedded hardware, where every cycle counts. There you could use &lt;a href=&quot;https://doc.qt.io/qt-6/qtquickcontrols-styles.html#compile-time-style-selection&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Compile-Time Style Selection&lt;/a&gt;, so the &lt;a href=&quot;https://doc.qt.io/qt-6/qtqml-qtquick-compiler-tech.html#the-qml-script-compiler&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QML compiler&lt;/a&gt; knows which style is in use and can generate C++ code for bindings.&lt;/p&gt;&lt;p data-block-key=&quot;3dr8v&quot;&gt;If you are creating a desktop application, your theming choice should be based, not on performance, but on the level of system integration and the user experience you wish to provide. A photography application might benefit from having a dark mode at all times so the picture colors can pop. An e-mail client, on the other hand, might do better integrating with the system&amp;#x27;s theme or allowing users to choose between a light theme and a dark theme. Light backgrounds generally provide better contrast, which makes them a good default choice for emails. However, users may prefer the system theme or a dark theme, if it&amp;#x27;s easier on their eyes.&lt;/p&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Resizing_Javier_Screenshot_20250110_123920&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_Resizing_Javier_Screenshot_20250110_123920.original.png&quot; class=&quot;Blog_Resizing_Javier_Screenshot_20250110_123920&quot; alt=&quot;Blog_Resizing_Javier_Screenshot_20250110_123920&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;8lg2j&quot;&gt;A window from one OS, with a light theme. Its contents can be read just fine.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Resizing_Javier_Screenshot_20250110_123546&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_Resizing_Javier_Screenshot_20250110_123546.original.png&quot; class=&quot;Blog_Resizing_Javier_Screenshot_20250110_123546&quot; alt=&quot;Blog_Resizing_Javier_Screenshot_20250110_123546&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;8lg2j&quot;&gt;A window from a different OS, with a dark theme. Some of it contents cannot be read due to a lack of contrast.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;crafting-seamless-and-theme-aware-qt-quick-applications&quot; anchor=&quot;crafting-seamless-and-theme-aware-qt-quick-applications&quot; data-block-key=&quot;4stax&quot;&gt;Crafting Seamless and Theme-Aware Qt Quick Applications&lt;/h2&gt;&lt;p data-block-key=&quot;99n3h&quot;&gt;By thoughtfully managing your Qt Quick application&amp;#x27;s window background color, you can significantly improve its responsiveness and aesthetic integration with the host platform. Whether you opt to align with the system&amp;#x27;s theme using &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-systempalette.html&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;SystemPalette&lt;/a&gt; or enforce a fixed style for uniformity, your choice should reflect the needs of your application and its users. Balancing system integration, performance, and user experience ensures your app not only looks great across platforms but also feels natural to use, providing a polished and professional result. With these tools and insights, you can create dynamic, theme-aware applications that stand out in usability and design.&lt;/p&gt;&lt;/div&gt;&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/integrate-qml-windows-background-with-the-systems-color-palette/&quot;&gt;Integrate QML Window&apos;s Background with the System&apos;s Color Palette&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><category>design</category><category>desktop</category><category>embedded</category><category>qml</category><category>qt</category><category>ux/ui</category></item><item><title>Model/View Drag and Drop in Qt - Part 3</title><link>https://www.kdab.com/modelview-drag-and-drop-in-qt-part-3/</link><guid isPermaLink="true">https://www.kdab.com/modelview-drag-and-drop-in-qt-part-3/</guid><description>&lt;p data-block-key=&quot;ar0am&quot;&gt;This post explores implementing drag-and-drop onto existing items in Qt, such as moving emails between folders. It covers both &lt;i&gt;Model/View&lt;/i&gt; and &lt;i&gt;Item Widget&lt;/i&gt; approaches, detailing key setup steps and improvements made to Qt along the way.&lt;/p&gt;</description><pubDate>Thu, 03 Apr 2025 08:43:00 GMT</pubDate><content:encoded>&lt;h1&gt;Model/View Drag and Drop in Qt - Part 3&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;1z9vu&quot;&gt;In this third blog post of the Model/View Drag and Drop series (&lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-part-1/&quot;&gt;part 1&lt;/a&gt; and &lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-in-qt-part-2/&quot;&gt;part 2&lt;/a&gt;), the idea is to implement dropping onto items, rather than in between items. QListWidget and QTableWidget have out of the box support for replacing the value of existing items when doing that, but there aren&apos;t many use cases for that. What is much more common is to associate a custom semantic to such a drop. For instance, the examples detailed below show email folders and their contents, and dropping an email onto another folder will move (or copy) the email into that folder.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step1&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part3-treeview-step1.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step1&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step1&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;44fbh&quot;&gt;Step 1&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;Initial state, the email is in the inbox&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step2&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part3-treeview-step2.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step2&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step2&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;44fbh&quot;&gt;Step 2&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;Dragging the email onto the Customers folder&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step3&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part3-treeview-step3.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step3&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step3&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;44fbh&quot;&gt;Step 3&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;Dropping the email&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step4&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part3-treeview-step4.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step4&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part3-treeview-step4&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;44fbh&quot;&gt;Step 4&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;The email is now in the customers folder&lt;/p&gt;&lt;h2 id=&quot;with-modelview-separation&quot; anchor=&quot;with-modelview-separation&quot; data-block-key=&quot;ksk9j&quot;&gt;With Model/View separation&lt;/h2&gt;&lt;p data-block-key=&quot;a95g8&quot;&gt;Example code can be found &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/model-view/drop-onto-items-with-model-view.cpp&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for flat models and &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/treemodel/drop-onto-items-with-treemodel.cpp&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for tree models.&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-view-on-the-drag-side&quot; anchor=&quot;setting-up-the-view-on-the-drag-side&quot; data-block-key=&quot;mfiqr&quot;&gt;Setting up the view on the drag side&lt;/h3&gt;&lt;p data-block-key=&quot;baki1&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropMode(QAbstractItemView::DragOnly)&lt;/code&gt;&lt;br/&gt; unless of course the same view should also support drops. In our example, only emails can be dragged, and only folders allow drops, so the drag and drop sides are distinct.&lt;/p&gt;&lt;p data-block-key=&quot;6qoh6&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropOverwriteMode(...)&lt;/code&gt;&lt;br/&gt; &lt;code&gt;true&lt;/code&gt; if moving should clear cells, &lt;code&gt;false&lt;/code&gt; if moving should remove rows.&lt;br/&gt; Note that the default is &lt;code&gt;true&lt;/code&gt; for &lt;code&gt;QTableView&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; for &lt;code&gt;QListView&lt;/code&gt; and &lt;code&gt;QTreeView&lt;/code&gt;. In our example, we want to remove emails that have been moved elsewhere, so &lt;code&gt;false&lt;/code&gt; is correct.&lt;/p&gt;&lt;p data-block-key=&quot;53bqd&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDefaultDropAction(Qt::MoveAction)&lt;/code&gt; so that the drag defaults to a move and not a copy, adjust as needed&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-model-on-the-drag-side&quot; anchor=&quot;setting-up-the-model-on-the-drag-side&quot; data-block-key=&quot;762wa&quot;&gt;Setting up the model on the drag side&lt;/h3&gt;&lt;p data-block-key=&quot;f1jgr&quot;&gt;To implement dragging items out of a model, you need to implement the following -- this is very similar to the section of the same name in the previous blog post, obviously:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;class EmailsModel : public QAbstractTableModel
{
    ~~~
    Qt::ItemFlags flags(const QModelIndex &amp;amp;index) const override
    {
        if (!index.isValid())
            return {};
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
    }

    // the default is &amp;quot;copy only&amp;quot;, change it
    Qt::DropActions supportedDragActions() const override { return Qt::MoveAction | Qt::CopyAction; }

    QMimeData *mimeData(const QModelIndexList &amp;amp;indexes) const override;

    bool removeRows(int position, int rows, const QModelIndex &amp;amp;parent) override;&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;☑ Reimplement &lt;code&gt;flags()&lt;/code&gt; to add &lt;code&gt;Qt::ItemIsDragEnabled&lt;/code&gt; in the case of a valid index&lt;/p&gt;&lt;p data-block-key=&quot;btaih&quot;&gt;☑ Reimplement &lt;code&gt;supportedDragActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction | Qt::CopyAction&lt;/code&gt; or whichever you want to support (the default is CopyAction only).&lt;/p&gt;&lt;p data-block-key=&quot;4k7os&quot;&gt;☑ Reimplement &lt;code&gt;mimeData()&lt;/code&gt; to serialize the complete data for the dragged items. If the views are always in the same process, you can get away with serializing only node pointers (if you have that) and application PID (to refuse dropping onto another process). See the previous part of this blog series for more details.&lt;/p&gt;&lt;p data-block-key=&quot;7p1a9&quot;&gt;☑ Reimplement &lt;code&gt;removeRows()&lt;/code&gt;, it will be called after a successful drop with &lt;code&gt;MoveAction&lt;/code&gt;. An example implementation looks like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;bool EmailsModel::removeRows(int position, int rows, const QModelIndex &amp;amp;parent)
{
    beginRemoveRows(parent, position, position + rows - 1);
    for (int row = 0; row &amp;lt; rows; ++row) {
        m_emailFolder-&amp;gt;emails.removeAt(position);
    }
    endRemoveRows();
    return true;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;setting-up-the-view-on-the-drop-side&quot; anchor=&quot;setting-up-the-view-on-the-drop-side&quot; data-block-key=&quot;4tcsf&quot;&gt;Setting up the view on the drop side&lt;/h3&gt;&lt;p data-block-key=&quot;170pv&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropMode(QAbstractItemView::DropOnly)&lt;/code&gt; unless of course it supports dragging too. In our example, we can drop onto email folders but we cannot reorganize the folders, so &lt;code&gt;DropOnly&lt;/code&gt; is correct.&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-model-on-the-drop-side&quot; anchor=&quot;setting-up-the-model-on-the-drop-side&quot; data-block-key=&quot;f2j2p&quot;&gt;Setting up the model on the drop side&lt;/h3&gt;&lt;p data-block-key=&quot;dui9h&quot;&gt;To implement dropping items into a model&apos;s existing items, you need to do the following:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;class FoldersModel : public QAbstractTableModel
{
    ~~~    
    Qt::ItemFlags flags(const QModelIndex &amp;amp;index) const override
    {
        CHECK_flags(index);
        if (!index.isValid())
            return {}; // do not allow dropping between items
        if (index.column() &amp;gt; 0)
            return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // don&amp;#x27;t drop on other columns
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled;
    }

    // the default is &amp;quot;copy only&amp;quot;, change it
    Qt::DropActions supportedDropActions() const override { return Qt::MoveAction | Qt::CopyAction; }
  
    QStringList mimeTypes() const override { return {QString::fromLatin1(s_emailsMimeType)}; }
  
    bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &amp;amp;parent) override;
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chbha&quot;&gt;☑ Reimplement &lt;code&gt;flags()&lt;/code&gt;&lt;br/&gt; For a valid index (and only in that case), add &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt;. As you can see, you can also restrict drops to column 0, which can be more sensible when using &lt;code&gt;QTreeView&lt;/code&gt; (the user should drop onto the folder name, not onto the folder size).&lt;/p&gt;&lt;p data-block-key=&quot;ep99i&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction | Qt::CopyAction&lt;/code&gt; or whichever you want to support (the default is CopyAction only).&lt;/p&gt;&lt;p data-block-key=&quot;dnh6m&quot;&gt;☑ Reimplement &lt;code&gt;mimeTypes()&lt;/code&gt; - the list should include the MIME type used by the drag model.&lt;/p&gt;&lt;p data-block-key=&quot;2g8a&quot;&gt;☑ Reimplement &lt;code&gt;dropMimeData()&lt;/code&gt;&lt;br/&gt; to deserialize the data and handle the drop.&lt;br/&gt; This could mean calling &lt;code&gt;setData()&lt;/code&gt; to replace item contents, or anything else that should happen on a drop: in the email example, this is where we copy or move the email into the destination folder. Once you&apos;re done, return true, so that the drag side then deletes the dragged rows by calling &lt;code&gt;removeRows()&lt;/code&gt; on its model.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;bool FoldersModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &amp;amp;parent)
{
    ~~~  // safety checks, see full example code

    EmailFolder *destFolder = folderForIndex(parent);

    const QByteArray encodedData = mimeData-&amp;gt;data(s_emailsMimeType);
    QDataStream stream(encodedData);
    ~~~ // code to detect and reject dropping onto the folder currently holding those emails

    while (!stream.atEnd()) {
        QString email;
        stream &amp;gt;&amp;gt; email;
        destFolder-&amp;gt;emails.append(email);
    }
    emit dataChanged(parent, parent); // update count

    return true; // let the view handle deletion on the source side by calling removeRows there
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;using-item-widgets&quot; anchor=&quot;using-item-widgets&quot; data-block-key=&quot;o5jxg&quot;&gt;Using item widgets&lt;/h2&gt;&lt;p data-block-key=&quot;f13cl&quot;&gt;Example code:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;6i1ck&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/qlistwidget/drop-onto-qlistwidgetitems.cpp&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QListWidget&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;902bi&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/qtablewidget/drop-onto-qtablewidgetitems.cpp&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTableWidget&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;3rqfn&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/qtreewidget/drop-onto-qtreewidgetitems.cpp&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTreeWidget&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;on-the-drag-side&quot; anchor=&quot;on-the-drag-side&quot; data-block-key=&quot;ohfhl&quot;&gt;On the &quot;drag&quot; side&lt;/h3&gt;&lt;p data-block-key=&quot;18t03&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropMode(QAbstractItemView::DragOnly)&lt;/code&gt; or &lt;code&gt;DragDrop&lt;/code&gt; if it should support both&lt;/p&gt;&lt;p data-block-key=&quot;ca2ba&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDefaultDropAction(Qt::MoveAction)&lt;/code&gt; so that the drag defaults to a move and not a copy, adjust as needed&lt;/p&gt;&lt;p data-block-key=&quot;evi3q&quot;&gt;☑ Reimplement &lt;code&gt;Widget::mimeData()&lt;/code&gt; to serialize the complete data for the dragged items. If the views are always in the same process, you can get away with serializing only item pointers and application PID (to refuse dropping onto another process). In our email folders example we also serialize the pointer to the source folder (where the emails come from) so that we can detect dropping onto the same folder (which should do nothing).&lt;/p&gt;&lt;p data-block-key=&quot;9ggql&quot;&gt;To serialize pointers in QDataStream, cast them to quintptr, see the &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/blob/main/ItemViews-DragAndDrop/part3-dropping-onto-items/qlistwidget/drop-onto-qlistwidgetitems.cpp#L58&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;example code&lt;/a&gt; for details.&lt;/p&gt;&lt;h3 id=&quot;on-the-drop-side&quot; anchor=&quot;on-the-drop-side&quot; data-block-key=&quot;fypts&quot;&gt;On the &quot;drop&quot; side&lt;/h3&gt;&lt;p data-block-key=&quot;csd0h&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropMode(QAbstractItemView::DropOnly)&lt;/code&gt; or &lt;code&gt;DragDrop&lt;/code&gt; if it should support both&lt;/p&gt;&lt;p data-block-key=&quot;8bf8n&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropOverwriteMode(true)&lt;/code&gt; for a minor improvement: no forbidden cursor when moving the drag between folders. Instead Qt only computes drop positions which are onto items, as we want here.&lt;/p&gt;&lt;p data-block-key=&quot;ahkov&quot;&gt;☑ Reimplement &lt;code&gt;Widget::mimeTypes()&lt;/code&gt; and return the same name as the one used on the drag side&apos;s &lt;code&gt;mimeData&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;2e3uc&quot;&gt;☑ Reimplement &lt;code&gt;Widget::dropMimeData()&lt;/code&gt; (note that the signature is different between &lt;code&gt;QListWidget&lt;/code&gt;, &lt;code&gt;QTableWidget&lt;/code&gt; and &lt;code&gt;QTreeWidget&lt;/code&gt;) This is where you deserialize the data and handle the drop. In the email example, this is where we copy or move the email into the destination folder.&lt;/p&gt;&lt;p data-block-key=&quot;dklo6&quot;&gt;Make sure to do all of the following:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;f8g44&quot;&gt;any necessary behind the scenes work (in our case, moving the actual email)&lt;/li&gt;&lt;li data-block-key=&quot;9afgt&quot;&gt;updating the UI (creating or deleting items as needed)&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;8m0jd&quot;&gt;This is a case where proper model/view separation is actually much simpler.&lt;/p&gt;&lt;h2 id=&quot;improvements-to-qt&quot; anchor=&quot;improvements-to-qt&quot; data-block-key=&quot;1cp4j&quot;&gt;Improvements to Qt&lt;/h2&gt;&lt;p data-block-key=&quot;ffn49&quot;&gt;While writing and testing these code examples, I improved the following things in Qt, in addition to those listed in the previous blog posts:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;7nmug&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-2553&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-2553&lt;/a&gt; QTreeView with setAutoExpandDelay() collapses items while dragging over it, fixed in Qt 6.8.1&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;conclusion&quot; anchor=&quot;conclusion&quot; data-block-key=&quot;6231l&quot;&gt;Conclusion&lt;/h2&gt;&lt;p data-block-key=&quot;al71j&quot;&gt;I hope you enjoyed this blog post series and learned a few things.&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/35_OrMik0ok?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Introduction to Qt Widgets (Part 67A) - Dropping Files onto Widgets&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;


&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-in-qt-part-3/&quot;&gt;Model/View Drag and Drop in Qt - Part 3&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>David Faure</dc:creator><category>c++</category><category>qt</category></item><item><title>Model/View Drag and Drop in Qt - Part 2</title><link>https://www.kdab.com/modelview-drag-and-drop-in-qt-part-2/</link><guid isPermaLink="true">https://www.kdab.com/modelview-drag-and-drop-in-qt-part-2/</guid><description>&lt;p data-block-key=&quot;1j2m5&quot;&gt;In this follow-up to our drag-and-drop guide, we explore how to move items between views in Qt’s model/view framework. Learn how to set up both drag and drop sides, handle MIME data, and implement key model methods. Whether you&apos;re working with model/view separation or with item widgets, this post provides practical examples to help you customize UI interactions effectively.&lt;/p&gt;</description><pubDate>Mon, 10 Mar 2025 08:19:00 GMT</pubDate><content:encoded>&lt;h1&gt;Model/View Drag and Drop in Qt - Part 2&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chaks&quot;&gt;In the &lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-part-1/&quot;&gt;previous blog&lt;/a&gt;, you learned all about moving items within a single view, to reorder them.&lt;/p&gt;&lt;p data-block-key=&quot;etoh6&quot;&gt;In part 2, we are still talking about moving items, and still about inserting them between existing items (never overwriting items) but this time the user can move items from one view to another. A typical use case is a list of available items on the left, and a list of selected items on the right (one concrete example would be to let the user customize which buttons should appear in a toolbar). This also often includes reordering items in the right-side list, the good news being that this comes for free (no extra code needed).&lt;/p&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step1&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part2-step1.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step1&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step1&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ebe0l&quot;&gt;Moving a row between treeviews, step 1&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step2&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part2-step2.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step2&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step2&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ebe0l&quot;&gt;Moving a row between treeviews, step 2&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step3&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/Blog_DragDrop_Qt_part2-step3.original.png&quot; class=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step3&quot; alt=&quot;Blog_Drag&amp;amp;Drop_Qt_part2-step3&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ebe0l&quot;&gt;Moving a row between treeviews, step 3&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;with-modelview-separation&quot; anchor=&quot;with-modelview-separation&quot; data-block-key=&quot;2bvtm&quot;&gt;With Model/View separation&lt;/h2&gt;&lt;p data-block-key=&quot;d6ka5&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part2-moving-items-between-views/model-view&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Example code&lt;/a&gt; for flat models and &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part2-moving-items-between-views/treemodel&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;example code&lt;/a&gt; for tree models.&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-view-on-the-drag-side&quot; anchor=&quot;setting-up-the-view-on-the-drag-side&quot; data-block-key=&quot;riiwb&quot;&gt;Setting up the view on the drag side&lt;/h3&gt;&lt;p data-block-key=&quot;6p241&quot;&gt;To allow dragging items out of the view, make sure to do the following:&lt;/p&gt;&lt;p data-block-key=&quot;fcvf1&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropMode(QAbstractItemView::DragOnly)&lt;/code&gt; (or &lt;code&gt;DragDrop&lt;/code&gt; if it should support both).&lt;/p&gt;&lt;p data-block-key=&quot;1bk19&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropOverwriteMode(false)&lt;/code&gt; so that &lt;code&gt;QTableView&lt;/code&gt; calls removeRows when moving rows, rather than just clearing their cells&lt;/p&gt;&lt;p data-block-key=&quot;68gvv&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDefaultDropAction(Qt::MoveAction)&lt;/code&gt; so it&apos;s a move and not a copy&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-model-on-the-drag-side&quot; anchor=&quot;setting-up-the-model-on-the-drag-side&quot; data-block-key=&quot;3io1k&quot;&gt;Setting up the model on the drag side&lt;/h3&gt;&lt;p data-block-key=&quot;bs2j1&quot;&gt;To implement dragging items out of a model, you need to implement the following:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;class CountryModel : public QAbstractTableModel
{
    ~~~
    Qt::ItemFlags flags(const QModelIndex &amp;amp;index) const override
    {
        if (!index.isValid())
            return {}; // depending on whether you want drops as well (next section)
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
    }

    // the default is &amp;quot;return supportedDropActions()&amp;quot;, let&amp;#x27;s be explicit
    Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }

    QMimeData *mimeData(const QModelIndexList &amp;amp;indexes) const override; // see below

    bool removeRows(int position, int rows, const QModelIndex &amp;amp;parent) override; // see below
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chaks&quot;&gt;More precisely, the check-list is the following:&lt;/p&gt;&lt;p data-block-key=&quot;2aq8&quot;&gt;☑ Reimplement &lt;code&gt;flags()&lt;/code&gt; to add &lt;code&gt;Qt::ItemIsDragEnabled&lt;/code&gt; in the case of a valid index&lt;/p&gt;&lt;p data-block-key=&quot;6ilmi&quot;&gt;☑ Reimplement &lt;code&gt;supportedDragActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;3n8ic&quot;&gt;☑ Reimplement &lt;code&gt;mimeData()&lt;/code&gt; to serialize the complete data for the dragged items. If the views are always in the same process, you can get away with serializing only node pointers (if you have that, e.g. for tree models) and application PID (to refuse dropping onto another process). Otherwise you can encode the actual data, like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;QMimeData *CountryModel::mimeData(const QModelIndexList &amp;amp;indexes) const
{
    QByteArray encodedData;
    QDataStream stream(&amp;amp;encodedData, QIODevice::WriteOnly);
    for (const QModelIndex &amp;amp;index : indexes) {
        // This calls operator&amp;lt;&amp;lt;(QDataStream &amp;amp;stream, const CountryData &amp;amp;countryData), which you must implement
        stream &amp;lt;&amp;lt; m_data.at(index.row());
    }

    QMimeData *mimeData = new QMimeData;
    mimeData-&amp;gt;setData(s_mimeType, encodedData);
    return mimeData;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chaks&quot;&gt;&lt;code&gt;s_mimeType&lt;/code&gt; is the name of the type of data (make up a name, it usually starts with &lt;code&gt;application/x-&lt;/code&gt;)&lt;/p&gt;&lt;p data-block-key=&quot;466rc&quot;&gt;☑ Reimplement &lt;code&gt;removeRows()&lt;/code&gt;, it will be called after a successful drop. For instance, if your data is in a vector called &lt;code&gt;m_data&lt;/code&gt;, the implementation would look like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;bool CountryModel::removeRows(int position, int rows, const QModelIndex &amp;amp;parent)
{
    beginRemoveRows(parent, position, position + rows - 1);
    for (int row = 0; row &amp;lt; rows; ++row)
        m_data.removeAt(position);
    endRemoveRows();
    return true;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;setting-up-the-view-on-the-drop-side&quot; anchor=&quot;setting-up-the-view-on-the-drop-side&quot; data-block-key=&quot;fdoo8&quot;&gt;Setting up the view on the drop side&lt;/h3&gt;&lt;p data-block-key=&quot;1nlju&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropMode(QAbstractItemView::DragDrop)&lt;/code&gt; (already done if both views should support dragging and dropping)&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-model-on-the-drop-side&quot; anchor=&quot;setting-up-the-model-on-the-drop-side&quot; data-block-key=&quot;3macl&quot;&gt;Setting up the model on the drop side&lt;/h3&gt;&lt;p data-block-key=&quot;bpo2m&quot;&gt;To implement dropping items into a model (between existing items), you need to implement the following:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;class DropModel : public QAbstractTableModel
{
    ~~~
    Qt::ItemFlags flags(const QModelIndex &amp;amp;index) const override
    {
        if (!index.isValid())
            return Qt::ItemIsDropEnabled;
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // and optionally Qt::ItemIsDragEnabled (previous section)
    }

    // the default is &amp;quot;copy only&amp;quot;, change it
    Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }

    QStringList mimeTypes() const override { return {QString::fromLatin1(s_mimeType)}; }

    bool dropMimeData(const QMimeData *mimeData, Qt::DropAction action, 
                      int row, int column, const QModelIndex &amp;amp;parent) override; // see below
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;chaks&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;1hb2o&quot;&gt;☑ Reimplement &lt;code&gt;flags()&lt;/code&gt;&lt;br/&gt; For a valid index, make sure &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt; is NOT set (except for tree models where we need to drop onto items in order to insert a first child).&lt;br/&gt; For the invalid index, add &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt;, to allow dropping between items.&lt;/p&gt;&lt;p data-block-key=&quot;c6b0b&quot;&gt;☑ Reimplement &lt;code&gt;mimeTypes()&lt;/code&gt; and return the name of the MIME type used by the &lt;code&gt;mimeData()&lt;/code&gt; function on the drag side.&lt;/p&gt;&lt;p data-block-key=&quot;7otep&quot;&gt;☑ Reimplement &lt;code&gt;dropMimeData()&lt;/code&gt;&lt;br/&gt; to deserialize the data and insert new rows.&lt;br/&gt; In the special case of in-process tree models, clone the dragged nodes.&lt;br/&gt; In both cases, once you&apos;re done, return true, so that the drag side then deletes the dragged rows by calling &lt;code&gt;removeRows()&lt;/code&gt; on its model.&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;bool DropModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int column, const QModelIndex &amp;amp;parent)
{
    ~~~  // safety checks, see full example code

    if (row == -1) // drop into empty area = append
        row = rowCount(parent);

    // decode data
    const QByteArray encodedData = mimeData-&amp;gt;data(s_mimeType);
    QDataStream stream(encodedData);
    QVector&amp;lt;CountryData&amp;gt; newCountries;
    while (!stream.atEnd()) {
        CountryData countryData;
        stream &amp;gt;&amp;gt; countryData;
        newCountries.append(countryData);
    }

    // insert new countries
    beginInsertRows(parent, row, row + newCountries.count() - 1);
    for (const CountryData &amp;amp;countryData : newCountries)
        m_data.insert(row++, countryData);
    endInsertRows();

    return true; // let the view handle deletion on the source side by calling removeRows there
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h2 id=&quot;using-item-widgets&quot; anchor=&quot;using-item-widgets&quot; data-block-key=&quot;u2nre&quot;&gt;Using item widgets&lt;/h2&gt;&lt;p data-block-key=&quot;3u2av&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part2-moving-items-between-views/itemwidgets&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Example code&lt;/a&gt; can be found following this link.&lt;/p&gt;&lt;h3 id=&quot;for-all-kinds-of-widgets&quot; anchor=&quot;for-all-kinds-of-widgets&quot; data-block-key=&quot;4ciwc&quot;&gt;For all kinds of widgets&lt;/h3&gt;&lt;p data-block-key=&quot;3bv9q&quot;&gt;On the &quot;drag&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;7aunc&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropMode(QAbstractItemView::DragOnly)&lt;/code&gt; or &lt;code&gt;DragDrop&lt;/code&gt; if it should support both&lt;/p&gt;&lt;p data-block-key=&quot;8vajf&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDefaultDropAction(Qt::MoveAction)&lt;/code&gt; so the drag starts as a move right away&lt;/p&gt;&lt;p data-block-key=&quot;1dkq5&quot;&gt;On the &quot;drop&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;7etkj&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropMode(QAbstractItemView::DropOnly)&lt;/code&gt; or &lt;code&gt;DragDrop&lt;/code&gt; if it should support both&lt;/p&gt;&lt;p data-block-key=&quot;47ha8&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; to return only &lt;code&gt;Qt::MoveAction&lt;/code&gt;&lt;/p&gt;&lt;h3 id=&quot;additional-requirements-for-qtablewidget&quot; anchor=&quot;additional-requirements-for-qtablewidget&quot; data-block-key=&quot;fswhx&quot;&gt;Additional requirements for QTableWidget&lt;/h3&gt;&lt;p data-block-key=&quot;b0jo2&quot;&gt;When using &lt;code&gt;QTableWidget&lt;/code&gt;, in addition to the common steps above you need to:&lt;/p&gt;&lt;p data-block-key=&quot;3prk2&quot;&gt;On the &quot;drag&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;33p4d&quot;&gt;☑ Call &lt;code&gt;item-&amp;gt;setFlags(item-&amp;gt;flags() &amp;amp; ~Qt::ItemIsDropEnabled);&lt;/code&gt; for each item, to disable dropping onto items.&lt;/p&gt;&lt;p data-block-key=&quot;5l9fm&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropOverwriteMode(false)&lt;/code&gt; so that after a move the rows are removed rather than cleared&lt;/p&gt;&lt;p data-block-key=&quot;37qks&quot;&gt;On the &quot;drop&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;aukud&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDragDropOverwriteMode(false)&lt;/code&gt; so that it inserts rows instead of replacing cells (the default is &lt;code&gt;false&lt;/code&gt; for the other views anyway)&lt;/p&gt;&lt;p data-block-key=&quot;54bnl&quot;&gt;☑ Another problem is that the items created by a drop will automatically get the &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt; flag, which you don&apos;t want. To solve this, use &lt;code&gt;widget-&amp;gt;setItemPrototype()&lt;/code&gt; with an item that has the right flags (see the example).&lt;/p&gt;&lt;h3 id=&quot;additional-requirements-for-qtreewidget&quot; anchor=&quot;additional-requirements-for-qtreewidget&quot; data-block-key=&quot;xy0ix&quot;&gt;Additional requirements for QTreeWidget&lt;/h3&gt;&lt;p data-block-key=&quot;3bgd2&quot;&gt;When using &lt;code&gt;QTreeWidget&lt;/code&gt;, you cannot disable dropping onto items (which creates a child of the item).&lt;/p&gt;&lt;p data-block-key=&quot;4159k&quot;&gt;You could call &lt;code&gt;item-&amp;gt;setFlags(item-&amp;gt;flags() &amp;amp; ~Qt::ItemIsDropEnabled);&lt;/code&gt; on your own items, but when &lt;code&gt;QTreeWidget&lt;/code&gt; creates new items upon a drop, you cannot prevent them from having the flag &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt; set. The prototype solution used above for &lt;code&gt;QTableWidget&lt;/code&gt; doesn&apos;t exist for &lt;code&gt;QTreeWidget&lt;/code&gt;.&lt;/p&gt;&lt;p data-block-key=&quot;bn3qv&quot;&gt;This means, if you want to let the user build and reorganize an actual tree, you can use &lt;code&gt;QTreeWidget&lt;/code&gt;. But if you just want a flat multi-column list, then you should use &lt;code&gt;QTreeView&lt;/code&gt; (see previous section on model/view separation).&lt;/p&gt;&lt;h2 id=&quot;addendum-movecopy-items-between-views&quot; anchor=&quot;addendum-movecopy-items-between-views&quot; data-block-key=&quot;ye2yn&quot;&gt;Addendum: Move/copy items between views&lt;/h2&gt;&lt;p data-block-key=&quot;f0bg3&quot;&gt;If the user should be able to choose between copying and moving items, follow the previous section and make the following changes.&lt;/p&gt;&lt;h3 id=&quot;with-modelview-separation&quot; anchor=&quot;with-modelview-separation&quot; data-block-key=&quot;gt2wm&quot;&gt;With Model/View separation&lt;/h3&gt;&lt;p data-block-key=&quot;5g8oh&quot;&gt;On the &quot;drag&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;1ou38&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDefaultDropAction(...)&lt;/code&gt; to choose whether the default should be move or copy. The user can press Shift to force a move, and Ctrl to force a copy.&lt;/p&gt;&lt;p data-block-key=&quot;akbil&quot;&gt;☑ Reimplement &lt;code&gt;supportedDragActions()&lt;/code&gt; in the model to return &lt;code&gt;Qt::MoveAction | Qt::CopyAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;9m4l2&quot;&gt;On the &quot;drop&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;79ftu&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; in the model to return &lt;code&gt;Qt::MoveAction | Qt::CopyAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;20u4f&quot;&gt;The good news is that there&apos;s nothing else to do.&lt;/p&gt;&lt;h3 id=&quot;using-item-widgets&quot; anchor=&quot;using-item-widgets&quot; data-block-key=&quot;eo36z&quot;&gt;Using item widgets&lt;/h3&gt;&lt;p data-block-key=&quot;civc1&quot;&gt;On the &quot;drag&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;cht14&quot;&gt;☑ Call &lt;code&gt;widget-&amp;gt;setDefaultDropAction(...)&lt;/code&gt; to choose whether the default should be move or copy. The user can press Shift to force a move, and Ctrl to force a copy.&lt;/p&gt;&lt;p data-block-key=&quot;dfojn&quot;&gt;Until Qt 6.10 there was no &lt;code&gt;setSupportedDragActions()&lt;/code&gt; method in the item widget classes (that was &lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-87465&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-87465&lt;/a&gt;, I implemented it for 6.10). Fortunately the default behavior is to use what &lt;code&gt;supportedDropActions()&lt;/code&gt; returns so if you just want move and copy in both, reimplementing &lt;code&gt;supportedDropActions()&lt;/code&gt; is enough.&lt;/p&gt;&lt;p data-block-key=&quot;f1135&quot;&gt;On the &quot;drop&quot; side:&lt;/p&gt;&lt;p data-block-key=&quot;d2u4p&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; in the item widget class to return &lt;code&gt;Qt::MoveAction | Qt::CopyAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;6f810&quot;&gt;The good news is that there&apos;s nothing else to do.&lt;/p&gt;&lt;h3 id=&quot;improvements-to-qt&quot; anchor=&quot;improvements-to-qt&quot; data-block-key=&quot;nxuuc&quot;&gt;Improvements to Qt&lt;/h3&gt;&lt;p data-block-key=&quot;18jv6&quot;&gt;While writing and testing these code examples, I improved the following things in Qt:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;dkpn9&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-1387&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-1387&lt;/a&gt; &quot;Drag and drop multiple columns with item views. Dragging a row and dropping it in a column &amp;gt; 0 creates multiple rows.&quot;, fixed in 6.8.1&lt;/li&gt;&lt;li data-block-key=&quot;1naij&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-36831&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-36831&lt;/a&gt; &quot;Drop indicator painted as single pixel when not shown&quot; fixed in 6.8.1&lt;/li&gt;&lt;li data-block-key=&quot;8jnjc&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-87465&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-87465&lt;/a&gt; ItemWidgets: add supportedDragActions()/setSupportedDragActions(), implemented in 6.10&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;conclusion&quot; anchor=&quot;conclusion&quot; data-block-key=&quot;n7g21&quot;&gt;Conclusion&lt;/h2&gt;&lt;p data-block-key=&quot;3rn34&quot;&gt;In the next blog post of this series, you will learn how to move (or copy) onto existing items, rather than between them.&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/35_OrMik0ok?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Introduction to Qt Widgets (Part 67A) - Dropping Files onto Widgets&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;


&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-in-qt-part-2/&quot;&gt;Model/View Drag and Drop in Qt - Part 2&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>David Faure</dc:creator><category>c++</category><category>qt</category></item><item><title>Model/View Drag and Drop in Qt - Part 1</title><link>https://www.kdab.com/modelview-drag-and-drop-part-1/</link><guid isPermaLink="true">https://www.kdab.com/modelview-drag-and-drop-part-1/</guid><description>&lt;p data-block-key=&quot;228lt&quot;&gt;This blog post is the first in a series on implementing drag-and-drop in the Qt model/view framework. It covers how to reorder items within a single view, whether you&apos;re using QListView, QTableView, or QTreeView with a custom model, or QListWidget, QTableWidget, or QTreeWidget with items. The post includes code examples, checklists, and insights into improvements made in Qt 6.8 for smoother drag-and-drop functionality.&lt;/p&gt;</description><pubDate>Thu, 06 Feb 2025 08:07:00 GMT</pubDate><content:encoded>&lt;h1&gt;Model/View Drag and Drop in Qt - Part 1&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;This blog series is all about implementing drag-and-drop in the Qt model/view framework. In addition to complete code examples, you&apos;ll find checklists that you can go through to make sure that you did not forget anything in your own implementation, when something isn&apos;t working as expected.&lt;/p&gt;&lt;p data-block-key=&quot;8b84o&quot;&gt;At first, we are going to look at Drag and Drop within a single view, to change the order of the items. The view can be a list, a table or a tree, there are very little differences in what you have to do.&lt;/p&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-table-step1&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-table-step1.original.png&quot; class=&quot;part1-table-step1&quot; alt=&quot;part1-table-step1&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Moving a row in a tableview, step 1&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-table-step2&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-table-step2.original.png&quot; class=&quot;part1-table-step2&quot; alt=&quot;part1-table-step2&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Moving a row in a tableview, step 2&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-table-step3&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-table-step3.original.png&quot; class=&quot;part1-table-step3&quot; alt=&quot;part1-table-step3&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Moving a row in a tableview, step 3&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;The main question, however, is whether you are using QListView/QTableView/QTreeView on top of a custom item model, or QListWidget/QTableWidget/QTreeWidget with items in them. Let&apos;s explore each one in turn.&lt;/p&gt;&lt;h2 id=&quot;with-modelview-separation&quot; anchor=&quot;with-modelview-separation&quot; data-block-key=&quot;zmu6n&quot;&gt;With Model/View separation&lt;/h2&gt;&lt;p data-block-key=&quot;30k34&quot;&gt;The code being discussed here is extracted from &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part1-reordering-elements/model-view&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;the example&lt;/a&gt;. That example features a flat model, while &lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part1-reordering-elements/treemodel&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;this example&lt;/a&gt; features a tree model. The checklist is the same for these two cases.&lt;/p&gt;&lt;h3 id=&quot;setting-up-the-view&quot; anchor=&quot;setting-up-the-view&quot; data-block-key=&quot;5rsnb&quot;&gt;Setting up the view&lt;/h3&gt;&lt;p data-block-key=&quot;6g39s&quot;&gt;☑ Call &lt;code&gt;view-&amp;gt;setDragDropMode(QAbstractItemView::InternalMove)&lt;/code&gt; to enable the mode where only moving within the same view is allowed&lt;/p&gt;&lt;p data-block-key=&quot;5an2c&quot;&gt;☑ When using &lt;code&gt;QTableView&lt;/code&gt;, call &lt;code&gt;view-&amp;gt;setDragDropOverwriteMode(false)&lt;/code&gt; so that it inserts rows instead of replacing cells (the default is &lt;code&gt;false&lt;/code&gt; for the other views anyway)&lt;/p&gt;&lt;h3 id=&quot;adding-drag-n-drop-support-to-the-model&quot; anchor=&quot;adding-drag-n-drop-support-to-the-model&quot; data-block-key=&quot;rv5to&quot;&gt;Adding drag-n-drop support to the model&lt;/h3&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-list&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-list.original.png&quot; class=&quot;part1-list&quot; alt=&quot;part1-list&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable ListView&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-table&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-table.original.png&quot; class=&quot;part1-table&quot; alt=&quot;part1-table&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable TableView&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;For a model being used in QListView or QTableView, all you need is something like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;class CountryModel : public QAbstractTableModel
{
    ~~~
    Qt::ItemFlags flags(const QModelIndex &amp;amp;index) const override
    {
        if (!index.isValid())
            return Qt::ItemIsDropEnabled; // allow dropping between items
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
    }

    // the default is &amp;quot;copy only&amp;quot;, change it
    Qt::DropActions supportedDropActions() const override { return Qt::MoveAction; }

    // the default is &amp;quot;return supportedDropActions()&amp;quot;, let&amp;#x27;s be explicit
    Qt::DropActions supportedDragActions() const override { return Qt::MoveAction; }

    QStringList mimeTypes() const override { return {QString::fromLatin1(s_mimeType)}; }

    bool moveRows(const QModelIndex &amp;amp;sourceParent, int sourceRow, int count, const QModelIndex &amp;amp;destinationParent, int destinationChild) override; // see below
};&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;The checklist for the changes you need to make in your model is therefore the following:&lt;/p&gt;&lt;p data-block-key=&quot;3gmg7&quot;&gt;☑ Reimplement &lt;code&gt;flags()&lt;/code&gt;&lt;br/&gt; For a valid index, add &lt;code&gt;Qt::ItemIsDragEnabled&lt;/code&gt; and make sure &lt;code&gt;Qt::ItemIsDropEnabled&lt;/code&gt; is NOT set (except for tree models where we need to drop onto items in order to insert a first child). \&lt;/p&gt;&lt;p data-block-key=&quot;2laoa&quot;&gt;☑ Reimplement &lt;code&gt;mimeTypes()&lt;/code&gt; and make up a name for the mimetype (usually starting with &lt;code&gt;application/x-&lt;/code&gt;)&lt;/p&gt;&lt;p data-block-key=&quot;9po6f&quot;&gt;☑ Reimplement &lt;code&gt;supportedDragActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;dd3l0&quot;&gt;☑ Reimplement &lt;code&gt;supportedDropActions()&lt;/code&gt; to return &lt;code&gt;Qt::MoveAction&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;jues&quot;&gt;☑ Reimplement &lt;code&gt;moveRows()&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;7gh1v&quot;&gt;Note that this approach is only valid when using &lt;code&gt;QListView&lt;/code&gt; or, assuming Qt &amp;gt;= 6.8.0, &lt;code&gt;QTableView&lt;/code&gt; - see the following sections for details.&lt;/p&gt;&lt;p data-block-key=&quot;aqmhr&quot;&gt;In a model that encapsulates a &lt;code&gt;QVector&lt;/code&gt; called &lt;code&gt;m_data&lt;/code&gt;, the implementation of &lt;code&gt;moveRows&lt;/code&gt; can look like this:&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;formatted-code&quot;&gt;
    &lt;pre&gt;&lt;code class=&quot;language-cpp  line-numbers &quot;&gt;bool CountryModel::moveRows(const QModelIndex &amp;amp;sourceParent, int sourceRow, int count, const QModelIndex &amp;amp;destinationParent, int destinationChild)
{
    if (!beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild))
        return false; // invalid move, e.g. no-op (move row 2 to row 2 or to row 3)

    for (int i = 0; i &amp;lt; count; ++i) {
        m_data.move(sourceRow + i, destinationChild + (sourceRow &amp;gt; destinationChild ? 0 : -1));
    }

    endMoveRows();
    return true;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;div class=&quot;rich-text&quot;&gt;&lt;h3 id=&quot;qtreeview-does-not-call-moverows&quot; anchor=&quot;qtreeview-does-not-call-moverows&quot; data-block-key=&quot;7rzqf&quot;&gt;QTreeView does not call moveRows&lt;/h3&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-tree&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-tree.original.png&quot; class=&quot;part1-tree&quot; alt=&quot;part1-tree&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable treeview&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-treemodel&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-treemodel.original.png&quot; class=&quot;part1-treemodel&quot; alt=&quot;part1-treemodel&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable treeview with a tree model&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;QTreeView does not (yet?) call &lt;code&gt;moveRows&lt;/code&gt; in the model, so you need to:&lt;/p&gt;&lt;p data-block-key=&quot;2n85v&quot;&gt;☑ Reimplement &lt;code&gt;mimeData()&lt;/code&gt; to encode row numbers for flat models, and node pointers for tree models&lt;/p&gt;&lt;p data-block-key=&quot;3iusc&quot;&gt;☑ Reimplement &lt;code&gt;dropMimeData()&lt;/code&gt; to implement the move and return false (meaning: all done)&lt;/p&gt;&lt;p data-block-key=&quot;fcc85&quot;&gt;Note that this means a move is in fact an insertion and a deletion, so the selection isn&apos;t automatically updated to point to the moved row(s).&lt;/p&gt;&lt;h3 id=&quot;qtableview-in-qt-680&quot; anchor=&quot;qtableview-in-qt-680&quot; data-block-key=&quot;c7rbr&quot;&gt;QTableView in Qt &amp;lt; 6.8.0&lt;/h3&gt;&lt;p data-block-key=&quot;24crl&quot;&gt;I implemented moving of rows in &lt;code&gt;QTableView&lt;/code&gt; itself for Qt 6.8.0, so that moving rows in a table view is simpler to implement (one method instead of two), more efficient, and so that selection is updated. If you&apos;re not yet using Qt &amp;gt;= 6.8.0 then you&apos;ll have to reimplement &lt;code&gt;mimeData()&lt;/code&gt; and &lt;code&gt;dropMimeData()&lt;/code&gt; in your model, as per the previous section.&lt;/p&gt;&lt;p data-block-key=&quot;cf0jh&quot;&gt;This concludes the section on how to implement a reorderable view using a separate model class.&lt;/p&gt;&lt;h2 id=&quot;using-item-widgets&quot; anchor=&quot;using-item-widgets&quot; data-block-key=&quot;s05h5&quot;&gt;Using item widgets&lt;/h2&gt;&lt;p data-block-key=&quot;6u93&quot;&gt;The alternative to model/view separation is the use of the item widgets (&lt;code&gt;QListWidget&lt;/code&gt;, &lt;code&gt;QTableWidget&lt;/code&gt; or &lt;code&gt;QTreeWidget&lt;/code&gt;) which you populate directly by creating items.&lt;/p&gt;&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-listwidget&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-listwidget.original.png&quot; class=&quot;part1-listwidget&quot; alt=&quot;part1-listwidget&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable QListWidget&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-tablewidget&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-tablewidget.original.png&quot; class=&quot;part1-tablewidget&quot; alt=&quot;part1-tablewidget&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable QTableWidget&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;part1-treewidget&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/part1-treewidget.original.png&quot; class=&quot;part1-treewidget&quot; alt=&quot;part1-treewidget&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;pnkqi&quot;&gt;Reorderable QTreeWidget&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ame85&quot;&gt;Here&apos;s what you need to do to allow users to reorder those items.&lt;/p&gt;&lt;p data-block-key=&quot;avskc&quot;&gt;&lt;a href=&quot;https://github.com/KDABLabs/blogs-qt/tree/main/ItemViews-DragAndDrop/part1-reordering-elements/itemwidgets&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Example code&lt;/a&gt; can be found following this link.&lt;/p&gt;&lt;h3 id=&quot;reorderable-qlistwidget&quot; anchor=&quot;reorderable-qlistwidget&quot; data-block-key=&quot;pyoci&quot;&gt;Reorderable QListWidget&lt;/h3&gt;&lt;p data-block-key=&quot;6dnej&quot;&gt;☑ Call &lt;code&gt;listWidget-&amp;gt;setDragDropMode(QAbstractItemView::InternalMove)&lt;/code&gt; to enable the mode where only moving within the same view is allowed&lt;/p&gt;&lt;p data-block-key=&quot;6c1ku&quot;&gt;For a &lt;code&gt;QListWidget&lt;/code&gt;, this is all you need. That was easy!&lt;/p&gt;&lt;h3 id=&quot;reorderable-qtablewidget&quot; anchor=&quot;reorderable-qtablewidget&quot; data-block-key=&quot;e6x07&quot;&gt;Reorderable QTableWidget&lt;/h3&gt;&lt;p data-block-key=&quot;8sglk&quot;&gt;When using &lt;code&gt;QTableWidget&lt;/code&gt;:&lt;/p&gt;&lt;p data-block-key=&quot;fo6ir&quot;&gt;☑ Call &lt;code&gt;tableWidget-&amp;gt;setDragDropMode(QAbstractItemView::InternalMove)&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;8cfv5&quot;&gt;☑ Call &lt;code&gt;tableWidget-&amp;gt;setDragDropOverwriteMode(false)&lt;/code&gt; so that it inserts rows instead of replacing cells&lt;/p&gt;&lt;p data-block-key=&quot;22rpq&quot;&gt;☑ Call &lt;code&gt;item-&amp;gt;setFlags(item-&amp;gt;flags() &amp;amp; ~Qt::ItemIsDropEnabled);&lt;/code&gt; on each item, to disable dropping onto items&lt;/p&gt;&lt;p data-block-key=&quot;cpaqu&quot;&gt;Note: Before Qt 6.8.0, &lt;code&gt;QTableWidget&lt;/code&gt; did not really support moving rows. It would instead move data into cells (like Excel). The example code shows a workaround, but since it calls code that inserts a row and deletes the old one, header data is lost in the process. My changes in Qt 6.8.0 implement support for moving rows in &lt;code&gt;QTableWidget&lt;/code&gt;&apos;s internal model, so it&apos;s all fixed there. If you really need this feature in older versions of Qt, consider switching to &lt;code&gt;QTableView&lt;/code&gt;.&lt;/p&gt;&lt;h3 id=&quot;reorderable-qtreewidget&quot; anchor=&quot;reorderable-qtreewidget&quot; data-block-key=&quot;o5ljf&quot;&gt;Reorderable QTreeWidget&lt;/h3&gt;&lt;p data-block-key=&quot;76fbk&quot;&gt;When using &lt;code&gt;QTreeWidget&lt;/code&gt;:&lt;/p&gt;&lt;p data-block-key=&quot;cjm4i&quot;&gt;☑ Call &lt;code&gt;tableWidget-&amp;gt;setDragDropMode(QAbstractItemView::InternalMove)&lt;/code&gt;&lt;/p&gt;&lt;p data-block-key=&quot;8ubr8&quot;&gt;☑ Call &lt;code&gt;item-&amp;gt;setFlags(item-&amp;gt;flags() &amp;amp; ~Qt::ItemIsDropEnabled);&lt;/code&gt; on each item, to disable dropping onto items&lt;/p&gt;&lt;h3 id=&quot;conclusion-about-reorderable-item-widgets&quot; anchor=&quot;conclusion-about-reorderable-item-widgets&quot; data-block-key=&quot;fafa0&quot;&gt;Conclusion about reorderable item widgets&lt;/h3&gt;&lt;p data-block-key=&quot;ckv9l&quot;&gt;Of course, you&apos;ll also need to iterate over the items at the end to grab the new order, like the example code does. As usual, item widgets lead to less code to write, but the runtime performance is worse than when using model/view separation. So, only use item widgets when the number of items is small (and you don&apos;t need proxy models).&lt;/p&gt;&lt;h2 id=&quot;improvements-to-qt&quot; anchor=&quot;improvements-to-qt&quot; data-block-key=&quot;os039&quot;&gt;Improvements to Qt&lt;/h2&gt;&lt;p data-block-key=&quot;6e6r8&quot;&gt;While writing and testing these code examples, I improved the following things in Qt 6.8:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;1ao5n&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-13873&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-13873&lt;/a&gt; / &lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-101475&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-101475&lt;/a&gt; - QTableView: implement moving rows by drag-n-drop&lt;/li&gt;&lt;li data-block-key=&quot;fokbn&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-69807&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-69807&lt;/a&gt; - Implement QTableModel::moveRows&lt;/li&gt;&lt;li data-block-key=&quot;5iu0p&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-130045&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-130045&lt;/a&gt; - QTableView: fix dropping between items when precisely on the cell border&lt;/li&gt;&lt;li data-block-key=&quot;cd23s&quot;&gt;&lt;a href=&quot;https://bugreports.qt.io/browse/QTBUG-1656&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;QTBUG-1656&lt;/a&gt; - Implement full-row drop indicator when the selection behavior is SelectRows&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;conclusion&quot; anchor=&quot;conclusion&quot; data-block-key=&quot;doo2y&quot;&gt;Conclusion&lt;/h2&gt;&lt;p data-block-key=&quot;1rpb3&quot;&gt;I hope this checklist will be useful when you have to implement your own reordering of items in a model or an item-widget. Please post a comment if anything appears to be incorrect or missing.&lt;/p&gt;&lt;p data-block-key=&quot;1bnuu&quot;&gt;In the next blog post of this series, you will learn how to move (or even copy) items from one view to another.&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/35_OrMik0ok?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;Introduction to Qt Widgets (Part 67A) - Dropping Files onto Widgets&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;


&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/modelview-drag-and-drop-part-1/&quot;&gt;Model/View Drag and Drop in Qt - Part 1&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>David Faure</dc:creator><category>c++</category><category>qt</category></item><item><title>KDAB Training Day - May 8th, 2025</title><link>https://www.kdab.com/kdab-training-day-may-8th-2025/</link><guid isPermaLink="true">https://www.kdab.com/kdab-training-day-may-8th-2025/</guid><description>&lt;p data-block-key=&quot;quovc&quot;&gt;Early-Bird tickets are on sale for the KDAB Training Day 2025 until 2025-03-31 23:59 The KDAB Training Day 2025 will take place in Munich on May 8th, right after the Qt World Summit on May 6th-7th. Choose to buy a combo ticket here (for access to QtWS and Training Day) or here (for access to […]&lt;/p&gt;</description><pubDate>Tue, 05 Nov 2024 12:56:00 GMT</pubDate><content:encoded>&lt;h1&gt;KDAB Training Day - May 8th, 2025&lt;/h1&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;igfc3&quot;&gt;&lt;i&gt;Early-Bird tickets&lt;/i&gt; are on sale for the KDAB Training Day 2025 until 2025-03-31 23:59&lt;/p&gt;&lt;/div&gt;


&lt;div class=&quot;image-variable-size-block&quot;&gt;
    &lt;div class=&quot;image-variable-positioning-block right-margin-auto left-margin-auto width-100 &quot; &gt;
            &lt;div class=&quot;image-variable-size-image&quot;&gt;
                
                
                
                &lt;img id=&quot;training-day-long-banner.png&quot; src=&quot;https://eu-central-1.linodeobjects.com/wagtail-production/images/training-day-long-banner.original.png&quot; class=&quot;training-day-long-banner.png&quot; alt=&quot;training-day-long-banner.png&quot;&gt;
                
                
        &lt;/div&gt;
        &lt;div class=&quot;image-variable-size-caption text-center&quot;&gt;&lt;div class=&quot;rich-text&quot;&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;rich-text&quot;&gt;&lt;p data-block-key=&quot;ap7up&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;The KDAB Training Day 2025&lt;/a&gt; will take place in Munich on May 8th, right after the &lt;a href=&quot;https://www.qt.io/qt-world-summit-2025&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Qt World Summit&lt;/a&gt; on May 6th-7th. Choose to buy a combo ticket &lt;a href=&quot;https://www.qt.io/qt-world-summit-2025&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; (for access to QtWS and Training Day) or &lt;a href=&quot;https://pretix.kdab.com/KDAB/KTD25/&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; (for access to Training Day only).&lt;/p&gt;&lt;p data-block-key=&quot;2tcbs&quot;&gt;Seats are limited, so don&apos;t wait too long if you want to participate in a specific course. Tickets include access to the selected training course, training material, lunch buffet, beverages, and coffee breaks. &lt;b&gt;Note:&lt;/b&gt; The Training Day is held at &lt;b&gt;Hotel NH Collection München Bavaria&lt;/b&gt;, located at the Munich Central Station &lt;i&gt;(not the same location as Qt World Summit)&lt;/i&gt;.&lt;/p&gt;&lt;p data-block-key=&quot;d352j&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;p data-block-key=&quot;6ryli&quot;&gt;Why should you attend the KDAB Training Day?&lt;/p&gt;&lt;p data-block-key=&quot;l96hp&quot;&gt;With over 20 years of experience and a rich store of well-structured, constantly updated training material, KDAB offers hands-on, practical programming training in &lt;a href=&quot;https://training.kdab.com/portfolio/qtqml/&quot;&gt;Qt/QML&lt;/a&gt;, &lt;a href=&quot;https://training.kdab.com/portfolio/modern-cpp/&quot;&gt;Modern C++&lt;/a&gt;, &lt;a href=&quot;https://training.kdab.com/portfolio/3dopengl/&quot;&gt;3D/OpenGL&lt;/a&gt;, &lt;a href=&quot;https://training.kdab.com/portfolio/debugging-and-profiling/&quot;&gt;Debugging &amp;amp; Profiling&lt;/a&gt;, and lately &lt;a href=&quot;https://training.kdab.com/portfolio/rust/&quot;&gt;Rust&lt;/a&gt; - both for beginners as well as experienced developers.&lt;/p&gt;&lt;p data-block-key=&quot;xzslp&quot;&gt;All courses provided at the Training Day include central parts of the regular 3- to 4-day courses available as scheduled or customized on-site training. Choosing a compact, learning-rich one-day course, lets you experience the quality and effectiveness of KDAB’s usual training offerings.&lt;/p&gt;&lt;p data-block-key=&quot;fcobh&quot;&gt;Courses available at the KDAB Training Day 2025&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;x0mfk&quot;&gt;&lt;a href=&quot;#qml-application-architecture&quot;&gt;QML Application Architecture&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;9m8qm&quot;&gt;&lt;a href=&quot;#qmlc-integration&quot;&gt;QML/C++ integration&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;7p8o4&quot;&gt;&lt;a href=&quot;#modern-c-paradigms&quot;&gt;Modern C++ Paradigms&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;edx0o&quot;&gt;&lt;a href=&quot;#integrating-rust-into-qt-applications&quot;&gt;Integrating Rust into Qt applications&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;hl06k&quot;&gt;&lt;a href=&quot;#effective-modern-qml&quot;&gt;Effective Modern QML&lt;/a&gt;&lt;/li&gt;&lt;li data-block-key=&quot;s2cbo&quot;&gt;&lt;a href=&quot;#integrating-custom-3d-renderers-with-qt-applications&quot;&gt;Integrating Custom 3D Renderers with Qt Applications&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;qml-application-architecture&quot; anchor=&quot;qml-application-architecture&quot; data-block-key=&quot;qnmor&quot;&gt;QML Application Architecture&lt;/h2&gt;&lt;p data-block-key=&quot;geirr&quot;&gt;In this training, we do a step-by-step walkthrough of how to build a QML-based embedded application from the ground up and discuss some challenges that are typically met along the way.&lt;/p&gt;&lt;p data-block-key=&quot;hdzm7&quot;&gt;An important part of that journey is an investigation of where to put the boundaries between what you do in C++ and what you do in QML. We also look at some of the tools and building blocks we have available in QML that can help us achieve well-performing, well-structured, and well-maintainable applications.&lt;/p&gt;&lt;p data-block-key=&quot;wim67&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;m49v3&quot;&gt;(Qt) developers looking to improve their understanding of how to construct maintainable and efficient larger-scale QML applications.&lt;/p&gt;&lt;p data-block-key=&quot;zhs37&quot;&gt;Prerequisite&lt;/p&gt;&lt;p data-block-key=&quot;0bdn1&quot;&gt;Some real-world experience working on QML applications as well as a basic understanding of Qt and C++.&lt;/p&gt;&lt;p data-block-key=&quot;abz7m&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;qmlc-integration&quot; anchor=&quot;qmlc-integration&quot; data-block-key=&quot;keojs&quot;&gt;QML/C++ Integration&lt;/h2&gt;&lt;p data-block-key=&quot;3dqei&quot;&gt;In this training, we start with a recap of fundamentals:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;b4n6c&quot;&gt;How do we expose C++ API to QML?&lt;/li&gt;&lt;li data-block-key=&quot;j9u24&quot;&gt;How do we make data available to QML?&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;1cte8&quot;&gt;Afterward, we explore several more advanced techniques, often widely deployed within Qt&apos;s QML modules, such as Qt Quick.&lt;/p&gt;&lt;p data-block-key=&quot;mpkf2&quot;&gt;This will answer questions such as:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;jo5ny&quot;&gt;How would I do a Loader like component?&lt;/li&gt;&lt;li data-block-key=&quot;ittt3&quot;&gt;How would I do a Layout like component?&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;1qw3d&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;2982n&quot;&gt;Qt/QML developers who are familiar with the QML APIs of QtQuick and related modules and who have wondered how these are implemented and want to use similar techniques in their project-specific APIs.&lt;/p&gt;&lt;p data-block-key=&quot;jr59q&quot;&gt;Prerequisite&lt;/p&gt;&lt;p data-block-key=&quot;3jxrd&quot;&gt;Some real-world experience working on QML applications as well as a basic understanding of Qt and C++.&lt;/p&gt;&lt;p data-block-key=&quot;e0emd&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;modern-c-paradigms&quot; anchor=&quot;modern-c-paradigms&quot; data-block-key=&quot;llojl&quot;&gt;Modern C++ Paradigms&lt;/h2&gt;&lt;p data-block-key=&quot;dsf92&quot;&gt;Modern C++ emphasizes safer, more efficient, and maintainable code through higher-level abstractions that reduce error-prone manual work.&lt;/p&gt;&lt;p data-block-key=&quot;tz6cq&quot;&gt;This training will explore key paradigms shaping recent C++ evolution, starting with value semantics in class design, which enhances code safety, local reasoning, and thread safety. We will examine modern C++ tools for creating value-oriented types, including move semantics, smart pointers, and other library enablers.&lt;/p&gt;&lt;p data-block-key=&quot;8dpio&quot;&gt;Next, we will look at expressive, type and value-based error handling.&lt;/p&gt;&lt;p data-block-key=&quot;zigla&quot;&gt;Finally, we&apos;ll cover range-based programming, which enables clean, declarative code and unlocks new patterns through lazy, composable transformations.&lt;/p&gt;&lt;p data-block-key=&quot;q6ped&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;8isno&quot;&gt;C++ developers who wish to improve the quality of their code, in particular those who wish to write future-proof APIs.&lt;/p&gt;&lt;p data-block-key=&quot;8n6ph&quot;&gt;Prerequisites&lt;/p&gt;&lt;p data-block-key=&quot;c4hll&quot;&gt;Prior professional experience in C++. Experience with the latest C++ standards (C++20/23/26) is a plus. We will use several examples inspired by Qt APIs, so Qt knowledge is also a plus (but this is not going to be a Qt training).&lt;/p&gt;&lt;p data-block-key=&quot;2r8ap&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;integrating-rust-into-qt-applications&quot; anchor=&quot;integrating-rust-into-qt-applications&quot; data-block-key=&quot;yb023&quot;&gt;Integrating Rust into Qt Applications&lt;/h2&gt;&lt;p data-block-key=&quot;5h7mg&quot;&gt;In this step-by-step course, we start with a Qt/C++ application and add Rust code to it piece by piece. To achieve this, we will cover:&lt;/p&gt;&lt;ul&gt;&lt;li data-block-key=&quot;gecw3&quot;&gt;Use of Cargo (Rusts build system) with CMake&lt;/li&gt;&lt;li data-block-key=&quot;e6rqy&quot;&gt;Accessing Rust code from C++ with CXX (and vice-versa)&lt;/li&gt;&lt;li data-block-key=&quot;sd983&quot;&gt;Defining your own QObject types in Rust with CXX-Qt&lt;/li&gt;&lt;/ul&gt;&lt;p data-block-key=&quot;lwnki&quot;&gt;We discuss when to use Rust compared to C++ to make the best of both languages and how to use them together effectively to make Qt applications safer and easier to maintain.&lt;/p&gt;&lt;p data-block-key=&quot;h8szb&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;k7841&quot;&gt;Qt/C++ Developers with an interest in Rust who want to learn how to use Rust in their existing applications.&lt;/p&gt;&lt;p data-block-key=&quot;qigmj&quot;&gt;Prerequisites&lt;/p&gt;&lt;p data-block-key=&quot;mw4l3&quot;&gt;Basic Qt/C++ knowledge, as well as basic Rust knowledge, is required. A working Qt installation with CMake and a working Rust installation is needed. We will provide material before the training day that participants should use to check their setup before the training.&lt;/p&gt;&lt;p data-block-key=&quot;y81t4&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;effective-modern-qml&quot; anchor=&quot;effective-modern-qml&quot; data-block-key=&quot;eli4s&quot;&gt;Effective Modern QML&lt;/h2&gt;&lt;p data-block-key=&quot;qthcx&quot;&gt;In this training, we look into all the new developments in QML over the last few years and how they lead to more expressive, performant, and maintainable code.&lt;/p&gt;&lt;p data-block-key=&quot;9dmn1&quot;&gt;This includes:&lt;br/&gt; - The qt_add_qml_module CMake API&lt;br/&gt; - Declarative type registration&lt;br/&gt; - The different QML compilers&lt;br/&gt; - New language and library features&lt;br/&gt; - New developments in Qt Quick Controls&lt;br/&gt; - Usage of tools like qmllint, QML Language Server, and qmlformat&lt;/p&gt;&lt;p data-block-key=&quot;lhn00&quot;&gt;The focus will be on gradually modernizing existing codebases with new tools and practices.&lt;/p&gt;&lt;p data-block-key=&quot;tsm66&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;licpc&quot;&gt;Developers who learned QML back in the days of Qt 5 and want to catch up with recent developments in QML and modernize their knowledge as well as codebases.&lt;/p&gt;&lt;p data-block-key=&quot;ov6qf&quot;&gt;Prerequities&lt;/p&gt;&lt;p data-block-key=&quot;fia6d&quot;&gt;Some real-world experience with QML and a desire to learn about modern best practices.&lt;/p&gt;&lt;p data-block-key=&quot;je3a8&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;integrating-custom-3d-renderers-with-qt-applications&quot; anchor=&quot;integrating-custom-3d-renderers-with-qt-applications&quot; data-block-key=&quot;z6hmr&quot;&gt;Integrating Custom 3D Renderers with Qt Applications&lt;/h2&gt;&lt;p data-block-key=&quot;r2mi4&quot;&gt;Qt has long offered ways of using low-level 3d libraries such as OpenGL to do custom rendering. Whether at the Window, the Widget, or Quick Item level, the underlying rendering system can be accessed in ways that make it safe to integrate such 3rd party renderers. This remains true in the Qt 6 timeline, although the underlying rendering system has changed and OpenGL has been replaced by RHI.&lt;/p&gt;&lt;p data-block-key=&quot;zc4jy&quot;&gt;In this course, we look at how the graphic stack is structured in Qt 6 and how third-party renderers can be integrated on the various platforms supported by Qt.&lt;/p&gt;&lt;p data-block-key=&quot;9jgtw&quot;&gt;We then focus on the specific case of integrating Vulkan-based renderers. Vulkan is the successor to OpenGL; it&apos;s much more powerful but harder to learn. To facilitate the initial use of Vulkan, we introduce KDGpu, a library that encapsulates Vulkan while preserving the underlying concepts of pipeline objects, buffer handling, synchronization, etc.&lt;/p&gt;&lt;p data-block-key=&quot;soj9b&quot;&gt;This course is for&lt;/p&gt;&lt;p data-block-key=&quot;sla8z&quot;&gt;This course targets developers wanting to understand the recent state of the graphics stack in Qt, discover the fundamental principles of modern graphics API, and integrate their custom renderers in their applications.&lt;/p&gt;&lt;p data-block-key=&quot;obnme&quot;&gt;Prerequisite&lt;/p&gt;&lt;p data-block-key=&quot;w7m3e&quot;&gt;Prior knowledge of Qt will be required. A basic understanding of 3d graphics would be beneficial.&lt;/p&gt;&lt;p data-block-key=&quot;2ebim&quot;&gt;&lt;a href=&quot;https://training.kdab.com/ktd25/&quot;&gt;Get your ticket&lt;/a&gt;&lt;/p&gt;&lt;p data-block-key=&quot;fc1c3&quot;&gt;&lt;i&gt;Video from KDAB Training Day 2023 held in Berlin&lt;/i&gt;&lt;/p&gt;&lt;/div&gt;







&lt;div class=&quot;cookieconsent-optin-marketing overlay-embed-block&quot;&gt;
    &lt;div style=&quot;padding-bottom: 56.49999999999999%;&quot; class=&quot;responsive-object&quot;&gt;
    &lt;iframe width=&quot;200&quot; height=&quot;113&quot; src=&quot;https://www.youtube.com/embed/Fv05J1V-uxo?feature=oembed&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen title=&quot;KDAB Training Day 2023&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;/div&gt;




&lt;style&gt;
.overlay-embed-block .responsive-object {
    position: relative;
}

.overlay-embed-block .responsive-object iframe,
.overlay-embed-block .responsive-object object,
.overlay-embed-block .responsive-object embed {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
&lt;/style&gt;


&lt;p&gt;The post &lt;a href=&quot;https://www.kdab.com/kdab-training-day-may-8th-2025/&quot;&gt;KDAB Training Day - May 8th, 2025&lt;/a&gt; appeared first on &lt;a href=&quot;https://www.kdab.com&quot;&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Editor Team</dc:creator><category>news</category><category>qml</category><category>qt</category><category>training</category></item></channel></rss>