<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Planet Qt</title>
    <link>http://planet.qt.io</link>
    <language>en</language>
    <description>"Planet Qt - http://planet.qt.io/"</description>
    <atom:link href="http://planet.qt.io/rss20.xml" rel="self" type="application/rss+xml"/>
    <item>
      <guid isPermaLink="false">https://sandroandrade.org/tag/planet-qt/rss/6a0874c35aec8e00012da311</guid>
      <title>Sandro S. Andrade: From Prompt to QObject: Building an LLM-Powered Action Runtime for Qt Applications</title>
      <pubDate>Sat, 16 May 2026 17:58:25 GMT</pubDate>
      <link>https://sandroandrade.org/from-prompt-to-qobject-building-an-llm-powered-action-runtime-for-qt-applications/</link>
      <description>&lt;hr&gt;
    &lt;img alt="From Prompt to QObject: Building an LLM-Powered Action Runtime for Qt Applications" src="https://sandroandrade.org/content/images/2026/05/9f719f82-3b9f-458d-88df-11f1a6de13be.png"&gt;
    &lt;p&gt;
      &lt;strong&gt;TL;DR:&lt;/strong&gt; this post presents an introspectable action runtime for AI-enabled Qt applications, where selected QObject instances are exposed through a smart-object registry, translated into a bounded planning context, and mutated through&#xA0;previewable, validated plans. The approach relies on Qt&#x2019;s existing meta-object system, using Q_PROPERTY, Q_INVOKABLE, object registration, recursive type discovery, and structured operations to keep LLM-generated actions constrained&#xA0;to the actual runtime object graph. The Smart Shapes QML and C++ examples show promising results with both a self-hosted &lt;em&gt;qwen3-coder:30b&lt;/em&gt; model and OpenAI&#x2019;s &lt;em&gt;gpt-5.4&lt;/em&gt;, while also exposing practical challenges around prompt refinement,&#xA0;context size, multi-action requests, operations versus JavaScript fallback, and domain-specific instructions. Future work points toward larger applications, stronger validation and permissions, better context management, and possibly&#xA0;a generic reflective MCP server for Qt applications.
    &lt;/p&gt;
    &lt;hr&gt;
    &lt;p&gt;
      Developing AI-enabled Qt applications often starts with a deceptively simple idea: let users describe what they want, then translate that intent into concrete changes in the running application. However, moving from a natural-language prompt to safe mutations over live QObject instances is not straightforward. The application needs to decide which objects are available, what properties and methods can be used, how to represent the intended changes before applying them, and how to keep LLM-generated output constrained to the actual runtime object graph. Given that, I&amp;aposve been working on designing an introspectable action runtime for Qt applications: selected objects are exposed through a smart-object registry, an LLM provider turns user prompts into previewable plans, and an applier executes validated operations or controlled scripts against those objects. In this article, I&#x2019;ll explore how these modules work together to&#xA0;transform prompts into structured, introspectable, and executable actions over Qt applications.
    &lt;/p&gt;
    &lt;p&gt;
      Given this, such action runtime platform should satisfy three key requirements:
    &lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;First, it must be generic and non-intrusive enough to be applied to a wide range of Qt applications, regardless of whether the UI is implemented with Qt Widgets, Qt Quick, or a&#xA0;combination of both. This means the infrastructure should rely on Qt&#x2019;s existing object model, meta-object information, properties, methods, and object ownership rules, instead of requiring application-specific adapters for every use&#xA0;case.
      &lt;/li&gt;
      &lt;li&gt;Second, it must be accurate when translating a user prompt into effective application behavior: natural-language requests should be converted into explicit, previewable, and validated plans that only reference exposed objects&#xA0;and supported operations.
      &lt;/li&gt;
      &lt;li&gt;Finally, performance should remain a first-class concern. The planning context sent to the provider must be rich enough to avoid ambiguous actions, but compact enough to keep latency under control, avoid&#xA0;unnecessary traversal of large object hierarchies, and preserve UI responsiveness while plans are generated and applied.
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;h2 id="architecture-overview"&gt;
      Architecture Overview
    &lt;/h2&gt;
    &lt;p&gt;
      Figure 1 presents the major components of our introspectable action runtime platform.
    &lt;/p&gt;
    &lt;figure class="kg-card kg-image-card kg-card-hascaption"&gt;
      &lt;img alt="From Prompt to QObject: Building an LLM-Powered Action Runtime for Qt Applications" class="kg-image" height="760" src="https://sandroandrade.org/content/images/2026/05/smartobjects-components-2.png" width="1500"&gt;&lt;b&gt;&lt;strong style="white-space: pre-wrap;"&gt;Figure 1:&lt;/strong&gt;&lt;/b&gt; &lt;span style="white-space: pre-wrap;"&gt;main components of Qt Instrospectable Action Runtime platform&lt;/span&gt;
    &lt;/figure&gt;
    &lt;p&gt;
      &lt;strong&gt;QSmartObjectRegistry&lt;/strong&gt; is the bridge to the live Qt object graph. It exposes selected QObject instances, assigns stable references, and describes classes, properties, methods, and collections.&#xA0;&lt;strong&gt;QSmartObjectPlanner&lt;/strong&gt; turns a prompt into a bounded planning context. It combines the user command with registry metadata, sends that context to a provider, and converts the response into a validated QSmartObjectPlan.&#xA0;&lt;strong&gt;QSmartObjectProvider&lt;/strong&gt; is the AI backend abstraction. &lt;strong&gt;QLLMSmartObjectProvider&lt;/strong&gt; is the concrete HTTP implementation, supporting OpenAI-compatible and Ollama-style chat endpoints.&#xA0;&lt;strong&gt;QSmartObjectPlan&lt;/strong&gt; is the previewable contract between planning and execution. It stores the summary, confidence, issues, mode, structured operations, or fallback script.&#xA0;&lt;strong&gt;QSmartObjectApplier&lt;/strong&gt; executes accepted plans. It either applies structured operations directly through Qt meta-object APIs or runs script fallback through QJSEngine.&#xA0;&lt;strong&gt;QSmartObjectExecution&lt;/strong&gt; reports the final outcome, including success state, summary, errors, and script console output.
    &lt;/p&gt;
    &lt;p&gt;
      For an application to be endowed with an intelligent prompt, its relevant runtime state and behavior must be made visible through Qt&#x2019;s meta-object system. In practice, this means modeling the objects that the prompt should control as&#xA0;QObject-derived classes, exposing editable state as Q_PROPERTY, and exposing safe actions as Q_INVOKABLE methods or slots (many Qt application are already implemented as such). Properties define what the system can inspect and mutate, while invokable functions define the operations that&#xA0;can be requested explicitly by the user. This is an important constraint: the prompt should not operate over arbitrary implementation details, but over a deliberate application surface that the developer decided to expose. The better&#xA0;this surface is named, typed, and organized, the more accurately a natural-language request can be translated into an effective application action.
    &lt;/p&gt;
    &lt;p&gt;
      Object registration and type discovery build on that exposed surface. The application registers selected live objects with &lt;strong&gt;QSmartObjectRegistry&lt;/strong&gt;, optionally giving them stable semantic identifiers and human-readable labels. From there,&#xA0;the registry assigns internal references to these objects and uses Qt meta-object introspection to discover their readable and writable properties, invokable methods, class names, and QObject-based collections. This metadata becomes&#xA0;the planning context consumed by &lt;strong&gt;QSmartObjectPlanner&lt;/strong&gt;: it tells the provider which objects exist, which types can be created or modified, and which operations are actually legal. In other words, registration selects the live objects&#xA0;that participate in prompting, while type discovery describes what the prompt is allowed to do with them.
    &lt;/p&gt;
    &lt;p&gt;
      Type discovery follows the QObject surface exposed by the application. Starting from the objects registered in &lt;strong&gt;QSmartObjectRegistry&lt;/strong&gt;, the implementation inspects their meta-objects and recursively discovers&#xA0;QObject-derived types referenced by Q_PROPERTY declarations, including direct QObject* properties and supported QObject collections such as QObjectList or QList&lt;T&gt;. It also walks readable runtime property values to find live child&#xA0;objects and collection items, so the planning context can include not only the explicitly registered object, but also the relevant object graph reachable from it. This keeps discovery aligned with Qt&#x2019;s meta-object system: arbitrary C++ implementation details remain hidden, while declared properties, invokable methods, and QObject relationships become available for planning. This enables registering central components, such as a Core object, which can end up&#xA0;registering all important objects in the application, such as controllers. Of course, developers can also define a more limited exposure model by individually registering only the desired objects or by turning off recursive type discovery.
    &lt;/p&gt;
    &lt;h2 id="prompt-engineering"&gt;
      Prompt Engineering
    &lt;/h2&gt;
    &lt;p&gt;
      One of the main challenges in this approach is that a fully generic prompt can describe the mechanics of object discovery, planning, validation, and execution, but it cannot always capture the application&#x2019;s domain semantics. The same&#xA0;property names and methods may have different meanings depending on the example, and some user requests require contextual rules that are not obvious from the meta-object data alone. For this reason, the generic smart-object prompt&#xA0;may be complemented by example-specific instructions. These instructions explain how the exposed objects should be interpreted in that particular application, which coordinate system is being used, how collections should be handled,&#xA0;which operations are preferred, and how ambiguous commands should be resolved. In practice, the generic prompt provides the execution contract, while the example-specific prompt gives the model the domain knowledge needed to produce&#xA0;accurate plans.
    &lt;/p&gt;
    &lt;p&gt;
      These are the most important fragments of currently adopted generic prompt:
    &lt;/p&gt;
    &lt;blockquote&gt;
      You translate natural-language editing requests into a smart-object mutation plan.&#xA0;Return only a JSON object. Do not wrap it in markdown.&#xA0;The JSON object contains either structured operations or a JavaScript script that will run against live QObject wrappers.&#xA0;The planning context contains two authoritative sections: availableClasses and instances.&#xA0;Use availableClasses as an exhaustive class catalog for all exposed objects and QObject-derived member types, and instances for live objects, aliases, and collection membership.&#xA0;Prefer operations mode. Use script mode only when the request cannot be represented with the supported operation vocabulary.&lt;br&gt;
      ...&lt;br&gt;
      Supported operations are setProperty, adjustProperty, callMethod, createObject, and destroyObject.&#xA0;Operation targets are direct object refs, created ids, or collection selections. Collection sources can use ownerRef for one owner, owner for a target resolving to one owner, or owners for a target resolving to many owners, including&#xA0;nested selection targets.&lt;br&gt;
      ...&lt;br&gt;
      For setProperty and adjustProperty, the property field must exactly match a writable property listed in availableClasses for the target object&amp;aposs class.&#xA0;For collection predicates, the predicate property must exactly match a readable property listed in availableClasses for the collection item class.&lt;br&gt;
      ...&lt;br&gt;
      Treat the planning context as authoritative.&#xA0;Do not invent members that are not explicitly listed there.&lt;br&gt;
      ...&lt;br&gt;
      If the request cannot be satisfied with the available classes, objects, properties, methods, or collection relations, do not approximate it. Return confidence 0.0, at least one issue, empty operations, and an empty script.&lt;br&gt;
      ...&lt;br&gt;
      The result must have this structure:&#xA0;{"summary":"short summary","confidence":0.0,"issues":["optional issue"],"mode":"operations","operations":[{"op":"setProperty","target": {"type":"object","ref":"registry-ref"},"property":"propertyName","value":"value"}],"script":""}&lt;br&gt;
      ...&lt;br&gt;
      For script fallback, set mode to script, operations to [], and script to the JavaScript statements.&#xA0;If the request is ambiguous, return an issue and the safest minimal plan.
    &lt;/blockquote&gt;
    &lt;h2 id="example-application"&gt;
      Example Application
    &lt;/h2&gt;
    &lt;p&gt;
      The current implementation includes both QML and C++ examples built around the same shape-editing scenario. In the QML example, the application uses the &lt;strong&gt;QtActionRuntime.SmartObjects&lt;/strong&gt; QML API directly: shapes are created in a Qt Quick scene,&#xA0;exposed through &lt;strong&gt;SmartObjectRegistry&lt;/strong&gt;, and controlled through &lt;strong&gt;LLMSmartObjectProvider&lt;/strong&gt;, &lt;strong&gt;SmartObjectPlanner&lt;/strong&gt;, and &lt;strong&gt;SmartObjectApplier&lt;/strong&gt; objects declared from QML. The C++ example implements the same workflow with a Qt Widgets interface and a &lt;strong&gt;SmartObjectsDemoController&lt;/strong&gt;, wiring the registry, provider, planner, and applier from C++ and reflecting the generated plan back into the UI before it is applied. Both examples expose shape objects with properties such as position,&#xA0;size, color, and type, then allow prompts like moving a circle or changing its color to be translated into validated smart-object plans, as described in Figure 2.
    &lt;/p&gt;
    &lt;figure class="kg-card kg-image-card kg-card-hascaption"&gt;
      &lt;img alt="From Prompt to QObject: Building an LLM-Powered Action Runtime for Qt Applications" class="kg-image" height="1040" src="https://sandroandrade.org/content/images/2026/05/smartshapes-class-diagram-1.png" width="1960"&gt;&lt;b&gt;&lt;strong style="white-space: pre-wrap;"&gt;Figure 2:&lt;/strong&gt;&lt;/b&gt; &lt;span style="white-space: pre-wrap;"&gt;smart shapes example&amp;aposs domain objects&lt;/span&gt;
    &lt;/figure&gt;
    &lt;h3 id="results"&gt;
      Results
    &lt;/h3&gt;
    &lt;p&gt;
      We tested the Smart Shapes example with both a self-hosted Ollama backend running &lt;strong&gt;qwen3-coder:30b&lt;/strong&gt; and OpenAI&#x2019;s &lt;strong&gt;gpt-5.4&lt;/strong&gt; model, and both produced good results for a range of natural-language commands. The prompts covered simple creation&#xA0;and editing requests, such as &#x201C;&lt;em&gt;create a new yellow circle&lt;/em&gt;&#x201D;, &#x201C;&lt;em&gt;rename the yellow circle to myCircle&lt;/em&gt;&#x201D;, and &#x201C;&lt;em&gt;move myCircle to the right of rectangleOne&lt;/em&gt;&#x201D;, as well as destructive and spatial operations like &#x201C;&lt;em&gt;remove the red circle&lt;/em&gt;&#x201D; and&#xA0;&#x201C;&lt;em&gt;arrange all circles evenly around rectangleOne, using a radius of 200 and the rectangle&#x2019;s center as the arrangement center&lt;/em&gt;&#x201D;. These tests helped validate that the exposed object model, generated planning context, and structured&#xA0;operation format were expressive enough for both local and hosted models to translate user intent into effective changes in the scene.
    &lt;/p&gt;
    &lt;figure class="kg-card kg-video-card kg-width-regular kg-card-hascaption"&gt;
      &lt;div class="kg-video-container"&gt;
        &lt;video height="788" src="https://sandroandrade.org/content/media/2026/05/untitled-1.webm" width="1120"&gt;&lt;/video&gt;
        &lt;div class="kg-video-overlay"&gt;
          &lt;button class="kg-video-large-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
          &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class="kg-video-player-container"&gt;
          &lt;div class="kg-video-player"&gt;
            &lt;button class="kg-video-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-pause-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="3" y="1"&gt;
              &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="14" y="1"&gt;&lt;/rect&gt;
            &lt;/rect&gt;&lt;/svg&gt;&lt;/button&gt; &lt;span class="kg-video-current-time"&gt;0:00&lt;/span&gt;
            &lt;div class="kg-video-time"&gt;
              /&lt;span class="kg-video-duration"&gt;0:13&lt;/span&gt;
            &lt;/div&gt;&lt;input class="kg-video-seek-slider" max="100" type="range" value="0"&gt; &lt;button class="kg-video-playback-rate"&gt;1&#xD7;&lt;/button&gt; &lt;button class="kg-video-unmute-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-mute-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;input class="kg-video-volume-slider" max="100" type="range" value="100"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;p dir="ltr"&gt;
        &lt;b&gt;&lt;strong style="white-space: pre-wrap;"&gt;Video 1:&lt;/strong&gt;&lt;/b&gt; &lt;span style="white-space: pre-wrap;"&gt;results for prompt "create a new yellow circle and a new purple circle in different positions"&lt;/span&gt;
      &lt;/p&gt;
    &lt;/figure&gt;
    &lt;p&gt;
      The next step was to investigate object collection traversal and object discovery in more complex object graphs. The Smart Shapes example already exercises a simple collection through the scene&#x2019;s list of shapes, but real applications&#xA0;usually expose deeper hierarchies: controllers own models, models expose collections, and collection items may reference other domain objects. The goal is to verify how well the planner can discover these relationships from registered&#xA0;root objects, follow QObject-valued properties and supported collections, and still generate accurate operations without requiring every object to be registered manually.
    &lt;/p&gt;
    &lt;figure class="kg-card kg-video-card kg-width-regular kg-card-hascaption"&gt;
      &lt;div class="kg-video-container"&gt;
        &lt;video height="788" src="https://sandroandrade.org/content/media/2026/05/untitled2.webm" width="1120"&gt;&lt;/video&gt;
        &lt;div class="kg-video-overlay"&gt;
          &lt;button class="kg-video-large-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
          &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class="kg-video-player-container"&gt;
          &lt;div class="kg-video-player"&gt;
            &lt;button class="kg-video-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-pause-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="3" y="1"&gt;
              &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="14" y="1"&gt;&lt;/rect&gt;
            &lt;/rect&gt;&lt;/svg&gt;&lt;/button&gt; &lt;span class="kg-video-current-time"&gt;0:00&lt;/span&gt;
            &lt;div class="kg-video-time"&gt;
              /&lt;span class="kg-video-duration"&gt;0:13&lt;/span&gt;
            &lt;/div&gt;&lt;input class="kg-video-seek-slider" max="100" type="range" value="0"&gt; &lt;button class="kg-video-playback-rate"&gt;1&#xD7;&lt;/button&gt; &lt;button class="kg-video-unmute-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-mute-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;input class="kg-video-volume-slider" max="100" type="range" value="100"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;p dir="ltr"&gt;
        &lt;b&gt;&lt;strong style="white-space: pre-wrap;"&gt;Video 2:&lt;/strong&gt;&lt;/b&gt; &lt;span style="white-space: pre-wrap;"&gt;results for prompt "change yellow circle&amp;aposs id to myCircle and position it to the right of circleTwo"&lt;/span&gt;
      &lt;/p&gt;
    &lt;/figure&gt;
    &lt;p&gt;
      No example-specific instructions were required, so far, for this example because the exposed QObject properties and invokable methods already provided enough semantic information for the planner to generate accurate operations.
    &lt;/p&gt;
    &lt;p&gt;
      Next, we want to try prompts involving multiple objects and multiple actions in a single request. Simple commands are useful to validate the basic planning pipeline, but real user interaction will often combine several intentions at&#xA0;once, such as creating an object, positioning it relative to another one, changing its visual attributes, and updating its identifier in the same prompt. These scenarios are important because they test whether the planner can&#xA0;decompose a compound request into a complete sequence of operations, preserve the correct order of execution, and avoid summarizing changes that were not actually represented in the generated plan. At this point, &lt;em&gt;qwen3-coder:30b&lt;/em&gt; occasionally started producing incorrect plans, while &lt;em&gt;gpt-5.4&lt;/em&gt; performed quite well.
    &lt;/p&gt;
    &lt;figure class="kg-card kg-video-card kg-width-regular kg-card-hascaption"&gt;
      &lt;div class="kg-video-container"&gt;
        &lt;video height="788" src="https://sandroandrade.org/content/media/2026/05/untitled3.webm" width="1120"&gt;&lt;/video&gt;
        &lt;div class="kg-video-overlay"&gt;
          &lt;button class="kg-video-large-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
          &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt;
        &lt;/div&gt;
        &lt;div class="kg-video-player-container"&gt;
          &lt;div class="kg-video-player"&gt;
            &lt;button class="kg-video-play-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-pause-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="3" y="1"&gt;
              &lt;rect height="22" rx="1.5" ry="1.5" width="7" x="14" y="1"&gt;&lt;/rect&gt;
            &lt;/rect&gt;&lt;/svg&gt;&lt;/button&gt; &lt;span class="kg-video-current-time"&gt;0:00&lt;/span&gt;
            &lt;div class="kg-video-time"&gt;
              /&lt;span class="kg-video-duration"&gt;0:13&lt;/span&gt;
            &lt;/div&gt;&lt;input class="kg-video-seek-slider" max="100" type="range" value="0"&gt; &lt;button class="kg-video-playback-rate"&gt;1&#xD7;&lt;/button&gt; &lt;button class="kg-video-unmute-icon"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;button class="kg-video-mute-icon kg-video-hide"&gt;&lt;svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;
            &lt;path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/button&gt; &lt;input class="kg-video-volume-slider" max="100" type="range" value="100"&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;p dir="ltr"&gt;
        &lt;b&gt;&lt;strong style="white-space: pre-wrap;"&gt;Video 3:&lt;/strong&gt;&lt;/b&gt; &lt;span style="white-space: pre-wrap;"&gt;results for prompt "move rectangleOne to (200, 200) and position all circles evenly distributed around the angles of a circle centered at rectangleOne and with a radius of 150"&lt;/span&gt;
      &lt;/p&gt;
    &lt;/figure&gt;
    &lt;p&gt;
      Notice that the circles are not actually distributed around rectangleOne&#x2019;s center. This happens because &lt;em&gt;gpt-5.4&lt;/em&gt; has no way to infer how shape centers are computed from the exposed properties alone. The issue was easily fixed by&#xA0;adding example-specific planning instructions, such as: &#x201C;&lt;em&gt;In this shape demo, x and y are top-left coordinates. Object centers are computed as (x + width / 2, y + height / 2)&lt;/em&gt;&#x201D;.
    &lt;/p&gt;
    &lt;h2 id="challenges-and-future-work"&gt;
      Challenges and Future Work
    &lt;/h2&gt;
    &lt;p&gt;
      The implementation also showed that the hard part is not simply calling an LLM, but defining a stable contract between the model and the Qt object graph. The implementation moved from an initial&#xA0;JavaScript-oriented approach to an &#x201C;&lt;em&gt;operations first, JavaScript after&lt;/em&gt;&#x201D; architecture, then added asynchronous plan generation, cancellation, richer registry metadata, collection predicates, runtime property values, and several rounds&#xA0;of prompt refinement. Prompt design became a central concern because the model must not invent properties, confuse planning metadata with writable object properties, skip parts of multi-action requests, or&#xA0;summarize mutations that were not actually emitted.
    &lt;/p&gt;
    &lt;p&gt;
      Context window sizing is another practical issue: the planning context must include enough classes, instances, collection relations, and runtime values to make accurate decisions,&#xA0;but not so much that local models lose reliability or exceed their useful context. The operations mode gives a safer and more introspectable path for common mutations such as setting properties, calling methods, creating objects,&#xA0;destroying objects, and selecting collection items. JavaScript remains useful as a fallback, but it is harder to validate and has a larger execution surface. Other important challenges include handling provider differences between Ollama-style and OpenAI-compatible endpoints, validating JSON responses, resolving object references safely, and deciding how much of the live object graph should be exposed to the&#xA0;prompt.
    &lt;/p&gt;
    &lt;p&gt;
      A natural direction for future work is to package this infrastructure as a generic reflective MCP server for Qt applications. Instead of each application embedding its own prompt-to-object bridge, a Qt MCP layer could expose selected&#xA0;QObject instances, properties, invokable methods, object collections, and runtime state through a standard protocol, allowing external agents to inspect and operate on live Qt applications in a controlled way. Beyond that, there are&#xA0;several interesting extensions: better permission models for deciding which objects and operations are visible, richer schema generation for enums and value types, configurable recursive discovery policies, stronger plan validation&#xA0;before execution, undo/redo integration, transaction support for multi-step plans, visual plan previews, and model-independent test suites for comparing local and hosted providers.
    &lt;/p&gt;
    &lt;p&gt;
      Another promising direction is to improve context&#xA0;management, so large applications can expose only the subset of the object graph relevant to a given prompt while still preserving enough semantic information for accurate planning.
    &lt;/p&gt;
    &lt;p&gt;
      Last but not least, this solution must be tested in larger and more complex applications. The Smart Shapes example is useful because it makes the core ideas easy to see, but real Qt applications have deeper object graphs, richer&#xA0;domain rules, long-lived controllers, asynchronous operations, permissions, and state that changes while the user is interacting with the system. Those are the scenarios that will really test whether reflective discovery, bounded&#xA0;planning contexts, structured operations, and fallback scripting can scale beyond a controlled demo. If this approach continues to work there, it opens an interesting path: Qt applications that can expose their own runtime&#xA0;capabilities and let users interact with them through intent, not just through predefined UI controls. What about including API documentation, in a &lt;em&gt;Retrieval-Augmented Generation&lt;/em&gt; (RAG)-like approach?
    &lt;/p&gt;
    &lt;p&gt;
      That&#x2019;s all for now. Lots of fun happening over here. &#x1F609;
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/qt-interface-framework-with-a-new-control-panel</guid>
      <title>The Qt Company Blog: Qt Interface Framework with a new Control Panel</title>
      <pubDate>Fri, 15 May 2026 10:03:57 GMT</pubDate>
      <link>https://www.qt.io/blog/qt-interface-framework-with-a-new-control-panel</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-interface-framework-with-a-new-control-panel?hsLang=en" title=""&gt;&lt;img alt="Qt Interface Framework with a new Control Panel" class="hs-featured-image" src="https://www.qt.io/hubfs/interface-framework-control-panel-banner.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      You've just implemented a new feature on the project you're working on. Now, it's time to test how does it work when the data is connected. In case you're working on a device which needs to listen to external devices or sensors, this might not be a trivial problem to solve.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-interface-framework-with-a-new-control-panel&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/qt-6.11.1-released</guid>
      <title>The Qt Company Blog: Qt 6.11.1 Released</title>
      <pubDate>Wed, 13 May 2026 10:57:09 GMT</pubDate>
      <link>https://www.qt.io/blog/qt-6.11.1-released</link>
      <description>&lt;p style="line-height: 1.44; color: #4d4d4d; background-color: #ffffff;"&gt;
      &lt;span&gt;Qt 6.11.1 is now available for download. As a patch release, Qt 6.11.1 doesn&#x2019;t introduce new features, but it delivers around 450 bug fixes, security improvements, and quality enhancements on top of Qt 6.11.0. For a full overview of the most notable changes, take a look at the &lt;a href="https://code.qt.io/cgit/qt/qtreleasenotes.git/about/qt/6.11.1/release-note.md"&gt;Qt 6.11.1 release notes&lt;/a&gt;.&lt;/span&gt;
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-6.11.1-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/qt-creator-19.0.2-released</guid>
      <title>The Qt Company Blog: Qt Creator 19.0.2 released</title>
      <pubDate>Wed, 13 May 2026 08:52:46 GMT</pubDate>
      <link>https://www.qt.io/blog/qt-creator-19.0.2-released</link>
      <description>&lt;h5&gt;
      We are happy to announce the release of Qt Creator 19.0.2!
    &lt;/h5&gt;
    &lt;p&gt;
      &lt;span&gt;The release fixes switching to English as the UI language in Qt Creator on systems with a non-English locale as well as a few other issues.&lt;/span&gt;
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-creator-19.0.2-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/ai-assisted-design-in-qt-design-studio</guid>
      <title>The Qt Company Blog: AI Assisted Design in Qt Design Studio: AI Assistant Just Got Smarter</title>
      <pubDate>Wed, 13 May 2026 05:16:57 GMT</pubDate>
      <link>https://www.qt.io/blog/ai-assisted-design-in-qt-design-studio</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/ai-assisted-design-in-qt-design-studio?hsLang=en" title=""&gt;&lt;img alt="AI Assisted Design in Qt Design Studio: AI Assistant Just Got Smarter" class="hs-featured-image" src="https://www.qt.io/hubfs/ai-assisted-design-in-qt-design-studio-thumbnail.webp" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      Qt Design Studio 4.8.2 ships a major upgrade to the AI assistant, transforming it into a fully agentic AI and taking AI-assisted design to the next level. It now has access to your entire QML project and can autonomously read, write, and refactor your files to complete tasks end to end.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fai-assisted-design-in-qt-design-studio&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/from-classroom-to-code-ii-innovative-qt-apps-by-future-developers</guid>
      <title>The Qt Company Blog: From Classroom to Code II: Innovative Qt Apps by Future Developers</title>
      <pubDate>Tue, 12 May 2026 12:31:39 GMT</pubDate>
      <link>https://www.qt.io/blog/from-classroom-to-code-ii-innovative-qt-apps-by-future-developers</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/from-classroom-to-code-ii-innovative-qt-apps-by-future-developers?hsLang=en" title=""&gt;&lt;img alt="Students from the on-site event displayed in the PhotoManufactura Application" class="hs-featured-image" src="https://www.qt.io/hubfs/linkedin-128.gif" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      &lt;a href="https://www.qt.io/blog/from-classroom-to-code-innovative-qt-apps-by-future-developers?hsLang=en"&gt;Last year&lt;/a&gt;, we shared the story of a new collaboration with the &lt;a href="https://www.th-koeln.de/en/"&gt;Cologne University of Applied Sciences&lt;/a&gt; (&lt;span&gt;German: TH K&#xF6;ln)&lt;/span&gt; for a new course titled &lt;span&gt;&lt;em&gt;Engineering Desktop Applications with C++ and Qt (EDA)&lt;/em&gt;&lt;/span&gt;. The first edition gave students the chance to explore modern C++ and Qt development in a hands-on setting, with teams designing and building their own music player application.
    &lt;/p&gt;
    &lt;p&gt;
      Now, the collaboration has successfully entered its second round.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Ffrom-classroom-to-code-ii-innovative-qt-apps-by-future-developers&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/introducing-the-mcp-tool-for-qt-documentation</guid>
      <title>The Qt Company Blog: Introducing the Documentation MCP Tool for Qt</title>
      <pubDate>Tue, 12 May 2026 06:29:42 GMT</pubDate>
      <link>https://www.qt.io/blog/introducing-the-mcp-tool-for-qt-documentation</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/introducing-the-mcp-tool-for-qt-documentation?hsLang=en" title=""&gt;&lt;img alt="Introducing the Documentation MCP Tool for Qt" class="hs-featured-image" src="https://www.qt.io/hubfs/Qt%20Documentation%20MCP%20Tool%20Title.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;h2&gt;
      How a Documentation MCP Tool Saves LLM Token Usage
    &lt;/h2&gt;
    &lt;p&gt;
      Every time an AI agent searches the web for Qt documentation today, it receives full HTML pages loaded with navigation chrome, cookie banners, related-article sidebars, and search-engine snippets that have nothing to do with the answer - burning thousands of LLM tokens before a single line of useful content appears. Qt's new official Model Context Protocol (MCP) tool for Qt documentation solves this directly.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fintroducing-the-mcp-tool-for-qt-documentation&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/introducing-the-qml-coding-skill-for-agentic-workflows</guid>
      <title>The Qt Company Blog: Introducing the QML Coding Skill for Agentic Workflows</title>
      <pubDate>Mon, 11 May 2026 12:20:31 GMT</pubDate>
      <link>https://www.qt.io/blog/introducing-the-qml-coding-skill-for-agentic-workflows</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/introducing-the-qml-coding-skill-for-agentic-workflows?hsLang=en" title=""&gt;&lt;img alt="Introducing the QML Coding Skill for Agentic Workflows" class="hs-featured-image" src="https://www.qt.io/hubfs/QML%20Agentic%20Coding%20Skill%20Title.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;h2&gt;
      The Challenge: Elevating AI-Generated QML to Best-Practise Quality
    &lt;/h2&gt;
    &lt;p&gt;
      Frontier Large Language Models have become genuinely capable QML authors. Benchmarks show models like Claude, GPT, and Gemini achieving between 75% and 86% accuracy on the QML100 benchmark for single-turn coding tasks - a result that reflects the depth of Qt&#x2019;s open-source ecosystem and the decades of publicly available QML code that has served as training material. For everyday UI components, a well-prompted AI agent can produce working, readable QML on the first attempt.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fintroducing-the-qml-coding-skill-for-agentic-workflows&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/qt-creator-20-beta-released</guid>
      <title>The Qt Company Blog: Qt Creator 20 Beta released</title>
      <pubDate>Fri, 08 May 2026 09:45:31 GMT</pubDate>
      <link>https://www.qt.io/blog/qt-creator-20-beta-released</link>
      <description>&lt;p style="font-weight: bold;"&gt;
      We are happy to announce the release of Qt Creator 20 Beta!
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-creator-20-beta-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.kdab.com/singleton-controllers-in-times-of-declarative-qml/</guid>
      <title>KDAB on Qt: Singleton Controllers in Times of Declarative QML</title>
      <pubDate>Thu, 07 May 2026 08:30:44 GMT</pubDate>
      <link>https://www.kdab.com/singleton-controllers-in-times-of-declarative-qml/</link>
      <description>&lt;h1&gt;
      Singleton Controllers in Times of Declarative QML
    &lt;/h1&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        Controller objects have been the main way to glue your QML UI to your application's actual implementation of the I/O and business logic. However, over the years, the way to actually expose that controller object has changed. And now, we contributed a change in &lt;code&gt;QQmlEngine&lt;/code&gt; that allows you to change it once again, and we believe: for the better.
      &lt;/p&gt;
      &lt;h2 id="what-are-"controllers"-anyway"&gt;
        What are "controllers" anyway?
      &lt;/h2&gt;
      &lt;p&gt;
        Conceptually, controllers are a thin glue layer between your business logic and your QML, exposing the data that the GUI needs in a format it can easily use. They are implemented as &lt;code&gt;QObject&lt;/code&gt;-derived instances, usually with properties exposing values that may or may not be writable, as well as potentially some &lt;code&gt;Q_INVOKABLE&lt;/code&gt; methods that can be triggered by the QML and maybe some signals.
      &lt;/p&gt;
      &lt;p&gt;
        Usually, these controllers are specific to a single logical group of values and functions within the wider application. An application may have a hand-full to dozens of them for a big system. Models exposing collections of data are usually made available as read-only properties returning a &lt;code&gt;QAbstractItemModel&lt;/code&gt;-derived data model on these controllers.
      &lt;/p&gt;
      &lt;p&gt;
        Often, these controllers need to be instantiated with some initialization, as they need references to the business-logic objects they expose to the GUI, listen for signals to get notifications of changes, etc. And that's where the trouble starts...
      &lt;/p&gt;
      &lt;h2 id="pre-qt-6"&gt;
        Pre-Qt 6
      &lt;/h2&gt;
      &lt;h3 id="context-properties"&gt;
        Context properties
      &lt;/h3&gt;
      &lt;p&gt;
        In the early days of QML, one would often use controller instances exposed to QML as context properties. Doing that allowed one to instantiate the controllers under control of C++, giving it all the references the objects needed at that time. We would often expose them to QML using a naming pattern like starting the name with a double underscore &lt;code&gt;__someController&lt;/code&gt; so that it was easy to recognize in the QML code. Using context properties however is no longer recommended. Their lookup is slow, and the QML compilers cannot reason about them, so code using them cannot be optimized. Nor is tooling available to help the QML programmer, as code completion and the likes are not possible.
      &lt;/p&gt;
      &lt;h3 id="singleton-instances"&gt;
        Singleton Instances
      &lt;/h3&gt;
      &lt;p&gt;
        Then came the &lt;code&gt;qmlRegisterSingletonInstance&lt;/code&gt; method. This method allowed one to register a QML singleton, but it would return the instance that you passed it as an argument and that you could instantiate however you needed. That was a good solution, but it didn't have a long useful life as it didn't mesh well with the declarative registration and it had issues with the one instance being the instance for &lt;i&gt;every&lt;/i&gt; QML engine in your application (if you had more than one).
      &lt;/p&gt;
      &lt;h2 id="post-qt-6"&gt;
        Post-Qt 6
      &lt;/h2&gt;
      &lt;p&gt;
        Since Qt 6, the recommended way to write QML is to create QML modules using declarative registration for C++-based objects. That has many benefits in terms of tooling and optimization, so it's good practice to do this. But it also meant that since Qt 6, one could no longer mix-and match imperative registration with declarative: you either used the one, or the other; which rendered the &lt;code&gt;qmlRegisterSingletonInstance&lt;/code&gt; method above useless.
      &lt;/p&gt;
      &lt;p&gt;
        There are many possible approaches that I have seen being applied to still control the creation of controller objects, usually by registering a singleton that has a static &lt;code&gt;create&lt;/code&gt; factory function and returning some C++ singletons there or something along those lines. That works, but isn't very elegant. An alternative approach is using initial properties on the root object, but that either requires accessessing the root id from other QML files or propagating the controllers all the way down the stack of items. Neither is a great solution for different reasons. My colleague Javier Cordero P&#xE9;rez is making a couple of videos about ways to do this, so I won't go into detail here. These videos will be added here once they have been released.
      &lt;/p&gt;
      &lt;h2 id="new-approach"&gt;
        New approach
      &lt;/h2&gt;
      &lt;p&gt;
        That building this connection between C++ and QML was so inelegant - despite being so important - inspired me to finally take matters into my own hands and write a patch.
      &lt;/p&gt;
      &lt;p&gt;
        The result is available starting with Qt 6.12 onward and it combines the good things of &lt;code&gt;qmlRegisterSingletonInstance&lt;/code&gt; and the declarative registration: you still register your controller type as a QML singleton so that the type is fully known by the tooling and access to it can be optimized. But we gain back the ability to provide a ready-made instance to the QML engine.
      &lt;/p&gt;
      &lt;h3 id="setexternalsingletoninstance"&gt;
        setExternalSingletonInstance
      &lt;/h3&gt;
      &lt;p&gt;
        The API on &lt;code&gt;QQmlEngine&lt;/code&gt; gained a single new method: &lt;a href="https://doc-snapshots.qt.io/qt6-dev/qqmlengine.html#setExternalSingletonInstance" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;QQmlEngine::setExternalSingletonInstance&lt;/code&gt;&lt;/a&gt;. It allows you to provide an instance of a type declared as a singleton as the instance to use in any QML running in that engine, just like you could with &lt;code&gt;qmlRegisterSingletonInstance&lt;/code&gt;. In contrast to that old registration function, however, you call this method on your specific QQmlEngine instance. Note that the type has to be (declaratively) registered as a singleton type for this call to work. If you are using more than one engine, it is up to you to decide if you want to provide the same instance to these different engines, or have separate instances.
      &lt;/p&gt;
      &lt;p&gt;
        This simple method gives you back an elegant, supported way to fully control the instantiation of the QML singleton, and thus easily connect it to your business logic or whatever else you need to with it. However, it is up to you make sure that you do this call before any QML code actually tries to access the singleton. Otherwise, the engine will (try to) create it's own instance as it used to. You cannot replace an already existing singleton instance, so once there is one, it is &lt;i&gt;the&lt;/i&gt; one.
      &lt;/p&gt;
      &lt;p&gt;
        It&#x2019;s up to you to make sure that the provided singleton instance outlives the QML that depends on it. You can do that in any way that works in your context, but you could consider parenting the instance to the &lt;code&gt;QQmlEngine&lt;/code&gt; instance, ordering the variables containing them on the stack correctly, or using &lt;code&gt;QQmlEngine::setObjectOwnership&lt;/code&gt; to hand ownership of the singleton to the QML engine.
      &lt;/p&gt;
      &lt;h3 id="qml_uncreatable-for-singletons"&gt;
        QML_UNCREATABLE for singletons
      &lt;/h3&gt;
      &lt;p&gt;
        If you are providing your QML singleton instance yourself anyway, you logically also don't &lt;i&gt;need&lt;/i&gt; it to be creatable by the engine either - although, it still can be, of course. If your controller type has a non-default constructor - perhaps to take in some references to your business logic instances - you can now mark your singleton with &lt;a href="https://doc-snapshots.qt.io/qt6-dev/qqmlintegration-h.html#QML_UNCREATABLE" rel="noopener noreferrer" target="_blank"&gt;&lt;code&gt;QML_UNCREATABLE&lt;/code&gt;&lt;/a&gt;, just like you can with other QML types. If you do that, you no longer need to supply a factory function (and even if you do, it won't be used).
      &lt;/p&gt;
      &lt;p&gt;
        Of course, if you mark a singleton as uncreatable, it is up to you to make sure you actually supply an instance via &lt;code&gt;QQmlEngine::setExternalSingletonInstance&lt;/code&gt; before the singleton is needed from QML.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;p&gt;
      The post &lt;a href="https://www.kdab.com/singleton-controllers-in-times-of-declarative-qml/"&gt;Singleton Controllers in Times of Declarative QML&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/security-advisory-type-confusion-and-heap-buffer-overflow-vulnerability-in-qt-svg-marker-handling</guid>
      <title>The Qt Company Blog: Security advisory: Type confusion and heap-buffer-overflow vulnerability in Qt SVG marker handling impacts Qt</title>
      <pubDate>Wed, 06 May 2026 12:30:04 GMT</pubDate>
      <link>https://www.qt.io/blog/security-advisory-type-confusion-and-heap-buffer-overflow-vulnerability-in-qt-svg-marker-handling</link>
      <description>&lt;p style="line-height: 26.266667px;"&gt;
      &lt;span style="color: #222840; background-color: #ffffff;"&gt;Type Confusion and Heap-based Buffer Overflow vulnerability in the SVG marker and mask handling of the Qt SVG module has been discovered and has been assigned the CVE id&lt;/span&gt; &lt;strong style="color: #222840;"&gt;CVE-2026-6210&lt;/strong&gt;&lt;span style="color: #222840; background-color: #ffffff;"&gt;.&lt;/span&gt;
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fsecurity-advisory-type-confusion-and-heap-buffer-overflow-vulnerability-in-qt-svg-marker-handling&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.qt.io/blog/qt-design-studio-4.8.2-released</guid>
      <title>The Qt Company Blog: Qt Design Studio 4.8.2 Released</title>
      <pubDate>Wed, 06 May 2026 09:57:42 GMT</pubDate>
      <link>https://www.qt.io/blog/qt-design-studio-4.8.2-released</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-design-studio-4.8.2-released?hsLang=en" title=""&gt;&lt;img alt="Qt Design Studio 4.8.2 Released" class="hs-featured-image" src="https://www.qt.io/hubfs/qds_4.8.2.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;h3 style="font-weight: bold;"&gt;
      Qt Design Studio 4.8.2 Is Here!
    &lt;/h3&gt;
    &lt;p&gt;
      Following our &lt;a href="https://www.qt.io/blog/qt-design-studio-4.8.1-released?hsLang=en"&gt;4.8.1 release&lt;/a&gt;, which introduced the Qt Design Studio AI Assistant in beta, we are back with a significant evolution of that feature, along with a few other updates. The 4.8.1 release laid the groundwork, a prompt-based tool that could generate QML from a natural language description or an image. That was a strong foundation, and the feedback we received helped shape where we took it next. In 4.8.2, the assistant has been rebuilt around a fundamentally more powerful architecture, taking &lt;a href="https://www.qt.io/blog/ai-assisted-design-in-qt-design-studio?hsLang=en"&gt;AI-assisted design&lt;/a&gt; to the next level.
    &lt;/p&gt;
    &lt;h3 style="font-weight: bold;"&gt;
      Qt Design Studio Goes Agentic
    &lt;/h3&gt;
    &lt;p&gt;
      With 4.8.2, Qt Design Studio takes a major step forward by introducing a fully agentic AI Assistant powered by the &lt;a href="https://modelcontextprotocol.io/"&gt;Model Context Protocol&lt;/a&gt; (MCP), an open standard for connecting AI models to external tools and data sources.&lt;br&gt;
      &lt;br&gt;
      This shift transforms the assistant from a passive helper into an active collaborator. Instead of working on a single file, it now understands your entire project structure and can operate across it using a rich set of MCP tools: reading files, creating components, modifying existing ones, and more.&lt;br&gt;
      &lt;br&gt;
      When you describe a goal, the assistant enters an agentic loop. It plans the task, selects the appropriate tools, executes them, evaluates the results, and continues iterating until the objective is complete. Every step is logged in the chat, so you can follow the process. Built on MCP, the assistant is designed to be extensible and future-proof, enabling integrations with external MCP server.&lt;br&gt;
      &lt;br&gt;
      The assistant supports leading models from Anthropic, Google, and OpenAI, and you can switch between providers within the same conversation. The agentic AI assistant is available to all Qt Design Studio users, we encourage you to try it out and share your feedback.
    &lt;/p&gt;
    &lt;p&gt;
      &lt;br&gt;
    &lt;/p&gt;
    &lt;p style="font-weight: bold; text-align: center;"&gt;
      &lt;span style="font-weight: normal;"&gt;Agentic AI at Work:&lt;/span&gt; &lt;span style="font-weight: normal;"&gt;Medical UI demo Created from a Single Prompt&lt;/span&gt;
    &lt;/p&gt;
    &lt;h3 style="font-weight: bold;"&gt;
      Qt Kit Updated to 6.8.7
    &lt;/h3&gt;
    &lt;p&gt;
      This release also bumps the bundled Qt Kit from 6.8.5 to 6.8.7, picking up the latest stability and maintenance improvements from the Qt 6.8 series.
    &lt;/p&gt;
    &lt;p&gt;
      &lt;strong&gt;Further Information&lt;/strong&gt;
    &lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;Our &lt;a href="https://wiki.qt.io/QtDesignStudio-changelog4.8.2"&gt;change log&lt;/a&gt; contains the full list of fixes and improvements included in this release.
      &lt;/li&gt;
      &lt;li&gt;If you run into any bugs or usability issues, please report them in the &lt;a href="https://bugreports.qt.io/projects/QDS"&gt;issue tracker&lt;/a&gt; &#x2014; your feedback helps us improve every release.
      &lt;/li&gt;
      &lt;li&gt;New to Qt Design Studio? Explore the &lt;a href="https://doc.qt.io/qtdesignstudio/index.html"&gt;online documentation&lt;/a&gt; or head to the &lt;a href="https://academy.qt.io/catalog?sort=date_published_desc&amp;live_sessions=false&amp;content_type=1"&gt;learning portal&lt;/a&gt; to get up to speed.
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;
      We look forward to hearing what you build with the new agentic assistant!
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track-eu1.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-design-studio-4.8.2-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.kdab.com/hotspot-v1-6-0-released/</guid>
      <title>KDAB on Qt: Hotspot v1.6.0 released</title>
      <pubDate>Fri, 13 Mar 2026 07:19:00 GMT</pubDate>
      <link>https://www.kdab.com/hotspot-v1-6-0-released/</link>
      <description>&lt;h1&gt;
      Hotspot v1.6.0 released
    &lt;/h1&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        &lt;a href="https://www.kdab.com/hotspot-a-gui-for-perf-report-video/"&gt;Hotspot&lt;/a&gt; is a standalone GUI designed to provide a user-friendly interface for analyzing performance data. It takes a &lt;code&gt;perf.data&lt;/code&gt; file, parses and evaluates its contents, and presents the results in a visually appealing and easily understandable manner. Hotspot&#x2019;s goal is to offer a modern alternative to &lt;code&gt;perf report&lt;/code&gt;, making performance analysis on Linux systems more intuitive and efficient.
      &lt;/p&gt;
      &lt;p&gt;
        Version 1.6.0 introduces powerful new features, improved workflows, and numerous bug fixes to make profiling even smoother.
      &lt;/p&gt;
      &lt;h2 id="changelog-for-hotspot-v1.6.0"&gt;
        ChangeLog for Hotspot v1.6.0
      &lt;/h2&gt;
      &lt;p&gt;
        &lt;a href="https://github.com/KDAB/hotspot/releases/tag/v1.6.0" rel="noopener noreferrer" target="_blank"&gt;This release&lt;/a&gt; focuses on usability improvements and extended analysis capabilities. The most notable additions are:
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;Support for archived perf files (e.g. &lt;code&gt;perf.data.zip&lt;/code&gt;)
        &lt;/li&gt;
        &lt;li&gt;Regex filtering in the flamegraph
        &lt;/li&gt;
        &lt;li&gt;Tracepoint support
        &lt;/li&gt;
        &lt;li&gt;Various bug fixes and stability improvements
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;h2 id="open-archived-perf-files-directly"&gt;
        Open Archived perf Files Directly
      &lt;/h2&gt;
      &lt;p&gt;
        Hotspot can now open perf recordings stored inside archives such as &lt;code&gt;perf.data.zip&lt;/code&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        This simplifies sharing profiling results, storing CI artifacts, and working with compressed recordings - no manual extraction required.
      &lt;/p&gt;
      &lt;h2 id="regex-in-the-flamegraph"&gt;
        Regex in the Flamegraph
      &lt;/h2&gt;
      &lt;p&gt;
        The Flamegraph view now supports &lt;b&gt;regular expression filtering&lt;/b&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        This makes it much easier to:
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;Match complex symbol patterns
        &lt;/li&gt;
        &lt;li&gt;Focus on specific subsystems or namespaces
        &lt;/li&gt;
        &lt;li&gt;Quickly narrow down large profiling datasets
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;
        Especially for large C++ codebases, regex search significantly speeds up navigation.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="image-variable-size-block"&gt;
      &lt;div class="image-variable-positioning-block right-margin-auto left-margin-auto width-100"&gt;
        &lt;div class="image-variable-size-image"&gt;
          &lt;img alt="Hotspot_V1.6.0_Regex_Example" class="Hotspot_V1.6.0_Regex_Example" id="Hotspot_V1.6.0_Regex_Example" src="https://eu-central-1.linodeobjects.com/wagtail-production/images/Clipboard_-_March_3_2026_1_17_PM.original.png" name="Hotspot_V1.6.0_Regex_Example"&gt;
        &lt;/div&gt;
        &lt;div class="image-variable-size-caption text-center"&gt;
          &lt;div class="rich-text"&gt;
            &lt;p&gt;
              Regex in the flamegraph
            &lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;h2 id="tracepoint-support"&gt;
        Tracepoint Support
      &lt;/h2&gt;
      &lt;p&gt;
        Hotspot 1.6.0 introduces support for &lt;b&gt;tracepoints&lt;/b&gt; captured via &lt;code&gt;perf&lt;/code&gt;.
      &lt;/p&gt;
      &lt;p&gt;
        This enables analysis of event-based data in addition to traditional sampling, giving deeper insight into system and runtime behavior.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="image-variable-size-block"&gt;
      &lt;div class="image-variable-positioning-block right-margin-auto left-margin-auto width-100"&gt;
        &lt;div class="image-variable-size-image"&gt;
          &lt;img alt="Hotspot_V1.6.0_Tracepoints_Example" class="Hotspot_V1.6.0_Tracepoints_Example" id="Hotspot_V1.6.0_Tracepoints_Example" src="https://eu-central-1.linodeobjects.com/wagtail-production/images/Clipboard_-_March_3_2026_1_23_PM.original.png" name="Hotspot_V1.6.0_Tracepoints_Example"&gt;
        &lt;/div&gt;
        &lt;div class="image-variable-size-caption text-center"&gt;
          &lt;div class="rich-text"&gt;
            &lt;p&gt;
              Tracepoints
            &lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;h2 id="bug-fixes-and-improvements"&gt;
        Bug Fixes and Improvements
      &lt;/h2&gt;
      &lt;p&gt;
        As usual, this release also includes numerous smaller fixes, UI refinements, and internal cleanups to improve overall stability and user experience.
      &lt;/p&gt;
      &lt;p&gt;
        For a complete overview of all changes, see the &lt;a href="https://github.com/KDAB/hotspot/releases/tag/v1.6.0" rel="noopener noreferrer" target="_blank"&gt;full changelog&lt;/a&gt; on GitHub.
      &lt;/p&gt;
      &lt;p&gt;
        Happy profiling!
      &lt;/p&gt;
      &lt;h2 id="videos"&gt;
        Videos
      &lt;/h2&gt;
      &lt;p&gt;
        Hotspot - A GUI for perf report:
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="cookieconsent-optin-marketing overlay-embed-block"&gt;
      &lt;div class="responsive-object"&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        Hotspot Demo from Embedded World 2022:
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="cookieconsent-optin-marketing overlay-embed-block"&gt;
      &lt;div class="responsive-object"&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;p&gt;
      The post &lt;a href="https://www.kdab.com/hotspot-v1-6-0-released/"&gt;Hotspot v1.6.0 released&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/</guid>
      <title>KDAB on Qt: Automating Repetitive GUI Interactions in Embedded Development with Spix</title>
      <pubDate>Thu, 19 Feb 2026 08:18:12 GMT</pubDate>
      <link>https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/</link>
      <description>&lt;h1&gt;
      Automating Repetitive GUI Interactions in Embedded Development with Spix
    &lt;/h1&gt;
    &lt;div class="image-variable-size-block"&gt;
      &lt;div class="image-variable-positioning-block right-margin-auto left-margin-auto width-100"&gt;
        &lt;div class="image-variable-size-image"&gt;
          &lt;img alt="2023-07-05-18-08-38-small_Blog_Christoph_Spix" src="https://www.kdab.com/documents/2023-07-05-18-08-38-small_1.gif"&gt;
        &lt;/div&gt;
        &lt;div class="image-variable-size-caption text-center"&gt;
          &lt;div class="rich-text"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&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&#x2019;s clear: this workflow is frustrating, error-prone, and a waste of valuable development time.
      &lt;/p&gt;
      &lt;p&gt;
        In this article, we&#x2019;ll look at how to automate these repetitive steps using &lt;a href="https://github.com/faaxm/spix" rel="noopener noreferrer" target="_blank"&gt;Spix&lt;/a&gt;, an open-source tool for GUI automation in Qt/QML applications. We&#x2019;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="the-problem:-click-fatigue-in-gui-testing"&gt;
        The Problem: Click Fatigue in GUI Testing
      &lt;/h2&gt;
      &lt;p&gt;
        Imagine this:
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;You start your application.
        &lt;/li&gt;
        &lt;li&gt;The login screen appears.
        &lt;/li&gt;
        &lt;li&gt;You enter your username and password.
        &lt;/li&gt;
        &lt;li&gt;You click "Login".
        &lt;/li&gt;
        &lt;li&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&gt;
        This is fine the first few times - but if you&#x2019;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&#x2019;t always applicable - especially when structural changes are involved or when you must work with "real" production data.
      &lt;/p&gt;
      &lt;p&gt;
        So, what&#x2019;s the alternative?
      &lt;/p&gt;
      &lt;h2 id="the-solution:-automating-gui-input-with-spix"&gt;
        The Solution: Automating GUI Input with Spix
      &lt;/h2&gt;
      &lt;p&gt;
        &lt;a href="https://github.com/faaxm/spix" rel="noopener noreferrer" target="_blank"&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&gt;Insert text into input fields
        &lt;/li&gt;
        &lt;li&gt;Click buttons
        &lt;/li&gt;
        &lt;li&gt;Wait for UI elements to appear
        &lt;/li&gt;
        &lt;li&gt;Take and compare screenshots
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&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="rich-text"&gt;
      &lt;h2 id="setting-up-spix-in-your-project"&gt;
        Setting up Spix in Your Project
      &lt;/h2&gt;
      &lt;p&gt;
        Getting Spix integrated requires a few straightforward steps:
      &lt;/p&gt;
      &lt;h3 id="1.-add-spix-as-a-dependency"&gt;
        1. &lt;b&gt;Add Spix as a dependency&lt;/b&gt;
      &lt;/h3&gt;
      &lt;ul&gt;
        &lt;li&gt;Typically done via a Git submodule into your project&#x2019;s third-party folder.
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-bash line-numbers"&gt;git submodule add 3rdparty/spix git@github.com:faaxm/spix.git&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;h3 id="2.-register-spix-in-cmake"&gt;
        2. &lt;b&gt;Register Spix in CMake&lt;/b&gt;
      &lt;/h3&gt;
      &lt;ul&gt;
        &lt;li&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&gt;Because of CMake quirks, you may also need to manually specify the path to Spix&#x2019;s CMake modules.
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-cmake line-numbers"&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="rich-text"&gt;
      &lt;h3 id="3.-link-against-spix"&gt;
        3. &lt;b&gt;Link against Spix&lt;/b&gt;
      &lt;/h3&gt;
      &lt;ul&gt;
        &lt;li&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="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-cmake line-numbers"&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="rich-text"&gt;
      &lt;h3 id="4.-initialize-spix-in-your-application"&gt;
        4. &lt;b&gt;Initialize Spix in your application&lt;/b&gt;
      &lt;/h3&gt;
      &lt;ul&gt;
        &lt;li&gt;Include Spix headers in &lt;code&gt;main.cpp&lt;/code&gt;.
        &lt;/li&gt;
        &lt;li&gt;Add some lines of boilerplate code:
          &lt;ul&gt;
            &lt;li&gt;Include the 2 Spix Headers (AnyRPCServer for Communication and QtQmlBot)
            &lt;/li&gt;
            &lt;li&gt;Start the Spix RPC server.
            &lt;/li&gt;
            &lt;li&gt;Create a &lt;code&gt;Spix::QtQmlBot&lt;/code&gt;.
            &lt;/li&gt;
            &lt;li&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="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-cpp line-numbers"&gt;#include &lt;Spix/AnyRpcServer.h&gt;
#include &lt;Spix/QtQmlBot.h&gt;
[...]

//Start the actual Runner/Server
spix::AnyRpcServer server;
auto bot = new spix::QtQmlBot();
bot-&gt;runTestServer(server);&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        At this point, your application is "Spix-enabled". 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;div class="rich-text"&gt;
      &lt;p&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;div class="rich-text"&gt;
      &lt;h2 id="where-spix-shines"&gt;
        Where Spix Shines
      &lt;/h2&gt;
      &lt;p&gt;
        Once the setup is done, Spix can be used to automate repetitive tasks. Let&#x2019;s look at two particularly useful examples:
      &lt;/p&gt;
      &lt;h3 id="1.-automating-logins-with-a-python-script"&gt;
        1. Automating Logins with a Python Script
      &lt;/h3&gt;
      &lt;p&gt;
        Instead of typing your credentials and clicking "Login" manually, you can write a simple Python script that:
      &lt;/p&gt;
      &lt;ul&gt;
        &lt;li&gt;Connects to the Spix server on &lt;code&gt;localhost:9000&lt;/code&gt;
        &lt;/li&gt;
        &lt;li&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&gt;Clicks the "Login" button (Items marked with "Quotes" are literal That-Specific-Text-Identifiers for Spix)
        &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-python line-numbers"&gt;import xmlrpc.client

session = xmlrpc.client.ServerProxy('http://localhost:9000')

session.inputText('mainWindow/userField', 'christoph')
session.inputText('mainWindow/passwordField', 'secret') 
session.mouseClick('mainWindow/"Login"')&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&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&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;div class="rich-text"&gt;
      &lt;p&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;div class="rich-text"&gt;
      &lt;h3 id="2.-screenshot-comparison"&gt;
        2. Screenshot Comparison
      &lt;/h3&gt;
      &lt;p&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="example-1:-full-screen-comparison"&gt;
        Example 1: Full-screen comparison
      &lt;/h4&gt;
      &lt;p&gt;
        Take a screenshot of the main window and store it first:
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-python line-numbers"&gt;import xmlrpc.client

session = xmlrpc.client.ServerProxy('http://localhost:9000')

[...]
session.takeScreenshot('mainWindow', '/tmp/screenshot.png')k&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        Now we can compare it with a reference image:
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-python line-numbers"&gt;from skimage import io
from skimage.metrics import structural_similarity as ssim

screenshot1 = io.imread('/tmp/reference.png', as_gray=True)
screenshot2 = io.imread('/tmp/screenshot.png', as_gray=True)

ssim_index = ssim(screenshot1, screenshot2, data_range=screenshot1.max() - screenshot1.min())

threshold = 0.95

if ssim_index == 1.0: 
    print("The screenshots are a perfect match")
elif ssim_index &gt;= threshold:
    print("The screenshots are similar, similarity: " + str(ssim_index * 100) + "%")
else:
    print("The screenshots are not similar at all, similarity: " + str(ssim_index * 100) + "%")&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&gt;
        This is useful for catching unexpected regressions in visual layout.
      &lt;/p&gt;
      &lt;h4 id="example-2:-finding-differences-in-the-same-ui"&gt;
        Example 2: Finding differences in the same UI
      &lt;/h4&gt;
      &lt;p&gt;
        Use OpenCV to highlight pixel-level differences between two screenshots&#x2014;for instance, missing or misaligned elements:
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class="formatted-code"&gt;
      &lt;pre&gt;&lt;code class="language-python line-numbers"&gt;import cv2

image1 = cv2.imread('/tmp/reference.png')
image2 = cv2.imread('/tmp/screenshot.png')

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('Difference Image', image1)
cv2.waitKey(0)&lt;/code&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class="rich-text"&gt;
      &lt;p&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="image-variable-size-block"&gt;
      &lt;div class="image-variable-positioning-block right-margin-auto left-margin-auto width-100"&gt;
        &lt;div class="image-variable-size-image"&gt;
          &lt;img alt="1024-637_Blog_Christoph_Spix" class="1024-637_Blog_Christoph_Spix" id="1024-637_Blog_Christoph_Spix" src="https://eu-central-1.linodeobjects.com/wagtail-production/images/1024-637_1.original.png" name="1024-637_Blog_Christoph_Spix"&gt;
        &lt;/div&gt;
        &lt;div class="image-variable-size-caption text-center"&gt;
          &lt;div class="rich-text"&gt;
            &lt;p&gt;
              Defective Image
            &lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="image-variable-size-block"&gt;
      &lt;div class="image-variable-positioning-block right-margin-auto left-margin-auto width-100"&gt;
        &lt;div class="image-variable-size-image"&gt;
          &lt;img alt="1024-639_Blog_Christoph_Spix" class="1024-639_Blog_Christoph_Spix" id="1024-639_Blog_Christoph_Spix" src="https://eu-central-1.linodeobjects.com/wagtail-production/images/1024-639_1.original.png" name="1024-639_Blog_Christoph_Spix"&gt;
        &lt;/div&gt;
        &lt;div class="image-variable-size-caption text-center"&gt;
          &lt;div class="rich-text"&gt;
            &lt;p&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="rich-text"&gt;
      &lt;h2 id="recap"&gt;
        Recap
      &lt;/h2&gt;
      &lt;p&gt;
        &lt;a href="https://github.com/faaxm/spix" rel="noopener noreferrer" target="_blank"&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&gt;Save time on repetitive input (like logins).
        &lt;/li&gt;
        &lt;li&gt;Share reproducible setup scripts with colleagues.
        &lt;/li&gt;
        &lt;li&gt;Perform lightweight visual regression testing in CI.
        &lt;/li&gt;
        &lt;li&gt;Interact with their applications on embedded devices remotely.
        &lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&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&gt;
        If you&#x2019;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="cookieconsent-optin-marketing overlay-embed-block"&gt;
      &lt;div class="responsive-object"&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;p&gt;
      The post &lt;a href="https://www.kdab.com/automating-repetitive-gui-interactions-in-embedded-development-with-spix/"&gt;Automating Repetitive GUI Interactions in Embedded Development with Spix&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.arnorehn.de/blog/?p=239</guid>
      <title>Arno Rehn on Qt: QFuture &#x2764;&#xFE0F; C++ coroutines</title>
      <pubDate>Mon, 09 Feb 2026 21:38:02 GMT</pubDate>
      <link>https://www.arnorehn.de/blog/2026/02/09/qfuture-c-coroutines/</link>
      <description>&lt;p&gt;
      Ever since C++20 introduced coroutine support, I was wondering how this could integrate with Qt. Apparently I wasn&#x2019;t the only one: before long, &lt;a href="https://qcoro.dev/"&gt;QCoro&lt;/a&gt; popped up. A really cool library! But it doesn&#x2019;t use the existing future and promise types in Qt; instead it introduces its own types and mechanisms to support coroutines. I kept wondering why no-one just made QFuture and QPromise compatible &#x2013; it would certainly be a more lightweight wrapper then.
    &lt;/p&gt;
    &lt;p&gt;
      With a recent project at work being a gargantuan mess of &lt;code&gt;QFuture::then()&lt;/code&gt; continuations (ever tried async looping constructs with continuations only? &lt;img alt="&#x1F974;" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f974.png" style="height: 1em;"&gt;) I had enough of a reason to finally sit down and implement this myself. The result: &lt;a href="https://gitlab.com/pumphaus/qawaitablefuture"&gt;https://gitlab.com/pumphaus/qawaitablefuture&lt;/a&gt;.
    &lt;/p&gt;
    &lt;h2 class="wp-block-heading"&gt;
      Example
    &lt;/h2&gt;
    &lt;pre class="EnlighterJSRAW"&gt;#include &lt;qawaitablefuture/qawaitablefuture.h&gt;

QFuture&lt;QByteArray&gt; fetchUrl(const QUrl &amp;url)
{
    QNetworkAccessManager nam;
    QNetworkRequest request(url);

    QNetworkReply *reply = nam.get(request);

    co_await QtFuture::connect(reply, &amp;QNetworkReply::finished);
    reply-&gt;deleteLater();

    if (reply-&gt;error()) {
        throw std::runtime_error(reply-&gt;errorString().toStdString());
    }
    co_return reply-&gt;readAll();
}&lt;/pre&gt;
    &lt;p&gt;
      It looks a lot like what you&#x2019;d write with QCoro, but it all fits in a single header and uses native &lt;a href="https://doc.qt.io/qt-6/qfuture.html"&gt;QFuture&lt;/a&gt; features to &#x2013; for example &#x2013; connect to a signal. It&#x2019;s really just syntax sugar around &lt;code&gt;QFuture::then()&lt;/code&gt;. Well, that, and a bit of effort to propagate cancellation and exceptions. Cancellation propagation works both ways: if you &lt;code&gt;co_await&lt;/code&gt; a canceled &lt;code&gt;QFuture&lt;/code&gt;, the &#x201C;outer&#x201D; &lt;code&gt;QFuture&lt;/code&gt; of coroutine will be canceled as well. If you &lt;a href="https://doc.qt.io/qt-6/qfuture.html#cancelChain"&gt;cancelChain()&lt;/a&gt; a suspended coroutine-backed &lt;code&gt;QFuture&lt;/code&gt;, cancellation will be propagated into the currently awaited &lt;code&gt;QFuture&lt;/code&gt;.
    &lt;/p&gt;
    &lt;p&gt;
      What&#x2019;s especially neat: You can configure where your coroutine will be resumed with &lt;code&gt;co_await continueOn(...)&lt;/code&gt;. It supports the same arguments as &lt;a href="https://doc.qt.io/qt-6/qfuture.html#then-1"&gt;QFuture::then()&lt;/a&gt;, so for example:
    &lt;/p&gt;
    &lt;pre class="EnlighterJSRAW"&gt;QFuture&lt;void&gt; SomeClass::someMember()
{
    co_await QAwaitableFuture::continueOn(this);
    co_await someLongRunningProcess();
    // Due to continueOn(this), if "this" is destroyed during someLongRunningProcess(),
    // the coroutine will be destroyed after the suspension point (-&gt; outer QFuture will be canceled)
    // and you won't access a dangling reference here.
    co_return this-&gt;frobnicate();
}

QFuture&lt;int&gt; multithreadedProcess()
{
    co_await QAwaitableFuture::continueOn(QtFuture::Launch::Async);

    double result1 = co_await foo();
    // resumes on a free thread in the thread pool
    process(result1);

    double result2 = co_await bar(result1);
    // resumes on a free thread in the thread pool
    double result3 = transmogrify(result2);

    co_return co_await baz(result3);
}&lt;/pre&gt;
    &lt;p&gt;
      See the docs for &lt;a href="https://doc.qt.io/qt-6/qfuture.html#then-3"&gt;QFuture::then()&lt;/a&gt; for details.
    &lt;/p&gt;
    &lt;p&gt;
      Also, if you want to check the canceled flag or report progress, you can access the actual QPromise that&#x2019;s backing the coroutine:
    &lt;/p&gt;
    &lt;pre class="EnlighterJSRAW"&gt;QFuture&lt;int&gt; heavyComputation()
{
    QPromise&lt;int&gt; &amp;promise = co_await QAwaitableFuture::promise();
    promise.setProgressRange(0, 100);

    double result = 0;

    for (int i = 0; i &lt; 100; ++i) {
        promise.setProgressValue(i);
        if (promise.isCanceled()) {
            co_return result;
        }
        frobnicationStep(&amp;result, i);
    }
    co_return result;
} 
&lt;/pre&gt;
    &lt;h2 class="wp-block-heading"&gt;
      Outlook
    &lt;/h2&gt;
    &lt;p&gt;
      I&#x2019;m looking to upstream this. It&#x2019;s too late for Qt 6.11 (already in feature freeze), but maybe 6.12? There have been some proposals for coroutine support on Qt&#x2019;s Gerrit already, but none made it past the proof-of-concept stage. Hopefully this one will make it. Let&#x2019;s see.
    &lt;/p&gt;
    &lt;p&gt;
      Otherwise, just use the single header from the &lt;a href="https://gitlab.com/pumphaus/qawaitablefuture"&gt;qawaitablefuture repo&lt;/a&gt;. It an be included as a git submodule, or you just vendor the header as-is.
    &lt;/p&gt;
    &lt;p&gt;
      Happy hacking!
    &lt;/p&gt;
    &lt;h2 class="wp-block-heading"&gt;
      Caveat: GCC &lt; 13
    &lt;/h2&gt;
    &lt;p&gt;
      There was a nasty bug in GCC&#x2019;s coroutine support: &lt;a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101367"&gt;https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101367&lt;/a&gt; It affects all GCC versions before 13.0.0 and effectively prevents you from writing &lt;code&gt;co_await foo([&amp;] { ... });&lt;/code&gt; &#x2013; i.e. you cannot await an expression involving a temporary lambda. You can rewrite this out as &lt;code&gt;auto f = foo([&amp;] { ... }); co_await f;&lt;/code&gt; and it will work. But there&#x2019;s no warning at compile time. As soon as the lambda with captures is a temporary expression inside the co_await, it will crash and burn at runtime. Fixed with GCC13+, but took me a while to figure out why things went haywire on Ubuntu 22.04 (defaults to GCC11).
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5141 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: Building a Custom Qt Stack on Linux</title>
      <pubDate>Thu, 05 Feb 2026 14:22:33 GMT</pubDate>
      <link>https://www.ics.com/blog/building-custom-qt-stack-linux</link>
      <description>&lt;p&gt;
      Thinking about compiling Qt on Linux? Discover why developers build it themselves, and what you should know before diving into source, modules and configuration.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">http://steveire.wordpress.com/?p=1749</guid>
      <title>Steveire's Blog: REST API Development with Qt 6</title>
      <pubDate>Wed, 14 Jan 2026 11:58:06 GMT</pubDate>
      <link>https://steveire.wordpress.com/2026/01/14/rest-api-development-with-qt-6/</link>
      <description>&lt;p class="wp-block-paragraph"&gt;
      This post describes an experiment using Qt 6.7&#x2019;s REST APIs to explore Stripe&#x2019;s payment model, and what I learned building a small desktop developer tool.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Recent Qt releases have included &lt;a href="https://www.qt.io/blog/restful-client-applications-in-qt-6.7-and-forward"&gt;several conveniences&lt;/a&gt; for developing clients of remote REST APIs. I recently tried it out with the &lt;a href="https://docs.stripe.com/api"&gt;Stripe payments REST API&lt;/a&gt; to get to grips with the Qt REST API in the real world. The overloading of the term &lt;em&gt;API&lt;/em&gt; is unhelpful, I find, but hopefully not too confusing here.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      As with almost &lt;a href="https://steveire.wordpress.com/2019/04/30/the-future-of-ast-matching-refactoring-tools-eurollvm-and-accu/"&gt;everything I try out&lt;/a&gt;, I created Qt desktop tooling as a developer aid to exploring the Stripe API and its behavior. Naming things is hard, but given that I want to put a &#x201C;Q&#x201D; in the name, googling &#x201C;cute stripes&#x201D; gives lots of hits about fashion, and the other too-obvious-to-say pun, I&#x2019;ve pushed it to GitHub as &#x201C;&lt;a href="https://github.com/steveire/qashmere"&gt;Qashmere&lt;/a&gt;&#x201C;:
    &lt;/p&gt;
    &lt;figure class="wp-block-image size-large"&gt;
      &lt;a href="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere.png"&gt;&lt;img alt="" class="wp-image-1761" height="870" src="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere.png?w=988" width="988"&gt;&lt;/a&gt;
    &lt;/figure&gt;
    &lt;h2 class="wp-block-heading"&gt;
      setAlternatingRowColors(true);
    &lt;/h2&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Developers using REST APIs will generally be familiar with existing tooling such as Postman and Bruno, for synthesizing calls to collections of REST APIs. Indeed, Qashmere uses the Stripe Postman JSON definition to present the collection of APIs and parameters. Such tools have scripting interfaces and state to create workflows that a client of the REST API needs to support, like &#x201C;create a payment, get the id of the payment back from the REST API and then cancel the payment with the id&#x201D;, or &#x201C;create a payment, get the id of the payment back from the REST API and then confirm it by id with a given credit card&#x201D;.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      So why create Qashmere? In addition to REST APIs, Stripe maintains objects which change state over time. The objects remain at REST until acted on by an external force, and when such an action happens a notification is sent to clients about those state changes, giving them a chance to react. I wanted to be able to collect the REST requests/responses and the notified events and present them as they relate to the Stripe objects. Postman doesn&#x2019;t know about events or about Stripe objects in particular, except that it is possible to write a script in Postman to extract the object which is part of a JSON payload. Postman also doesn&#x2019;t know that if a Payment Intent is created, there are a subset of next steps which could be in a workflow, such as cancel, capture or confirm payment etc.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Something that I discovered in the course of trying this out is that when I confirm a Payment Intent, a new Charge object is created and sent to me with the event notification system. Experimental experiences like that help build intuition.
    &lt;/p&gt;
    &lt;figure class="wp-block-image size-large"&gt;
      &lt;a href="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere_2.png"&gt;&lt;img alt="" class="wp-image-1763" height="814" src="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere_2.png?w=870" width="870"&gt;&lt;/a&gt;
    &lt;/figure&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Stripe operates with real money, but it also provides for sandboxes where synthetic payments, customers etc can be created and processed with synthetic payment methods and cards. As Qashmere is only useful as a developer tool or learning aid, it only works with Stripe sandboxes.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Events from Stripe are sent to pre-configured web servers owned by the client. The web servers need to have a public IP address, which is obviously not appropriate for a desktop application. A WebSocket API would be more suitable and indeed the stripe cli tool uses a WebSocket to receive events, but the WebSocket protocol is not documented or stable. Luckily the stripe cli tool can be used to relay events to another HTTP server, so Qashmere runs a &lt;a href="https://doc.qt.io/qt-6/qhttpserver.html"&gt;&lt;code&gt;QHttpServer&lt;/code&gt;&lt;/a&gt; for that purpose.
    &lt;/p&gt;
    &lt;figure class="wp-block-image size-large"&gt;
      &lt;a href="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere_architecture-1.png"&gt;&lt;img alt="" class="wp-image-1754" height="483" src="https://steveire.wordpress.com/wp-content/uploads/2026/01/qashmere_architecture-1.png?w=1024" width="1024"&gt;&lt;/a&gt;
    &lt;/figure&gt;
    &lt;h2 class="wp-block-heading"&gt;
      Implementation with Qt REST API
    &lt;/h2&gt;
    &lt;p class="wp-block-paragraph"&gt;
      The &lt;a href="https://doc.qt.io/qt-6/qrestreply.html"&gt;&lt;code&gt;QRestReply&lt;/code&gt;&lt;/a&gt; wraps a &lt;code&gt;QNetworkReply&lt;/code&gt; pointer and provides convenience API for accessing the HTTP return code and for creating a &lt;a href="https://doc.qt.io/qt-6/qjsondocument.html"&gt;&lt;code&gt;QJsonDocument&lt;/code&gt;&lt;/a&gt; from the body of the response. It must be created manually if using &lt;code&gt;QNetworkAccessManager&lt;/code&gt; directly. However the new &lt;a href="https://doc.qt.io/qt-6/qrestaccessmanager.html"&gt;&lt;code&gt;QRestAccessManager&lt;/code&gt;&lt;/a&gt; wraps a &lt;code&gt;QNetworkAccessManager&lt;/code&gt; pointer, again to provide convenience APIs and overloads for making requests that are needed in REST APIs (though some less common verbs like &lt;code&gt;OPTIONS&lt;/code&gt; and &lt;code&gt;TRACE&lt;/code&gt; are not built-in). The &lt;code&gt;QRestAccessManager&lt;/code&gt; has conveniences like overloads that provide a way to supply callbacks which already take the &lt;code&gt;QRestReply&lt;/code&gt; wrapper object as a parameter. If using a &lt;code&gt;QJsonDocument&lt;/code&gt; request overload, the &#x201C;&lt;code&gt;application/json&lt;/code&gt;&#x201D; &lt;code&gt;Content-Type&lt;/code&gt; is automatically set in the header.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      One of the inconveniences of &lt;code&gt;QRestAccessManager&lt;/code&gt; is that in Qashmere I use an external definition of the REST API from the Postman definition which includes the HTTP method. Because the &lt;code&gt;QRestAccessManager&lt;/code&gt; provides strongly typed API for making requests I need to do something like:
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;if (method == "POST") {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;rest.post(request, requestData, this, replyHandler);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;} else if (method == "GET") {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;rest.get(request, this, replyHandler);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;} else if (method == "DELETE") {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;rest.deleteResource(request, this, replyHandler);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;There is a &lt;code&gt;sendCustomRequest&lt;/code&gt; class API which can be used with a string, but it does not have an overload for &lt;code&gt;QJsonDocument&lt;/code&gt;, so the convenience of having the &lt;code&gt;Content-Type&lt;/code&gt; header set is lost. This may be an oversight in the &lt;code&gt;QRestAccessManager&lt;/code&gt; API.&lt;/code&gt;
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Another missing feature is URL parameter interpolation. Many REST APIs are described as something like &lt;code&gt;/v1/object/:object_id/cancel&lt;/code&gt;, and it would be convenient to have a safe way to interpolate the parameters into the URL, such as:
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QUrl result = QRestAccessManager::interpolatePathParameters(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"/v1/accounts/:account_id/object/:object_id/cancel", {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"account_id", "acc_1234"},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"object_id", "obj_5678"}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;);&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;This is needed to avoid bugs such as a user-supplied parameter containing a slash for example.&lt;/code&gt;
    &lt;/p&gt;
    &lt;h2 class="wp-block-heading"&gt;
      &lt;code&gt;Coding Con Currency&lt;/code&gt;
    &lt;/h2&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;In recent years I&#x2019;ve been writing and reading more Typescript/Angular code which consumes REST services, and less C++. I&#x2019;ve enjoyed the way &lt;code&gt;Promise&lt;/code&gt;s work in that environment, allowing sequences of REST requests, for example, to be easy to write and read. A test of a pseudo API could &lt;code&gt;await&lt;/code&gt; on requests to complete and invoke the next one with something like:&lt;/code&gt;
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;requestFactory.setBaseURL("http://some_service.com");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;async testWorkflow(username: string, password: string) {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const loginRequest = requestFactory.makeRequest("/login");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const loginRequestData = new Map();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;loginRequestData.setParam("username", username);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;loginRequestData.setParam("password", password);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const loginResponse = await requestAPI.post(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;loginRequest, loginRequestData);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const bearerToken = loginResponse.getData();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;requestAPI.setBearerToken(bearerToken);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const listingRequest = requestFactory.makeRequest("/list_items");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const listingResponse = await requestAPI.get(listingRequest);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const listing = JSON.parse(listingResponse.getData());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const firstItemRequest = requestFactory.makeRequest(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"/retrieve_item/:item_id",&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;item_id: listing[0].item_id&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;const firstItem = await requestAPI.get(firstItemRequest);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;The availability of &lt;code&gt;async&lt;/code&gt; functions and the &lt;code&gt;Promise&lt;/code&gt; to await on make a test like this quite easy to write, and the in-application use of the API uses the same &lt;code&gt;Promise&lt;/code&gt;s, so there is little friction between application code and test code.&lt;/code&gt;
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      I wanted to see if I can recreate something like that based on the Qt networking APIs. I briefly tried using C++20 coroutines because they would allow a style closer to &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;, but the integration friction with existing Qt types was higher than I wanted for an experiment.
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      Using the methods in &lt;code&gt;QtFuture&lt;/code&gt; however, we already have a way to create objects representing the response from a REST API. The result is similar to the Typescript example, but with different ergonomics, using &lt;code&gt;.then&lt;/code&gt; instead of the &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords.
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;struct RestRequest&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QString method;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QString requestUrl;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QHttpHeaders headers;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QHash&lt;QString, QString&gt; urlParams;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QUrlQuery queryParams;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;std::variant&lt;QUrlQuery, QJsonDocument&gt; requestData;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;};&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;struct RestResponse&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QJsonDocument jsonDoc;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QHttpHeaders headers;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QNetworkReply::NetworkError error;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QUrl url;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;int statusCode;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;};&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QFuture&lt;RestResponse&gt; makeRequest(RestRequest restRequest)&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto url = interpolatePathParameters(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;restRequest.requestUrl,&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;restRequest.urlParams);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto request = requestFactory.createRequest(url);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto requestBodyDoc = extractRequestContent(restRequest.requestData);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto requestBody = requestBodyDoc.toJson(QJsonDocument::Compact);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto reply = qRestManager.sendCustomRequest(request,&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;restRequest.method.toUtf8(),&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;requestBody,&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;&amp;qnam,&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;[](QRestReply &amp;) {});&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;return QtFuture::connect(reply, &amp;QNetworkReply::finished).then(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;[reply]() {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QRestReply restReply(reply);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto responseDoc = restReply.readJson();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;if (!responseDoc) {&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;throw std::runtime_error("Failed to read response");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;RestResponse response;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;response.jsonDoc = *responseDoc;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;response.statusCode = restReply.httpStatus();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;response.error = restReply.error();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;response.headers = reply-&gt;headers();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;response.url = reply-&gt;url();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;return response;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;The &lt;code&gt;QRestAccessManager&lt;/code&gt; API requires the creation of a dummy response function when creating a custom request because it is not really designed to be used this way. The result is an API accepting a request and returning a &lt;code&gt;QFuture&lt;/code&gt; with the &lt;code&gt;QJsonDocument&lt;/code&gt; content. While it is possible for a REST endpoint to return something else, we can follow the Qt philosophy of making the most expected case as easy as possible, while leaving most of the rest possible another way. This utility makes writing unit tests relatively straightforward too:&lt;br&gt;&lt;/code&gt;
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;RemoteAPI remoteApi;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;remoteApi.setBaseUrl(QUrl("https://dog.ceo"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto responseFuture = remoteApi.makeRequest(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"GET",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"api/breed/:breed/:sub_breed/images/random",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"breed", "wolfhound"},&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"sub_breed", "irish"}&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;}});&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QFutureWatcher&lt;RestResponse&gt; watcher;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QSignalSpy spy(&amp;watcher, &amp;QFutureWatcherBase::finished);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;watcher.setFuture(responseFuture);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(spy.wait(10000));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto jsonObject = responseFuture.result().jsonDoc.object();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(jsonObject["status"], "success");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QRegularExpression regex(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;R"(https://images\.dog\.ceo/breeds/wolfhound-irish/[^.]+.jpg)");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(regex.match(jsonObject["message"].toString()).hasMatch());&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;The result is quite similar to the Typescript above, but only because we can use &lt;code&gt;spy.wait&lt;/code&gt;. In application code, we still need to use &lt;code&gt;.then&lt;/code&gt; with a callback, but we can additionally use &lt;code&gt;.onFailed&lt;/code&gt; and &lt;code&gt;.onCanceled&lt;/code&gt; instead of making multiple signal/slot connections.&lt;/code&gt;
    &lt;/p&gt;
    &lt;p class="wp-block-paragraph"&gt;
      With the addition of &lt;code&gt;QtFuture::whenAll&lt;/code&gt;, it is easy to make multiple REST requests at once and react when they are all finished, so perhaps something else has been gained too, compared to a signal/slot model:
    &lt;/p&gt;
    &lt;div class="wp-block-code"&gt;
      &lt;div class="cm-editor"&gt;
        &lt;div class="cm-scroller"&gt;
          &lt;pre&gt;
&lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;RemoteAPI remoteApi;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;remoteApi.setBaseUrl(QUrl("https://dog.ceo"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto responseFuture = remoteApi.requestMultiple({&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"GET",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"api/breeds/list/all",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"GET",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"api/breed/:breed/:sub_breed/images/random",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{{"breed", "german"}, {"sub_breed", "shepherd"}}},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"GET",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;"api/breed/:breed/:sub_breed/images/random/:num_results",&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{{"breed", "wolfhound"},&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"sub_breed", "irish"},&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"num_results", "3"}}},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;{"GET", "api/breed/:breed/list", {}, {{"breed", "hound"}}},&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;});&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QFutureWatcher&lt;QList&lt;RestResponse&gt;&gt; watcher;&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QSignalSpy spy(&amp;watcher, &amp;QFutureWatcherBase::finished);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;watcher.setFuture(responseFuture);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(spy.wait(10000));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto four_responses = responseFuture.result();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(four_responses.size(), 4);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(four_responses[0].jsonDoc.object()["status"], "success");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(four_responses[0].jsonDoc.object()["message"].&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;toObject()["greyhound"].isArray());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QRegularExpression germanShepherdRegex(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;R"(https://images.dog.ceo/breeds/german-shepherd/[^.]+.jpg)");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(four_responses[1].jsonDoc.object()["status"], "success");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(germanShepherdRegex.match(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;four_responses[1].jsonDoc.object()["message"].toString()).hasMatch());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QRegularExpression irishWolfhoundRegex(&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;R"(https://images.dog.ceo/breeds/wolfhound-irish/[^.]+.jpg)");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(four_responses[2].jsonDoc.object()["status"], "success");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto irishWolfhoundList =&lt;/code&gt;
          &lt;/div&gt;
          &lt;pre&gt; &lt;/pre&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;four_responses[2].jsonDoc.object()["message"].toArray();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(irishWolfhoundList.size(), 3);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(irishWolfhoundRegex.match(irishWolfhoundList[0].toString()).&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;hasMatch());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(irishWolfhoundRegex.match(irishWolfhoundList[1].toString()).&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;hasMatch());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(irishWolfhoundRegex.match(irishWolfhoundList[2].toString()).&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;hasMatch());&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;&lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE(four_responses[3].jsonDoc.object()["status"], "success");&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;auto houndList = four_responses[3].jsonDoc.object()["message"].toArray();&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QCOMPARE_GE(houndList.size(), 7);&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("afghan"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("basset"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("blood"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("english"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("ibizan"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("plott"));&lt;/code&gt;
          &lt;/div&gt;
          &lt;div class="cm-line"&gt;
            &lt;code&gt;QVERIFY(houndList.contains("walker"));&lt;/code&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;h2 class="wp-block-heading"&gt;
      &lt;code&gt;setAutoDeleteReplies(false);&lt;/code&gt;
    &lt;/h2&gt;
    &lt;p class="wp-block-paragraph"&gt;
      &lt;code&gt;I attempted to use new API additions in recent Qt 6 versions to interact with a few real-world REST services. The additions are valuable, but it seems that there are a few places where improvements might be possible. My attempt to make the API feel closer to what developers in other environments might be accustomed to had some success, but I&#x2019;m not sure &lt;code&gt;QFuture&lt;/code&gt; is really intended to be used this way.&lt;br&gt;
      Do readers have any feedback? Would using QCoro improve the coroutine experience? Is it very unusual to create an application with QWidgets instead of QML these days? Should I have used PyQt and the python networking APIs?&lt;/code&gt;
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">tag:blogger.com,1999:blog-2997739907109253354.post-2539162574495956459</guid>
      <title>Lorn Potter: Debugging Qt WebAssembly - DWARF</title>
      <pubDate>Tue, 09 Dec 2025 00:23:35 GMT</pubDate>
      <link>http://qtandeverything.blogspot.com/2025/12/debugging-qt-webassembly-dwarf.html</link>
      <description>&lt;p&gt;
      &#xA0;
    &lt;/p&gt;
    &lt;p&gt;
      One of the most tedious tasks a developer will do is debugging a nagging bug. It's worse when it's a web app, and even worse when its a webassembly web app.
    &lt;/p&gt;
    &lt;p&gt;
      &lt;br class="Apple-interchange-newline"&gt;
      The easiest way to debug Qt Webassembly is by configuring using the -g argument, or CMAKE_BUILD_TYPE=Debug . &lt;a href="https://emscripten.org/docs/porting/Debugging.html#debugging-dwarf" target="_blank"&gt;Emscripten&lt;/a&gt; embeds DWARF symbols in the wasm binaries.&#xA0;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;span style="background-color: #f1c232;"&gt;&lt;b&gt;NOTE:&lt;/b&gt;&#xA0;Debugging wasm files with DWARF works&#xA0;&lt;b&gt;only&lt;/b&gt; in the Chrome browser with the help of a browser extension.&#xA0;&lt;/span&gt;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;a href="https://goo.gle/wasm-debugging-extension" target="_blank"&gt;C/C++ DevTools Support (DWARF)&lt;/a&gt;&#xA0;browser extension. If you are using Safari or Firefox, or do not want to or cannot install a browser extension, you will need to generate source maps, which I will look at in my next blog post.&#xA0;
    &lt;/p&gt;
    &lt;h3&gt;
      DWARF debugging
    &lt;/h3&gt;
    &lt;p&gt;
      You need to also enable DWARF in the browser developer tools settings, but you do not need symlinks to the source directories, as you would need to using source maps, as the binaries are embedded with the full directory path. Like magic!
    &lt;/p&gt;
    &lt;p&gt;
      &#xA0;Emscripten embeds DWARF symbols into the binaries built with -g by default, so re-building Qt or your application in debug mode is all you need to do.
    &lt;/p&gt;
    &lt;p&gt;
      Qt builds debug libraries by default using the optimized argument -g2, which produces less debugging info, but results in faster link times. To preserve debug symbols you need to build Qt debug using the -g or -g3 argument. Both of these do the same thing.
    &lt;/p&gt;
    &lt;h3 style="text-align: left;"&gt;
      Using DWARF debugger
    &lt;/h3&gt;
    &lt;div class="separator" style="clear: both; text-align: center;"&gt;
      &lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6e5dEWIzlOGSPzJk9uUX1nDg_LZW4NdA-vXRDNP8YHhwKZf-3qj9BY7sijyNAzqSA0Zw3nYGQTgBtsDDZhzkP52UZWmnU2sd3XkFwuBQ9qCS67CtPEMcoSI9bN6dDYWmszENc5wuq548ATAR6mscpAoTQ8No31gOefQT-KU4uoGk4z-Iiga67AdODzOw/s2606/Screenshot%202025-12-09%20at%209.18.11%E2%80%AFam.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="632" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6e5dEWIzlOGSPzJk9uUX1nDg_LZW4NdA-vXRDNP8YHhwKZf-3qj9BY7sijyNAzqSA0Zw3nYGQTgBtsDDZhzkP52UZWmnU2sd3XkFwuBQ9qCS67CtPEMcoSI9bN6dDYWmszENc5wuq548ATAR6mscpAoTQ8No31gOefQT-KU4uoGk4z-Iiga67AdODzOw/w640-h632/Screenshot%202025-12-09%20at%209.18.11%E2%80%AFam.png" width="640"&gt;&lt;/a&gt;
    &lt;/div&gt;&lt;br&gt;
    &lt;div&gt;
      &lt;br&gt;
    &lt;/div&gt;
    &lt;div&gt;
      Open Chome with the extention mentioned before installed, and open the console tools. Navigate to the Qt for WebAssembly web application you need to debug. Once it opens, it may take a few seconds for all the symbols and files to get parsed. If you are debugging into Qt, this will take quite a few seconds - just keep waiting.&#xA0;
    &lt;/div&gt;
    &lt;div&gt;
      The javascript console will soon contain file source file paths and sources. You can find your file to debug, and set breakpoints. Just reload the page and once it hits a breakpoint, it will stop execution and highlight the current line in the source view.&#xA0; It also will show variable names and values.
    &lt;/div&gt;
    &lt;div&gt;
      &lt;br&gt;
    &lt;/div&gt;
    &lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br&gt;
    You can then step though your code as you would debugging a desktop application.
    &lt;div&gt;
      &lt;br&gt;
    &lt;/div&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.basyskom.de/?p=12315</guid>
      <title>Qt &#x2013; basysKom GmbH: Boosting PySide with C++ models</title>
      <pubDate>Mon, 01 Dec 2025 13:03:23 GMT</pubDate>
      <link>https://www.basyskom.de/boosting-pyside-with-c-models/</link>
      <description>&lt;p&gt;
      &lt;a href="https://www.basyskom.de/boosting-pyside-with-c-models/"&gt;&lt;img align="left" alt="Boosting PySide with C++ models" height="150" src="https://www.basyskom.de/wp-content/uploads/2020/07/Qt_logo_space-01-01-300x150.png" style="margin: 0 20px 20px 0;" width="300"&gt;&lt;/a&gt;
    &lt;/p&gt;
    &lt;p&gt;
      In a recent series of blog posts, we have demonstrated that Python and Qt fit together very well. Due to its accessibility, ease-of-use and third-party ecosystem, it is really straightforward to prototype and productize applications. Still, Python has one significant disadvantage: It is not necessarily the most performant programming language.
    &lt;/p&gt;
    &lt;p&gt;
      &lt;a href="https://www.basyskom.de/boosting-pyside-with-c-models/" rel="nofollow"&gt;Continue reading Boosting PySide with C++ models at basysKom GmbH.&lt;/a&gt;
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5116 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: Rust Might be the Right Replacement for C++</title>
      <pubDate>Tue, 25 Nov 2025 21:58:19 GMT</pubDate>
      <link>https://www.ics.com/blog/rust-might-be-right-replacement-c</link>
      <description>&lt;p&gt;
      Up-and-coming programming language Rust is designed for memory safety without sacrificing performance.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5108 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: It's Baaack! Qt Speech Returns for Qt 6.4.0 Release</title>
      <pubDate>Tue, 25 Nov 2025 21:01:25 GMT</pubDate>
      <link>https://www.ics.com/blog/its-baaack-qt-speech-returns-qt-640-release</link>
      <description>&lt;p&gt;
      The &lt;strong&gt;Qt Speech&lt;/strong&gt; module was introduced in Qt 5.8.0. I made a &lt;a href="https://www.ics.com/blog/text-speech-look-qt-speech-module"&gt;blog post&lt;/a&gt;&#xA0;at that time (June 2017), looking at how it provided cross-platform support for text-to-speech. With the Qt 6.0.0 release, &lt;strong&gt;Qt Speech&lt;/strong&gt; was one of the modules that were no longer available. In the upcoming Qt 6.4.0 release, it is again going to be part of Qt.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5107 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: What's New in Qt 6.5?</title>
      <pubDate>Tue, 25 Nov 2025 20:16:10 GMT</pubDate>
      <link>https://www.ics.com/blog/whats-new-qt-65</link>
      <description>&lt;p&gt;
      Explore the latest tools and modules in the new Qt 6.5.0 LTS release.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5091 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: How to Configure and Use the Qt Creator-GitLab Integration</title>
      <pubDate>Thu, 20 Nov 2025 18:49:27 GMT</pubDate>
      <link>https://www.ics.com/blog/how-configure-and-use-qt-creator-gitlab-integration</link>
      <description>&lt;p&gt;
      Qt Creator IDE has a helpful but not well-documented plugin that allows you to browse and clone projects from a GitLab server.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.ics.com/5081 at https://www.ics.com</guid>
      <title>ICS Insights: Qt and QML: Get Ready for C++23</title>
      <pubDate>Wed, 19 Nov 2025 21:28:33 GMT</pubDate>
      <link>https://www.ics.com/blog/get-ready-c23</link>
      <description>&lt;p&gt;
      Slated for release in December, C++23 will include incremental improvements, clarifications, and removal of previously deprecated features.
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://blog.felgo.com/updates/release-4-3-1-qt-play-store-16kb-page-size-support</guid>
      <title/>
      <pubDate>Tue, 18 Nov 2025 08:14:59 GMT</pubDate>
      <link>https://blog.felgo.com/updates/release-4-3-1-qt-play-store-16kb-page-size-support</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://blog.felgo.com/updates/release-4-3-1-qt-play-store-16kb-page-size-support" title=""&gt;&lt;img alt="Release 4.3.1: Android 16KB Page Size Support for Google Play with Felgo &amp; Qt" class="hs-featured-image" src="https://blog.felgo.com/hubfs/felgo-release-4-3-1-google-16kb-page-size.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      The Felgo 4.3.1 adds Android 16KB page size support with a custom&lt;span style="font-weight: normal;"&gt;&lt;span style="margin: 0px; padding: 0px;"&gt;&#xA0;&lt;span style="font-weight: bold;"&gt;Qt 6.8.3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Read on to learn more about the release.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=6147417&amp;k=14&amp;r=https%3A%2F%2Fblog.felgo.com%2Fupdates%2Frelease-4-3-1-qt-play-store-16kb-page-size-support&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://somcosoftware.com/en/blog/mastering-qt-multithreading-without-losing-your-mind</guid>
      <title>Scythe Studio Qt Blog: Mastering Qt Multithreading Without Losing Your Mind</title>
      <pubDate>Fri, 07 Nov 2025 10:35:30 GMT</pubDate>
      <link>https://somcosoftware.com/en/blog/mastering-qt-multithreading-without-losing-your-mind</link>
      <description>&lt;p&gt;
      As applications get more complex and performance expectations rise, multithreading becomes essential. In my experience, Qt provides a powerful &#x2014; [&#x2026;]
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://blog.felgo.com/meet-the-qt-community-in-vienna-qt-day-austria-cee-2025</guid>
      <title/>
      <pubDate>Fri, 07 Nov 2025 09:57:53 GMT</pubDate>
      <link>https://blog.felgo.com/meet-the-qt-community-in-vienna-qt-day-austria-cee-2025</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://blog.felgo.com/meet-the-qt-community-in-vienna-qt-day-austria-cee-2025" title=""&gt;&lt;img alt="Meet the Qt Community in Vienna &#x2013; Qt Day Austria &amp; CEE 2025" class="hs-featured-image" src="https://blog.felgo.com/hubfs/Bildschirmfoto%202025-11-05%20um%2013.08.36.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      On &lt;strong&gt;November 13&lt;/strong&gt;, the Qt and QML community will meet in &lt;strong&gt;Vienna&lt;/strong&gt; for a full day of inspiring talks, networking and knowledge sharing.
    &lt;/p&gt;
    &lt;p&gt;
      Join developers, tech leads and companies for a day full of insights, real world experiences and community exchange.&lt;br&gt;
      &lt;strong&gt;Free to attend&lt;/strong&gt;, but seats are limited - &lt;strong&gt;first come, first serve!&lt;/strong&gt; &lt;span style="font-weight: normal;"&gt;Read on for all the details:&lt;/span&gt;
    &lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;
        &lt;a href="https://blog.felgo.com/tag/planet-qt/rss.xml#Hereiswhatawaitsyou"&gt;Here is what awaits you&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href="https://blog.felgo.com/tag/planet-qt/rss.xml#agendahighlights"&gt;Agenda Highlights&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href="https://blog.felgo.com/tag/planet-qt/rss.xml#thelocation"&gt;The Location&lt;/a&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;a href="https://blog.felgo.com/tag/planet-qt/rss.xml#secureyourspot"&gt;Secure Your Spot&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ul&gt;&lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=6147417&amp;k=14&amp;r=https%3A%2F%2Fblog.felgo.com%2Fmeet-the-qt-community-in-vienna-qt-day-austria-cee-2025&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://www.basyskom.de/?p=12275</guid>
      <title>Qt &#x2013; basysKom GmbH: Qt WebEngine Custom Server Certificates</title>
      <pubDate>Mon, 03 Nov 2025 10:00:10 GMT</pubDate>
      <link>https://www.basyskom.de/qt-webengine-custom-server-certificates/</link>
      <description>&lt;p&gt;
      &lt;a href="https://www.basyskom.de/qt-webengine-custom-server-certificates/"&gt;&lt;img align="left" alt="Qt WebEngine Custom Server Certificates" height="150" src="https://www.basyskom.de/wp-content/uploads/2020/07/Qt_logo_space-01-01-300x150.png" style="margin: 0 20px 20px 0;" width="300"&gt;&lt;/a&gt;
    &lt;/p&gt;
    &lt;p&gt;
      In this blog post, we&#x2019;re having a look at how we added support for custom server certificates to Qt WebEngine. This way an application can talk to a server using a self-signed TLS certificate without adding it to the system-wide certificate store.
    &lt;/p&gt;
    &lt;p&gt;
      &lt;a href="https://www.basyskom.de/qt-webengine-custom-server-certificates/" rel="nofollow"&gt;Continue reading Qt WebEngine Custom Server Certificates at basysKom GmbH.&lt;/a&gt;
    &lt;/p&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">https://blog.felgo.com/updates/release-4-3-0-felgo-qml-hot-reload-qt-6-8</guid>
      <title/>
      <pubDate>Fri, 24 Oct 2025 06:15:00 GMT</pubDate>
      <link>https://blog.felgo.com/updates/release-4-3-0-felgo-qml-hot-reload-qt-6-8</link>
      <description>&lt;div class="hs-featured-image-wrapper"&gt;
      &lt;a class="hs-featured-image-link" href="https://blog.felgo.com/updates/release-4-3-0-felgo-qml-hot-reload-qt-6-8" title=""&gt;&lt;img alt="Release 4.3.0: Felgo QML Hot Reload, Android 15, Qt 6.8 &amp; Qt Creator 17" class="hs-featured-image" src="https://blog.felgo.com/hubfs/felgo-release-4-3-0-hot-reload-qt-683.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;
    &lt;/div&gt;
    &lt;p&gt;
      The Felgo 4.3.0 update adds many &lt;span style="font-weight: normal;"&gt;new features and improvements for &lt;span style="font-weight: bold;"&gt;Felgo QML Hot Reload&lt;/span&gt;&lt;/span&gt;.&lt;span style="font-weight: normal;"&gt;&#xA0;&lt;span style="margin: 0px; padding: 0px;"&gt;The release also updates to &lt;span style="font-weight: bold;"&gt;Qt 6.8.3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;, Android 15 Support&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;, and&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;Qt Creator 17&lt;/span&gt;. Read on to learn more about the release.
    &lt;/p&gt;&lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=6147417&amp;k=14&amp;r=https%3A%2F%2Fblog.felgo.com%2Fupdates%2Frelease-4-3-0-felgo-qml-hot-reload-qt-6-8&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
    </item>
    <item>
      <guid isPermaLink="false">tag:www.pythonguis.com,2025-10-09:/faq/pyqt6-qsettings-how-to-use-qsettings/</guid>
      <title>Python GUIs - qt: Saving and Restoring Application Settings with QSettings in PyQt6 &#x2014; Learn how to use QSettings to remember user preferences, window sizes, and configuration options between sessions</title>
      <pubDate>Thu, 09 Oct 2025 09:00:00 GMT</pubDate>
      <link>https://www.pythonguis.com/faq/pyqt6-qsettings-how-to-use-qsettings/</link>
      <description/>
    </item>
  </channel>
</rss>
