This service tests the validity of an RSS 2.0 feed, checking to see that it follows the rules of the RSS specification. For advice from the RSS Advisory Board on how to implement RSS and handle issues such as enclosures and HTML encoding, read the RSS Best Practices Profile. This checker is also a validator of Atom and RSS 1.0 feeds.

Use this tester regularly to ensure that your RSS feed continues to work well in the wide audience of RSS readers, podcast clients and other software that supports the format.

 

Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

  • line 362, column 0: style attribute contains potentially dangerous content: 79.5% (7 occurrences) [help]

    <div style="padding: 79.5% 0 0 0;"></div>
  • line 458, column 0: Non-html tag: connectionevaluator (8 occurrences) [help]

    auto evaluator = std::make_shared<ConnectionEvaluator>(); // Shared ow ...
  • line 1424, column 0: description should not contain html tag [help]

    <html>
  • line 1425, column 0: description should not contain head tag [help]

    <head>
  • line 1426, column 0: description should not contain meta tag [help]

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  • line 1427, column 0: description should not contain style tag [help]

    <style>
  • line 1439, column 0: description should not contain body tag [help]

    <body>
  • line 1442, column 0: description should not contain script tag (3 occurrences) [help]

    <script src="jquery.min.js"></script>
  • line 3187, column 0: Invalid HTML: EOF in middle of construct, at line 65, column 40 [help]

    <p>To start, we need to <code>#include <emscripten/bind.h> ...
  • line 3415, column 100: title should not contain HTML: – [help]

    ... &amp;#8211; First Steps with Qt for MCUs</title>
                                                 ^

Source: http://planet.qt-project.org/rss20.xml

  1. <?xml version="1.0"?>
  2. <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
  3.  <channel>
  4.    <title>Planet Qt</title>
  5.    <link>http://planet.qt.io</link>
  6.    <language>en</language>
  7.    <description>"Planet Qt - http://planet.qt.io/"</description>
  8.    <atom:link href="http://planet.qt.io/rss20.xml" rel="self" type="application/rss+xml"/>
  9.    <item>
  10.      <guid isPermaLink="false">https://www.basyskom.de/?p=9069</guid>
  11.      <title>Qt &#x2013; basysKom GmbH: How To Use Modern QML Tooling in Practice</title>
  12.      <pubDate>Fri, 26 Apr 2024 07:37:58 GMT</pubDate>
  13.      <link>https://www.basyskom.de/2024/how-to-use-modern-qml-tooling-in-practice/</link>
  14.      <description>&lt;p&gt;&lt;a href="https://www.basyskom.de/2024/how-to-use-modern-qml-tooling-in-practice/"&gt;&lt;img align="left" alt="How To Use Modern QML Tooling in Practice" 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;
  15. &lt;p&gt;Qt 5.15 introduced &#x201C;Automatic Type Registration&#x201D;. With it, a C++ class can be marked as &#x201C;QML_ELEMENT&#x201D; to be automatically registered to the QML engine. Qt 6 takes this to the next level and builds all of its tooling around the so-called QML Modules. Let&#x2019;s talk about what this new infrastructure means to your application in practice and how to benefit from it in an existing project.&lt;/p&gt;
  16. &lt;p&gt;&lt;a href="https://www.basyskom.de/2024/how-to-use-modern-qml-tooling-in-practice/" rel="nofollow"&gt;Continue reading How To Use Modern QML Tooling in Practice at basysKom GmbH.&lt;/a&gt;&lt;/p&gt;</description>
  17.    </item>
  18.    <item>
  19.      <guid isPermaLink="false">https://www.qt.io/blog/qt-meetup-community-events-in-toronto-and-detroit</guid>
  20.      <title>The Qt Company Blog: Qt Meetup: Community Events in Toronto and Detroit!</title>
  21.      <pubDate>Thu, 25 Apr 2024 15:21:53 GMT</pubDate>
  22.      <link>https://www.qt.io/blog/qt-meetup-community-events-in-toronto-and-detroit</link>
  23.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-meetup-community-events-in-toronto-and-detroit" title=""&gt;&lt;img alt="Qt Meetup: Community Events in Toronto and Detroit!" class="hs-featured-image" src="https://www.qt.io/hubfs/Qt%20Toronto%20%2B%20Detroit%20May%202024.jpg" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  24. &lt;p&gt;Hey Qt,&lt;/p&gt;
  25. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-meetup-community-events-in-toronto-and-detroit&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  26.    </item>
  27.    <item>
  28.      <guid isPermaLink="false">https://blog.felgo.com/updates/felgohotreload-1.2.0-load-from-cache-auto-connect-qt-6-7</guid>
  29.      <title>Felgo: Felgo Hot Reload 1.2.0: Load from Cache, Auto-Connect from Command Line, Improved QML Reload and Qt 6.7 Support</title>
  30.      <pubDate>Wed, 24 Apr 2024 12:47:04 GMT</pubDate>
  31.      <link>https://blog.felgo.com/updates/felgohotreload-1.2.0-load-from-cache-auto-connect-qt-6-7</link>
  32.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://blog.felgo.com/updates/felgohotreload-1.2.0-load-from-cache-auto-connect-qt-6-7" title=""&gt;&lt;img alt="Felgo Hot Reload 1.2.0: Load from Cache, Auto-Connect from Command Line, Improved QML Reload and Qt 6.7 Support" class="hs-featured-image" src="https://blog.felgo.com/hubfs/felgo-hot-reload-product-release.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  33. &lt;p&gt;The Felgo QML Hot Reload release 1.2.0 brings additional options on the connection screen, command line arguments, several QML Hot Reload improvements, and an overhauled user interface. Read on to check out all of the updates below:&lt;/p&gt;
  34. &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%2Ffelgohotreload-1.2.0-load-from-cache-auto-connect-qt-6-7&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
  35.    </item>
  36.    <item>
  37.      <guid isPermaLink="false">https://www.qt.io/blog/qt-safe-renderer-2.1.0-beta-3-released</guid>
  38.      <title>The Qt Company Blog: Qt Safe Renderer 2.1.0 Beta 3 Released</title>
  39.      <pubDate>Fri, 19 Apr 2024 16:15:29 GMT</pubDate>
  40.      <link>https://www.qt.io/blog/qt-safe-renderer-2.1.0-beta-3-released</link>
  41.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-safe-renderer-2.1.0-beta-3-released" title=""&gt;&lt;img alt="Qt Safe Renderer 2.1.0 Beta 3 Released" class="hs-featured-image" src="https://www.qt.io/hubfs/qtsr-qtcluster-telltales-eventsender-1-1.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  42. &lt;p&gt;&lt;span&gt;We have released Qt Safe Renderer 2.1.0 Beta 3 for commercial license holders today. It provides a snapshot of upcoming Qt Safe Renderer features and the following improvements for &lt;span&gt;Qt Safe Layout Tool QML and JavaScript parsing&lt;/span&gt;:&lt;br&gt;&lt;/span&gt;&lt;/p&gt;
  43. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-safe-renderer-2.1.0-beta-3-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  44.    </item>
  45.    <item>
  46.      <guid isPermaLink="false">https://www.qt.io/blog/qt-for-android-automotive-6.7-is-released</guid>
  47.      <title>The Qt Company Blog: Qt Android Automotive 6.7 is released</title>
  48.      <pubDate>Fri, 19 Apr 2024 12:24:29 GMT</pubDate>
  49.      <link>https://www.qt.io/blog/qt-for-android-automotive-6.7-is-released</link>
  50.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-for-android-automotive-6.7-is-released" title=""&gt;&lt;img alt="Qt Android Automotive 6.7 is released" class="hs-featured-image" src="https://doc.qt.io/qt-6/images/select_example_project.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  51. &lt;p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;The latest release of&lt;/span&gt; &lt;span&gt;Qt for Android Automotive (&lt;/span&gt;&lt;span&gt;QtAA&lt;/span&gt;&lt;span&gt;) is out, based on &lt;a href="https://www.qt.io/blog/qt-6.7-released"&gt;Qt 6.7.&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/span&gt;&lt;/p&gt;
  52. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-for-android-automotive-6.7-is-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  53.    </item>
  54.    <item>
  55.      <guid isPermaLink="false">https://www.qt.io/blog/security-advisory-potential-use-after-free-issue-in-qt-for-webassemblys-implementation-of-qnetworkreply</guid>
  56.      <title>The Qt Company Blog: Security advisory: Potential Use-After-Free issue in Qt for WebAssembly&#x2019;s implementation of QNetworkReply</title>
  57.      <pubDate>Thu, 18 Apr 2024 09:00:00 GMT</pubDate>
  58.      <link>https://www.qt.io/blog/security-advisory-potential-use-after-free-issue-in-qt-for-webassemblys-implementation-of-qnetworkreply</link>
  59.      <description>&lt;p&gt;A recently reported potential Use-After-Free issue in Qt&#x2019;s wasm implementation of QNetworkReply has been assigned the CVE id CVE-2024-30161.&lt;/p&gt;
  60. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fsecurity-advisory-potential-use-after-free-issue-in-qt-for-webassemblys-implementation-of-qnetworkreply&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  61.    </item>
  62.    <item>
  63.      <guid isPermaLink="false">https://www.ics.com/4827 at https://www.ics.com</guid>
  64.      <title>ICS Insights: Qt and QML: Key Takeaways from 2024 Embedded World</title>
  65.      <pubDate>Tue, 16 Apr 2024 15:43:15 GMT</pubDate>
  66.      <link>https://www.ics.com/blog/key-takeaways-2024-embedded-world</link>
  67.      <description>&lt;p&gt;With the 2024 Embedded World Exhibition &amp; Conference in the rear view, here are some key impressions from the ICS team around the future of embedded development.&lt;/p&gt;</description>
  68.    </item>
  69.    <item>
  70.      <guid isPermaLink="false">https://www.qt.io/blog/qtcs24-sep-5-6-save-the-date</guid>
  71.      <title>The Qt Company Blog: QtCS24 Sep 5-6 Save the Date!</title>
  72.      <pubDate>Fri, 12 Apr 2024 09:30:57 GMT</pubDate>
  73.      <link>https://www.qt.io/blog/qtcs24-sep-5-6-save-the-date</link>
  74.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qtcs24-sep-5-6-save-the-date" title=""&gt;&lt;img alt="QtCS24 Sep 5-6 Save the Date!" class="hs-featured-image" src="https://www.qt.io/hubfs/QtCS24%20Save%20the%20Date-2.jpg" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  75. &lt;p style="font-size: 10px;"&gt;tldr; save the date for our QtCS24 Sep 5-6 in W&#xFC;rzburg.&lt;br&gt;
  76. Stay tuned for more information.&lt;/p&gt;
  77. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqtcs24-sep-5-6-save-the-date&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  78.    </item>
  79.    <item>
  80.      <guid isPermaLink="false">https://www.qt.io/blog/qt-for-mcus-2.5.3-lts-released</guid>
  81.      <title>The Qt Company Blog: Qt for MCUs 2.5.3 LTS Released</title>
  82.      <pubDate>Thu, 11 Apr 2024 13:16:42 GMT</pubDate>
  83.      <link>https://www.qt.io/blog/qt-for-mcus-2.5.3-lts-released</link>
  84.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-for-mcus-2.5.3-lts-released" title=""&gt;&lt;img alt="Qt for MCUs 2.5.3 LTS Released" class="hs-featured-image" src="https://www.qt.io/hubfs/_Website_Blog/Upload_Here/Qt%20for%20MCUs%20release%202.5.3.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  85. &lt;p&gt;Qt for MCUs 2.5.3 LTS (Long-Term Support) has been released and is available for download.&lt;span&gt;&#xA0;&lt;/span&gt;&lt;span&gt;As a patch release, Qt for MCUs 2.5.3 LTS provides bug fixes and other improvements, and maintains source compatibility with Qt for MCUs 2.5.x. It does not&lt;/span&gt; &lt;span&gt;add any new functionality.&lt;/span&gt;&lt;/p&gt;
  86. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-for-mcus-2.5.3-lts-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  87.    </item>
  88.    <item>
  89.      <guid isPermaLink="false">https://www.kdab.com/?p=33391</guid>
  90.      <title>KDAB on Qt: Recursive Instantiation with Qt Quick and JSON</title>
  91.      <pubDate>Thu, 11 Apr 2024 07:00:37 GMT</pubDate>
  92.      <link>https://www.kdab.com/recursive-instantiation-with-qt-quick-and-json/</link>
  93.      <description>&lt;p&gt;Recently I was tasked to come up with an architecture for remote real time instantiation and updating of arbitrary QML components.&lt;/p&gt;
  94. &lt;p&gt;This entry shows how you can use a simple variation of the factory method pattern in QML for instantiating arbitrary components. I&#x2019;ve split my findings into 3 blog entries, each one covering a slightly different topic. Part 1 focuses on the software design pattern used to dynamically instantiate components. Part 2 shows how to layout these dynamic components by incorporating QML&#x2019; s positioning and layout APIs. The last entry, consisting of Parts 3 and 4, addresses the anchors API and important safety aspects.&lt;/p&gt;
  95. &lt;p&gt;This is Part 1: Recursive Instantiation with Qt Quick and JSON.&lt;/p&gt;
  96. &lt;p&gt;The original factory method pattern made use of static methods to programmatically instantiate objects of different classes, instead of having to call their constructors. It achieved that by having the classes share a common ancestor. Our variation of the popular pattern uses a Loader to choose which component to load, and a Repeater to dynamically instantiate arbitrary instances of this loader using a model.&lt;/p&gt;
  97. &lt;p&gt;Here we specify which components with a JSON array and use a Repeater to load them.&lt;/p&gt;
  98. &lt;pre class="language-js" tabindex="0"&gt;
  99. &lt;code class="language-js"&gt;&lt;span class="token comment"&gt;    &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;root&lt;/span&gt;
  100.    // A JSON representation of a QML layout:&lt;/span&gt;
  101.    property &lt;span class="token keyword"&gt;var&lt;/span&gt; &lt;span class="token literal-property property"&gt;factoryModel&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;
  102.        &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  103.            &lt;span class="token string-property property"&gt;"component"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;
  104.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;
  105.        &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  106.            &lt;span class="token string-property property"&gt;"component"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;
  107.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  108.    &lt;span class="token punctuation"&gt;]&lt;/span&gt;
  109. &lt;span class="token comment"&gt;    // Root of our component factory&lt;/span&gt;
  110.    Repeater &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  111.        &lt;span class="token literal-property property"&gt;model&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; root.factoryModel
  112.        &lt;span class="token literal-property property"&gt;delegate&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  113. &lt;span class="token punctuation"&gt;    }&lt;/span&gt;&lt;/code&gt;
  114. &lt;/pre&gt;
  115. &lt;p&gt;To be able to instantiate any kind of item, you can use a Component with a Loader inside, as the Repeater&#x2019;s delegate. This allows you to load a different component based on the Repeater&#x2019;s model data.&lt;/p&gt;
  116. &lt;pre class="language-javascript" tabindex="0"&gt;
  117. &lt;code class="language-javascript"&gt;    &lt;span class="token comment"&gt;// Root component of the factory and nodes&lt;/span&gt;
  118.    Component &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  119.        &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  120.        Loader &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  121.            &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; instantiator
  122.            required property var modelData
  123.            &lt;span class="token literal-property property"&gt;sourceComponent&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token keyword"&gt;switch&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;component&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  124.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"Button"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  125.                &lt;span class="token keyword"&gt;return&lt;/span&gt; buttonComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  126.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"RowLayout"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  127.                &lt;span class="token keyword"&gt;return&lt;/span&gt; rowLayoutComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  128.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"Item"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  129.                &lt;span class="token keyword"&gt;default&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token keyword"&gt;return&lt;/span&gt; itemComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  130.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  131.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  132.    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;
  133. &lt;/pre&gt;
  134. &lt;p&gt;To assign values from the model to the component, add a method that gets called when the Loader&#x2019;s onItemChanged event is triggered. I use this method to take care of anything that involves the component&#x2019;s properties:&lt;/p&gt;
  135. &lt;pre class="language-javascript" tabindex="0"&gt;
  136. &lt;code class="language-javascript"&gt;    &lt;span class="token comment"&gt;// Root component of the factory and nodes&lt;/span&gt;
  137.    Component &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  138.        &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  139.        Loader &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  140.            &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; instantiator
  141.            required property var modelData
  142.            &lt;span class="token literal-property property"&gt;sourceComponent&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token keyword"&gt;switch&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;component&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  143.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"Button"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  144.                &lt;span class="token keyword"&gt;return&lt;/span&gt; buttonComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  145.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"RowLayout"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  146.                &lt;span class="token keyword"&gt;return&lt;/span&gt; rowLayoutComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  147.                &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"Item"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  148.                &lt;span class="token keyword"&gt;default&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token keyword"&gt;return&lt;/span&gt; itemComp&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  149.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  150.            &lt;span class="token literal-property property"&gt;onItemChanged&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  151.                &lt;span class="token comment"&gt;// Pass children (see explanation below)&lt;/span&gt;
  152.                &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;typeof&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;children&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;===&lt;/span&gt; &lt;span class="token string"&gt;"object"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;
  153.                    item&lt;span class="token punctuation"&gt;.&lt;/span&gt;model &lt;span class="token operator"&gt;=&lt;/span&gt; modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;children&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  154.  
  155.                &lt;span class="token comment"&gt;// Button properties&lt;/span&gt;
  156.                &lt;span class="token keyword"&gt;switch&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;component&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  157.                    &lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token string"&gt;"Button"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt;
  158.                    &lt;span class="token comment"&gt;// If the model contains certain value, we may assign it:&lt;/span&gt;
  159.                    &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;typeof&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;text&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;!==&lt;/span&gt; &lt;span class="token string"&gt;"undefined"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;
  160.                        item&lt;span class="token punctuation"&gt;.&lt;/span&gt;text &lt;span class="token operator"&gt;=&lt;/span&gt; modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;text&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  161.                    &lt;span class="token keyword"&gt;break&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  162.                &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  163.  
  164.                &lt;span class="token comment"&gt;// Item properties&lt;/span&gt;
  165.                &lt;span class="token comment"&gt;// Since Item is the parent of all repeatable, we don't need to check&lt;/span&gt;
  166.                &lt;span class="token comment"&gt;// if the component supports Item properties before we assign them:&lt;/span&gt;
  167.                &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;typeof&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;x&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;!==&lt;/span&gt; &lt;span class="token string"&gt;"undefined"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;
  168.                    loaderComp&lt;span class="token punctuation"&gt;.&lt;/span&gt;x &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;Number&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;x&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  169.                &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;typeof&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;y&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;!==&lt;/span&gt; &lt;span class="token string"&gt;"undefined"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;
  170.                    loaderComp&lt;span class="token punctuation"&gt;.&lt;/span&gt;y &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;Number&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;modelData&lt;span class="token punctuation"&gt;.&lt;/span&gt;y&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
  171.                &lt;span class="token comment"&gt;// ...&lt;/span&gt;
  172.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  173.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  174.    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;
  175. &lt;/pre&gt;
  176. &lt;p&gt;Examples of components that loaderComp could load are defined below. To enable recursion, these components must contain a Repeater that instantiates children components, with loaderComp set as the delegate:&lt;/p&gt;
  177. &lt;pre class="language-javascript" tabindex="0"&gt;
  178. &lt;code class="language-javascript"&gt;    Component &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  179.        &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; itemComp
  180.        Item &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  181.            property alias children&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater&lt;span class="token punctuation"&gt;.&lt;/span&gt;model
  182.            &lt;span class="token literal-property property"&gt;children&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; Repeater &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  183.                &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater
  184.                &lt;span class="token literal-property property"&gt;delegate&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  185.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  186.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  187.    &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  188.    Component &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  189.        &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; buttonComp
  190.        Button &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  191.            property alias children&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater&lt;span class="token punctuation"&gt;.&lt;/span&gt;model
  192.            &lt;span class="token literal-property property"&gt;children&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; Repeater &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  193.                &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater
  194.                &lt;span class="token literal-property property"&gt;delegate&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  195.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  196.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  197.    &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  198.    Component &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  199.        &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; rowLayoutComp
  200.        RowLayout &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  201.            property alias children&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater&lt;span class="token punctuation"&gt;.&lt;/span&gt;model
  202.            &lt;span class="token literal-property property"&gt;children&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; Repeater &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  203.                &lt;span class="token literal-property property"&gt;id&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; itemRepeater
  204.                &lt;span class="token literal-property property"&gt;delegate&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; loaderComp
  205.            &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  206.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  207.    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;
  208. &lt;/pre&gt;
  209. &lt;p&gt;The Repeater inside of the components allows us to instantiate components recursively, by having a branch or more of children components in the model, like so:&lt;/p&gt;
  210. &lt;pre class="language-javascript" tabindex="0"&gt;
  211. &lt;code class="language-javascript"&gt;    &lt;span class="token comment"&gt;// This model lays out buttons vertically&lt;/span&gt;
  212.    property &lt;span class="token keyword"&gt;var&lt;/span&gt; &lt;span class="token literal-property property"&gt;factoryModel&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;
  213.        &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  214.            &lt;span class="token string-property property"&gt;"component"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"RowLayout"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;
  215.            &lt;span class="token string-property property"&gt;"children"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;
  216.                &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  217.                    &lt;span class="token string-property property"&gt;"component"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button",&lt;/span&gt;
  218.                    &lt;span class="token string-property property"&gt;"text"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button 1"&lt;/span&gt;
  219.                &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;
  220.                &lt;span class="token punctuation"&gt;{&lt;/span&gt;
  221.                    &lt;span class="token string-property property"&gt;"component"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button",&lt;/span&gt;
  222.                    &lt;span class="token string-property property"&gt;"text"&lt;/span&gt;&lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;"Button 2"&lt;/span&gt;
  223.                &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  224.            &lt;span class="token punctuation"&gt;]&lt;/span&gt;
  225.        &lt;span class="token punctuation"&gt;}&lt;/span&gt;
  226.    &lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;/code&gt;
  227. &lt;/pre&gt;
  228. &lt;p&gt;Here we&#x2019;ve seen how we can use a Repeater, a JSON model, a Loader delegate, and simple recursive definition to instantiate arbitrary QML objects from a JSON description. In my next entry I will focus on how you can lay out these arbitrarily instantiated objects on your screen.&lt;/p&gt;
  229. &lt;p&gt;Thanks to &lt;a href="https://www.kdab.com/trainer/kevin-krammer/"&gt;Kevin Krammer&lt;/a&gt; and &lt;a href="https://www.kdab.com/trainer/jan-marker/"&gt;Jan Marker&lt;/a&gt; whose insights helped improve the code you&#x2019;ve seen here.&lt;/p&gt;
  230. &lt;p&gt;I hope you&#x2019;ve found this useful! Part 2 may be found already or later by following &lt;a href="https://wp.me/p2b2Fz-8Sr"&gt;this link&lt;/a&gt;.&lt;/p&gt;
  231. &lt;h5&gt;Reference&lt;/h5&gt;
  232. &lt;ul&gt;
  233. &lt;li&gt;To see a real world application of this factory design pattern in action, watch &#x201C;QML for building beautiful desktop apps | Dev/Des 2021&#x201D;, by Prashanth N. Udupa &lt;a href="https://youtu.be/l2nC-onPGQs?si=Q-xawseUUzsNADk9&amp;t=1720" rel="noopener noreferrer" target="_blank"&gt;https://www.youtube.com/watch?v=l2nC-onPGQs&lt;/a&gt;&lt;/li&gt;
  234. &lt;/ul&gt;
  235. &lt;div class="panel panel-info"&gt;
  236. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  237. &lt;div class="panel-body"&gt;
  238. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  239. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  240. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  241. &lt;/div&gt;
  242. &lt;/div&gt;
  243. &lt;p&gt;The post &lt;a href="https://www.kdab.com/recursive-instantiation-with-qt-quick-and-json/"&gt;Recursive Instantiation with Qt Quick and JSON&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  244.    </item>
  245.    <item>
  246.      <guid isPermaLink="false">https://www.qt.io/blog/qt-project-top-contributors-of-2022-0</guid>
  247.      <title>The Qt Company Blog: Qt Project: Top Contributors of 2023!</title>
  248.      <pubDate>Wed, 10 Apr 2024 10:12:35 GMT</pubDate>
  249.      <link>https://www.qt.io/blog/qt-project-top-contributors-of-2022-0</link>
  250.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-project-top-contributors-of-2022-0" title=""&gt;&lt;img alt="Qt Project: Top Contributors of 2023!" class="hs-featured-image" src="https://www.qt.io/hubfs/Qt%20Project%20Top%20Contributors%202023.jpg" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  251. &lt;p&gt;So, 2023 was a successful year for Qt - and we highlight &lt;span&gt;&lt;span&gt;the &lt;a href="https://www.qt.io/blog/qt-6.5-lts-released" style="font-weight: bold;"&gt;Qt 6.5&lt;/a&gt;&#xA0;and &lt;a href="https://www.qt.io/blog/qt-6.6-released" style="font-weight: bold;"&gt;Qt 6.6&lt;/a&gt;&#xA0;releases, &lt;a href="https://www.qt.io/qt-world-summit-2023" style="font-weight: bold;"&gt;Qt World Summit&lt;/a&gt;, and &lt;a href="https://www.qt.io/blog/contributor-summit-2023-qt-highlights" style="font-weight: bold;"&gt;Qt Contributor Summit&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
  252. &lt;p&gt;Our community stays vibrant and engaged with the Qt Project through our forums, mailings lists, asking and answering questions, offering technical advice, reporting bugs, contributing patches, and in many other forms helping Qt flourish.&lt;/p&gt;
  253. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-project-top-contributors-of-2022-0&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  254.    </item>
  255.    <item>
  256.      <guid isPermaLink="false">https://www.qt.io/blog/insights-from-industry-experts-improving-software-dev-productivity</guid>
  257.      <title>The Qt Company Blog: Insights from Industry Experts: Improving Software Dev Productivity</title>
  258.      <pubDate>Wed, 10 Apr 2024 07:36:07 GMT</pubDate>
  259.      <link>https://www.qt.io/blog/insights-from-industry-experts-improving-software-dev-productivity</link>
  260.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/insights-from-industry-experts-improving-software-dev-productivity" title=""&gt;&lt;img alt="Insights from Industry Experts: Improving Software Dev Productivity" class="hs-featured-image" src="https://www.qt.io/hubfs/iStock_000043979843Large_ICT%20copy.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  261. &lt;p&gt;&#xA0;&lt;/p&gt;
  262. &lt;p&gt;Software development is a dynamic and constantly evolving field that requires professionals to stay up-to-date with the latest technologies and tools to improve their productivity and efficiency. For developers, the ultimate goal is to complete tasks effectively, leading to better products and faster time-to-market. These topics were explored in our &lt;a href="https://www.qt.io/qt-world-summit-2023"&gt;World Summit QtWS23&lt;/a&gt; last November, where &lt;a href="https://www.qt.io/resources/videos/panel-discussion-is-software-making-the-lives-of-developers-easier-with-kate-kevlin-and-volker?hsLang=en"&gt;experts Kate Gregory, Kevlin Henney, and Volker Hilsheimer&lt;/a&gt; shared valuable insights.&#xA0;&lt;/p&gt;
  263. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Finsights-from-industry-experts-improving-software-dev-productivity&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  264.    </item>
  265.    <item>
  266.      <guid isPermaLink="false">https://www.qt.io/blog/qt-for-android-automotive-6.6.3-is-released</guid>
  267.      <title>The Qt Company Blog: Qt for Android Automotive 6.6.3 is released</title>
  268.      <pubDate>Tue, 09 Apr 2024 19:15:14 GMT</pubDate>
  269.      <link>https://www.qt.io/blog/qt-for-android-automotive-6.6.3-is-released</link>
  270.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-for-android-automotive-6.6.3-is-released" title=""&gt;&lt;img alt="Qt for Android Automotive 6.6.3 is released" class="hs-featured-image" src="https://www.qt.io/hubfs/Outrun%20automotive%20demo/Apps.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  271. &lt;p&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;The latest release of&lt;/span&gt; &lt;span&gt;Qt for Android Automotive (&lt;/span&gt;&lt;span&gt;QtAA&lt;/span&gt;&lt;span&gt;) is out, based on &lt;a href="https://www.qt.io/blog/qt-6.6.3-released"&gt;Qt 6.6.3&lt;/a&gt;&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;with&lt;/span&gt;&lt;/span&gt; more than 300 bug fixes, security updates, and other improvements to the top of the Qt 6.6.2 release.&lt;br&gt;&lt;/span&gt;&lt;/p&gt;
  272. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-for-android-automotive-6.6.3-is-released&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  273.    </item>
  274.    <item>
  275.      <guid isPermaLink="false">https://www.qt.io/blog/qt-for-python-release-6.7</guid>
  276.      <title>The Qt Company Blog: Qt for Python release: 6.7 is now available! &#x1F40D;</title>
  277.      <pubDate>Tue, 09 Apr 2024 11:16:36 GMT</pubDate>
  278.      <link>https://www.qt.io/blog/qt-for-python-release-6.7</link>
  279.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://www.qt.io/blog/qt-for-python-release-6.7" title=""&gt;&lt;img alt="Qt for Python release: 6.7 is now available! &#x1F40D;" class="hs-featured-image" src="https://www.qt.io/hubfs/qt%20release-2.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  280. &lt;img alt="" height="1" src="https://track.hubspot.com/__ptq.gif?a=149513&amp;k=14&amp;r=https%3A%2F%2Fwww.qt.io%2Fblog%2Fqt-for-python-release-6.7&amp;bu=https%253A%252F%252Fwww.qt.io%252Fblog&amp;bvt=rss" width="1"&gt;</description>
  281.    </item>
  282.    <item>
  283.      <guid isPermaLink="false">https://www.kdab.com/?p=34100</guid>
  284.      <title>KDAB on Qt: Embedding the Servo Web Engine in Qt</title>
  285.      <pubDate>Fri, 05 Apr 2024 08:00:03 GMT</pubDate>
  286.      <link>https://www.kdab.com/embedding-servo-in-qt/</link>
  287.      <description>&lt;p&gt;With the Qt WebEngine module, Qt makes it possible to embed a webview component inside an otherwise native application. Under the hood, Qt WebEngine uses the Chromium browser engine, currently the de facto standard engine for such use cases.&lt;/p&gt;
  288. &lt;p&gt;While the task of writing a brand new standard-compliant browser engine is infamous as being almost unachievable nowadays (and certainly so with Chromium coming in at 31 million lines of code), the Rust ecosystem has been brewing up a new web rendering engine called &lt;a href="https://servo.org/"&gt;Servo&lt;/a&gt;. Initially created by Mozilla in 2012, Servo is still being developed today, now under the stewardship of the Linux Foundation.&lt;/p&gt;
  289. &lt;p&gt;With the browser inherently being exposed to the internet, it is usually the biggest attack vector on a system. Naturally this makes Servo very attractive as an alternative browser engine, given that it is written in a memory-safe language.&lt;/p&gt;
  290. &lt;h2&gt;A Servo WebView&lt;/h2&gt;
  291. &lt;p&gt;At KDAB we managed to embed the Servo web engine inside Qt, by using our &lt;a href="https://github.com/KDAB/cxx-qt"&gt;CXX-Qt&lt;/a&gt; library as a bridge between Rust and C++. This means that we can now use Servo as an alternative to Chromium for webviews in Qt applications.&lt;/p&gt;
  292. &lt;p&gt;From a QML perspective this component is similar to the Chromium &lt;a href="https://doc.qt.io/qt-6/qml-qtwebview-webview.html"&gt;WebView&lt;/a&gt;, such as providing &lt;code&gt;canGoBack&lt;/code&gt;, &lt;code&gt;canGoForward&lt;/code&gt;, &lt;code&gt;loading&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt; properties and &lt;code&gt;goBack&lt;/code&gt;, &lt;code&gt;goForward&lt;/code&gt; methods. The QML item itself acts in the same way with the contents being rendered to match its size.&lt;/p&gt;
  293. &lt;pre class="brush: plain; title: ; notranslate"&gt;
  294. import QtQuick
  295. import QtQuick.Window
  296.  
  297. import com.kdab.servo
  298.  
  299. Window {
  300.  height: 720
  301.  width: 1280
  302.  title: webView.title
  303.  visible: true
  304.  
  305.  ServoWebView {
  306.    id: webView
  307.    anchors.fill: parent
  308.    url: "https://servo.org/"
  309.  }
  310. }
  311. &lt;/pre&gt;
  312. &lt;p&gt;The screenshot below shows a basic QML application with a toolbar containing back, forward, go buttons and an address bar. We use CXX-Qt to define Qt properties, invokables, and event handlers (e.g. touch events) in Rust and trigger events in the Servo engine. Then any update requests from Servo can trigger an update of the Qt side via the Qt event loop.&lt;/p&gt;
  313. &lt;p&gt;&lt;img alt="" class="aligncenter wp-image-34507 size-full" height="833" src="https://www.kdab.com/wp-content/uploads/stories/cxx-qt-servo-webview.png" width="1286"&gt;&lt;/p&gt;
  314. &lt;p&gt;As we move towards stabilising &lt;a href="https://github.com/KDAB/cxx-qt/"&gt;CXX-Qt&lt;/a&gt; at KDAB, investigating real world use cases, such as exposing Servo to Qt, allows us to identify potential missing functionality and explore what is possible when joining the Rust and Qt ecosystems together.&lt;/p&gt;
  315. &lt;h2&gt;Technical details&lt;/h2&gt;
  316. &lt;p&gt;Under the hood most of the heavy lifting is done by our &lt;a href="https://github.com/KDAB/cxx-qt/"&gt;CXX-Qt&lt;/a&gt; bindings, which already bridges the obvious gap between the Rust and Qt/C++ worlds. However, some further glue is needed to connect the rendering contexts of Servo to being able to render the surfaces into the actual Qt application. Internally, Servo uses &lt;a href="https://github.com/servo/surfman"&gt;surfman&lt;/a&gt;, a Rust library to manage rendering surfaces. At the time of writing, surfman supports OpenGL and Metal, with support for Vulkan being planned.&lt;/p&gt;
  317. &lt;p&gt;We use surfman to &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview/blob/157b65bb44c7bb2ef5d84542f03dccc0de18c002/src/windowheadless.rs#L29"&gt;create a new OpenGL context&lt;/a&gt;, that &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview/blob/157b65bb44c7bb2ef5d84542f03dccc0de18c002/src/servothread.rs#L76-L81"&gt;Servo then uses for rendering&lt;/a&gt;. To render the result into the QtQuick scene, we &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview/blob/157b65bb44c7bb2ef5d84542f03dccc0de18c002/src/servothread.rs#L145-L161"&gt;borrow the surface&lt;/a&gt; from Servo, &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview/blob/157b65bb44c7bb2ef5d84542f03dccc0de18c002/src/renderer.rs#L130"&gt;create a new framebuffer object&lt;/a&gt; and &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview/blob/157b65bb44c7bb2ef5d84542f03dccc0de18c002/src/renderer.rs#L133"&gt;blit the framebuffer&lt;/a&gt; into a &lt;a href="https://doc.qt.io/qt-6/qquickframebufferobject.html"&gt;QQuickFrameBufferObject&lt;/a&gt; on the Qt side.&lt;/p&gt;
  318. &lt;h2&gt;Future possibilities&lt;/h2&gt;
  319. &lt;p&gt;Servo development is &lt;a href="https://servo.org/blog/2023/12/18/this-year-in-servo/"&gt;active&lt;/a&gt; again after a period of less activity, therefore the API is evolving and there is work to improve the API for &lt;a href="https://servo.org/blog/2024/01/19/embedding-update/"&gt;embedders&lt;/a&gt;. This could result in a simpler and documented process for integrating Servo into apps. Also as part of the &lt;a href="https://tauri.app/"&gt;Tauri&lt;/a&gt; and Servo &lt;a href="https://nlnet.nl/project/Tauri-Servo/"&gt;collaboration&lt;/a&gt;, a backend for &lt;a href="https://github.com/tauri-apps/wry"&gt;WRY&lt;/a&gt; could become available. All of these result in many possible changes for the bridge to Qt, as currently this demo directly constructs Servo components (similar to servoshell) but could instead use a shared library or WRY instead.&lt;/p&gt;
  320. &lt;p&gt;On the Qt side, there are areas that could be improved or investigated further. For example, currently we are using a framebuffer object which forces use of the OpenGL backend, but with RHI, developers might want to use other backends. A way to solve this for QML would be to change the implementation to instead use a custom Qt Scene Graph node, which can then have implementations for Vulkan, OpenGL etc and read from the Servo engine.&lt;/p&gt;
  321. &lt;p&gt;Alternatively &lt;a href="https://www.qt.io/blog/qt-6.7-released#hybrid-applications-with-native-ui-elements-and-rendering"&gt;Qt 6.7 has introduced a new QQuickRhiItem element&lt;/a&gt;, which is currently a technical preview, but can be used as a &lt;a href="https://doc-snapshots.qt.io/qt6-6.7/qquickrhiitem.html"&gt;rendering API-agnostic alternative to QQuickFrameBufferObject&lt;/a&gt;.&lt;/p&gt;
  322. &lt;p&gt;If this sounds interesting to your use case or you would like to collaborate with us, the code for this tech demo is available on GitHub under &lt;a href="https://github.com/KDABLabs/cxx-qt-servo-webview"&gt;KDABLabs/cxx-qt-servo-webview&lt;/a&gt; or &lt;a href="https://www.kdab.com/about/contact/"&gt;contact KDAB directly&lt;/a&gt;. We also have a &lt;a href="https://cxx-qt.zulipchat.com"&gt;Zulip chat&lt;/a&gt; if you want to discuss any parts of bridging Servo or CXX-Qt with us.&lt;/p&gt;
  323. &lt;p&gt;Come and see us at &lt;a href="https://www.embedded-world.de/en"&gt;Embedded World 2024&lt;/a&gt; where we will have the Servo demo and &lt;a href="https://www.kdab.com/kdab-at-embedded-world-2024/"&gt;others&lt;/a&gt; on display!&lt;/p&gt;
  324. &lt;p&gt;&#xA0;&lt;/p&gt;
  325. &lt;p&gt;The post &lt;a href="https://www.kdab.com/embedding-servo-in-qt/"&gt;Embedding the Servo Web Engine in Qt&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  326.    </item>
  327.    <item>
  328.      <guid isPermaLink="false">https://www.basyskom.de/?p=8828</guid>
  329.      <title>Qt &#x2013; basysKom GmbH: Use Compute Shader in Qt Quick</title>
  330.      <pubDate>Tue, 02 Apr 2024 09:14:23 GMT</pubDate>
  331.      <link>https://www.basyskom.de/2024/use-compute-shader-in-qt-quick/</link>
  332.      <description>&lt;p&gt;&lt;a href="https://www.basyskom.de/2024/use-compute-shader-in-qt-quick/"&gt;&lt;img align="left" alt="Use Compute Shader in Qt Quick" 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;
  333. &lt;p&gt;With this blog post, we introduce the&#xA0;QtQuickComputeItem&#xA0;- a Qt Quick item that allows you to easily integrate compute shader into your Qt Quick Code.&lt;br&gt;
  334. Compute&lt;br&gt;
  335. Shader are used to perform arbitrary computations on the GPU. For&lt;br&gt;
  336. example, the screenshot below shows a Qt Quick application that&lt;br&gt;
  337. generates Gray Scott Reaction Diffusion patterns.&#xA0; The simulation is executed by a compute shader that is configured directly in QML.&lt;/p&gt;
  338. &lt;p&gt;&lt;a href="https://www.basyskom.de/2024/use-compute-shader-in-qt-quick/" rel="nofollow"&gt;Continue reading Use Compute Shader in Qt Quick at basysKom GmbH.&lt;/a&gt;&lt;/p&gt;</description>
  339.    </item>
  340.    <item>
  341.      <guid isPermaLink="false">tag:www.pythonguis.com,2024-03-27:/faq/adding-images-to-pyside6-applications/</guid>
  342.      <title>Python GUIs - qt: Q&amp;A: How Do I Display Images in PySide6? &#x2014; Using QLabel to easily add images to your applications</title>
  343.      <pubDate>Wed, 27 Mar 2024 06:00:00 GMT</pubDate>
  344.      <link>https://www.pythonguis.com/faq/adding-images-to-pyside6-applications/</link>
  345.      <description>&lt;p&gt;Adding images to your application is a common requirement, whether you're building an image/photo viewer, or just want to add some decoration to your GUI. Unfortunately, because of how this is done in Qt, it can be a little bit tricky to work out at first.&lt;/p&gt;
  346. &lt;p&gt;In this short tutorial, we will look at how you can insert an external image into your PySide6 application layout, using both code and Qt Designer.&lt;/p&gt;
  347. &lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;
  348. &lt;ul&gt;
  349. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#which-widget-to-use"&gt;Which widget to use?&lt;/a&gt;&lt;/li&gt;
  350. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#using-qt-designer"&gt;Using Qt Designer&lt;/a&gt;&lt;/li&gt;
  351. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#using-code"&gt;Using Code&lt;/a&gt;&lt;/li&gt;
  352. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  353. &lt;/ul&gt;
  354. &lt;/div&gt;
  355. &lt;h3 id="which-widget-to-use"&gt;Which widget to use?&lt;/h3&gt;
  356. &lt;p&gt;Since you're wanting to insert an image you might be expecting to use a widget named &lt;code&gt;QImage&lt;/code&gt; or similar, but that would make a bit too much sense! &lt;code&gt;QImage&lt;/code&gt; is actually Qt's image &lt;em&gt;object&lt;/em&gt; type, which is used to store the actual image data for use within your application. The &lt;em&gt;widget&lt;/em&gt; you use to display an image is &lt;code&gt;QLabel&lt;/code&gt;.&lt;/p&gt;
  357. &lt;p&gt;The primary use of &lt;code&gt;QLabel&lt;/code&gt; is of course to add labels to a UI, but it also has the ability to display an image &#x2014; or &lt;em&gt;pixmap&lt;/em&gt; &#x2014; instead, covering the entire area of the widget. Below we'll look at how to use &lt;code&gt;QLabel&lt;/code&gt; to display a widget in your applications.&lt;/p&gt;
  358. &lt;h3 id="using-qt-designer"&gt;Using Qt Designer&lt;/h3&gt;
  359. &lt;p&gt;First, create a &lt;em&gt;MainWindow&lt;/em&gt; object in Qt Designer and add a "Label" to it. You can find Label at in &lt;em&gt;Display Widgets&lt;/em&gt; in the bottom of the left hand panel. Drag this onto the &lt;code&gt;QMainWindow&lt;/code&gt; to add it.&lt;/p&gt;
  360. &lt;p&gt;&lt;img alt="MainWindow with a single QLabel added" height="1027" src="https://www.pythonguis.com/static/faq/adding-images-to-applications/1.png" width="1917"&gt; &lt;em&gt;MainWindow with a single QLabel added&lt;/em&gt;&lt;/p&gt;
  361. &lt;p&gt;Next, with the Label selected, look in the right hand &lt;code&gt;QLabel&lt;/code&gt; properties panel for the &lt;code&gt;pixmap&lt;/code&gt; property (scroll down to the blue region). From the property editor dropdown select "Choose File&#x2026;" and select an image file to insert.&lt;/p&gt;
  362. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;
  363. &lt;p&gt;As you can see, the image is inserted, but the image is kept at its original size, cropped to the boundaries of the&lt;code&gt;QLabel&lt;/code&gt; box. You need to resize the &lt;code&gt;QLabel&lt;/code&gt; to be able to see the entire image.&lt;/p&gt;
  364. &lt;p&gt;In the same controls panel, click to enable &lt;code&gt;scaledContents&lt;/code&gt;.&lt;/p&gt;
  365. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;
  366. &lt;p&gt;When &lt;code&gt;scaledContents&lt;/code&gt; is enabled the image is resized to the fit the bounding box of the &lt;code&gt;QLabel&lt;/code&gt; widget. This shows the entire image at all times, although it does not respect the aspect ratio of the image if you resize the widget.&lt;/p&gt;
  367. &lt;p&gt;You can now save your UI to file (e.g. as &lt;code&gt;mainwindow.ui&lt;/code&gt;).&lt;/p&gt;
  368. &lt;p&gt;To view the resulting UI, we can use the standard application template below. This loads the &lt;code&gt;.ui&lt;/code&gt; file we've created (&lt;code&gt;mainwindow.ui&lt;/code&gt;) creates the window and starts up the application.&lt;/p&gt;
  369. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-PySide6"&gt;PySide6&lt;/span&gt;
  370. &lt;pre&gt;
  371. &lt;code class="PySide6"&gt;import sys
  372. from PySide6 import QtWidgets
  373. from PySide6.QtUiTools import QUiLoader
  374.  
  375. loader = QUiLoader()
  376. app = QtWidgets.QApplication(sys.argv)
  377. window = loader.load("mainwindow.ui", None)
  378. window.show()
  379. app.exec()
  380. &lt;/code&gt;
  381. &lt;/pre&gt;&lt;/div&gt;
  382. &lt;p&gt;Running the above code will create a window, with the image displayed in the middle.&lt;/p&gt;
  383. &lt;p&gt;&lt;img alt="QtDesigner application showing a Cat" height="639" src="https://www.pythonguis.com/static/faq/adding-images-to-applications/5.png" width="802"&gt; &lt;em&gt;QtDesigner application showing a Cat&lt;/em&gt;&lt;/p&gt;
  384. &lt;h3 id="using-code"&gt;Using Code&lt;/h3&gt;
  385. &lt;p&gt;Instead of using Qt Designer, you might also want to show an image in your application through code. As before we use a &lt;code&gt;QLabel&lt;/code&gt; widget and add a &lt;em&gt;pixmap&lt;/em&gt; image to it. This is done using the &lt;code&gt;QLabel&lt;/code&gt; method &lt;code&gt;.setPixmap()&lt;/code&gt;. The full code is shown below.&lt;/p&gt;
  386. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-PySide6"&gt;PySide6&lt;/span&gt;
  387. &lt;pre&gt;
  388. &lt;code class="PySide6"&gt;import sys
  389. from PySide6.QtGui import QPixmap
  390. from PySide6.QtWidgets import QMainWindow, QApplication, QLabel
  391.  
  392. class MainWindow(QMainWindow):
  393.  
  394.    def __init__(self):
  395.        super(MainWindow, self).__init__()
  396.        self.title = "Image Viewer"
  397.        self.setWindowTitle(self.title)
  398.  
  399.        label = QLabel(self)
  400.        pixmap = QPixmap('cat.jpg')
  401.        label.setPixmap(pixmap)
  402.        self.setCentralWidget(label)
  403.        self.resize(pixmap.width(), pixmap.height())
  404.  
  405.  
  406. app = QApplication(sys.argv)
  407. w = MainWindow()
  408. w.show()
  409. sys.exit(app.exec())
  410. &lt;/code&gt;
  411. &lt;/pre&gt;&lt;/div&gt;
  412. &lt;p&gt;The block of code below shows the process of creating the &lt;code&gt;QLabel&lt;/code&gt;, creating a &lt;code&gt;QPixmap&lt;/code&gt; object from our file &lt;code&gt;cat.jpg&lt;/code&gt; (passed as a file path), setting this &lt;code&gt;QPixmap&lt;/code&gt; onto the &lt;code&gt;QLabel&lt;/code&gt; with &lt;code&gt;.setPixmap()&lt;/code&gt; and then finally resizing the window to fit the image.&lt;/p&gt;
  413. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  414. &lt;pre&gt;
  415. &lt;code class="python"&gt;label = QLabel(self)
  416. pixmap = QPixmap('cat.jpg')
  417. label.setPixmap(pixmap)
  418. self.setCentralWidget(label)
  419. self.resize(pixmap.width(), pixmap.height())
  420. &lt;/code&gt;
  421. &lt;/pre&gt;&lt;/div&gt;
  422. &lt;p&gt;Launching this code will show a window with the cat photo displayed and the window sized to the size of the image.&lt;/p&gt;
  423. &lt;p&gt;&lt;img alt="QMainWindow with Cat image displayed" height="439" src="https://www.pythonguis.com/static/faq/adding-images-to-applications/4.png" width="602"&gt; &lt;em&gt;QMainWindow with Cat image displayed&lt;/em&gt;&lt;/p&gt;
  424. &lt;p&gt;Just as in Qt designer, you can call &lt;code&gt;.setScaledContents(True)&lt;/code&gt; on your &lt;code&gt;QLabel&lt;/code&gt; image to enable scaled mode, which resizes the image to fit the available space.&lt;/p&gt;
  425. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  426. &lt;pre&gt;
  427. &lt;code class="python"&gt;label = QLabel(self)
  428. pixmap = QPixmap('cat.jpg')
  429. label.setPixmap(pixmap)
  430. label.setScaledContents(True)
  431. self.setCentralWidget(label)
  432. self.resize(pixmap.width(), pixmap.height())
  433. &lt;/code&gt;
  434. &lt;/pre&gt;&lt;/div&gt;
  435. &lt;p class="admonition admonition-note"&gt;Notice that you set the scaled state on the &lt;code&gt;QLabel&lt;/code&gt; widget and not the image pixmap itself.&lt;/p&gt;
  436. &lt;h3 id="conclusion"&gt;Conclusion&lt;/h3&gt;
  437. &lt;p&gt;In this quick tutorial we've covered how to insert images into your Qt UIs using &lt;code&gt;QLabel&lt;/code&gt; both from Qt Designer and directly from PySide6 code.&lt;/p&gt;</description>
  438.    </item>
  439.    <item>
  440.      <guid isPermaLink="false">https://www.kdab.com/?p=33552</guid>
  441.      <title>KDAB on Qt: Introducing the ConnectionEvaluator in KDBindings</title>
  442.      <pubDate>Thu, 21 Mar 2024 08:00:17 GMT</pubDate>
  443.      <link>https://www.kdab.com/introducing-the-connectionevaluator-in-kdbindings/</link>
  444.      <description>&lt;p&gt;Managing the timing and context of signals and slots in multithreaded applications, especially those with a GUI, can be a complex task. The concept of deferred connection evaluation offers a nice and easy API, allowing for controlled and efficient signal-slot connections. This approach is particularly useful when dealing with worker threads and GUI threads.&lt;/p&gt;
  445. &lt;p&gt;A classic example &lt;span class="hljs-keyword"&gt;where&lt;/span&gt; &lt;span class="hljs-keyword"&gt;cross&lt;/span&gt;-thread signal-slot connections are useful &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; we have a worker thread performing &lt;span class="hljs-keyword"&gt;some&lt;/span&gt; computations &lt;span class="hljs-keyword"&gt;or&lt;/span&gt; data collection &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; periodically emits signals. The GUI thread can &lt;span class="hljs-keyword"&gt;connect&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; these signals &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; &lt;span class="hljs-keyword"&gt;then&lt;/span&gt; display the data however it wishes. Graphical display usually must happen &lt;span class="hljs-keyword"&gt;on&lt;/span&gt; the main thread &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; at specific times. Therefore, controlling exactly &lt;span class="hljs-keyword"&gt;when&lt;/span&gt; the receiving slots &lt;span class="hljs-keyword"&gt;get&lt;/span&gt; executed &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; &lt;span class="hljs-keyword"&gt;of&lt;/span&gt; critical importance &lt;span class="hljs-keyword"&gt;for&lt;/span&gt; correctness &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; performance.&lt;/p&gt;
  446. &lt;h2&gt;&lt;em&gt;A Quick Recap on Signals &amp; Slots and KDBindings&lt;/em&gt;&lt;/h2&gt;
  447. &lt;p&gt;Signals and slots are integral to event handling in C++ applications. Signals, emitted upon certain events or conditions, trigger connected slots (functions or methods) to respond accordingly. This framework is highly effective, but there are cases where immediate slot invocation is not ideal, such as in multithreaded applications where you might want to emit a signal in one thread and handle it in another, like a GUI event loop.&lt;/p&gt;
  448. &lt;p&gt;&lt;a href="https://github.com/KDAB/KDBindings"&gt;KDBindings&lt;/a&gt; &lt;span class="hljs-keyword"&gt;is&lt;/span&gt; a &lt;span class="hljs-keyword"&gt;header&lt;/span&gt;&#x2013;&lt;span class="hljs-keyword"&gt;only&lt;/span&gt; C++&lt;span class="hljs-number"&gt;17&lt;/span&gt; library that implements the signals &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; slots design pattern. &lt;span class="hljs-keyword"&gt;In&lt;/span&gt; addition, KDBindings &lt;span class="hljs-keyword"&gt;also&lt;/span&gt; provides an easy &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; use property &lt;span class="hljs-keyword"&gt;and&lt;/span&gt; bindings &lt;span class="hljs-keyword"&gt;system&lt;/span&gt; &lt;span class="hljs-keyword"&gt;to&lt;/span&gt; &lt;span class="hljs-keyword"&gt;enable&lt;/span&gt; reactive programming &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; C++. For more information, read &lt;a href="https://www.kdab.com/signals-slots-properties-bindings/"&gt;this introduction blog&lt;/a&gt;.&lt;/p&gt;
  449. &lt;h2&gt;&lt;em&gt;Understanding Deferred Connection Evaluation&lt;/em&gt;&lt;/h2&gt;
  450. &lt;p&gt;In Qt, a signal that should be evaluated on a different thread will be executed by the event loop of that thread. As &lt;a href="https://www.kdab.com/signals-slots-properties-bindings/"&gt;KDBindings&lt;/a&gt; doesn&#x2019;t have its own event loop and needs to be able to integrate into any framework, we&#x2019;re introducing the &lt;strong&gt;ConnectionEvaluator&lt;/strong&gt; as our solution to those nuanced requirements. It allows for a deferred evaluation of connections, providing a much-needed flexibility in handling signal emissions.&lt;/p&gt;
  451. &lt;p&gt;In multithreaded environments, the immediate execution of slots in response to signals can lead to complications. Deferred connection evaluation addresses this by delaying the execution of a slot until a developer-determined point. This is achieved through a &lt;strong&gt;ConnectionEvaluator&lt;/strong&gt;, akin to a &lt;strong&gt;BindingEvaluator&lt;/strong&gt;, which governs when a slot is called.&lt;/p&gt;
  452. &lt;h2&gt;&lt;em&gt;Implementing and Utilizing Deferred Connections&lt;/em&gt;&lt;/h2&gt;
  453. &lt;p&gt;We have introduced &lt;strong&gt;connectDeferred.&lt;/strong&gt; This function, mirroring the standard connect method, takes a &lt;strong&gt;ConnectionEvaluator&lt;/strong&gt; as its first argument, followed by the standard signal and slot parameters.&lt;/p&gt;
  454. &lt;p&gt;Signals emitted are queued in the &lt;strong&gt;ConnectionEvaluator&lt;/strong&gt; instead of immediately triggering the slot. Developers can then execute these queued slots at an appropriate time, akin to the &lt;strong&gt;evaluateAll&lt;/strong&gt; method in the &lt;strong&gt;BindingEvaluator&lt;/strong&gt;.&lt;/p&gt;
  455. &lt;h4&gt;&lt;em&gt;How It Works&lt;/em&gt;&lt;/h4&gt;
  456. &lt;p&gt;&lt;strong&gt;1. Create a ConnectionEvaluator:&lt;/strong&gt;&lt;/p&gt;
  457. &lt;pre class="brush: cpp; title: ; notranslate"&gt;
  458. auto evaluator = std::make_shared&lt;ConnectionEvaluator&gt;(); // Shared ownership for proper lifetime management
  459. &lt;/pre&gt;
  460. &lt;p&gt;&lt;strong&gt;2. Connect with Deferred Evaluation:&lt;/strong&gt;&lt;/p&gt;
  461. &lt;pre class="brush: cpp; title: ; notranslate"&gt;
  462. Signal&lt;int&gt; signal;
  463. int value = 0;
  464.  
  465. auto connection = signal.connectDeferred(evaluator, [&amp;value](int increment) {
  466. value += increment;
  467. });
  468. &lt;/pre&gt;
  469. &lt;div class="line number6 index5 alt1"&gt;&lt;/div&gt;
  470. &lt;p&gt;&lt;strong&gt;3. Queue Deferred Connections&lt;/strong&gt;&lt;/p&gt;
  471. &lt;p&gt;When the signal emits, connected slots aren&#x2019;t executed immediately but are queued:&lt;/p&gt;
  472. &lt;pre class="brush: cpp; title: ; notranslate"&gt;
  473. signal.emit(5);  // The slot is queued, not executed.
  474. &lt;/pre&gt;
  475. &lt;p&gt;&lt;strong&gt;4. Evaluate Deferred Connections&lt;/strong&gt;&lt;/p&gt;
  476. &lt;p&gt;Execute the queued connections at the desired time:&lt;/p&gt;
  477. &lt;pre class="brush: cpp; title: ; notranslate"&gt;
  478. evaluator.evaluateDeferredConnections();  // Executes the queued slot.
  479. &lt;/pre&gt;
  480. &lt;h4&gt;&lt;em&gt;Usage Example&lt;/em&gt;&lt;/h4&gt;
  481. &lt;p&gt;To illustrate how this enhanced signal/slot system works in a multithreaded scenario, let&#x2019;s have a look at a usage example. Consider a scenario where a worker thread emits signals, but we want the connected slots to be executed in an event loop on the GUI thread:&lt;/p&gt;
  482. &lt;pre class="brush: cpp; title: ; notranslate"&gt;
  483. Signal&lt;int&gt; workerSignal;
  484. int guiValue = 0;
  485. auto evaluator = std::make_shared&lt;ConnectionEvaluator&gt;();
  486.  
  487. // Connect a slot to the workerSignal with deferred evaluation
  488. workerSignal.connectDeferred(evaluator, [&amp;guiValue](int value) {
  489. // This slot will be executed later in the GUI thread's event loop
  490. guiValue += value;
  491. });
  492.  
  493. // ... Worker thread emits signals ...
  494.  
  495. // In the GUI thread's event loop or at the right time
  496. evaluator-&gt;evaluateDeferredConnections();
  497.  
  498. // The connected slot is now executed, and guiValue is updated
  499. &lt;/pre&gt;
  500. &lt;p&gt;In this example, the connectDeferred function allows us to queue the connection for deferred execution, and the ConnectionEvaluator determines when it should be invoked. This level of control enables more sophisticated and responsive applications.&lt;/p&gt;
  501. &lt;h2&gt;&lt;em&gt;Conclusion&lt;/em&gt;&lt;/h2&gt;
  502. &lt;p&gt;In simple terms, the ConnectionEvaluator is a valuable tool we&#x2019;ve added to KDBindings. It lets you decide when exactly your connections should &#x2018;wake up&#x2019; and do their jobs. This is especially helpful in complex applications where you want to make sure that certain tasks are performed at the right time and in the right order (preferably in multithreading applications). Think of it like having a remote control for your connections, allowing you to press &#x2018;play&#x2019; whenever you&#x2019;re ready.&lt;/p&gt;
  503. &lt;p&gt;It may also be worthwhile mentioning that we will be integrating this feature into the KDFoundation library and event loop in the &lt;a href="https://github.com/KDAB/KDUtils"&gt;KDUtils GitHub repo&lt;/a&gt;. Additionally, it&#x2019;s important to note that it could easily be integrated into any application or framework, regardless of whether it utilizes an event loop.&lt;/p&gt;
  504. &lt;div class="panel panel-info"&gt;
  505. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  506. &lt;div class="panel-body"&gt;
  507. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  508. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  509. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  510. &lt;/div&gt;
  511. &lt;/div&gt;
  512. &lt;p&gt;The post &lt;a href="https://www.kdab.com/introducing-the-connectionevaluator-in-kdbindings/"&gt;Introducing the ConnectionEvaluator in KDBindings&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  513.    </item>
  514.    <item>
  515.      <guid isPermaLink="false">https://www.kdab.com/?p=33542</guid>
  516.      <title>KDAB on Qt: Reducing Visual Studio Installations with Toolchains</title>
  517.      <pubDate>Thu, 07 Mar 2024 08:00:40 GMT</pubDate>
  518.      <link>https://www.kdab.com/reducing-visual-studio-installations-with-toolchains/</link>
  519.      <description>&lt;p&gt;If you work on C++ projects on Windows that need to be built with multiple Visual Studio C++ compiler versions, you need some way to manage the installations of all these build environments. Either you have multiple IDEs installed, or you know about build tools (&lt;a class="external-link" href="https://aka.ms/vs/17/release/vs_BuildTools.exe" rel="nofollow"&gt;https://aka.ms/vs/17/release/vs_BuildTools.exe&lt;/a&gt;) and maybe keep only the latest full VS IDE plus older Build Tools.&lt;/p&gt;
  520. &lt;p&gt;However, it turns out that you can have just the latest IDE but with multiple toolchains installed for older compiler targets. You won&#x2019;t even need the Build Tools.&lt;/p&gt;
  521. &lt;p&gt;To use these toolchains you need to install them in your chosen VS installation and then call &lt;code&gt;vcvarsall.bat&lt;/code&gt; with an appropriate parameter.&lt;/p&gt;
  522. &lt;p&gt;You can even have &lt;em&gt;no&lt;/em&gt; IDE installed if you don&#x2019;t need it but only the Build Tools with the required toolchains. That&#x2019;s useful when you use a different IDE like &lt;a href="https://www.jetbrains.com/clion/"&gt;JetBrains Clion&lt;/a&gt; or &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt;. Note, however, that to be license- compliant, you still need a valid Visual Studio subscription.&lt;/p&gt;
  523. &lt;h2&gt;Installing the toolchain&lt;/h2&gt;
  524. &lt;ol&gt;
  525. &lt;li&gt;Go to the Visual Studio Installer and click &#x201C;Modify&#x201D; on your main VS version (2022 in my case).&lt;/li&gt;
  526. &lt;li&gt;Go to &#x201C;Individual components&#x201D; and search for the appropriate toolchain. For example, to get the latest VS2019 C++ compiler in VS 2022 installer, you need to look at this:&lt;img alt="Screenshot of Visual Studio 2022 installer illustrating how to locate Visual Studio 2019 toolchain" class="alignnone wp-image-33544 size-large" height="614" src="https://www.kdab.com/wp-content/uploads/stories/vs_installer_2022_toolchain_2019-1024x614.png" width="1024"&gt;How do you know that 14.29 corresponds to VS 2019? Well, you have to consult this table: &lt;a class="external-link" href="https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering" rel="nofollow"&gt;https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering&lt;/a&gt; &#x2013; look at the &#x201C;runtime library version&#x201D; column as that&#x2019;s the C++ compiler version really.&lt;/li&gt;
  527. &lt;li&gt;Finish the installation of the desired components.&lt;/li&gt;
  528. &lt;/ol&gt;
  529. &lt;h2&gt;Setting up the environment from cmd.exe&lt;/h2&gt;
  530. &lt;p&gt;The only thing you need to do to start with a different toolchain is to pass an option to your &lt;code&gt;vcvarsall.bat&lt;/code&gt; invocation:&lt;/p&gt;
  531. &lt;pre&gt;
  532. &lt;code&gt;C:\Users\mikom&gt;"c:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat" -vcvars_ver=14.29
  533. &lt;/code&gt;
  534. &lt;/pre&gt;
  535. &lt;p&gt;With such a call, I get a shell where cl.exe indeed uses the VS2019 compiler variant:&lt;/p&gt;
  536. &lt;p&gt;&lt;img alt="Screenshot of windows command prompt showing the results of using the discussed technique. It shows that visual studio 2019 compiler, version 19.29 is set up from Visual Studio 2022 installation folder" class="alignnone wp-image-33545 size-large" height="589" src="https://www.kdab.com/wp-content/uploads/stories/vs_toolchain_cmd-1024x589.png" width="1024"&gt;&lt;/p&gt;
  537. &lt;p&gt;As you can see, I called &lt;code&gt;vcvarsall.bat&lt;/code&gt; from VS2022 yet I got VS2019 variant of the compiler For more info about &lt;code&gt;vcvarsall.bat&lt;/code&gt; see: &lt;a class="external-link" href="https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line" rel="nofollow"&gt;https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line&lt;/a&gt;&lt;span class="confluence-embedded-file-wrapper confluence-embedded-manual-size"&gt;.&lt;/span&gt;&lt;/p&gt;
  538. &lt;h2 id="id-20240201ReducingVSinstallationswithtoolchains-SettinguptheenvironmentforPowerShell"&gt;Setting up the environment for PowerShell&lt;/h2&gt;
  539. &lt;p&gt;If you do your compilation in Powershell, &lt;code&gt;vcvarsall.bat&lt;/code&gt; is not very helpful. It will spawn an underlying &lt;code&gt;cmd.exe&lt;/code&gt;, set the necessary env vars inside it, and close it without altering your PowerShell environment.&lt;/p&gt;
  540. &lt;p&gt;(You may try to do some hacks of printing the environment in the child &lt;code&gt;cmd.exe&lt;/code&gt; and adopting it to your Pwsh shell, but that&#x2019;s a hack).&lt;/p&gt;
  541. &lt;p&gt;For setting up a development environment from PowerShell, Microsoft introduced a PowerShell module that does just that.&lt;/p&gt;
  542. &lt;p&gt;To get it, you first have to load the module:&lt;/p&gt;
  543. &lt;pre&gt;
  544. &lt;code class="language-pwsh"&gt;Import-Module "C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
  545. &lt;/code&gt;
  546. &lt;/pre&gt;
  547. &lt;p&gt;And then call the &lt;code&gt;Enter-VsDevShell&lt;/code&gt; cmdlet with appropriate parameters:&lt;/p&gt;
  548. &lt;pre&gt;
  549. &lt;code class="language-pwsh"&gt;Enter-VsDevShell -VsInstallPath 'C:\Program Files\Microsoft Visual Studio\2022\Professional\' -DevCmdArguments "-vcvars_ver=14.29" -Arch amd64 -SkipAutomaticLocation
  550. &lt;/code&gt;
  551. &lt;/pre&gt;
  552. &lt;p&gt;This cmdlet internally passes arguments to &lt;code&gt;vcvarsall.bat&lt;/code&gt; so you specify the toolchain version as above.&lt;/p&gt;
  553. &lt;p&gt;With this invocation, you get your desired &lt;code&gt;cl.exe&lt;/code&gt; compiler:&lt;/p&gt;
  554. &lt;p&gt;&lt;img alt="Screenshot of windows powershell console showing the results of using the discussed technique. It shows that visual studio 2019 compiler, version 19.29 is set up from Visual Studio 2022 installation folder" class="alignnone wp-image-33546 size-large" height="351" src="https://www.kdab.com/wp-content/uploads/stories/vs_toolchain_pwsh-1024x351.png" width="1024"&gt;&lt;/p&gt;
  555. &lt;p&gt;For more info about Powershell DevShell module see: &lt;a class="external-link" href="https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell" rel="nofollow"&gt;https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell&lt;/a&gt;&lt;/p&gt;
  556. &lt;h2 id="id-20240201ReducingVSinstallationswithtoolchains-SettingupQtCreatorKitwithatoolchain"&gt;Setting up Qt Creator Kit with a toolchain&lt;/h2&gt;
  557. &lt;p&gt;Unfortunately, Qt Creator doesn&#x2019;t detect the toolchains in a single Visual Studio installation as multiple kits. You have to configure the compiler and the kit yourself:&lt;/p&gt;
  558. &lt;p&gt;&lt;span class="confluence-embedded-file-wrapper confluence-embedded-manual-size"&gt;&lt;img alt="Screenshot showing the Qt Creator kit setup illustrating how to configure custom Visual Studio compiler version through a toolchain" class="alignnone wp-image-33547 size-large" height="645" src="https://www.kdab.com/wp-content/uploads/stories/vs_toolchain_qtcreator-1024x645.png" width="1024"&gt;&lt;/span&gt;&lt;/p&gt;
  559. &lt;h2 id="id-20240201ReducingVSinstallationswithtoolchains-Iamascript,howdoIknowwhereisVisualStudioinstalled?"&gt;I am a script, how do I know where Visual Studio is installed?&lt;/h2&gt;
  560. &lt;p&gt;If you want to query the system for VS installation path programatically (to find either &lt;code&gt;vcvarsall.bat&lt;/code&gt; or the DevShell PowerShell module) you can use the &lt;code&gt;vswhere&lt;/code&gt; tool (&lt;a class="external-link" href="https://github.com/microsoft/vswhere" rel="nofollow"&gt;https://github.com/microsoft/vswhere&lt;/a&gt;).&lt;/p&gt;
  561. &lt;p&gt;It&#x2019;s a small-ish (0.5MB) self-contained &lt;code&gt;.exe&lt;/code&gt; so you can just drop it in your repository and don&#x2019;t care if it&#x2019;s in the system. You can also install it with &lt;a href="https://learn.microsoft.com/en-us/windows/package-manager/winget/"&gt;&lt;code&gt;winget&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
  562. &lt;pre&gt;
  563. &lt;code&gt;winget install vswhere
  564. &lt;/code&gt;
  565. &lt;/pre&gt;
  566. &lt;p&gt;It queries the well-known registry entries and does some other magic to find out what Visual Studio installations your machine has.&lt;/p&gt;
  567. &lt;p&gt;By default it looks for the latest version of Visual Studio available and returns easily parseable key:value pairs with various infos about the installation. Most notably, the installation path in &lt;code&gt;installationPath&lt;/code&gt;.&lt;/p&gt;
  568. &lt;p&gt;It also has various querying capabilities, like showing only the VS installation that have the C++ workload installed.&lt;/p&gt;
  569. &lt;p&gt;For example, to get the installation path of the newest Visual Studio with C++ workload, you call:&lt;/p&gt;
  570. &lt;pre&gt;
  571. &lt;code&gt;vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath&lt;/code&gt;
  572. &lt;/pre&gt;
  573. &lt;p&gt;&lt;img alt="Screenshot illustrating the output of calling vswhere to locate Visual Studio installation. Query: vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath results in the output of: C:\Program Files\Microsoft Visual Studio\2022\Professional" class="alignnone wp-image-33548 size-large" height="178" src="https://www.kdab.com/wp-content/uploads/stories/vswhere-1024x178.png" width="1024"&gt;&lt;/p&gt;
  574. &lt;h2 id="id-20240201ReducingVSinstallationswithtoolchains-Caveats"&gt;Caveats&lt;/h2&gt;
  575. &lt;p&gt;I haven&#x2019;t found an easy way to query &lt;code&gt;vcvarsall&lt;/code&gt; for something along the lines &#x201C;give me the latest available toolchain in a given VS product line (2019, 2022 etc.)&#x201D;. So if you call an explicit version (like &lt;code&gt;14.29&lt;/code&gt;) and a newer one appears, you will still be looking for the older one. However:&lt;/p&gt;
  576. &lt;ul&gt;
  577. &lt;li&gt;When &lt;code&gt;vcvarsall.bat&lt;/code&gt; is called without any toolchain parameter (&lt;code&gt;vcvars_ver&lt;/code&gt;), it defaults to itself so you may assume that it&#x2019;s the latest one in this installation folder.&lt;/li&gt;
  578. &lt;li&gt;Microsoft seems to stop bumping the relevant part of the version of the Visual Studio C++ compiler once the next version of VS is out. So for example it seems that &lt;code&gt;14.29&lt;/code&gt; will be a proper target for VS2019 C++ compiler until the end of time.&lt;/li&gt;
  579. &lt;/ul&gt;
  580. &lt;div class="panel panel-info"&gt;
  581. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  582. &lt;div class="panel-body"&gt;
  583. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  584. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  585. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  586. &lt;/div&gt;
  587. &lt;/div&gt;
  588. &lt;p&gt;The post &lt;a href="https://www.kdab.com/reducing-visual-studio-installations-with-toolchains/"&gt;Reducing Visual Studio Installations with Toolchains&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  589.    </item>
  590.    <item>
  591.      <guid isPermaLink="false">tag:www.pythonguis.com,2024-03-06:/faq/pyside6-drag-drop-widgets/</guid>
  592.      <title>Python GUIs - qt: Drag &amp; Drop Widgets with PySide6 &#x2014; Sort widgets visually with drag and drop in a container</title>
  593.      <pubDate>Wed, 06 Mar 2024 13:00:00 GMT</pubDate>
  594.      <link>https://www.pythonguis.com/faq/pyside6-drag-drop-widgets/</link>
  595.      <description>&lt;p&gt;I had an interesting question from a reader of my &lt;a href="https://www.pythonguis.com/pyside6-book/"&gt;PySide6 book&lt;/a&gt;, about how to handle dragging and dropping of widgets in a container showing the dragged widget as it is moved.&lt;/p&gt;
  596. &lt;blockquote&gt;
  597. &lt;p&gt;I'm interested in managing movement of a QWidget with mouse in a container. I've implemented the application with drag &amp; drop, exchanging the position of buttons, but I want to show the motion of &lt;code&gt;QPushButton&lt;/code&gt;, like what you see in Qt Designer. Dragging a widget should show the widget itself, not just the mouse pointer.&lt;/p&gt;
  598. &lt;/blockquote&gt;
  599. &lt;p&gt;First, we'll implement the simple case which drags widgets without showing anything extra. Then we can extend it to answer the question. By the end of this quick tutorial we'll have a generic drag drop implementation which looks like the following.&lt;/p&gt;
  600. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;
  601. &lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;
  602. &lt;ul&gt;
  603. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#drag-drop-widgets"&gt;Drag &amp; Drop Widgets&lt;/a&gt;&lt;/li&gt;
  604. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#visual-drag-drop"&gt;Visual Drag &amp; Drop&lt;/a&gt;&lt;/li&gt;
  605. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#generic-drag-drop-container"&gt;Generic Drag &amp; Drop Container&lt;/a&gt;&lt;/li&gt;
  606. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#adding-a-visual-drop-target"&gt;Adding a Visual Drop Target&lt;/a&gt;&lt;/li&gt;
  607. &lt;/ul&gt;
  608. &lt;/div&gt;
  609. &lt;h2 id="drag-drop-widgets"&gt;Drag &amp; Drop Widgets&lt;/h2&gt;
  610. &lt;p&gt;We'll start with a simple application which creates a window using &lt;code&gt;QWidget&lt;/code&gt; and places a series of &lt;code&gt;QPushButton&lt;/code&gt; widgets into it.&lt;/p&gt;
  611. &lt;p class="admonition admonition-tip"&gt;You can substitute &lt;code&gt;QPushButton&lt;/code&gt; for any other widget you like, e.g. &lt;code&gt;QLabel&lt;/code&gt;. Any widget can have drag behavior implemented on it, although some input widgets will not work well as we capture the mouse events for the drag.&lt;/p&gt;
  612. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  613. &lt;pre&gt;
  614. &lt;code class="python"&gt;from PySide6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  615.  
  616.  
  617. class Window(QWidget):
  618.    def __init__(self):
  619.        super().__init__()
  620.  
  621.        self.blayout = QHBoxLayout()
  622.        for l in ["A", "B", "C", "D"]:
  623.            btn = QPushButton(l)
  624.            self.blayout.addWidget(btn)
  625.  
  626.        self.setLayout(self.blayout)
  627.  
  628.  
  629. app = QApplication([])
  630. w = Window()
  631. w.show()
  632.  
  633. app.exec()
  634.  
  635. &lt;/code&gt;
  636. &lt;/pre&gt;&lt;/div&gt;
  637. &lt;p&gt;If you run this you should see something like this.&lt;/p&gt;
  638. &lt;p&gt;&lt;img alt="Widgets in a layout" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/windows-in-layout.png" width="421"&gt; &lt;em&gt;The series of &lt;code&gt;QPushButton widgets&lt;/code&gt; in a horizontal layout.&lt;/em&gt;&lt;/p&gt;
  639. &lt;p class="admonition admonition-note"&gt;Here we're creating a window, but the &lt;code&gt;Window&lt;/code&gt; widget is subclassed from &lt;code&gt;QWidget&lt;/code&gt;, meaning you can add this widget to any other layout. See later for an example of a generic object sorting widget.&lt;/p&gt;
  640. &lt;p&gt;&lt;code&gt;QPushButton&lt;/code&gt; objects aren't usually draggable, so to handle the mouse movements and initiate a drag we need to implement a subclass. We can add the following to the top of the file.&lt;/p&gt;
  641. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  642. &lt;pre&gt;
  643. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt
  644. from PySide6.QtGui import QDrag
  645. from PySide6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  646.  
  647.  
  648. class DragButton(QPushButton):
  649.    def mouseMoveEvent(self, e):
  650.        if e.buttons() == Qt.MouseButton.LeftButton:
  651.            drag = QDrag(self)
  652.            mime = QMimeData()
  653.            drag.setMimeData(mime)
  654.            drag.exec(Qt.DropAction.MoveAction)
  655.  
  656. &lt;/code&gt;
  657. &lt;/pre&gt;&lt;/div&gt;
  658. &lt;p&gt;We implement a &lt;code&gt;mouseMoveEvent&lt;/code&gt; which accepts the single &lt;code&gt;e&lt;/code&gt; parameter of the event. We check to see if the &lt;em&gt;left&lt;/em&gt; mouse button is pressed on this event -- as it would be when dragging -- and then initiate a drag. To start a drag, we create a &lt;code&gt;QDrag&lt;/code&gt; object, passing in &lt;code&gt;self&lt;/code&gt; to give us access later to the widget that was dragged. We also &lt;em&gt;must&lt;/em&gt; pass in mime data. This is used for including information about what is dragged, particularly for passing data between applications. However, as here, it is fine to leave this empty.&lt;/p&gt;
  659. &lt;p&gt;Finally, we initiate a drag by calling &lt;code&gt;drag.exec_(Qt.MoveAction)&lt;/code&gt;. As with dialogs &lt;code&gt;exec_()&lt;/code&gt; starts a new event loop, blocking the main loop until the drag is complete. The parameter &lt;code&gt;Qt.MoveAction&lt;/code&gt; tells the drag handler what type of operation is happening, so it can show the appropriate icon tip to the user.&lt;/p&gt;
  660. &lt;p&gt;You can update the main window code to use our new &lt;code&gt;DragButton&lt;/code&gt; class as follows.&lt;/p&gt;
  661. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  662. &lt;pre&gt;
  663. &lt;code class="python"&gt;class Window(QWidget):
  664.    def __init__(self):
  665.        super().__init__()
  666.        self.setAcceptDrops(True)
  667.  
  668.        self.blayout = QHBoxLayout()
  669.        for l in ["A", "B", "C", "D"]:
  670.            btn = DragButton(l)
  671.            self.blayout.addWidget(btn)
  672.  
  673.        self.setLayout(self.blayout)
  674.  
  675.    def dragEnterEvent(self, e):
  676.        e.accept()
  677. &lt;/code&gt;
  678. &lt;/pre&gt;&lt;/div&gt;
  679. &lt;p&gt;If you run the code now, you &lt;em&gt;can&lt;/em&gt; drag the buttons, but you'll notice the drag is forbidden.&lt;/p&gt;
  680. &lt;p&gt;&lt;img alt="Drag forbidden" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-forbidden.png" width="421"&gt; &lt;em&gt;Dragging of the widget starts but is forbidden.&lt;/em&gt;&lt;/p&gt;
  681. &lt;p&gt;What's happening? The mouse movement is being detected by our &lt;code&gt;DragButton&lt;/code&gt; object and the drag started, but the main window does not accept drag &amp; drop.&lt;/p&gt;
  682. &lt;p&gt;To fix this we need to enable drops on the window and implement &lt;code&gt;dragEnterEvent&lt;/code&gt; to actually accept them.&lt;/p&gt;
  683. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  684. &lt;pre&gt;
  685. &lt;code class="python"&gt;class Window(QWidget):
  686.    def __init__(self):
  687.        super().__init__()
  688.        self.setAcceptDrops(True)
  689.  
  690.        self.blayout = QHBoxLayout()
  691.        for l in ["A", "B", "C", "D"]:
  692.            btn = DragButton(l)
  693.            self.blayout.addWidget(btn)
  694.  
  695.        self.setLayout(self.blayout)
  696.  
  697.    def dragEnterEvent(self, e):
  698.        e.accept()
  699.  
  700. &lt;/code&gt;
  701. &lt;/pre&gt;&lt;/div&gt;
  702. &lt;p&gt;If you run this now, you'll see the drag is now accepted and you see the move icon. This indicates that the drag has started and been accepted by the window we're dragging onto. The icon shown is determined by the action we pass when calling &lt;code&gt;drag.exec_()&lt;/code&gt;.&lt;/p&gt;
  703. &lt;p&gt;&lt;img alt="Drag accepted" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-accepted.png" width="421"&gt; &lt;em&gt;Dragging of the widget starts and is accepted, showing a move icon.&lt;/em&gt;&lt;/p&gt;
  704. &lt;p&gt;Releasing the mouse button during a drag drop operation triggers a &lt;code&gt;dropEvent&lt;/code&gt; on the widget you're currently hovering the mouse over (if it is configured to accept drops). In our case that's the window. To handle the move we need to implement the code to do this in our &lt;code&gt;dropEvent&lt;/code&gt; method.&lt;/p&gt;
  705. &lt;p&gt;The drop event contains the position the mouse was at when the button was released &amp; the drop triggered. We can use this to determine where to move the widget to.&lt;/p&gt;
  706. &lt;p&gt;To determine where to place the widget, we iterate over all the widgets in the layout, &lt;em&gt;until&lt;/em&gt; we find one who's &lt;code&gt;x&lt;/code&gt; position is &lt;em&gt;greater&lt;/em&gt; than that of the mouse pointer. If so then when insert the widget directly to the left of this widget and exit the loop.&lt;/p&gt;
  707. &lt;p&gt;If we get to the end of the loop without finding a match, we must be dropping past the end of the existing items, so we increment &lt;code&gt;n&lt;/code&gt; one further (in the &lt;code&gt;else:&lt;/code&gt; block below).&lt;/p&gt;
  708. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  709. &lt;pre&gt;
  710. &lt;code class="python"&gt;    def dropEvent(self, e):
  711.        pos = e.position()
  712.        widget = e.source()
  713.        self.blayout.removeWidget(widget)
  714.  
  715.        for n in range(self.blayout.count()):
  716.            # Get the widget at each index in turn.
  717.            w = self.blayout.itemAt(n).widget()
  718.            if pos.x() &lt; w.x():
  719.                # We didn't drag past this widget.
  720.                # insert to the left of it.
  721.                break
  722.        else:
  723.            # We aren't on the left hand side of any widget,
  724.            # so we're at the end. Increment 1 to insert after.
  725.            n += 1
  726.  
  727.        self.blayout.insertWidget(n, widget)
  728.  
  729.        e.accept()
  730. &lt;/code&gt;
  731. &lt;/pre&gt;&lt;/div&gt;
  732. &lt;p&gt;The effect of this is that if you drag 1 pixel past the start of another widget the drop will happen to the right of it, which is a bit confusing. To fix this we can adjust the cut off to use the middle of the widget using &lt;code&gt;if pos.x() &lt; w.x() + w.size().width() // 2:&lt;/code&gt; -- that is x + half of the width.&lt;/p&gt;
  733. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  734. &lt;pre&gt;
  735. &lt;code class="python"&gt;    def dropEvent(self, e):
  736.        pos = e.position()
  737.        widget = e.source()
  738.        self.blayout.removeWidget(widget)
  739.  
  740.        for n in range(self.blayout.count()):
  741.            # Get the widget at each index in turn.
  742.            w = self.blayout.itemAt(n).widget()
  743.            if pos.x() &lt; w.x() + w.size().width() // 2:
  744.                # We didn't drag past this widget.
  745.                # insert to the left of it.
  746.                break
  747.        else:
  748.            # We aren't on the left hand side of any widget,
  749.            # so we're at the end. Increment 1 to insert after.
  750.            n += 1
  751.  
  752.        self.blayout.insertWidget(n, widget)
  753.  
  754.        e.accept()
  755.  
  756. &lt;/code&gt;
  757. &lt;/pre&gt;&lt;/div&gt;
  758. &lt;p&gt;The complete working drag-drop code is shown below.&lt;/p&gt;
  759. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  760. &lt;pre&gt;
  761. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt
  762. from PySide6.QtGui import QDrag
  763. from PySide6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  764.  
  765.  
  766. class DragButton(QPushButton):
  767.    def mouseMoveEvent(self, e):
  768.        if e.buttons() == Qt.MouseButton.LeftButton:
  769.            drag = QDrag(self)
  770.            mime = QMimeData()
  771.            drag.setMimeData(mime)
  772.            drag.exec(Qt.DropAction.MoveAction)
  773.  
  774.  
  775. class Window(QWidget):
  776.    def __init__(self):
  777.        super().__init__()
  778.        self.setAcceptDrops(True)
  779.  
  780.        self.blayout = QHBoxLayout()
  781.        for l in ["A", "B", "C", "D"]:
  782.            btn = DragButton(l)
  783.            self.blayout.addWidget(btn)
  784.  
  785.        self.setLayout(self.blayout)
  786.  
  787.    def dragEnterEvent(self, e):
  788.        e.accept()
  789.  
  790.    def dropEvent(self, e):
  791.        pos = e.position()
  792.        widget = e.source()
  793.        self.blayout.removeWidget(widget)
  794.  
  795.        for n in range(self.blayout.count()):
  796.            # Get the widget at each index in turn.
  797.            w = self.blayout.itemAt(n).widget()
  798.            if pos.x() &lt; w.x() + w.size().width() // 2:
  799.                # We didn't drag past this widget.
  800.                # insert to the left of it.
  801.                break
  802.        else:
  803.            # We aren't on the left hand side of any widget,
  804.            # so we're at the end. Increment 1 to insert after.
  805.            n += 1
  806.  
  807.        self.blayout.insertWidget(n, widget)
  808.  
  809.        e.accept()
  810.  
  811.  
  812. app = QApplication([])
  813. w = Window()
  814. w.show()
  815.  
  816. app.exec()
  817.  
  818. &lt;/code&gt;
  819. &lt;/pre&gt;&lt;/div&gt;
  820. &lt;h2 id="visual-drag-drop"&gt;Visual Drag &amp; Drop&lt;/h2&gt;
  821. &lt;p&gt;We now have a working drag &amp; drop implementation. Next we'll move onto improving the UX by showing the drag visually. First we'll add support for showing the button being dragged next to the mouse point as it is dragged. That way the user knows exactly what it is they are dragging.&lt;/p&gt;
  822. &lt;p&gt;Qt's &lt;code&gt;QDrag&lt;/code&gt; handler natively provides a mechanism for showing dragged objects which we can use. We can update our &lt;code&gt;DragButton&lt;/code&gt; class to pass a &lt;em&gt;pixmap&lt;/em&gt; image to &lt;code&gt;QDrag&lt;/code&gt; and this will be displayed under the mouse pointer as the drag occurs. To show the widget, we just need to get a &lt;code&gt;QPixmap&lt;/code&gt; of the widget we're dragging.&lt;/p&gt;
  823. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  824. &lt;pre&gt;
  825. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt
  826. from PySide6.QtGui import QDrag
  827. from PySide6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  828.  
  829.  
  830. class DragButton(QPushButton):
  831.    def mouseMoveEvent(self, e):
  832.        if e.buttons() == Qt.MouseButton.LeftButton:
  833.            drag = QDrag(self)
  834.            mime = QMimeData()
  835.            drag.setMimeData(mime)
  836.            drag.exec(Qt.DropAction.MoveAction)
  837.  
  838. &lt;/code&gt;
  839. &lt;/pre&gt;&lt;/div&gt;
  840. &lt;p&gt;To create the pixmap we create a &lt;code&gt;QPixmap&lt;/code&gt; object passing in the size of the widget this event is fired on with &lt;code&gt;self.size()&lt;/code&gt;. This creates an empty &lt;em&gt;pixmap&lt;/em&gt; which we can then pass into &lt;code&gt;self.render&lt;/code&gt; to &lt;em&gt;render&lt;/em&gt; -- or draw -- the current widget onto it. That's it. Then we set the resulting pixmap on the &lt;code&gt;drag&lt;/code&gt; object.&lt;/p&gt;
  841. &lt;p&gt;If you run the code with this modification you'll see something like the following --&lt;/p&gt;
  842. &lt;p&gt;&lt;img alt="Drag visual" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-visual.png" width="421"&gt; &lt;em&gt;Dragging of the widget showing the dragged widget.&lt;/em&gt;&lt;/p&gt;
  843. &lt;h2 id="generic-drag-drop-container"&gt;Generic Drag &amp; Drop Container&lt;/h2&gt;
  844. &lt;p&gt;We now have a working drag and drop behavior implemented on our window. We can take this a step further and implement a &lt;em&gt;generic&lt;/em&gt; drag drop widget which allows us to sort arbitrary objects. In the code below we've created a new widget &lt;code&gt;DragWidget&lt;/code&gt; which can be added to any window.&lt;/p&gt;
  845. &lt;p&gt;You can add &lt;em&gt;items&lt;/em&gt; -- instances of &lt;code&gt;DragItem&lt;/code&gt; -- which you want to be sorted, as well as setting data on them. When items are re-ordered the new order is emitted as a signal &lt;code&gt;orderChanged&lt;/code&gt;.&lt;/p&gt;
  846. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  847. &lt;pre&gt;
  848. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt, Signal
  849. from PySide6.QtGui import QDrag, QPixmap
  850. from PySide6.QtWidgets import (
  851.    QApplication,
  852.    QHBoxLayout,
  853.    QLabel,
  854.    QMainWindow,
  855.    QVBoxLayout,
  856.    QWidget,
  857. )
  858.  
  859.  
  860. class DragItem(QLabel):
  861.    def __init__(self, *args, **kwargs):
  862.        super().__init__(*args, **kwargs)
  863.        self.setContentsMargins(25, 5, 25, 5)
  864.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  865.        self.setStyleSheet("border: 1px solid black;")
  866.        # Store data separately from display label, but use label for default.
  867.        self.data = self.text()
  868.  
  869.    def set_data(self, data):
  870.        self.data = data
  871.  
  872.    def mouseMoveEvent(self, e):
  873.        if e.buttons() == Qt.MouseButton.LeftButton:
  874.            drag = QDrag(self)
  875.            mime = QMimeData()
  876.            drag.setMimeData(mime)
  877.  
  878.            pixmap = QPixmap(self.size())
  879.            self.render(pixmap)
  880.            drag.setPixmap(pixmap)
  881.  
  882.            drag.exec(Qt.DropAction.MoveAction)
  883.  
  884.  
  885. class DragWidget(QWidget):
  886.    """
  887.    Generic list sorting handler.
  888.    """
  889.  
  890.    orderChanged = Signal(list)
  891.  
  892.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  893.        super().__init__()
  894.        self.setAcceptDrops(True)
  895.  
  896.        # Store the orientation for drag checks later.
  897.        self.orientation = orientation
  898.  
  899.        if self.orientation == Qt.Orientation.Vertical:
  900.            self.blayout = QVBoxLayout()
  901.        else:
  902.            self.blayout = QHBoxLayout()
  903.  
  904.        self.setLayout(self.blayout)
  905.  
  906.    def dragEnterEvent(self, e):
  907.        e.accept()
  908.  
  909.    def dropEvent(self, e):
  910.        pos = e.position()
  911.        widget = e.source()
  912.        self.blayout.removeWidget(widget)
  913.  
  914.        for n in range(self.blayout.count()):
  915.            # Get the widget at each index in turn.
  916.            w = self.blayout.itemAt(n).widget()
  917.            if self.orientation == Qt.Orientation.Vertical:
  918.                # Drag drop vertically.
  919.                drop_here = pos.y() &lt; w.y() + w.size().height() // 2
  920.            else:
  921.                # Drag drop horizontally.
  922.                drop_here = pos.x() &lt; w.x() + w.size().width() // 2
  923.  
  924.            if drop_here:
  925.                break
  926.  
  927.        else:
  928.            # We aren't on the left hand/upper side of any widget,
  929.            # so we're at the end. Increment 1 to insert after.
  930.            n += 1
  931.  
  932.        self.blayout.insertWidget(n, widget)
  933.        self.orderChanged.emit(self.get_item_data())
  934.  
  935.        e.accept()
  936.  
  937.    def add_item(self, item):
  938.        self.blayout.addWidget(item)
  939.  
  940.    def get_item_data(self):
  941.        data = []
  942.        for n in range(self.blayout.count()):
  943.            # Get the widget at each index in turn.
  944.            w = self.blayout.itemAt(n).widget()
  945.            data.append(w.data)
  946.        return data
  947.  
  948.  
  949. class MainWindow(QMainWindow):
  950.    def __init__(self):
  951.        super().__init__()
  952.        self.drag = DragWidget(orientation=Qt.Orientation.Vertical)
  953.        for n, l in enumerate(["A", "B", "C", "D"]):
  954.            item = DragItem(l)
  955.            item.set_data(n)  # Store the data.
  956.            self.drag.add_item(item)
  957.  
  958.        # Print out the changed order.
  959.        self.drag.orderChanged.connect(print)
  960.  
  961.        container = QWidget()
  962.        layout = QVBoxLayout()
  963.        layout.addStretch(1)
  964.        layout.addWidget(self.drag)
  965.        layout.addStretch(1)
  966.        container.setLayout(layout)
  967.  
  968.        self.setCentralWidget(container)
  969.  
  970.  
  971. app = QApplication([])
  972. w = MainWindow()
  973. w.show()
  974.  
  975. app.exec()
  976.  
  977. &lt;/code&gt;
  978. &lt;/pre&gt;&lt;/div&gt;
  979. &lt;p&gt;&lt;img alt="Generic drag drop horizontal" height="139" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-generic-horizontal.png" width="306"&gt; &lt;em&gt;Generic drag-drop sorting in horizontal orientation.&lt;/em&gt;&lt;/p&gt;
  980. &lt;p&gt;You'll notice that when creating the item, you can set the label by passing it in as a parameter (just like for a normal &lt;code&gt;QLabel&lt;/code&gt; which we've subclassed from). But you can also set a data value, which is the internal value of this item -- this is what will be emitted when the order changes, or if you call &lt;code&gt;get_item_data&lt;/code&gt; yourself. This separates the visual representation from what is actually being sorted, meaning you can use this to sort &lt;em&gt;anything&lt;/em&gt; not just strings.&lt;/p&gt;
  981. &lt;p&gt;In the example above we're passing in the enumerated index as the data, so dragging will output (via the &lt;code&gt;print&lt;/code&gt; connected to &lt;code&gt;orderChanged&lt;/code&gt;) something like:&lt;/p&gt;
  982. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  983. &lt;pre&gt;
  984. &lt;code class="python"&gt;[1, 0, 2, 3]
  985. [1, 2, 0, 3]
  986. [1, 0, 2, 3]
  987. [1, 2, 0, 3]
  988. &lt;/code&gt;
  989. &lt;/pre&gt;&lt;/div&gt;
  990. &lt;p&gt;If you remove the &lt;code&gt;item.set_data(n)&lt;/code&gt; you'll see the labels emitted on changes.&lt;/p&gt;
  991. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  992. &lt;pre&gt;
  993. &lt;code class="python"&gt;['B', 'A', 'C', 'D']
  994. ['B', 'C', 'A', 'D']
  995. &lt;/code&gt;
  996. &lt;/pre&gt;&lt;/div&gt;
  997. &lt;p&gt;We've also implemented &lt;em&gt;orientation&lt;/em&gt; onto the &lt;code&gt;DragWidget&lt;/code&gt; using the Qt built in flags &lt;code&gt;Qt.Orientation.Vertical&lt;/code&gt; or &lt;code&gt;Qt.Orientation.Horizontal&lt;/code&gt;. This setting this allows you sort items either vertically or horizontally -- the calculations are handled for both directions.&lt;/p&gt;
  998. &lt;p&gt;&lt;img alt="Generic drag drop vertical" height="216" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-generic-vertical.png" width="202"&gt; &lt;em&gt;Generic drag-drop sorting in vertical orientation.&lt;/em&gt;&lt;/p&gt;
  999. &lt;h2 id="adding-a-visual-drop-target"&gt;Adding a Visual Drop Target&lt;/h2&gt;
  1000. &lt;p&gt;If you experiment with the drag-drop tool above you'll notice that it doesn't feel completely intuitive. When dragging you don't know where an item will be inserted until you drop it. If it ends up in the wrong place, you'll then need to pick it up and re-drop it again, using &lt;em&gt;guesswork&lt;/em&gt; to get it right.&lt;/p&gt;
  1001. &lt;p&gt;With a bit of practice you can get the hang of it, but it would be nicer to make the behavior immediately obvious for users. Many drag-drop interfaces solve this problem by showing a preview of where the item will be dropped while dragging -- either by showing the item in the place where it will be dropped, or showing some kind of placeholder.&lt;/p&gt;
  1002. &lt;p&gt;In this final section we'll implement this type of drag and drop preview indicator.&lt;/p&gt;
  1003. &lt;p&gt;The first step is to define our target indicator. This is just another label, which in our example is empty, with custom styles applied to make it have a solid "shadow" like background. This makes it obviously different to the items in the list, so it stands out as something distinct.&lt;/p&gt;
  1004. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1005. &lt;pre&gt;
  1006. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt, Signal
  1007. from PySide6.QtGui import QDrag, QPixmap
  1008. from PySide6.QtWidgets import (
  1009.    QApplication,
  1010.    QHBoxLayout,
  1011.    QLabel,
  1012.    QMainWindow,
  1013.    QVBoxLayout,
  1014.    QWidget,
  1015. )
  1016.  
  1017.  
  1018. class DragTargetIndicator(QLabel):
  1019.    def __init__(self, parent=None):
  1020.        super().__init__(parent)
  1021.        self.setContentsMargins(25, 5, 25, 5)
  1022.        self.setStyleSheet(
  1023.            "QLabel { background-color: #ccc; border: 1px solid black; }"
  1024.        )
  1025.  
  1026.  
  1027. &lt;/code&gt;
  1028. &lt;/pre&gt;&lt;/div&gt;
  1029. &lt;p class="admonition admonition-tip"&gt;We've copied the contents margins from the items in the list. If you change your list items, remember to also update the indicator dimensions to match.&lt;/p&gt;
  1030. &lt;p&gt;The drag item is unchanged, but we need to implement some additional behavior on our &lt;code&gt;DragWidget&lt;/code&gt; to add the target, control showing and moving it.&lt;/p&gt;
  1031. &lt;p&gt;First we'll add the drag target indicator to the layout on our &lt;code&gt;DragWidget&lt;/code&gt;. This is hidden to begin with, but will be shown during the drag.&lt;/p&gt;
  1032. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1033. &lt;pre&gt;
  1034. &lt;code class="python"&gt;class DragWidget(QWidget):
  1035.    """
  1036.    Generic list sorting handler.
  1037.    """
  1038.  
  1039.    orderChanged = Signal(list)
  1040.  
  1041.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  1042.        super().__init__()
  1043.        self.setAcceptDrops(True)
  1044.  
  1045.        # Store the orientation for drag checks later.
  1046.        self.orientation = orientation
  1047.  
  1048.        if self.orientation == Qt.Orientation.Vertical:
  1049.            self.blayout = QVBoxLayout()
  1050.        else:
  1051.            self.blayout = QHBoxLayout()
  1052.  
  1053.        # Add the drag target indicator. This is invisible by default,
  1054.        # we show it and move it around while the drag is active.
  1055.        self._drag_target_indicator = DragTargetIndicator()
  1056.        self.blayout.addWidget(self._drag_target_indicator)
  1057.        self._drag_target_indicator.hide()
  1058.  
  1059.        self.setLayout(self.blayout)
  1060. &lt;/code&gt;
  1061. &lt;/pre&gt;&lt;/div&gt;
  1062. &lt;p&gt;Next we modify the &lt;code&gt;DragWidget.dragMoveEvent&lt;/code&gt; to show the drag target indicator. We show it by &lt;em&gt;inserting&lt;/em&gt; it into the layout and then calling &lt;code&gt;.show&lt;/code&gt; -- inserting a widget which is already in a layout will move it. We also hide the original item which is being dragged.&lt;/p&gt;
  1063. &lt;p&gt;In the earlier examples we determined the position on drop by removing the widget being dragged, and then iterating over what is left. Because we now need to calculate the drop location before the drop, we take a different approach.&lt;/p&gt;
  1064. &lt;p class="admonition admonition-tip"&gt;If we wanted to do it the same way, we'd need to remove the item on drag start, hold onto it and implement re-inserting at it's old position on drag fail. That's a lot of work.&lt;/p&gt;
  1065. &lt;p&gt;Instead, the dragged item is left in place and hidden during move.&lt;/p&gt;
  1066. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1067. &lt;pre&gt;
  1068. &lt;code class="python"&gt;    def dragMoveEvent(self, e):
  1069.        # Find the correct location of the drop target, so we can move it there.
  1070.        index = self._find_drop_location(e)
  1071.        if index is not None:
  1072.            # Inserting moves the item if its alreaady in the layout.
  1073.            self.blayout.insertWidget(index, self._drag_target_indicator)
  1074.            # Hide the item being dragged.
  1075.            e.source().hide()
  1076.            # Show the target.
  1077.            self._drag_target_indicator.show()
  1078.        e.accept()
  1079.  
  1080. &lt;/code&gt;
  1081. &lt;/pre&gt;&lt;/div&gt;
  1082. &lt;p&gt;The method &lt;code&gt;self._find_drop_location&lt;/code&gt; finds the index where the drag target will be shown (or the item dropped when the mouse released). We'll implement that next.&lt;/p&gt;
  1083. &lt;p&gt;The calculation of the drop location follows the same pattern as before. We iterate over the items in the layout and calculate whether our mouse drop location is to the left of each widget. If it isn't to the left of any widget, we drop on the far right.&lt;/p&gt;
  1084. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1085. &lt;pre&gt;
  1086. &lt;code class="python"&gt;    def _find_drop_location(self, e):
  1087.        pos = e.position()
  1088.        spacing = self.blayout.spacing() / 2
  1089.  
  1090.        for n in range(self.blayout.count()):
  1091.            # Get the widget at each index in turn.
  1092.            w = self.blayout.itemAt(n).widget()
  1093.  
  1094.            if self.orientation == Qt.Orientation.Vertical:
  1095.                # Drag drop vertically.
  1096.                drop_here = (
  1097.                    pos.y() &gt;= w.y() - spacing
  1098.                    and pos.y() &lt;= w.y() + w.size().height() + spacing
  1099.                )
  1100.            else:
  1101.                # Drag drop horizontally.
  1102.                drop_here = (
  1103.                    pos.x() &gt;= w.x() - spacing
  1104.                    and pos.x() &lt;= w.x() + w.size().width() + spacing
  1105.                )
  1106.  
  1107.            if drop_here:
  1108.                # Drop over this target.
  1109.                break
  1110.  
  1111.        return n
  1112. &lt;/code&gt;
  1113. &lt;/pre&gt;&lt;/div&gt;
  1114. &lt;p&gt;The drop location &lt;code&gt;n&lt;/code&gt; is returned for use in the &lt;code&gt;dragMoveEvent&lt;/code&gt; to place the drop target indicator.&lt;/p&gt;
  1115. &lt;p&gt;Next wee need to update the &lt;code&gt;get_item_data&lt;/code&gt; handler to ignore the drop target indicator. To do this we check &lt;code&gt;w&lt;/code&gt; against &lt;code&gt;self._drag_target_indicator&lt;/code&gt; and skip if it is the same. With this change the method will work as expected.&lt;/p&gt;
  1116. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1117. &lt;pre&gt;
  1118. &lt;code class="python"&gt;    def get_item_data(self):
  1119.        data = []
  1120.        for n in range(self.blayout.count()):
  1121.            # Get the widget at each index in turn.
  1122.            w = self.blayout.itemAt(n).widget()
  1123.            if w != self._drag_target_indicator:
  1124.                # The target indicator has no data.
  1125.                data.append(w.data)
  1126.        return data
  1127.  
  1128. &lt;/code&gt;
  1129. &lt;/pre&gt;&lt;/div&gt;
  1130. &lt;p&gt;If you run the code a this point the drag behavior will work as expected. But if you drag the widget outside of the window and drop you'll notice a problem: the target indicator will stay in place, but dropping the item won't drop the item in that position (the drop will be cancelled).&lt;/p&gt;
  1131. &lt;p&gt;To fix that we need to implement a &lt;code&gt;dragLeaveEvent&lt;/code&gt; which hides the indicator.&lt;/p&gt;
  1132. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1133. &lt;pre&gt;
  1134. &lt;code class="python"&gt;    def dragLeaveEvent(self, e):
  1135.        self._drag_target_indicator.hide()
  1136.        e.accept()
  1137. &lt;/code&gt;
  1138. &lt;/pre&gt;&lt;/div&gt;
  1139. &lt;p&gt;With those changes, the drag-drop behavior should be working as intended. The complete code is shown below.&lt;/p&gt;
  1140. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1141. &lt;pre&gt;
  1142. &lt;code class="python"&gt;from PySide6.QtCore import QMimeData, Qt, Signal
  1143. from PySide6.QtGui import QDrag, QPixmap
  1144. from PySide6.QtWidgets import (
  1145.    QApplication,
  1146.    QHBoxLayout,
  1147.    QLabel,
  1148.    QMainWindow,
  1149.    QVBoxLayout,
  1150.    QWidget,
  1151. )
  1152.  
  1153.  
  1154. class DragTargetIndicator(QLabel):
  1155.    def __init__(self, parent=None):
  1156.        super().__init__(parent)
  1157.        self.setContentsMargins(25, 5, 25, 5)
  1158.        self.setStyleSheet(
  1159.            "QLabel { background-color: #ccc; border: 1px solid black; }"
  1160.        )
  1161.  
  1162.  
  1163. class DragItem(QLabel):
  1164.    def __init__(self, *args, **kwargs):
  1165.        super().__init__(*args, **kwargs)
  1166.        self.setContentsMargins(25, 5, 25, 5)
  1167.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  1168.        self.setStyleSheet("border: 1px solid black;")
  1169.        # Store data separately from display label, but use label for default.
  1170.        self.data = self.text()
  1171.  
  1172.    def set_data(self, data):
  1173.        self.data = data
  1174.  
  1175.    def mouseMoveEvent(self, e):
  1176.        if e.buttons() == Qt.MouseButton.LeftButton:
  1177.            drag = QDrag(self)
  1178.            mime = QMimeData()
  1179.            drag.setMimeData(mime)
  1180.  
  1181.            pixmap = QPixmap(self.size())
  1182.            self.render(pixmap)
  1183.            drag.setPixmap(pixmap)
  1184.  
  1185.            drag.exec(Qt.DropAction.MoveAction)
  1186.            self.show() # Show this widget again, if it's dropped outside.
  1187.  
  1188.  
  1189. class DragWidget(QWidget):
  1190.    """
  1191.    Generic list sorting handler.
  1192.    """
  1193.  
  1194.    orderChanged = Signal(list)
  1195.  
  1196.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  1197.        super().__init__()
  1198.        self.setAcceptDrops(True)
  1199.  
  1200.        # Store the orientation for drag checks later.
  1201.        self.orientation = orientation
  1202.  
  1203.        if self.orientation == Qt.Orientation.Vertical:
  1204.            self.blayout = QVBoxLayout()
  1205.        else:
  1206.            self.blayout = QHBoxLayout()
  1207.  
  1208.        # Add the drag target indicator. This is invisible by default,
  1209.        # we show it and move it around while the drag is active.
  1210.        self._drag_target_indicator = DragTargetIndicator()
  1211.        self.blayout.addWidget(self._drag_target_indicator)
  1212.        self._drag_target_indicator.hide()
  1213.  
  1214.        self.setLayout(self.blayout)
  1215.  
  1216.    def dragEnterEvent(self, e):
  1217.        e.accept()
  1218.  
  1219.    def dragLeaveEvent(self, e):
  1220.        self._drag_target_indicator.hide()
  1221.        e.accept()
  1222.  
  1223.    def dragMoveEvent(self, e):
  1224.        # Find the correct location of the drop target, so we can move it there.
  1225.        index = self._find_drop_location(e)
  1226.        if index is not None:
  1227.            # Inserting moves the item if its alreaady in the layout.
  1228.            self.blayout.insertWidget(index, self._drag_target_indicator)
  1229.            # Hide the item being dragged.
  1230.            e.source().hide()
  1231.            # Show the target.
  1232.            self._drag_target_indicator.show()
  1233.        e.accept()
  1234.  
  1235.    def dropEvent(self, e):
  1236.        widget = e.source()
  1237.        # Use drop target location for destination, then remove it.
  1238.        self._drag_target_indicator.hide()
  1239.        index = self.blayout.indexOf(self._drag_target_indicator)
  1240.        if index is not None:
  1241.            self.blayout.insertWidget(index, widget)
  1242.            self.orderChanged.emit(self.get_item_data())
  1243.            widget.show()
  1244.            self.blayout.activate()
  1245.        e.accept()
  1246.  
  1247.    def _find_drop_location(self, e):
  1248.        pos = e.position()
  1249.        spacing = self.blayout.spacing() / 2
  1250.  
  1251.        for n in range(self.blayout.count()):
  1252.            # Get the widget at each index in turn.
  1253.            w = self.blayout.itemAt(n).widget()
  1254.  
  1255.            if self.orientation == Qt.Orientation.Vertical:
  1256.                # Drag drop vertically.
  1257.                drop_here = (
  1258.                    pos.y() &gt;= w.y() - spacing
  1259.                    and pos.y() &lt;= w.y() + w.size().height() + spacing
  1260.                )
  1261.            else:
  1262.                # Drag drop horizontally.
  1263.                drop_here = (
  1264.                    pos.x() &gt;= w.x() - spacing
  1265.                    and pos.x() &lt;= w.x() + w.size().width() + spacing
  1266.                )
  1267.  
  1268.            if drop_here:
  1269.                # Drop over this target.
  1270.                break
  1271.  
  1272.        return n
  1273.  
  1274.    def add_item(self, item):
  1275.        self.blayout.addWidget(item)
  1276.  
  1277.    def get_item_data(self):
  1278.        data = []
  1279.        for n in range(self.blayout.count()):
  1280.            # Get the widget at each index in turn.
  1281.            w = self.blayout.itemAt(n).widget()
  1282.            if w != self._drag_target_indicator:
  1283.                # The target indicator has no data.
  1284.                data.append(w.data)
  1285.        return data
  1286.  
  1287.  
  1288. class MainWindow(QMainWindow):
  1289.    def __init__(self):
  1290.        super().__init__()
  1291.        self.drag = DragWidget(orientation=Qt.Orientation.Vertical)
  1292.        for n, l in enumerate(["A", "B", "C", "D"]):
  1293.            item = DragItem(l)
  1294.            item.set_data(n)  # Store the data.
  1295.            self.drag.add_item(item)
  1296.  
  1297.        # Print out the changed order.
  1298.        self.drag.orderChanged.connect(print)
  1299.  
  1300.        container = QWidget()
  1301.        layout = QVBoxLayout()
  1302.        layout.addStretch(1)
  1303.        layout.addWidget(self.drag)
  1304.        layout.addStretch(1)
  1305.        container.setLayout(layout)
  1306.  
  1307.        self.setCentralWidget(container)
  1308.  
  1309.  
  1310. app = QApplication([])
  1311. w = MainWindow()
  1312. w.show()
  1313.  
  1314. app.exec()
  1315.  
  1316. &lt;/code&gt;
  1317. &lt;/pre&gt;&lt;/div&gt;
  1318. &lt;p&gt;If you run this example on macOS you may notice that the widget drag preview (the &lt;code&gt;QPixmap&lt;/code&gt; created on &lt;code&gt;DragItem&lt;/code&gt;) is a bit blurry. On high-resolution screens you need to set the &lt;em&gt;device pixel ratio&lt;/em&gt; and scale up the pixmap when you create it. Below is a modified &lt;code&gt;DragItem&lt;/code&gt; class which does this.&lt;/p&gt;
  1319. &lt;p&gt;Update &lt;code&gt;DragItem&lt;/code&gt; to support high resolution screens.&lt;/p&gt;
  1320. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1321. &lt;pre&gt;
  1322. &lt;code class="python"&gt;class DragItem(QLabel):
  1323.    def __init__(self, *args, **kwargs):
  1324.        super().__init__(*args, **kwargs)
  1325.        self.setContentsMargins(25, 5, 25, 5)
  1326.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  1327.        self.setStyleSheet("border: 1px solid black;")
  1328.        # Store data separately from display label, but use label for default.
  1329.        self.data = self.text()
  1330.  
  1331.    def set_data(self, data):
  1332.        self.data = data
  1333.  
  1334.    def mouseMoveEvent(self, e):
  1335.        if e.buttons() == Qt.MouseButton.LeftButton:
  1336.            drag = QDrag(self)
  1337.            mime = QMimeData()
  1338.            drag.setMimeData(mime)
  1339.  
  1340.            # Render at x2 pixel ratio to avoid blur on Retina screens.
  1341.            pixmap = QPixmap(self.size().width() * 2, self.size().height() * 2)
  1342.            pixmap.setDevicePixelRatio(2)
  1343.            self.render(pixmap)
  1344.            drag.setPixmap(pixmap)
  1345.  
  1346.            drag.exec(Qt.DropAction.MoveAction)
  1347.            self.show() # Show this widget again, if it's dropped outside.
  1348. &lt;/code&gt;
  1349. &lt;/pre&gt;&lt;/div&gt;
  1350. &lt;p&gt;That's it! We've created a generic drag-drop handled which can be added to any projects where you need to be able to reposition items within a list. You should feel free to experiment with the styling of the drag items and targets as this won't affect the behavior.&lt;/p&gt;
  1351. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;</description>
  1352.    </item>
  1353.    <item>
  1354.      <guid isPermaLink="false">https://www.kdab.com/?p=33514</guid>
  1355.      <title>KDAB on Qt: Incredibly Simple QR Generation in QML</title>
  1356.      <pubDate>Thu, 22 Feb 2024 08:00:42 GMT</pubDate>
  1357.      <link>https://www.kdab.com/incredibly-simple-qr-generation-in-qml/</link>
  1358.      <description>&lt;div class="stackedit__html"&gt;
  1359. &lt;h2 id="the-need-for-simple--modular-qr-generation-in-qml"&gt;The Need for Simple &amp; Modular QR Generation in QML&lt;/h2&gt;
  1360. &lt;p&gt;Recently, our designer Nuno Pinheiro needed to generate QR codes for an Android app in QML and started asking around about a simple way to do this. The best existing QML solution was &lt;a href="https://github.com/ftylitak/qzxing"&gt;QZXing&lt;/a&gt;, a Qt/QML wrapper for the 1D/2D barcode image processing library ZXing. He felt this was too much.&lt;/p&gt;
  1361. &lt;p&gt;QZXing is quite a large and feature-rich library and is a great choice for something that requires a lot more rigorous work with encoding and decoding barcodes and QR. However, this application wasn&#x2019;t focused around barcode processing. It just needed to display a few QR codes below its other content; it didn&#x2019;t need something so heavy-duty. It seemed like too much work to build and link this library and register QML types in C++ if there was something simpler available.&lt;/p&gt;
  1362. &lt;h2 id="finding-a-javascript-library-to-wrap-in-qml"&gt;Finding A JavaScript Library to Wrap in QML&lt;/h2&gt;
  1363. &lt;p&gt;There are plenty of minimal QR Code libraries in JS, and JS files can be imported natively in QML. Why not just slap a minified JS file into our Qt resources and expose its functionality through a QML object? No compiling libraries, no CMake, simple setup for a simple task.&lt;/p&gt;
  1364. &lt;p&gt;My colleague, the one and only Javier O. Cordero P&#xE9;rez attempted to tackle this first using &lt;a href="https://github.com/davidshimjs/qrcodejs"&gt;QRCode.js&lt;/a&gt;. He found a few issues, which I&#x2019;ll let him explain. This is what Javier contributed:&lt;/p&gt;
  1365. &lt;h2 id="why-most-browser-libraries-don&#x2019;t-work-with-qml"&gt;Why Most Browser Libraries Don&#x2019;t Work With QML&lt;/h2&gt;
  1366. &lt;p&gt;Not all ECMAScript or JavaScript environments are created equal. &lt;a href="https://doc.qt.io/qt-6/qtqml-javascript-hostenvironment.html"&gt;QML, for example, doesn&#x2019;t have a DOM (Document Object Model) that represents the contents on screen&lt;/a&gt;. That feature comes from HTML, so when a JS library designed for use in the browser attempts to access the DOM from QML, it can&#x2019;t find these APIs. This limits the use of JS libraries in QML to business logic. Frontend JS libaries would have to be ported to QML in order to work.&lt;/p&gt;
  1367. &lt;blockquote&gt;
  1368. &lt;p&gt;&lt;em&gt;Note to those concerned with performance:&lt;/em&gt; At the time of writing, JS data structures, and many JS and C++ design patterns don&#x2019;t optimize well in QML code when using QML compilers. You should use C++ for backend code if you work in embedded or performance is a concern for you. Even JavaScript libraries have started a trend of moving away from pure JS in favor of Rust and WASM for backend code. Having said that, we cannot understate the convenience of having JS or QML modules or libraries you can simply plug and play. This is why we did this in the first place.&lt;/p&gt;
  1369. &lt;/blockquote&gt;
  1370. &lt;p&gt;In my first approach to using &lt;code&gt;qrcodejs&lt;/code&gt;, I tried using the library from within a QML slot (&lt;code&gt;Component.onCompleted&lt;/code&gt;) and found that &lt;code&gt;QRCode.js&lt;/code&gt; calls &lt;code&gt;document.documentElement&lt;/code&gt;, &lt;code&gt;document.getElementById&lt;/code&gt;, &lt;code&gt;document.documentElement&lt;/code&gt;, and &lt;code&gt;document.createElement&lt;/code&gt;, which are undefined, because &lt;code&gt;document&lt;/code&gt; is typically an &lt;code&gt;HTMLDocument&lt;/code&gt;, part of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API#structure_of_an_html_document"&gt;HTML DOM API&lt;/a&gt;.&lt;/p&gt;
  1371. &lt;p&gt;I then began attempting to refactor the code, but quickly realized there was no easy way to get the library to use QtQuick&#x2019;s Canvas element. I knew from past experiences that Canvas performs very poorly on Android, so, being pressed for time and Android being our target platform, I came up with a different solution.&lt;/p&gt;
  1372. &lt;h2 id="embedding-and-communicating-with-a-browser-view"&gt;Embedding and Communicating With A Browser View&lt;/h2&gt;
  1373. &lt;p&gt;My second approach was to give &lt;code&gt;QRCode.js&lt;/code&gt; a browser to work with. I chose to use &lt;code&gt;QtWebView&lt;/code&gt;, because on mobile, it displays web content using the operating system&#x2019;s web view.&lt;/p&gt;
  1374. &lt;p&gt;To keep things simple, I sent the QRCode&#x2019;s data to the web page by encoding it to a safe character space using Base64 encoding and passing the result as a URL attribute. This attribute is then decoded inside the page and then sent to the library to generate a QR code on the Canvas. The WebView dimensions are also passed as attributes so the image can be produced at the width of the shortest side.&lt;/p&gt;
  1375. &lt;p&gt;This is what my solution looked like at this point:&lt;/p&gt;
  1376. &lt;pre&gt;
  1377. &lt;code class="prism language-qml"&gt;import QtQuick 2.15
  1378. import QtQuick.Window 2.15
  1379.  
  1380. Window {
  1381.    id: document
  1382.    QRCode {
  1383.        id: qr
  1384.        text: "https://kdab.com/"
  1385.        anchors.centerIn: parent
  1386.        // The smallest dimension determines and fixes QR code size
  1387.        width: 400
  1388.        height: 600
  1389.    }
  1390.    width: 640
  1391.    height: 480
  1392.    visible: true
  1393.    title: qsTr("Web based embedded QR Code")
  1394. }
  1395. &lt;/code&gt;
  1396. &lt;/pre&gt;
  1397. &lt;pre&gt;
  1398. &lt;code class="prism language-qml"&gt;// QRCode.qml
  1399. import QtQuick 2.15
  1400. import QtWebView 1.15
  1401.  
  1402. Item {
  1403.    required property string text
  1404.    // Due to platform limitations, overlapping the WebView with other QML components is not supported.
  1405.    // Doing this will have unpredictable results which may differ from platform to platform.
  1406.    WebView {
  1407.        id: document
  1408.        // String is encoded using base64 and transfered through page URL
  1409.        url: "qrc:///qr-loader.html?w=" + width + "&amp;t=" + Qt.btoa(text)
  1410.        // Keep view dimensions to a minimum
  1411.        width: parent.width &lt; parent.height ? parent.width : parent.height
  1412.        height: parent.height &lt; parent.width ? parent.height : parent.width
  1413.        anchors.centerIn: parent
  1414.        // Note: To update the contents after the page has loaded, we could expand upon this
  1415.        // by calling runJavaScript(script: string, callback: var) from the WebView component.
  1416.        // Any method attributes, such as dimensions or the QR Code&#x2019;s contents would have to
  1417.        // be concatenated inside the script parameter.
  1418.    }
  1419. }
  1420. &lt;/code&gt;
  1421. &lt;/pre&gt;
  1422. &lt;pre&gt;
  1423. &lt;code class="prism language-html"&gt;// qr-loader.html&gt;
  1424. &lt;html&gt;
  1425. &lt;head&gt;
  1426. &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
  1427. &lt;style&gt;
  1428. body {
  1429.  margin: 0;
  1430.  padding: 0;
  1431. }
  1432. #qr {
  1433.  width: 100%;
  1434.  height: 100%;
  1435.  margin: auto;
  1436. }
  1437. &lt;/style&gt;
  1438. &lt;/head&gt;
  1439. &lt;body&gt;
  1440. &lt;h1&gt;u&lt;/h1&gt;
  1441. &lt;div id="q"&gt;&lt;/div&gt;
  1442. &lt;script src="jquery.min.js"&gt;&lt;/script&gt;
  1443. &lt;script src="qrcode.min.js"&gt;&lt;/script&gt;
  1444. &lt;script&gt;
  1445. function generateQRCode() {
  1446.  const s = new URLSearchParams(document.location.search);
  1447.  const w = Number(s.get("w"));
  1448.  const t = atob(s.get("t"));
  1449.  new QRCode(document.getElementById("q"), {
  1450.    text: t,
  1451.    width: w,
  1452.    height: w
  1453.  });
  1454. }
  1455. generateQRCode();
  1456. &lt;/script&gt;
  1457. &lt;/body&gt;
  1458. &lt;/code&gt;
  1459. &lt;/pre&gt;
  1460. &lt;h2 id="why-you-should-avoid-qtwebview-on-mobile"&gt;Why You Should Avoid QtWebView On Mobile&lt;/h2&gt;
  1461. &lt;p&gt;If you read the comments in the code, you&#x2019;ll notice that &lt;em&gt;&#x201C;due to platform limitations, overlapping the WebView with other QML components is not supported. Doing this will have unpredictable results which may differ from platform to platform.&#x201D;&lt;/em&gt; Additionally, there is so much overhead in loading an embedded site that you can see the exact moment the QR code appears on screen.&lt;/p&gt;
  1462. &lt;p&gt;Unfortunately for Nuno, &lt;code&gt;QtWebView&lt;/code&gt; is unable to load pages embedded as Qt resources on mobile systems. This is because by default, Qt resources become a part of the app&#x2019;s binary, which can&#x2019;t be read by the embedded browser. If the site was stored online or the app hosted its own web server, we could load our resources from there. Since this app didn&#x2019;t do either of those things, all resources had to be copied into a temporary folder and accessed via the &lt;code&gt;file://&lt;/code&gt; protocol. Even then, the embedded browser would fail to locate or load the resources, making it necessary to inline all of our resources into the HTML for this to work.&lt;/p&gt;
  1463. &lt;p&gt;As you can see, what started as a simple way to use a JS library on the desktop, quickly became cumbersome and difficult to maintain for mobile devices. Given more time, I would&#x2019;ve chosen to instead re-implement &lt;code&gt;QRCode.js&lt;/code&gt;'s algorithm using QtQuick&#x2019;s Shapes API. The Shapes API would allow the QR code to be rendered in a single pass of the scene graph.&lt;/p&gt;
  1464. &lt;p&gt;Fortunately, there&#x2019;s a better, simpler and more practical solution. I will defer back to Matt here, who figured it out:&lt;/p&gt;
  1465. &lt;p&gt;&lt;span style="color: #0077c8; font-family: inherit; font-size: 27px;"&gt;Proper JS in QML Solution&lt;/span&gt;&lt;/p&gt;
  1466. &lt;p&gt;I decided to expand on Javier&#x2019;s idea and try &lt;a href="https://github.com/papnkukn/qrcode-svg"&gt;qrcode-svg&lt;/a&gt;. This library uses a modified version of QRCode.js and enables creation of an SVG string from the QR Code data.&lt;/p&gt;
  1467. &lt;p&gt;Here&#x2019;s an example snipped from the project&#x2019;s README:&lt;/p&gt;
  1468. &lt;pre&gt;
  1469. &lt;code class="prism language-js"&gt;var qrcode = new QRCode({
  1470.  content: "Hello World!",
  1471.  container: "svg-viewbox", // Responsive use
  1472.  join: true // Crisp rendering and 4-5x reduced file size
  1473. });
  1474. var svg = qrcode.svg();
  1475. &lt;/code&gt;
  1476. &lt;/pre&gt;
  1477. &lt;p&gt;Since the data is SVG, it can be used with QML&#x2019;s &lt;code&gt;Image&lt;/code&gt; item natively by transforming it into a data URI and using that as the source for the image. There&#x2019;s no need to write or read anything to disk, just append the string to &lt;code&gt;"data:image/svg+xml;utf8,"&lt;/code&gt; and use that as the source file.&lt;/p&gt;
  1478. &lt;h2 id="starting-our-wrapper"&gt;Starting Our Wrapper&lt;/h2&gt;
  1479. &lt;p&gt;We can just wrap the function call up in a QML type, called QR, and use that wherever we need a QR code. Let&#x2019;s make a ridiculously basic &lt;code&gt;QtObject&lt;/code&gt; that takes a content string and uses the library to produce an SVG:&lt;/p&gt;
  1480. &lt;pre&gt;
  1481. &lt;code class="prism language-qml"&gt;// QR.qml
  1482.  
  1483. import QtQuick
  1484. import "qrcode.min.js" as QrSvg
  1485.  
  1486. QtObject {
  1487.    id: root
  1488.  
  1489.    required property string content
  1490.    property string svgString: ""
  1491.  
  1492.    Component.onCompleted: {
  1493.        root.svgString = new QrSvg.QRCode({
  1494.            content: root.content
  1495.        }).svg()
  1496.    }
  1497. }
  1498. &lt;/code&gt;
  1499. &lt;/pre&gt;
  1500. &lt;p&gt;So, whenever we make a &lt;code&gt;QR&lt;/code&gt; object, the string bound to &lt;code&gt;content&lt;/code&gt; is used to make the SVG and store it in &lt;code&gt;svgString&lt;/code&gt;. Then we can render it in an &lt;code&gt;Image&lt;/code&gt; item:&lt;/p&gt;
  1501. &lt;pre&gt;
  1502. &lt;code class="prism language-qml"&gt;// example.qml
  1503.  
  1504. import QtQuick
  1505. import QtQuick.Window
  1506.  
  1507. Window {
  1508.    visible: true
  1509.  
  1510.    QR {
  1511.        id: qrObj
  1512.        content: "hello QR!"
  1513.    }
  1514.  
  1515.    Image {
  1516.        source: "data:image/svg+xml;utf8," + qrObj.svgString
  1517.    }
  1518. }
  1519. &lt;/code&gt;
  1520. &lt;/pre&gt;
  1521. &lt;p&gt;This is basically effortless and works like a charm.&lt;/p&gt;
  1522. &lt;h2 id="finishing-up-the-wrapper"&gt;Finishing Up The Wrapper&lt;/h2&gt;
  1523. &lt;p&gt;Now let&#x2019;s completely wrap the QRCode constructor, so all the options from qrcode-svg are exposed by our QML object. We just need to set all options in the constructor through QML properties and give all the unrequired properties default values.&lt;/p&gt;
  1524. &lt;p&gt;While we&#x2019;re at it, let&#x2019;s go ahead and connect to &lt;code&gt;onContentChanged&lt;/code&gt;, so we can refresh the SVG automatically when the content changes.&lt;/p&gt;
  1525. &lt;pre&gt;
  1526. &lt;code class="prism language-qml"&gt;// QR.qml
  1527.  
  1528. import QtQuick
  1529.  
  1530. import "qrcode.min.js" as QrSvg
  1531.  
  1532. QtObject {
  1533.    id: root
  1534.  
  1535.    required property string content
  1536.    property int padding: 4
  1537.    property int width: 256
  1538.    property int height: 256
  1539.    property string color: "black"
  1540.    property string background: "white"
  1541.    property string ecl: "M"
  1542.    property bool join: false
  1543.    property bool predefined: false
  1544.    property bool pretty: true
  1545.    property bool swap: false
  1546.    property bool xmlDeclaration: true
  1547.    property string container: "svg"
  1548.  
  1549.    property string svgString: ""
  1550.  
  1551.    function createSvgString() {
  1552.        root.svgString = new QrSvg.QRCode({
  1553.            content: root.content,
  1554.            padding: root.padding,
  1555.            width: root.width,
  1556.            height: root.height,
  1557.            color: root.color,
  1558.            background: root.background,
  1559.            ecl: root.ecl,
  1560.            join: root.join,
  1561.            predefined: root.predefined,
  1562.            pretty: root.pretty,
  1563.            swap: root.swap,
  1564.            xmlDeclaration: root.xmlDeclaration,
  1565.            container: root.container
  1566.        }).svg()
  1567.    }
  1568.  
  1569.    onContentChanged: createSvgString()
  1570.    Component.onCompleted: createSvgString()
  1571. }
  1572. &lt;/code&gt;
  1573. &lt;/pre&gt;
  1574. &lt;h2 id="nice-and-easy"&gt;Nice and Easy&lt;/h2&gt;
  1575. &lt;p&gt;With these 45 lines of QML and the minified JS file, we have a QML wrapper for the library. Now any arbitrary QML project can include these two files and generate any QR Code that qrcode-svg can make.&lt;/p&gt;
  1576. &lt;p&gt;Here I use it to re-generate a QR code as you type the content into a TextInput:&lt;/p&gt;
  1577. &lt;pre&gt;
  1578. &lt;code class="prism language-qml"&gt;// example.qml
  1579.  
  1580. import QtQuick
  1581. import QtQuick.Window
  1582. import QtQuick.Controls
  1583.  
  1584. Window {
  1585.    id: root
  1586.  
  1587.    visible: true
  1588.  
  1589.    QR {
  1590.        id: qrObj
  1591.        content: txtField.text
  1592.        join: true
  1593.    }
  1594.  
  1595.    TextField {
  1596.        id: txtField
  1597.        width: parent.width
  1598.    }
  1599.  
  1600.    Image {
  1601.        anchors.top: txtField.bottom
  1602.        source: (qrObj.svgString === "")
  1603.                    ? ""
  1604.                    : ("data:image/svg+xml;utf8," + qrObj.svgString)
  1605.    }
  1606. }
  1607. &lt;/code&gt;
  1608. &lt;/pre&gt;
  1609. &lt;p&gt;This runs well when deployed on Android, and the image re-renders on content change in under 30 milliseconds, sometimes as low as 7.&lt;/p&gt;
  1610. &lt;p&gt;Hopefully this code will be useful to those looking for the simplest no-frills method to generate a QR code in QML, and maybe the post can inspire other QML developers who feel like they&#x2019;re overcomplicating something really simple.&lt;/p&gt;
  1611. &lt;blockquote&gt;
  1612. &lt;p&gt;&lt;em&gt;The solution associated with this post is available &lt;a href="https://github.com/KDABLabs/QR-Code-Generator-QML"&gt;in a GitHub repo linked here&lt;/a&gt;, so it can be used for your projects and tweaked if needed. There is also a branch that contains the code for Javier's alternate solution, &lt;a href="https://github.com/KDABLabs/QR-Code-Generator-QML/tree/alternative-web-solution"&gt;available here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
  1613. &lt;/blockquote&gt;
  1614. &lt;blockquote&gt;
  1615. &lt;p&gt;&lt;em&gt;Note: Nuno settled on QZXing before we got a chance to show him this solution, and was so frustrated about not having it earlier that he made us write this blog post &lt;img alt="&#x1F605;" class="wp-smiley" src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f605.png" style="height: 1em;"&gt;&lt;/em&gt;&lt;/p&gt;
  1616. &lt;/blockquote&gt;
  1617. &lt;div class="panel panel-info"&gt;
  1618. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  1619. &lt;div class="panel-body"&gt;
  1620. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  1621. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  1622. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  1623. &lt;/div&gt;
  1624. &lt;/div&gt;
  1625. &lt;/div&gt;
  1626. &lt;p&gt;The post &lt;a href="https://www.kdab.com/incredibly-simple-qr-generation-in-qml/"&gt;Incredibly Simple QR Generation in QML&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  1627.    </item>
  1628.    <item>
  1629.      <guid isPermaLink="false">tag:www.pythonguis.com,2024-02-07:/faq/pyqt6-drag-drop-widgets/</guid>
  1630.      <title>Python GUIs - qt: Drag &amp; Drop Widgets with PyQt6 &#x2014; Sort widgets visually with drag and drop in a container</title>
  1631.      <pubDate>Wed, 07 Feb 2024 13:00:00 GMT</pubDate>
  1632.      <link>https://www.pythonguis.com/faq/pyqt6-drag-drop-widgets/</link>
  1633.      <description>&lt;p&gt;I had an interesting question from a reader of my &lt;a href="https://www.pythonguis.com/pyqt6-book/"&gt;PyQt6 book&lt;/a&gt;, about how to handle dragging and dropping of widgets in a container showing the dragged widget as it is moved.&lt;/p&gt;
  1634. &lt;blockquote&gt;
  1635. &lt;p&gt;I'm interested in managing movement of a QWidget with mouse in a container. I've implemented the application with drag &amp; drop, exchanging the position of buttons, but I want to show the motion of &lt;code&gt;QPushButton&lt;/code&gt;, like what you see in Qt Designer. Dragging a widget should show the widget itself, not just the mouse pointer.&lt;/p&gt;
  1636. &lt;/blockquote&gt;
  1637. &lt;p&gt;First, we'll implement the simple case which drags widgets without showing anything extra. Then we can extend it to answer the question. By the end of this quick tutorial we'll have a generic drag drop implementation which looks like the following.&lt;/p&gt;
  1638. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;
  1639. &lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;
  1640. &lt;ul&gt;
  1641. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#drag-drop-widgets"&gt;Drag &amp; Drop Widgets&lt;/a&gt;&lt;/li&gt;
  1642. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#visual-drag-drop"&gt;Visual Drag &amp; Drop&lt;/a&gt;&lt;/li&gt;
  1643. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#generic-drag-drop-container"&gt;Generic Drag &amp; Drop Container&lt;/a&gt;&lt;/li&gt;
  1644. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#adding-a-visual-drop-target"&gt;Adding a Visual Drop Target&lt;/a&gt;&lt;/li&gt;
  1645. &lt;/ul&gt;
  1646. &lt;/div&gt;
  1647. &lt;h2 id="drag-drop-widgets"&gt;Drag &amp; Drop Widgets&lt;/h2&gt;
  1648. &lt;p&gt;We'll start with a simple application which creates a window using &lt;code&gt;QWidget&lt;/code&gt; and places a series of &lt;code&gt;QPushButton&lt;/code&gt; widgets into it.&lt;/p&gt;
  1649. &lt;p class="admonition admonition-tip"&gt;You can substitute &lt;code&gt;QPushButton&lt;/code&gt; for any other widget you like, e.g. &lt;code&gt;QLabel&lt;/code&gt;. Any widget can have drag behavior implemented on it, although some input widgets will not work well as we capture the mouse events for the drag.&lt;/p&gt;
  1650. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1651. &lt;pre&gt;
  1652. &lt;code class="python"&gt;from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  1653.  
  1654.  
  1655. class Window(QWidget):
  1656.    def __init__(self):
  1657.        super().__init__()
  1658.  
  1659.        self.blayout = QHBoxLayout()
  1660.        for l in ["A", "B", "C", "D"]:
  1661.            btn = QPushButton(l)
  1662.            self.blayout.addWidget(btn)
  1663.  
  1664.        self.setLayout(self.blayout)
  1665.  
  1666.  
  1667. app = QApplication([])
  1668. w = Window()
  1669. w.show()
  1670.  
  1671. app.exec()
  1672.  
  1673.  
  1674. &lt;/code&gt;
  1675. &lt;/pre&gt;&lt;/div&gt;
  1676. &lt;p&gt;If you run this you should see something like this.&lt;/p&gt;
  1677. &lt;p&gt;&lt;img alt="Widgets in a layout" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/windows-in-layout.png" width="421"&gt; &lt;em&gt;The series of &lt;code&gt;QPushButton widgets&lt;/code&gt; in a horizontal layout.&lt;/em&gt;&lt;/p&gt;
  1678. &lt;p class="admonition admonition-note"&gt;Here we're creating a window, but the &lt;code&gt;Window&lt;/code&gt; widget is subclassed from &lt;code&gt;QWidget&lt;/code&gt;, meaning you can add this widget to any other layout. See later for an example of a generic object sorting widget.&lt;/p&gt;
  1679. &lt;p&gt;&lt;code&gt;QPushButton&lt;/code&gt; objects aren't usually draggable, so to handle the mouse movements and initiate a drag we need to implement a subclass. We can add the following to the top of the file.&lt;/p&gt;
  1680. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1681. &lt;pre&gt;
  1682. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt
  1683. from PyQt6.QtGui import QDrag
  1684. from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  1685.  
  1686.  
  1687. class DragButton(QPushButton):
  1688.    def mouseMoveEvent(self, e):
  1689.        if e.buttons() == Qt.MouseButton.LeftButton:
  1690.            drag = QDrag(self)
  1691.            mime = QMimeData()
  1692.            drag.setMimeData(mime)
  1693.            drag.exec(Qt.DropAction.MoveAction)
  1694. &lt;/code&gt;
  1695. &lt;/pre&gt;&lt;/div&gt;
  1696. &lt;p&gt;We implement a &lt;code&gt;mouseMoveEvent&lt;/code&gt; which accepts the single &lt;code&gt;e&lt;/code&gt; parameter of the event. We check to see if the &lt;em&gt;left&lt;/em&gt; mouse button is pressed on this event -- as it would be when dragging -- and then initiate a drag. To start a drag, we create a &lt;code&gt;QDrag&lt;/code&gt; object, passing in &lt;code&gt;self&lt;/code&gt; to give us access later to the widget that was dragged. We also &lt;em&gt;must&lt;/em&gt; pass in mime data. This is used for including information about what is dragged, particularly for passing data between applications. However, as here, it is fine to leave this empty.&lt;/p&gt;
  1697. &lt;p&gt;Finally, we initiate a drag by calling &lt;code&gt;drag.exec_(Qt.MoveAction)&lt;/code&gt;. As with dialogs &lt;code&gt;exec_()&lt;/code&gt; starts a new event loop, blocking the main loop until the drag is complete. The parameter &lt;code&gt;Qt.MoveAction&lt;/code&gt; tells the drag handler what type of operation is happening, so it can show the appropriate icon tip to the user.&lt;/p&gt;
  1698. &lt;p&gt;You can update the main window code to use our new &lt;code&gt;DragButton&lt;/code&gt; class as follows.&lt;/p&gt;
  1699. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1700. &lt;pre&gt;
  1701. &lt;code class="python"&gt;class Window(QWidget):
  1702.    def __init__(self):
  1703.        super().__init__()
  1704.  
  1705.        self.blayout = QHBoxLayout()
  1706.        for l in ["A", "B", "C", "D"]:
  1707.            btn = DragButton(l)
  1708.            self.blayout.addWidget(btn)
  1709.  
  1710.        self.setLayout(self.blayout)
  1711.  
  1712. &lt;/code&gt;
  1713. &lt;/pre&gt;&lt;/div&gt;
  1714. &lt;p&gt;If you run the code now, you &lt;em&gt;can&lt;/em&gt; drag the buttons, but you'll notice the drag is forbidden.&lt;/p&gt;
  1715. &lt;p&gt;&lt;img alt="Drag forbidden" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-forbidden.png" width="421"&gt; &lt;em&gt;Dragging of the widget starts but is forbidden.&lt;/em&gt;&lt;/p&gt;
  1716. &lt;p&gt;What's happening? The mouse movement is being detected by our &lt;code&gt;DragButton&lt;/code&gt; object and the drag started, but the main window does not accept drag &amp; drop.&lt;/p&gt;
  1717. &lt;p&gt;To fix this we need to enable drops on the window and implement &lt;code&gt;dragEnterEvent&lt;/code&gt; to actually accept them.&lt;/p&gt;
  1718. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1719. &lt;pre&gt;
  1720. &lt;code class="python"&gt;class Window(QWidget):
  1721.    def __init__(self):
  1722.        super().__init__()
  1723.        self.setAcceptDrops(True)
  1724.  
  1725.        self.blayout = QHBoxLayout()
  1726.        for l in ["A", "B", "C", "D"]:
  1727.            btn = DragButton(l)
  1728.            self.blayout.addWidget(btn)
  1729.  
  1730.        self.setLayout(self.blayout)
  1731.  
  1732.    def dragEnterEvent(self, e):
  1733.        e.accept()
  1734.  
  1735. &lt;/code&gt;
  1736. &lt;/pre&gt;&lt;/div&gt;
  1737. &lt;p&gt;If you run this now, you'll see the drag is now accepted and you see the move icon. This indicates that the drag has started and been accepted by the window we're dragging onto. The icon shown is determined by the action we pass when calling &lt;code&gt;drag.exec_()&lt;/code&gt;.&lt;/p&gt;
  1738. &lt;p&gt;&lt;img alt="Drag accepted" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-accepted.png" width="421"&gt; &lt;em&gt;Dragging of the widget starts and is accepted, showing a move icon.&lt;/em&gt;&lt;/p&gt;
  1739. &lt;p&gt;Releasing the mouse button during a drag drop operation triggers a &lt;code&gt;dropEvent&lt;/code&gt; on the widget you're currently hovering the mouse over (if it is configured to accept drops). In our case that's the window. To handle the move we need to implement the code to do this in our &lt;code&gt;dropEvent&lt;/code&gt; method.&lt;/p&gt;
  1740. &lt;p&gt;The drop event contains the position the mouse was at when the button was released &amp; the drop triggered. We can use this to determine where to move the widget to.&lt;/p&gt;
  1741. &lt;p&gt;To determine where to place the widget, we iterate over all the widgets in the layout, &lt;em&gt;until&lt;/em&gt; we find one who's &lt;code&gt;x&lt;/code&gt; position is &lt;em&gt;greater&lt;/em&gt; than that of the mouse pointer. If so then when insert the widget directly to the left of this widget and exit the loop.&lt;/p&gt;
  1742. &lt;p&gt;If we get to the end of the loop without finding a match, we must be dropping past the end of the existing items, so we increment &lt;code&gt;n&lt;/code&gt; one further (in the &lt;code&gt;else:&lt;/code&gt; block below).&lt;/p&gt;
  1743. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1744. &lt;pre&gt;
  1745. &lt;code class="python"&gt;    def dropEvent(self, e):
  1746.        pos = e.position()
  1747.        widget = e.source()
  1748.        self.blayout.removeWidget(widget)
  1749.  
  1750.        for n in range(self.blayout.count()):
  1751.            # Get the widget at each index in turn.
  1752.            w = self.blayout.itemAt(n).widget()
  1753.            if pos.x() &lt; w.x():
  1754.                # We didn't drag past this widget.
  1755.                # insert to the left of it.
  1756.                break
  1757.        else:
  1758.            # We aren't on the left hand side of any widget,
  1759.            # so we're at the end. Increment 1 to insert after.
  1760.            n += 1
  1761.        self.blayout.insertWidget(n, widget)
  1762.  
  1763.        e.accept()
  1764.  
  1765. &lt;/code&gt;
  1766. &lt;/pre&gt;&lt;/div&gt;
  1767. &lt;p&gt;The effect of this is that if you drag 1 pixel past the start of another widget the drop will happen to the right of it, which is a bit confusing. To fix this we can adjust the cut off to use the middle of the widget using &lt;code&gt;if pos.x() &lt; w.x() + w.size().width() // 2:&lt;/code&gt; -- that is x + half of the width.&lt;/p&gt;
  1768. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1769. &lt;pre&gt;
  1770. &lt;code class="python"&gt;    def dropEvent(self, e):
  1771.        pos = e.position()
  1772.        widget = e.source()
  1773.        self.blayout.removeWidget(widget)
  1774.  
  1775.        for n in range(self.blayout.count()):
  1776.            # Get the widget at each index in turn.
  1777.            w = self.blayout.itemAt(n).widget()
  1778.            if pos.x() &lt; w.x() + w.size().width() // 2:
  1779.                # We didn't drag past this widget.
  1780.                # insert to the left of it.
  1781.                break
  1782.        else:
  1783.            # We aren't on the left hand side of any widget,
  1784.            # so we're at the end. Increment 1 to insert after.
  1785.            n += 1
  1786.        self.blayout.insertWidget(n, widget)
  1787.  
  1788.        e.accept()
  1789.  
  1790. &lt;/code&gt;
  1791. &lt;/pre&gt;&lt;/div&gt;
  1792. &lt;p&gt;The complete working drag-drop code is shown below.&lt;/p&gt;
  1793. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1794. &lt;pre&gt;
  1795. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt
  1796. from PyQt6.QtGui import QDrag
  1797. from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  1798.  
  1799.  
  1800. class DragButton(QPushButton):
  1801.    def mouseMoveEvent(self, e):
  1802.        if e.buttons() == Qt.MouseButton.LeftButton:
  1803.            drag = QDrag(self)
  1804.            mime = QMimeData()
  1805.            drag.setMimeData(mime)
  1806.            drag.exec(Qt.DropAction.MoveAction)
  1807.  
  1808.  
  1809. class Window(QWidget):
  1810.    def __init__(self):
  1811.        super().__init__()
  1812.        self.setAcceptDrops(True)
  1813.  
  1814.        self.blayout = QHBoxLayout()
  1815.        for l in ["A", "B", "C", "D"]:
  1816.            btn = DragButton(l)
  1817.            self.blayout.addWidget(btn)
  1818.  
  1819.        self.setLayout(self.blayout)
  1820.  
  1821.    def dragEnterEvent(self, e):
  1822.        e.accept()
  1823.  
  1824.    def dropEvent(self, e):
  1825.        pos = e.position()
  1826.        widget = e.source()
  1827.        self.blayout.removeWidget(widget)
  1828.  
  1829.        for n in range(self.blayout.count()):
  1830.            # Get the widget at each index in turn.
  1831.            w = self.blayout.itemAt(n).widget()
  1832.            if pos.x() &lt; w.x() + w.size().width() // 2:
  1833.                # We didn't drag past this widget.
  1834.                # insert to the left of it.
  1835.                break
  1836.        else:
  1837.            # We aren't on the left hand side of any widget,
  1838.            # so we're at the end. Increment 1 to insert after.
  1839.            n += 1
  1840.  
  1841.        self.blayout.insertWidget(n, widget)
  1842.  
  1843.        e.accept()
  1844.  
  1845.  
  1846. app = QApplication([])
  1847. w = Window()
  1848. w.show()
  1849.  
  1850. app.exec()
  1851.  
  1852. &lt;/code&gt;
  1853. &lt;/pre&gt;&lt;/div&gt;
  1854. &lt;h2 id="visual-drag-drop"&gt;Visual Drag &amp; Drop&lt;/h2&gt;
  1855. &lt;p&gt;We now have a working drag &amp; drop implementation. Next we'll move onto improving the UX by showing the drag visually. First we'll add support for showing the button being dragged next to the mouse point as it is dragged. That way the user knows exactly what it is they are dragging.&lt;/p&gt;
  1856. &lt;p&gt;Qt's &lt;code&gt;QDrag&lt;/code&gt; handler natively provides a mechanism for showing dragged objects which we can use. We can update our &lt;code&gt;DragButton&lt;/code&gt; class to pass a &lt;em&gt;pixmap&lt;/em&gt; image to &lt;code&gt;QDrag&lt;/code&gt; and this will be displayed under the mouse pointer as the drag occurs. To show the widget, we just need to get a &lt;code&gt;QPixmap&lt;/code&gt; of the widget we're dragging.&lt;/p&gt;
  1857. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1858. &lt;pre&gt;
  1859. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt
  1860. from PyQt6.QtGui import QDrag, QPixmap
  1861. from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QWidget
  1862.  
  1863.  
  1864. class DragButton(QPushButton):
  1865.    def mouseMoveEvent(self, e):
  1866.        if e.buttons() == Qt.MouseButton.LeftButton:
  1867.            drag = QDrag(self)
  1868.            mime = QMimeData()
  1869.            drag.setMimeData(mime)
  1870.  
  1871.            pixmap = QPixmap(self.size())
  1872.            self.render(pixmap)
  1873.            drag.setPixmap(pixmap)
  1874.  
  1875.            drag.exec(Qt.DropAction.MoveAction)
  1876.  
  1877. &lt;/code&gt;
  1878. &lt;/pre&gt;&lt;/div&gt;
  1879. &lt;p&gt;To create the pixmap we create a &lt;code&gt;QPixmap&lt;/code&gt; object passing in the size of the widget this event is fired on with &lt;code&gt;self.size()&lt;/code&gt;. This creates an empty &lt;em&gt;pixmap&lt;/em&gt; which we can then pass into &lt;code&gt;self.render&lt;/code&gt; to &lt;em&gt;render&lt;/em&gt; -- or draw -- the current widget onto it. That's it. Then we set the resulting pixmap on the &lt;code&gt;drag&lt;/code&gt; object.&lt;/p&gt;
  1880. &lt;p&gt;If you run the code with this modification you'll see something like the following --&lt;/p&gt;
  1881. &lt;p&gt;&lt;img alt="Drag visual" height="93" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-visual.png" width="421"&gt; &lt;em&gt;Dragging of the widget showing the dragged widget.&lt;/em&gt;&lt;/p&gt;
  1882. &lt;h2 id="generic-drag-drop-container"&gt;Generic Drag &amp; Drop Container&lt;/h2&gt;
  1883. &lt;p&gt;We now have a working drag and drop behavior implemented on our window. We can take this a step further and implement a &lt;em&gt;generic&lt;/em&gt; drag drop widget which allows us to sort arbitrary objects. In the code below we've created a new widget &lt;code&gt;DragWidget&lt;/code&gt; which can be added to any window.&lt;/p&gt;
  1884. &lt;p&gt;You can add &lt;em&gt;items&lt;/em&gt; -- instances of &lt;code&gt;DragItem&lt;/code&gt; -- which you want to be sorted, as well as setting data on them. When items are re-ordered the new order is emitted as a signal &lt;code&gt;orderChanged&lt;/code&gt;.&lt;/p&gt;
  1885. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  1886. &lt;pre&gt;
  1887. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt, pyqtSignal
  1888. from PyQt6.QtGui import QDrag, QPixmap
  1889. from PyQt6.QtWidgets import (
  1890.    QApplication,
  1891.    QHBoxLayout,
  1892.    QLabel,
  1893.    QMainWindow,
  1894.    QVBoxLayout,
  1895.    QWidget,
  1896. )
  1897.  
  1898.  
  1899. class DragItem(QLabel):
  1900.    def __init__(self, *args, **kwargs):
  1901.        super().__init__(*args, **kwargs)
  1902.        self.setContentsMargins(25, 5, 25, 5)
  1903.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  1904.        self.setStyleSheet("border: 1px solid black;")
  1905.        # Store data separately from display label, but use label for default.
  1906.        self.data = self.text()
  1907.  
  1908.    def set_data(self, data):
  1909.        self.data = data
  1910.  
  1911.    def mouseMoveEvent(self, e):
  1912.        if e.buttons() == Qt.MouseButton.LeftButton:
  1913.            drag = QDrag(self)
  1914.            mime = QMimeData()
  1915.            drag.setMimeData(mime)
  1916.  
  1917.            pixmap = QPixmap(self.size())
  1918.            self.render(pixmap)
  1919.            drag.setPixmap(pixmap)
  1920.  
  1921.            drag.exec(Qt.DropAction.MoveAction)
  1922.  
  1923.  
  1924. class DragWidget(QWidget):
  1925.    """
  1926.    Generic list sorting handler.
  1927.    """
  1928.  
  1929.    orderChanged = pyqtSignal(list)
  1930.  
  1931.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  1932.        super().__init__()
  1933.        self.setAcceptDrops(True)
  1934.  
  1935.        # Store the orientation for drag checks later.
  1936.        self.orientation = orientation
  1937.  
  1938.        if self.orientation == Qt.Orientation.Vertical:
  1939.            self.blayout = QVBoxLayout()
  1940.        else:
  1941.            self.blayout = QHBoxLayout()
  1942.  
  1943.        self.setLayout(self.blayout)
  1944.  
  1945.    def dragEnterEvent(self, e):
  1946.        e.accept()
  1947.  
  1948.    def dropEvent(self, e):
  1949.        pos = e.position()
  1950.        widget = e.source()
  1951.        self.blayout.removeWidget(widget)
  1952.  
  1953.        for n in range(self.blayout.count()):
  1954.            # Get the widget at each index in turn.
  1955.            w = self.blayout.itemAt(n).widget()
  1956.            if self.orientation == Qt.Orientation.Vertical:
  1957.                # Drag drop vertically.
  1958.                drop_here = pos.y() &lt; w.y() + w.size().height() // 2
  1959.            else:
  1960.                # Drag drop horizontally.
  1961.                drop_here = pos.x() &lt; w.x() + w.size().width() // 2
  1962.  
  1963.            if drop_here:
  1964.                break
  1965.  
  1966.        else:
  1967.            # We aren't on the left hand/upper side of any widget,
  1968.            # so we're at the end. Increment 1 to insert after.
  1969.            n += 1
  1970.  
  1971.        self.blayout.insertWidget(n, widget)
  1972.        self.orderChanged.emit(self.get_item_data())
  1973.  
  1974.        e.accept()
  1975.  
  1976.    def add_item(self, item):
  1977.        self.blayout.addWidget(item)
  1978.  
  1979.    def get_item_data(self):
  1980.        data = []
  1981.        for n in range(self.blayout.count()):
  1982.            # Get the widget at each index in turn.
  1983.            w = self.blayout.itemAt(n).widget()
  1984.            data.append(w.data)
  1985.        return data
  1986.  
  1987.  
  1988. class MainWindow(QMainWindow):
  1989.    def __init__(self):
  1990.        super().__init__()
  1991.        self.drag = DragWidget(orientation=Qt.Orientation.Vertical)
  1992.        for n, l in enumerate(["A", "B", "C", "D"]):
  1993.            item = DragItem(l)
  1994.            item.set_data(n)  # Store the data.
  1995.            self.drag.add_item(item)
  1996.  
  1997.        # Print out the changed order.
  1998.        self.drag.orderChanged.connect(print)
  1999.  
  2000.        container = QWidget()
  2001.        layout = QVBoxLayout()
  2002.        layout.addStretch(1)
  2003.        layout.addWidget(self.drag)
  2004.        layout.addStretch(1)
  2005.        container.setLayout(layout)
  2006.  
  2007.        self.setCentralWidget(container)
  2008.  
  2009.  
  2010. app = QApplication([])
  2011. w = MainWindow()
  2012. w.show()
  2013.  
  2014. app.exec()
  2015.  
  2016. &lt;/code&gt;
  2017. &lt;/pre&gt;&lt;/div&gt;
  2018. &lt;p&gt;&lt;img alt="Generic drag drop horizontal" height="139" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-generic-horizontal.png" width="306"&gt; &lt;em&gt;Generic drag-drop sorting in horizontal orientation.&lt;/em&gt;&lt;/p&gt;
  2019. &lt;p&gt;You'll notice that when creating the item, you can set the label by passing it in as a parameter (just like for a normal &lt;code&gt;QLabel&lt;/code&gt; which we've subclassed from). But you can also set a data value, which is the internal value of this item -- this is what will be emitted when the order changes, or if you call &lt;code&gt;get_item_data&lt;/code&gt; yourself. This separates the visual representation from what is actually being sorted, meaning you can use this to sort &lt;em&gt;anything&lt;/em&gt; not just strings.&lt;/p&gt;
  2020. &lt;p&gt;In the example above we're passing in the enumerated index as the data, so dragging will output (via the &lt;code&gt;print&lt;/code&gt; connected to &lt;code&gt;orderChanged&lt;/code&gt;) something like:&lt;/p&gt;
  2021. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2022. &lt;pre&gt;
  2023. &lt;code class="python"&gt;[1, 0, 2, 3]
  2024. [1, 2, 0, 3]
  2025. [1, 0, 2, 3]
  2026. [1, 2, 0, 3]
  2027. &lt;/code&gt;
  2028. &lt;/pre&gt;&lt;/div&gt;
  2029. &lt;p&gt;If you remove the &lt;code&gt;item.set_data(n)&lt;/code&gt; you'll see the labels emitted on changes.&lt;/p&gt;
  2030. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2031. &lt;pre&gt;
  2032. &lt;code class="python"&gt;['B', 'A', 'C', 'D']
  2033. ['B', 'C', 'A', 'D']
  2034. &lt;/code&gt;
  2035. &lt;/pre&gt;&lt;/div&gt;
  2036. &lt;p&gt;We've also implemented &lt;em&gt;orientation&lt;/em&gt; onto the &lt;code&gt;DragWidget&lt;/code&gt; using the Qt built in flags &lt;code&gt;Qt.Orientation.Vertical&lt;/code&gt; or &lt;code&gt;Qt.Orientation.Horizontal&lt;/code&gt;. This setting this allows you sort items either vertically or horizontally -- the calculations are handled for both directions.&lt;/p&gt;
  2037. &lt;p&gt;&lt;img alt="Generic drag drop vertical" height="216" src="https://www.pythonguis.com/static/faq/drag-drop-widgets/drag-generic-vertical.png" width="202"&gt; &lt;em&gt;Generic drag-drop sorting in vertical orientation.&lt;/em&gt;&lt;/p&gt;
  2038. &lt;h2 id="adding-a-visual-drop-target"&gt;Adding a Visual Drop Target&lt;/h2&gt;
  2039. &lt;p&gt;If you experiment with the drag-drop tool above you'll notice that it doesn't feel completely intuitive. When dragging you don't know where an item will be inserted until you drop it. If it ends up in the wrong place, you'll then need to pick it up and re-drop it again, using &lt;em&gt;guesswork&lt;/em&gt; to get it right.&lt;/p&gt;
  2040. &lt;p&gt;With a bit of practice you can get the hang of it, but it would be nicer to make the behavior immediately obvious for users. Many drag-drop interfaces solve this problem by showing a preview of where the item will be dropped while dragging -- either by showing the item in the place where it will be dropped, or showing some kind of placeholder.&lt;/p&gt;
  2041. &lt;p&gt;In this final section we'll implement this type of drag and drop preview indicator.&lt;/p&gt;
  2042. &lt;p&gt;The first step is to define our target indicator. This is just another label, which in our example is empty, with custom styles applied to make it have a solid "shadow" like background. This makes it obviously different to the items in the list, so it stands out as something distinct.&lt;/p&gt;
  2043. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2044. &lt;pre&gt;
  2045. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt, pyqtSignal
  2046. from PyQt6.QtGui import QDrag, QPixmap
  2047. from PyQt6.QtWidgets import (
  2048.    QApplication,
  2049.    QHBoxLayout,
  2050.    QLabel,
  2051.    QMainWindow,
  2052.    QVBoxLayout,
  2053.    QWidget,
  2054. )
  2055.  
  2056.  
  2057. class DragTargetIndicator(QLabel):
  2058.    def __init__(self, parent=None):
  2059.        super().__init__(parent)
  2060.        self.setContentsMargins(25, 5, 25, 5)
  2061.        self.setStyleSheet(
  2062.            "QLabel { background-color: #ccc; border: 1px solid black; }"
  2063.        )
  2064.  
  2065.  
  2066. &lt;/code&gt;
  2067. &lt;/pre&gt;&lt;/div&gt;
  2068. &lt;p class="admonition admonition-tip"&gt;We've copied the contents margins from the items in the list. If you change your list items, remember to also update the indicator dimensions to match.&lt;/p&gt;
  2069. &lt;p&gt;The drag item is unchanged, but we need to implement some additional behavior on our &lt;code&gt;DragWidget&lt;/code&gt; to add the target, control showing and moving it.&lt;/p&gt;
  2070. &lt;p&gt;First we'll add the drag target indicator to the layout on our &lt;code&gt;DragWidget&lt;/code&gt;. This is hidden to begin with, but will be shown during the drag.&lt;/p&gt;
  2071. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2072. &lt;pre&gt;
  2073. &lt;code class="python"&gt;class DragWidget(QWidget):
  2074.    """
  2075.    Generic list sorting handler.
  2076.    """
  2077.  
  2078.    orderChanged = pyqtSignal(list)
  2079.  
  2080.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  2081.        super().__init__()
  2082.        self.setAcceptDrops(True)
  2083.  
  2084.        # Store the orientation for drag checks later.
  2085.        self.orientation = orientation
  2086.  
  2087.        if self.orientation == Qt.Orientation.Vertical:
  2088.            self.blayout = QVBoxLayout()
  2089.        else:
  2090.            self.blayout = QHBoxLayout()
  2091.  
  2092.        # Add the drag target indicator. This is invisible by default,
  2093.        # we show it and move it around while the drag is active.
  2094.        self._drag_target_indicator = DragTargetIndicator()
  2095.        self.blayout.addWidget(self._drag_target_indicator)
  2096.        self._drag_target_indicator.hide()
  2097.  
  2098.        self.setLayout(self.blayout)
  2099. &lt;/code&gt;
  2100. &lt;/pre&gt;&lt;/div&gt;
  2101. &lt;p&gt;Next we modify the &lt;code&gt;DragWidget.dragMoveEvent&lt;/code&gt; to show the drag target indicator. We show it by &lt;em&gt;inserting&lt;/em&gt; it into the layout and then calling &lt;code&gt;.show&lt;/code&gt; -- inserting a widget which is already in a layout will move it. We also hide the original item which is being dragged.&lt;/p&gt;
  2102. &lt;p&gt;In the earlier examples we determined the position on drop by removing the widget being dragged, and then iterating over what is left. Because we now need to calculate the drop location before the drop, we take a different approach.&lt;/p&gt;
  2103. &lt;p class="admonition admonition-tip"&gt;If we wanted to do it the same way, we'd need to remove the item on drag start, hold onto it and implement re-inserting at it's old position on drag fail. That's a lot of work.&lt;/p&gt;
  2104. &lt;p&gt;Instead, the dragged item is left in place and hidden during move.&lt;/p&gt;
  2105. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2106. &lt;pre&gt;
  2107. &lt;code class="python"&gt;    def dragMoveEvent(self, e):
  2108.        # Find the correct location of the drop target, so we can move it there.
  2109.        index = self._find_drop_location(e)
  2110.        if index is not None:
  2111.            # Inserting moves the item if its alreaady in the layout.
  2112.            self.blayout.insertWidget(index, self._drag_target_indicator)
  2113.            # Hide the item being dragged.
  2114.            e.source().hide()
  2115.            # Show the target.
  2116.            self._drag_target_indicator.show()
  2117.        e.accept()
  2118.  
  2119. &lt;/code&gt;
  2120. &lt;/pre&gt;&lt;/div&gt;
  2121. &lt;p&gt;The method &lt;code&gt;self._find_drop_location&lt;/code&gt; finds the index where the drag target will be shown (or the item dropped when the mouse released). We'll implement that next.&lt;/p&gt;
  2122. &lt;p&gt;The calculation of the drop location follows the same pattern as before. We iterate over the items in the layout and calculate whether our mouse drop location is to the left of each widget. If it isn't to the left of any widget, we drop on the far right.&lt;/p&gt;
  2123. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2124. &lt;pre&gt;
  2125. &lt;code class="python"&gt;    def _find_drop_location(self, e):
  2126.        pos = e.position()
  2127.        spacing = self.blayout.spacing() / 2
  2128.  
  2129.        for n in range(self.blayout.count()):
  2130.            # Get the widget at each index in turn.
  2131.            w = self.blayout.itemAt(n).widget()
  2132.  
  2133.            if self.orientation == Qt.Orientation.Vertical:
  2134.                # Drag drop vertically.
  2135.                drop_here = (
  2136.                    pos.y() &gt;= w.y() - spacing
  2137.                    and pos.y() &lt;= w.y() + w.size().height() + spacing
  2138.                )
  2139.            else:
  2140.                # Drag drop horizontally.
  2141.                drop_here = (
  2142.                    pos.x() &gt;= w.x() - spacing
  2143.                    and pos.x() &lt;= w.x() + w.size().width() + spacing
  2144.                )
  2145.  
  2146.            if drop_here:
  2147.                # Drop over this target.
  2148.                break
  2149.  
  2150.        return n
  2151. &lt;/code&gt;
  2152. &lt;/pre&gt;&lt;/div&gt;
  2153. &lt;p&gt;The drop location &lt;code&gt;n&lt;/code&gt; is returned for use in the &lt;code&gt;dragMoveEvent&lt;/code&gt; to place the drop target indicator.&lt;/p&gt;
  2154. &lt;p&gt;Next wee need to update the &lt;code&gt;get_item_data&lt;/code&gt; handler to ignore the drop target indicator. To do this we check &lt;code&gt;w&lt;/code&gt; against &lt;code&gt;self._drag_target_indicator&lt;/code&gt; and skip if it is the same. With this change the method will work as expected.&lt;/p&gt;
  2155. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2156. &lt;pre&gt;
  2157. &lt;code class="python"&gt;    def get_item_data(self):
  2158.        data = []
  2159.        for n in range(self.blayout.count()):
  2160.            # Get the widget at each index in turn.
  2161.            w = self.blayout.itemAt(n).widget()
  2162.            if w != self._drag_target_indicator:
  2163.                # The target indicator has no data.
  2164.                data.append(w.data)
  2165.        return data
  2166.  
  2167. &lt;/code&gt;
  2168. &lt;/pre&gt;&lt;/div&gt;
  2169. &lt;p&gt;If you run the code a this point the drag behavior will work as expected. But if you drag the widget outside of the window and drop you'll notice a problem: the target indicator will stay in place, but dropping the item won't drop the item in that position (the drop will be cancelled).&lt;/p&gt;
  2170. &lt;p&gt;To fix that we need to implement a &lt;code&gt;dragLeaveEvent&lt;/code&gt; which hides the indicator.&lt;/p&gt;
  2171. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2172. &lt;pre&gt;
  2173. &lt;code class="python"&gt;    def dragLeaveEvent(self, e):
  2174.        self._drag_target_indicator.hide()
  2175.        e.accept()
  2176. &lt;/code&gt;
  2177. &lt;/pre&gt;&lt;/div&gt;
  2178. &lt;p&gt;With those changes, the drag-drop behavior should be working as intended. The complete code is shown below.&lt;/p&gt;
  2179. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2180. &lt;pre&gt;
  2181. &lt;code class="python"&gt;from PyQt6.QtCore import QMimeData, Qt, pyqtSignal
  2182. from PyQt6.QtGui import QDrag, QPixmap
  2183. from PyQt6.QtWidgets import (
  2184.    QApplication,
  2185.    QHBoxLayout,
  2186.    QLabel,
  2187.    QMainWindow,
  2188.    QVBoxLayout,
  2189.    QWidget,
  2190. )
  2191.  
  2192.  
  2193. class DragTargetIndicator(QLabel):
  2194.    def __init__(self, parent=None):
  2195.        super().__init__(parent)
  2196.        self.setContentsMargins(25, 5, 25, 5)
  2197.        self.setStyleSheet(
  2198.            "QLabel { background-color: #ccc; border: 1px solid black; }"
  2199.        )
  2200.  
  2201.  
  2202. class DragItem(QLabel):
  2203.    def __init__(self, *args, **kwargs):
  2204.        super().__init__(*args, **kwargs)
  2205.        self.setContentsMargins(25, 5, 25, 5)
  2206.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  2207.        self.setStyleSheet("border: 1px solid black;")
  2208.        # Store data separately from display label, but use label for default.
  2209.        self.data = self.text()
  2210.  
  2211.    def set_data(self, data):
  2212.        self.data = data
  2213.  
  2214.    def mouseMoveEvent(self, e):
  2215.        if e.buttons() == Qt.MouseButton.LeftButton:
  2216.            drag = QDrag(self)
  2217.            mime = QMimeData()
  2218.            drag.setMimeData(mime)
  2219.  
  2220.            pixmap = QPixmap(self.size())
  2221.            self.render(pixmap)
  2222.            drag.setPixmap(pixmap)
  2223.  
  2224.            drag.exec(Qt.DropAction.MoveAction)
  2225.            self.show() # Show this widget again, if it's dropped outside.
  2226.  
  2227.  
  2228. class DragWidget(QWidget):
  2229.    """
  2230.    Generic list sorting handler.
  2231.    """
  2232.  
  2233.    orderChanged = pyqtSignal(list)
  2234.  
  2235.    def __init__(self, *args, orientation=Qt.Orientation.Vertical, **kwargs):
  2236.        super().__init__()
  2237.        self.setAcceptDrops(True)
  2238.  
  2239.        # Store the orientation for drag checks later.
  2240.        self.orientation = orientation
  2241.  
  2242.        if self.orientation == Qt.Orientation.Vertical:
  2243.            self.blayout = QVBoxLayout()
  2244.        else:
  2245.            self.blayout = QHBoxLayout()
  2246.  
  2247.        # Add the drag target indicator. This is invisible by default,
  2248.        # we show it and move it around while the drag is active.
  2249.        self._drag_target_indicator = DragTargetIndicator()
  2250.        self.blayout.addWidget(self._drag_target_indicator)
  2251.        self._drag_target_indicator.hide()
  2252.  
  2253.        self.setLayout(self.blayout)
  2254.  
  2255.    def dragEnterEvent(self, e):
  2256.        e.accept()
  2257.  
  2258.    def dragLeaveEvent(self, e):
  2259.        self._drag_target_indicator.hide()
  2260.        e.accept()
  2261.  
  2262.    def dragMoveEvent(self, e):
  2263.        # Find the correct location of the drop target, so we can move it there.
  2264.        index = self._find_drop_location(e)
  2265.        if index is not None:
  2266.            # Inserting moves the item if its alreaady in the layout.
  2267.            self.blayout.insertWidget(index, self._drag_target_indicator)
  2268.            # Hide the item being dragged.
  2269.            e.source().hide()
  2270.            # Show the target.
  2271.            self._drag_target_indicator.show()
  2272.        e.accept()
  2273.  
  2274.    def dropEvent(self, e):
  2275.        widget = e.source()
  2276.        # Use drop target location for destination, then remove it.
  2277.        self._drag_target_indicator.hide()
  2278.        index = self.blayout.indexOf(self._drag_target_indicator)
  2279.        if index is not None:
  2280.            self.blayout.insertWidget(index, widget)
  2281.            self.orderChanged.emit(self.get_item_data())
  2282.            widget.show()
  2283.            self.blayout.activate()
  2284.        e.accept()
  2285.  
  2286.    def _find_drop_location(self, e):
  2287.        pos = e.position()
  2288.        spacing = self.blayout.spacing() / 2
  2289.  
  2290.        for n in range(self.blayout.count()):
  2291.            # Get the widget at each index in turn.
  2292.            w = self.blayout.itemAt(n).widget()
  2293.  
  2294.            if self.orientation == Qt.Orientation.Vertical:
  2295.                # Drag drop vertically.
  2296.                drop_here = (
  2297.                    pos.y() &gt;= w.y() - spacing
  2298.                    and pos.y() &lt;= w.y() + w.size().height() + spacing
  2299.                )
  2300.            else:
  2301.                # Drag drop horizontally.
  2302.                drop_here = (
  2303.                    pos.x() &gt;= w.x() - spacing
  2304.                    and pos.x() &lt;= w.x() + w.size().width() + spacing
  2305.                )
  2306.  
  2307.            if drop_here:
  2308.                # Drop over this target.
  2309.                break
  2310.  
  2311.        return n
  2312.  
  2313.    def add_item(self, item):
  2314.        self.blayout.addWidget(item)
  2315.  
  2316.    def get_item_data(self):
  2317.        data = []
  2318.        for n in range(self.blayout.count()):
  2319.            # Get the widget at each index in turn.
  2320.            w = self.blayout.itemAt(n).widget()
  2321.            if w != self._drag_target_indicator:
  2322.                # The target indicator has no data.
  2323.                data.append(w.data)
  2324.        return data
  2325.  
  2326.  
  2327. class MainWindow(QMainWindow):
  2328.    def __init__(self):
  2329.        super().__init__()
  2330.        self.drag = DragWidget(orientation=Qt.Orientation.Vertical)
  2331.        for n, l in enumerate(["A", "B", "C", "D"]):
  2332.            item = DragItem(l)
  2333.            item.set_data(n)  # Store the data.
  2334.            self.drag.add_item(item)
  2335.  
  2336.        # Print out the changed order.
  2337.        self.drag.orderChanged.connect(print)
  2338.  
  2339.        container = QWidget()
  2340.        layout = QVBoxLayout()
  2341.        layout.addStretch(1)
  2342.        layout.addWidget(self.drag)
  2343.        layout.addStretch(1)
  2344.        container.setLayout(layout)
  2345.  
  2346.        self.setCentralWidget(container)
  2347.  
  2348.  
  2349. app = QApplication([])
  2350. w = MainWindow()
  2351. w.show()
  2352.  
  2353. app.exec()
  2354.  
  2355. &lt;/code&gt;
  2356. &lt;/pre&gt;&lt;/div&gt;
  2357. &lt;p&gt;If you run this example on macOS you may notice that the widget drag preview (the &lt;code&gt;QPixmap&lt;/code&gt; created on &lt;code&gt;DragItem&lt;/code&gt;) is a bit blurry. On high-resolution screens you need to set the &lt;em&gt;device pixel ratio&lt;/em&gt; and scale up the pixmap when you create it. Below is a modified &lt;code&gt;DragItem&lt;/code&gt; class which does this.&lt;/p&gt;
  2358. &lt;p&gt;Update &lt;code&gt;DragItem&lt;/code&gt; to support high resolution screens.&lt;/p&gt;
  2359. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2360. &lt;pre&gt;
  2361. &lt;code class="python"&gt;class DragItem(QLabel):
  2362.    def __init__(self, *args, **kwargs):
  2363.        super().__init__(*args, **kwargs)
  2364.        self.setContentsMargins(25, 5, 25, 5)
  2365.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  2366.        self.setStyleSheet("border: 1px solid black;")
  2367.        # Store data separately from display label, but use label for default.
  2368.        self.data = self.text()
  2369.  
  2370.    def set_data(self, data):
  2371.        self.data = data
  2372.  
  2373.    def mouseMoveEvent(self, e):
  2374.        if e.buttons() == Qt.MouseButton.LeftButton:
  2375.            drag = QDrag(self)
  2376.            mime = QMimeData()
  2377.            drag.setMimeData(mime)
  2378.  
  2379.            # Render at x2 pixel ratio to avoid blur on Retina screens.
  2380.            pixmap = QPixmap(self.size().width() * 2, self.size().height() * 2)
  2381.            pixmap.setDevicePixelRatio(2)
  2382.            self.render(pixmap)
  2383.            drag.setPixmap(pixmap)
  2384.  
  2385.            drag.exec(Qt.DropAction.MoveAction)
  2386.            self.show() # Show this widget again, if it's dropped outside.
  2387. &lt;/code&gt;
  2388. &lt;/pre&gt;&lt;/div&gt;
  2389. &lt;p&gt;That's it! We've created a generic drag-drop handled which can be added to any projects where you need to be able to reposition items within a list. You should feel free to experiment with the styling of the drag items and targets as this won't affect the behavior.&lt;/p&gt;
  2390. &lt;div style="padding: 79.5% 0 0 0;"&gt;&lt;/div&gt;</description>
  2391.    </item>
  2392.    <item>
  2393.      <guid isPermaLink="false">tag:www.pythonguis.com,2024-02-05:/docs/qlineedit-widget/</guid>
  2394.      <title>Python GUIs - qt: QLineEdit &#x2014; A Simple Text Input Widget</title>
  2395.      <pubDate>Mon, 05 Feb 2024 06:00:00 GMT</pubDate>
  2396.      <link>https://www.pythonguis.com/docs/qlineedit-widget/</link>
  2397.      <description>&lt;p&gt;The &lt;code&gt;QLineEdit&lt;/code&gt; class is a versatile tool for single-line text input. The widget facilitates text manipulation by supporting insertion, deletion, selection, and cut-copy-paste operations natively. You can use line edits when you need to accept text input from your users in a PyQt/PySide application.&lt;/p&gt;
  2398. &lt;p&gt;The widget is highly customizable. You can set it up to include placeholder text, input masks, input validators, and more. It also supports many keyboard shortcuts out of the box and is able to process custom ones. This feature opens an opportunity to enhance user input speed and efficiency.&lt;/p&gt;
  2399. &lt;p&gt;In this article, you will learn the basics of using &lt;code&gt;QLineEdit&lt;/code&gt; by going through its most commonly used features and capabilities.&lt;/p&gt;
  2400. &lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of Contents&lt;/span&gt;
  2401. &lt;ul&gt;
  2402. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#creating-line-edit-widgets-with-qlineedit"&gt;Creating Line Edit Widgets With QLineEdit&lt;/a&gt;
  2403. &lt;ul&gt;
  2404. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#creating-non-editable-line-edits"&gt;Creating Non-Editable Line Edits&lt;/a&gt;&lt;/li&gt;
  2405. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#creating-line-edits-for-passwords"&gt;Creating Line Edits for Passwords&lt;/a&gt;&lt;/li&gt;
  2406. &lt;/ul&gt;
  2407. &lt;/li&gt;
  2408. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#manipulating-the-input-in-a-line-edit"&gt;Manipulating the Input in a Line Edit&lt;/a&gt;&lt;/li&gt;
  2409. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#aligning-and-formatting-the-text-in-a-line-edit"&gt;Aligning and Formatting the Text in a Line Edit&lt;/a&gt;&lt;/li&gt;
  2410. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#connecting-signals-and-slots"&gt;Connecting Signals and Slots&lt;/a&gt;&lt;/li&gt;
  2411. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#validating-input-in-line-edits"&gt;Validating Input in Line Edits&lt;/a&gt;&lt;/li&gt;
  2412. &lt;li&gt;&lt;a href="https://www.pythonguis.com/feeds/qt.tag.atom.xml#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  2413. &lt;/ul&gt;
  2414. &lt;/div&gt;
  2415. &lt;h2 id="creating-line-edit-widgets-with-qlineedit"&gt;Creating Line Edit Widgets With &lt;code&gt;QLineEdit&lt;/code&gt;&lt;/h2&gt;
  2416. &lt;p&gt;A line edit allows the user to enter and edit a single line of plain text with a useful collection of editing functionalities, such as insertion, deletion, selection, cut-copy-paste, and drag-and-drop operations.&lt;/p&gt;
  2417. &lt;p&gt;If you've used &lt;a href="https://www.pythonguis.com/pyqt6/"&gt;PyQt&lt;/a&gt; or &lt;a href="https://www.pythonguis.com/pyside6/"&gt;PySide&lt;/a&gt; to create GUI applications in Python, then it'd be likely that you already know about the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html"&gt;&lt;code&gt;QLineEdit&lt;/code&gt;&lt;/a&gt; class. This class allows you to create line edits in your graphical interfaces (GUI) quickly.&lt;/p&gt;
  2418. &lt;p&gt;The &lt;code&gt;QLineEidt&lt;/code&gt; class provides two different constructors that you can use to create line edits according to your needs:&lt;/p&gt;
  2419. &lt;table&gt;
  2420. &lt;thead&gt;
  2421. &lt;tr&gt;
  2422. &lt;th&gt;Constructor&lt;/th&gt;
  2423. &lt;th&gt;Description&lt;/th&gt;
  2424. &lt;/tr&gt;
  2425. &lt;/thead&gt;
  2426. &lt;tbody&gt;
  2427. &lt;tr&gt;
  2428. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#QLineEdit"&gt;&lt;code&gt;QLineEdit(parent: QWidget = None)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2429. &lt;td&gt;Constructs a line edit with a parent widget but without text&lt;/td&gt;
  2430. &lt;/tr&gt;
  2431. &lt;tr&gt;
  2432. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#QLineEdit-1"&gt;&lt;code&gt;QLineEdit(text: str, parent: QWidget = None)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2433. &lt;td&gt;Constructs a line edit with default text and a parent widget&lt;/td&gt;
  2434. &lt;/tr&gt;
  2435. &lt;/tbody&gt;
  2436. &lt;/table&gt;
  2437. &lt;p&gt;The parent widget would be the window or dialog where you need to place the line edit. The text can be a default text that will appear in the line edit when you run the application.&lt;/p&gt;
  2438. &lt;p&gt;To illustrate how to use the above constructors, we can code a demo example:&lt;/p&gt;
  2439. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2440. &lt;pre&gt;
  2441. &lt;code class="python"&gt;from PyQt6.QtWidgets import QApplication, QLineEdit, QVBoxLayout, QWidget
  2442.  
  2443. class Window(QWidget):
  2444.    def __init__(self, parent=None):
  2445.        super().__init__(parent)
  2446.        self.setWindowTitle("QLineEdit Constructors")
  2447.        self.resize(300, 100)
  2448.        # Line edit with a parent widget
  2449.        top_line_edit = QLineEdit(parent=self)
  2450.        # Line edit with a parent widget and a default text
  2451.        bottom_line_edit = QLineEdit(
  2452.            "Hello! This is a line edit.", parent=self
  2453.        )
  2454.  
  2455.        layout = QVBoxLayout()
  2456.        layout.addWidget(top_line_edit)
  2457.        layout.addWidget(bottom_line_edit)
  2458.        self.setLayout(layout)
  2459.  
  2460. app = QApplication([])
  2461. window = Window()
  2462. window.show()
  2463. app.exec()
  2464. &lt;/code&gt;
  2465. &lt;/pre&gt;&lt;/div&gt;
  2466. &lt;p&gt;In this example, we first do the required imports and then define the &lt;code&gt;Window&lt;/code&gt; class inheriting from &lt;code&gt;QWidget&lt;/code&gt;. Inside &lt;code&gt;Window&lt;/code&gt;, we create two &lt;code&gt;QLineEdit&lt;/code&gt; widgets.&lt;/p&gt;
  2467. &lt;p&gt;To create the first line edit, we use the first constructor of &lt;code&gt;QLineEdit&lt;/code&gt;, passing only a &lt;code&gt;parent&lt;/code&gt; widget. For the second line editor, we use the second constructor, which requires the parent widget and a default text. Note that the text is a regular Python string.&lt;/p&gt;
  2468. &lt;p&gt;Save the code to a file called &lt;code&gt;constructors.py&lt;/code&gt; file and run it from your command line. You'll get a window that looks something like this:&lt;/p&gt;
  2469. &lt;p&gt;&lt;img alt="QLineEdit constructors example" height="256" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-constructors.png" width="600"&gt; &lt;em&gt;Standard window showing our two line edits.&lt;/em&gt;&lt;/p&gt;
  2470. &lt;p&gt;The first line edit has no text. In most cases, this is how you would create your line edits because they're designed for accepting input. If you'd like to just display some text, then you can use a &lt;code&gt;QLabel&lt;/code&gt; widget instead. The second line edit displays the text that you passed to the constructor.&lt;/p&gt;
  2471. &lt;p&gt;Both line edits are ready for accepting input text. Note that you can use all the following keyboard shortcuts to optimize your text input process:&lt;/p&gt;
  2472. &lt;table&gt;
  2473. &lt;thead&gt;
  2474. &lt;tr&gt;
  2475. &lt;th align="left"&gt;Keys&lt;/th&gt;
  2476. &lt;th align="left"&gt;Action&lt;/th&gt;
  2477. &lt;/tr&gt;
  2478. &lt;/thead&gt;
  2479. &lt;tbody&gt;
  2480. &lt;tr&gt;
  2481. &lt;td align="left"&gt;Left Arrow&lt;/td&gt;
  2482. &lt;td align="left"&gt;Moves the cursor one character to the left&lt;/td&gt;
  2483. &lt;/tr&gt;
  2484. &lt;tr&gt;
  2485. &lt;td align="left"&gt;Shift+Left Arrow&lt;/td&gt;
  2486. &lt;td align="left"&gt;Moves and selects text one character to the left&lt;/td&gt;
  2487. &lt;/tr&gt;
  2488. &lt;tr&gt;
  2489. &lt;td align="left"&gt;Right Arrow&lt;/td&gt;
  2490. &lt;td align="left"&gt;Moves the cursor one character to the right&lt;/td&gt;
  2491. &lt;/tr&gt;
  2492. &lt;tr&gt;
  2493. &lt;td align="left"&gt;Shift+Right Arrow&lt;/td&gt;
  2494. &lt;td align="left"&gt;Moves and selects text one character to the right&lt;/td&gt;
  2495. &lt;/tr&gt;
  2496. &lt;tr&gt;
  2497. &lt;td align="left"&gt;Home&lt;/td&gt;
  2498. &lt;td align="left"&gt;Moves the cursor to the beginning of the line&lt;/td&gt;
  2499. &lt;/tr&gt;
  2500. &lt;tr&gt;
  2501. &lt;td align="left"&gt;End&lt;/td&gt;
  2502. &lt;td align="left"&gt;Moves the cursor to the end of the line&lt;/td&gt;
  2503. &lt;/tr&gt;
  2504. &lt;tr&gt;
  2505. &lt;td align="left"&gt;Backspace&lt;/td&gt;
  2506. &lt;td align="left"&gt;Deletes the character to the left of the cursor&lt;/td&gt;
  2507. &lt;/tr&gt;
  2508. &lt;tr&gt;
  2509. &lt;td align="left"&gt;Ctrl+Backspace&lt;/td&gt;
  2510. &lt;td align="left"&gt;Deletes the word to the left of the cursor&lt;/td&gt;
  2511. &lt;/tr&gt;
  2512. &lt;tr&gt;
  2513. &lt;td align="left"&gt;Delete&lt;/td&gt;
  2514. &lt;td align="left"&gt;Deletes the character to the right of the cursor&lt;/td&gt;
  2515. &lt;/tr&gt;
  2516. &lt;tr&gt;
  2517. &lt;td align="left"&gt;Ctrl+Delete&lt;/td&gt;
  2518. &lt;td align="left"&gt;Deletes the word to the right of the cursor&lt;/td&gt;
  2519. &lt;/tr&gt;
  2520. &lt;tr&gt;
  2521. &lt;td align="left"&gt;Ctrl+A&lt;/td&gt;
  2522. &lt;td align="left"&gt;Select all&lt;/td&gt;
  2523. &lt;/tr&gt;
  2524. &lt;tr&gt;
  2525. &lt;td align="left"&gt;Ctrl+C&lt;/td&gt;
  2526. &lt;td align="left"&gt;Copies the selected text to the clipboard&lt;/td&gt;
  2527. &lt;/tr&gt;
  2528. &lt;tr&gt;
  2529. &lt;td align="left"&gt;Ctrl+Insert&lt;/td&gt;
  2530. &lt;td align="left"&gt;Copies the selected text to the clipboard&lt;/td&gt;
  2531. &lt;/tr&gt;
  2532. &lt;tr&gt;
  2533. &lt;td align="left"&gt;Ctrl+K&lt;/td&gt;
  2534. &lt;td align="left"&gt;Deletes to the end of the line&lt;/td&gt;
  2535. &lt;/tr&gt;
  2536. &lt;tr&gt;
  2537. &lt;td align="left"&gt;Ctrl+V&lt;/td&gt;
  2538. &lt;td align="left"&gt;Pastes the clipboard text into the line edit&lt;/td&gt;
  2539. &lt;/tr&gt;
  2540. &lt;tr&gt;
  2541. &lt;td align="left"&gt;Shift+Insert&lt;/td&gt;
  2542. &lt;td align="left"&gt;Pastes the clipboard text into the line edit&lt;/td&gt;
  2543. &lt;/tr&gt;
  2544. &lt;tr&gt;
  2545. &lt;td align="left"&gt;Ctrl+X&lt;/td&gt;
  2546. &lt;td align="left"&gt;Deletes the selected text and copies it to the clipboard&lt;/td&gt;
  2547. &lt;/tr&gt;
  2548. &lt;tr&gt;
  2549. &lt;td align="left"&gt;Shift+Delete&lt;/td&gt;
  2550. &lt;td align="left"&gt;Deletes the selected text and copies it to the clipboard&lt;/td&gt;
  2551. &lt;/tr&gt;
  2552. &lt;tr&gt;
  2553. &lt;td align="left"&gt;Ctrl+Z&lt;/td&gt;
  2554. &lt;td align="left"&gt;Undoes the last operation&lt;/td&gt;
  2555. &lt;/tr&gt;
  2556. &lt;tr&gt;
  2557. &lt;td align="left"&gt;Ctrl+Y&lt;/td&gt;
  2558. &lt;td align="left"&gt;Redoes the last undone operation&lt;/td&gt;
  2559. &lt;/tr&gt;
  2560. &lt;/tbody&gt;
  2561. &lt;/table&gt;
  2562. &lt;p&gt;That's a lot of shortcuts! This table is just a sample of all the features that the &lt;code&gt;QLineEdit&lt;/code&gt; class provides out of the box.&lt;/p&gt;
  2563. &lt;p&gt;In addition to these keyboard shortcuts, the &lt;code&gt;QLineEdit&lt;/code&gt; class provides a context menu that you can trigger by clicking on a line edit using the right button of your mouse:&lt;/p&gt;
  2564. &lt;p&gt;&lt;img alt="QLineEdit context menu" height="592" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-context-menu.png" width="662"&gt; &lt;em&gt;QLineEdit with a context menu visible.&lt;/em&gt;&lt;/p&gt;
  2565. &lt;p&gt;The built-in context menu provides basic edition options, such as cut, copy, paste, and delete. It also has options for undoing and redoing edits, and for selecting all the content of a given line edit.&lt;/p&gt;
  2566. &lt;h3 id="creating-non-editable-line-edits"&gt;Creating Non-Editable Line Edits&lt;/h3&gt;
  2567. &lt;p&gt;Sometimes, we need to make a line edit non-editable. By default, all line edits are editable because their main use case is to provide text input for the user. However, in some situations, a non-editable line edit can be useful.&lt;/p&gt;
  2568. &lt;p&gt;For example, say that you're creating a GUI application that generates some recovery keys for the users. The user must be able to copy the key to a safe place so that they can use it to recover access if they forget their password. In this situation, creating a non-editable line edit can provide a suitable solution.&lt;/p&gt;
  2569. &lt;p&gt;To make a line edit read-only, we can use the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#readOnly-prop"&gt;&lt;code&gt;readOnly&lt;/code&gt;&lt;/a&gt; property and its setter method &lt;code&gt;setReadOnly()&lt;/code&gt; as in the following example:&lt;/p&gt;
  2570. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2571. &lt;pre&gt;
  2572. &lt;code class="python"&gt;import secrets
  2573.  
  2574. from PyQt6.QtWidgets import (
  2575.    QApplication,
  2576.    QLabel,
  2577.    QLineEdit,
  2578.    QVBoxLayout,
  2579.    QWidget,
  2580. )
  2581.  
  2582. class Window(QWidget):
  2583.    def __init__(self, parent=None):
  2584.        super().__init__(parent)
  2585.        self.setWindowTitle("Non-editable QLineEdit")
  2586.        self.resize(300, 100)
  2587.        non_editable_line_edit = QLineEdit(parent=self)
  2588.        non_editable_line_edit.setReadOnly(True)
  2589.        non_editable_line_edit.setText(secrets.token_hex(16))
  2590.  
  2591.        layout = QVBoxLayout()
  2592.        layout.addWidget(QLabel(parent=self, text="Your secret key:"))
  2593.        layout.addWidget(non_editable_line_edit)
  2594.        self.setLayout(layout)
  2595.  
  2596. app = QApplication([])
  2597. window = Window()
  2598. window.show()
  2599. app.exec()
  2600. &lt;/code&gt;
  2601. &lt;/pre&gt;&lt;/div&gt;
  2602. &lt;p&gt;In this example, we create a non-editable line edit by using the &lt;code&gt;setReadOnly()&lt;/code&gt; method. When we set the &lt;code&gt;readOnly&lt;/code&gt; property to &lt;code&gt;True&lt;/code&gt;, our line edit won't accept editions. It'll only allow us to select and copy its content.&lt;/p&gt;
  2603. &lt;p&gt;Go ahead and run the application from your command line to explore how this line edit works. You'll get a window like the following:&lt;/p&gt;
  2604. &lt;p&gt;&lt;img alt="Non-editable line edit" height="424" src="https://www.pythonguis.com/static/docs/qlineedit/non-editable-lineedit.png" width="662"&gt; &lt;em&gt;A read-only line edit with editing disabled.&lt;/em&gt;&lt;/p&gt;
  2605. &lt;p&gt;If you play a bit with this line edit, you'll soon discover that you can't change its text. You'll also note that the options in the context menu are now limited to &lt;em&gt;Copy&lt;/em&gt; and &lt;em&gt;Select All&lt;/em&gt;.&lt;/p&gt;
  2606. &lt;h3 id="creating-line-edits-for-passwords"&gt;Creating Line Edits for Passwords&lt;/h3&gt;
  2607. &lt;p&gt;Another cool feature of the &lt;code&gt;QLineEdit&lt;/code&gt; class is that it allows you to create text input for passwords. This can be pretty convenient for those applications that manage several users, and each user needs to have access credentials.&lt;/p&gt;
  2608. &lt;p&gt;You can create line edits for passwords by using the &lt;a href="https://www.riverbankcomputing.com/static/Docs/PyQt6/api/qtwidgets/qlineedit.html#echoMode"&gt;&lt;code&gt;echoMode()&lt;/code&gt;&lt;/a&gt; method. This method takes one of the following constants as an argument:&lt;/p&gt;
  2609. &lt;table&gt;
  2610. &lt;thead&gt;
  2611. &lt;tr&gt;
  2612. &lt;th&gt;Constant&lt;/th&gt;
  2613. &lt;th&gt;Value&lt;/th&gt;
  2614. &lt;th&gt;Description&lt;/th&gt;
  2615. &lt;/tr&gt;
  2616. &lt;/thead&gt;
  2617. &lt;tbody&gt;
  2618. &lt;tr&gt;
  2619. &lt;td&gt;&lt;code&gt;QLineEdit.EchoMode.Normal&lt;/code&gt;&lt;/td&gt;
  2620. &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
  2621. &lt;td&gt;Display characters as you enter them.&lt;/td&gt;
  2622. &lt;/tr&gt;
  2623. &lt;tr&gt;
  2624. &lt;td&gt;&lt;code&gt;QLineEdit.EchoMode.NoEcho&lt;/code&gt;&lt;/td&gt;
  2625. &lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
  2626. &lt;td&gt;Display no characters when you enter them.&lt;/td&gt;
  2627. &lt;/tr&gt;
  2628. &lt;tr&gt;
  2629. &lt;td&gt;&lt;code&gt;QLineEdit.EchoMode.Password&lt;/code&gt;&lt;/td&gt;
  2630. &lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
  2631. &lt;td&gt;Display platform-dependent password mask characters instead of the characters you enter.&lt;/td&gt;
  2632. &lt;/tr&gt;
  2633. &lt;tr&gt;
  2634. &lt;td&gt;&lt;code&gt;QLineEdit.EchoMode.PasswordEchoOnEdit&lt;/code&gt;&lt;/td&gt;
  2635. &lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
  2636. &lt;td&gt;Display characters as you enter them while editing. Display characters as the &lt;code&gt;Password&lt;/code&gt; mode does when reading.&lt;/td&gt;
  2637. &lt;/tr&gt;
  2638. &lt;/tbody&gt;
  2639. &lt;/table&gt;
  2640. &lt;p&gt;The &lt;code&gt;Normal&lt;/code&gt; mode is the default. The &lt;code&gt;NoEcho&lt;/code&gt; mode may be appropriate for critical passwords where even the length of the password should be kept secret. The &lt;code&gt;Password&lt;/code&gt; mode is appropriate for most password use cases, however &lt;code&gt;PasswordEchoOnEdit&lt;/code&gt; can be used instead if you need to give users some confirmation of what they are typing.&lt;/p&gt;
  2641. &lt;p&gt;Here's a sample app that shows a user and password form:&lt;/p&gt;
  2642. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2643. &lt;pre&gt;
  2644. &lt;code class="python"&gt;from PyQt6.QtWidgets import (
  2645.    QApplication,
  2646.    QFormLayout,
  2647.    QLineEdit,
  2648.    QWidget,
  2649. )
  2650.  
  2651. class Window(QWidget):
  2652.    def __init__(self, parent=None):
  2653.        super().__init__(parent)
  2654.        self.setWindowTitle("Password QLineEdit")
  2655.        self.resize(300, 100)
  2656.        username_line_edit = QLineEdit(parent=self)
  2657.        password_line_edit = QLineEdit(parent=self)
  2658.        password_line_edit.setEchoMode(QLineEdit.EchoMode.Password)
  2659.  
  2660.        layout = QFormLayout()
  2661.        layout.addRow("Username:", username_line_edit)
  2662.        layout.addRow("Password:", password_line_edit)
  2663.        self.setLayout(layout)
  2664.  
  2665. app = QApplication([])
  2666. window = Window()
  2667. window.show()
  2668. app.exec()
  2669. &lt;/code&gt;
  2670. &lt;/pre&gt;&lt;/div&gt;
  2671. &lt;p&gt;In this example, you call &lt;code&gt;setEchoMode()&lt;/code&gt; on the &lt;code&gt;password_line_edit&lt;/code&gt; widget using the &lt;code&gt;Password&lt;/code&gt; mode as an argument. When you run this code from your command line, you get the following window on your screen:&lt;/p&gt;
  2672. &lt;p&gt;&lt;img alt="Password line edit" height="256" src="https://www.pythonguis.com/static/docs/qlineedit/password-qlineedit.png" width="600"&gt; &lt;em&gt;Window with a username and password line edit.&lt;/em&gt;&lt;/p&gt;
  2673. &lt;p&gt;The &lt;code&gt;username_line_edit&lt;/code&gt; line edit is in &lt;code&gt;Normal&lt;/code&gt; mode, so we can see the characters as we type them in. In contrast, the Password line edit is in &lt;code&gt;Password&lt;/code&gt; mode. In this case, when we enter a character, the line edit shows the platform's character for passwords.&lt;/p&gt;
  2674. &lt;h2 id="manipulating-the-input-in-a-line-edit"&gt;Manipulating the Input in a Line Edit&lt;/h2&gt;
  2675. &lt;p&gt;You can change the text of a line edit using the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#text-prop"&gt;&lt;code&gt;setText()&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#insert"&gt;&lt;code&gt;insert()&lt;/code&gt;&lt;/a&gt; methods. You can retrieve the text with the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#text-prop"&gt;&lt;code&gt;text()&lt;/code&gt;&lt;/a&gt; method. However, these are not the only operations that you can perform with the text of a line edit.&lt;/p&gt;
  2676. &lt;p&gt;The following table shows a summary of some of the most commonly used methods for text manipulation in line edits:&lt;/p&gt;
  2677. &lt;table&gt;
  2678. &lt;thead&gt;
  2679. &lt;tr&gt;
  2680. &lt;th&gt;Method&lt;/th&gt;
  2681. &lt;th&gt;Description&lt;/th&gt;
  2682. &lt;/tr&gt;
  2683. &lt;/thead&gt;
  2684. &lt;tbody&gt;
  2685. &lt;tr&gt;
  2686. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#text-prop"&gt;&lt;code&gt;setText(text)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2687. &lt;td&gt;Sets the text of a line edit to &lt;code&gt;text&lt;/code&gt;, clears the selection, clears the undo/redo history, moves the cursor to the end of the line, and resets the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#modified-prop"&gt;modified&lt;/a&gt; property to false.&lt;/td&gt;
  2688. &lt;/tr&gt;
  2689. &lt;tr&gt;
  2690. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#insert"&gt;&lt;code&gt;insert(text)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2691. &lt;td&gt;Deletes any selected text, inserts &lt;code&gt;text&lt;/code&gt;, and validates the result. If it is valid, it sets it as the new contents of the line edit.&lt;/td&gt;
  2692. &lt;/tr&gt;
  2693. &lt;tr&gt;
  2694. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#clear"&gt;&lt;code&gt;clear()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2695. &lt;td&gt;Clears the contents of the line edit.&lt;/td&gt;
  2696. &lt;/tr&gt;
  2697. &lt;tr&gt;
  2698. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#copy"&gt;&lt;code&gt;copy()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2699. &lt;td&gt;Copies the selected text to the clipboard.&lt;/td&gt;
  2700. &lt;/tr&gt;
  2701. &lt;tr&gt;
  2702. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#cut"&gt;&lt;code&gt;cut()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2703. &lt;td&gt;Copies the selected text to the clipboard and deletes it from the line edit.&lt;/td&gt;
  2704. &lt;/tr&gt;
  2705. &lt;tr&gt;
  2706. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#paste"&gt;&lt;code&gt;paste()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2707. &lt;td&gt;Inserts the clipboard's text at the cursor position, deleting any selected text.&lt;/td&gt;
  2708. &lt;/tr&gt;
  2709. &lt;tr&gt;
  2710. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#redo"&gt;&lt;code&gt;redo()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2711. &lt;td&gt;Redoes the last operation if redo is &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#redoAvailable-prop"&gt;available&lt;/a&gt;. Redo becomes available once the user has performed one or more undo operations on text in the line edit.&lt;/td&gt;
  2712. &lt;/tr&gt;
  2713. &lt;tr&gt;
  2714. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#undo"&gt;&lt;code&gt;undo()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2715. &lt;td&gt;Undoes the last operation if undo is &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#undoAvailable-prop"&gt;available&lt;/a&gt;. Undo becomes available once the user has modified the text in the line edit.&lt;/td&gt;
  2716. &lt;/tr&gt;
  2717. &lt;tr&gt;
  2718. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#selectAll"&gt;&lt;code&gt;selectAll()&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2719. &lt;td&gt;Selects all the text and moves the cursor to the end.&lt;/td&gt;
  2720. &lt;/tr&gt;
  2721. &lt;/tbody&gt;
  2722. &lt;/table&gt;
  2723. &lt;p&gt;You can use any of these methods to manipulate the text of a line edit from your code. Consider the following example where you have two line edits and two buttons that take advantage of some of the above methods to copy some text from one line edit to the other:&lt;/p&gt;
  2724. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2725. &lt;pre&gt;
  2726. &lt;code class="python"&gt;from PyQt6.QtWidgets import (
  2727.    QApplication,
  2728.    QGridLayout,
  2729.    QLabel,
  2730.    QLineEdit,
  2731.    QPushButton,
  2732.    QWidget,
  2733. )
  2734.  
  2735. class Window(QWidget):
  2736.    def __init__(self, parent=None):
  2737.        super().__init__(parent)
  2738.        self.setWindowTitle("Copy and Paste")
  2739.        self.resize(300, 100)
  2740.  
  2741.        self.source_line_edit = QLineEdit(parent=self)
  2742.        self.source_line_edit.setText("Hello, World!")
  2743.        self.dest_line_edit = QLineEdit(parent=self)
  2744.  
  2745.        copy_button = QPushButton(parent=self, text="Copy")
  2746.        paste_button = QPushButton(parent=self, text="Paste")
  2747.  
  2748.        copy_button.clicked.connect(self.copy)
  2749.        paste_button.clicked.connect(self.paste)
  2750.  
  2751.        layout = QGridLayout()
  2752.        layout.addWidget(self.source_line_edit, 0, 0)
  2753.        layout.addWidget(copy_button, 0, 1)
  2754.        layout.addWidget(self.dest_line_edit, 1, 0)
  2755.        layout.addWidget(paste_button, 1, 1)
  2756.        self.setLayout(layout)
  2757.  
  2758.    def copy(self):
  2759.        self.source_line_edit.selectAll()
  2760.        self.source_line_edit.copy()
  2761.  
  2762.    def paste(self):
  2763.        self.dest_line_edit.clear()
  2764.        self.dest_line_edit.paste()
  2765.  
  2766. app = QApplication([])
  2767. window = Window()
  2768. window.show()
  2769. app.exec()
  2770. &lt;/code&gt;
  2771. &lt;/pre&gt;&lt;/div&gt;
  2772. &lt;p&gt;In this example, we create two line edits. The first one will hold some sample text. The second line edit will receive the text. Then, we create two buttons and connect their &lt;code&gt;clicked&lt;/code&gt; signals to the &lt;code&gt;copy()&lt;/code&gt; and &lt;code&gt;paste()&lt;/code&gt; slots.&lt;/p&gt;
  2773. &lt;p&gt;Inside the &lt;code&gt;copy()&lt;/code&gt; method we first select all the text from the source line edit. Then we use the &lt;code&gt;copy()&lt;/code&gt; method to copy the selected text to the clipboard. In &lt;code&gt;paste()&lt;/code&gt;, we call &lt;code&gt;clear()&lt;/code&gt; on the destination line edit to remove any previous text. Then, we use the &lt;code&gt;paste()&lt;/code&gt; method to copy the clipboard's content.&lt;/p&gt;
  2774. &lt;p&gt;Go ahead and run the application. You'll get the following window on your screen:&lt;/p&gt;
  2775. &lt;p&gt;&lt;img alt="QLineEdit Copy and Paste" height="256" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-text-manipulation.png" width="600"&gt; &lt;em&gt;QLineEdit with Copy &amp; Paste buttons attached to handlers.&lt;/em&gt;&lt;/p&gt;
  2776. &lt;p&gt;Once you've run the app, then you can click the &lt;em&gt;Copy&lt;/em&gt; button to copy the text in the first line edit. Next, you can click the &lt;em&gt;Paste&lt;/em&gt; button to paste the copied text to the second line edit. Go ahead and give it a try!&lt;/p&gt;
  2777. &lt;h2 id="aligning-and-formatting-the-text-in-a-line-edit"&gt;Aligning and Formatting the Text in a Line Edit&lt;/h2&gt;
  2778. &lt;p&gt;You can also align and format the text in a line edit. For example, for text alignment, you can use the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#alignment-prop"&gt;&lt;code&gt;setAlignment()&lt;/code&gt;&lt;/a&gt; method with one or more alignment flags. Some of the most useful flags that you can find in the &lt;a href="https://doc.qt.io/qt-6/qt.html#AlignmentFlag-enum"&gt;&lt;code&gt;Qt.AlignmentFlag&lt;/code&gt;&lt;/a&gt; namespace includes the following:&lt;/p&gt;
  2779. &lt;table&gt;
  2780. &lt;thead&gt;
  2781. &lt;tr&gt;
  2782. &lt;th&gt;Flag&lt;/th&gt;
  2783. &lt;th&gt;Description&lt;/th&gt;
  2784. &lt;/tr&gt;
  2785. &lt;/thead&gt;
  2786. &lt;tbody&gt;
  2787. &lt;tr&gt;
  2788. &lt;td&gt;&lt;code&gt;AlignLeft&lt;/code&gt;&lt;/td&gt;
  2789. &lt;td&gt;Aligns with the left edge.&lt;/td&gt;
  2790. &lt;/tr&gt;
  2791. &lt;tr&gt;
  2792. &lt;td&gt;&lt;code&gt;AlignRight&lt;/code&gt;&lt;/td&gt;
  2793. &lt;td&gt;Aligns with the right edge.&lt;/td&gt;
  2794. &lt;/tr&gt;
  2795. &lt;tr&gt;
  2796. &lt;td&gt;&lt;code&gt;AlignHCenter&lt;/code&gt;&lt;/td&gt;
  2797. &lt;td&gt;Centers horizontally in the available space.&lt;/td&gt;
  2798. &lt;/tr&gt;
  2799. &lt;tr&gt;
  2800. &lt;td&gt;&lt;code&gt;AlignJustify&lt;/code&gt;&lt;/td&gt;
  2801. &lt;td&gt;Justifies the text in the available space.&lt;/td&gt;
  2802. &lt;/tr&gt;
  2803. &lt;tr&gt;
  2804. &lt;td&gt;&lt;code&gt;AlignTop&lt;/code&gt;&lt;/td&gt;
  2805. &lt;td&gt;Aligns with the top.&lt;/td&gt;
  2806. &lt;/tr&gt;
  2807. &lt;tr&gt;
  2808. &lt;td&gt;&lt;code&gt;AlignBottom&lt;/code&gt;&lt;/td&gt;
  2809. &lt;td&gt;Aligns with the bottom.&lt;/td&gt;
  2810. &lt;/tr&gt;
  2811. &lt;tr&gt;
  2812. &lt;td&gt;&lt;code&gt;AlignVCenter&lt;/code&gt;&lt;/td&gt;
  2813. &lt;td&gt;Centers vertically in the available space.&lt;/td&gt;
  2814. &lt;/tr&gt;
  2815. &lt;tr&gt;
  2816. &lt;td&gt;&lt;code&gt;AlignCenter&lt;/code&gt;&lt;/td&gt;
  2817. &lt;td&gt;Centers in both dimensions.&lt;/td&gt;
  2818. &lt;/tr&gt;
  2819. &lt;/tbody&gt;
  2820. &lt;/table&gt;
  2821. &lt;p&gt;If you want to apply multiple alignment flags to a given line edit, you don't have to call &lt;code&gt;setAlignment()&lt;/code&gt; multiple times. You can just use the bitwise OR operator (&lt;code&gt;|&lt;/code&gt;) to combine them. Consider the following example:&lt;/p&gt;
  2822. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2823. &lt;pre&gt;
  2824. &lt;code class="python"&gt;from PyQt6.QtCore import Qt
  2825. from PyQt6.QtWidgets import QApplication, QLineEdit
  2826.  
  2827. class Window(QLineEdit):
  2828.    def __init__(self, parent=None):
  2829.        super().__init__(parent)
  2830.        self.setWindowTitle("Aligning Text")
  2831.        self.resize(300, 100)
  2832.        self.setText("Hello, World!")
  2833.        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
  2834.  
  2835. app = QApplication([])
  2836. window = Window()
  2837. window.show()
  2838. app.exec()
  2839. &lt;/code&gt;
  2840. &lt;/pre&gt;&lt;/div&gt;
  2841. &lt;p&gt;In this example, we use a &lt;code&gt;QLineEdit&lt;/code&gt; as the only component of our app's GUI. Using the &lt;code&gt;setAlignment()&lt;/code&gt; method, we center the &lt;code&gt;"Hello, World!"&lt;/code&gt; message in both directions, horizontally and vertically. To do this, we use the &lt;code&gt;AlignCenter&lt;/code&gt; flag. Here's what the app looks like:&lt;/p&gt;
  2842. &lt;p&gt;&lt;img alt="QLineEdit text alignment" height="256" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-text-alignment.png" width="600"&gt; &lt;em&gt;QLineEdit with text alignment set.&lt;/em&gt;&lt;/p&gt;
  2843. &lt;p&gt;Go ahead and play with other flags to see their effect on the text alignment. Use the &lt;code&gt;|&lt;/code&gt; bitwise operator to combine several alignment flags.&lt;/p&gt;
  2844. &lt;p&gt;Line edits also have a &lt;code&gt;textMargins&lt;/code&gt; property that you can tweak to customize the text alignment using specific values. To set margin values for your text, you can use the &lt;code&gt;setTextMargins()&lt;/code&gt; method, which has the following signatures:&lt;/p&gt;
  2845. &lt;table&gt;
  2846. &lt;thead&gt;
  2847. &lt;tr&gt;
  2848. &lt;th&gt;Method&lt;/th&gt;
  2849. &lt;th&gt;Description&lt;/th&gt;
  2850. &lt;/tr&gt;
  2851. &lt;/thead&gt;
  2852. &lt;tbody&gt;
  2853. &lt;tr&gt;
  2854. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#setTextMargins"&gt;&lt;code&gt;setTextMargins(left, top, right, bottom)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2855. &lt;td&gt;Sets the margins around the text to have the sizes &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, and &lt;code&gt;bottom&lt;/code&gt;.&lt;/td&gt;
  2856. &lt;/tr&gt;
  2857. &lt;tr&gt;
  2858. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#setTextMargins-1"&gt;&lt;code&gt;setTextMargins(margins)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2859. &lt;td&gt;Sets the &lt;code&gt;margins&lt;/code&gt; around the text using a &lt;a href="https://doc.qt.io/qt-6/qmargins.html"&gt;&lt;code&gt;QMargins&lt;/code&gt;&lt;/a&gt; object.&lt;/td&gt;
  2860. &lt;/tr&gt;
  2861. &lt;/tbody&gt;
  2862. &lt;/table&gt;
  2863. &lt;p&gt;The first signature allows you to provide four integer values as the left, top, right, and bottom margins for the text. The second signature accepts a &lt;code&gt;QMargins&lt;/code&gt; object as an argument. To build this object, you can use four integer values with the same meaning as the &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;, and &lt;code&gt;bottom&lt;/code&gt; arguments in the first signature.&lt;/p&gt;
  2864. &lt;p&gt;Here's an example of how to set custom margins for the text in a line edit:&lt;/p&gt;
  2865. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2866. &lt;pre&gt;
  2867. &lt;code class="python"&gt;from PyQt6.QtWidgets import QApplication, QLineEdit
  2868.  
  2869. class Window(QLineEdit):
  2870.    def __init__(self, parent=None):
  2871.        super().__init__(parent)
  2872.        self.setWindowTitle("Aligning Text")
  2873.        self.resize(300, 100)
  2874.        self.setText("Hello, World!")
  2875.        self.setTextMargins(30, 30, 0, 0)
  2876.  
  2877. app = QApplication([])
  2878. window = Window()
  2879. window.show()
  2880. app.exec()
  2881. &lt;/code&gt;
  2882. &lt;/pre&gt;&lt;/div&gt;
  2883. &lt;p&gt;In this example, you set the left and top margins to custom values. Here's how this app looks when you run it:&lt;/p&gt;
  2884. &lt;p&gt;&lt;img alt="QLineEdit text margins" height="256" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-text-margins.png" width="600"&gt; &lt;em&gt;QLineEdit with text margins added.&lt;/em&gt;&lt;/p&gt;
  2885. &lt;p&gt;Using the &lt;code&gt;setTextMargins()&lt;/code&gt; method, we can place the text in the desired place in a line edit, which may be a requirement in some situations.&lt;/p&gt;
  2886. &lt;h2 id="connecting-signals-and-slots"&gt;Connecting Signals and Slots&lt;/h2&gt;
  2887. &lt;p&gt;When you're creating a GUI application and you need to use line edits, you may need to perform actions when the user enters or modifies the content of the line edit. To do this, you need to connect some of the signals of the line edit to specific slots or functions.&lt;/p&gt;
  2888. &lt;p&gt;Depending on specific user events, the &lt;code&gt;QLineEdit&lt;/code&gt; class can emit several different signals. Here's is a summary of these signals and their corresponding meaning:&lt;/p&gt;
  2889. &lt;table&gt;
  2890. &lt;thead&gt;
  2891. &lt;tr&gt;
  2892. &lt;th&gt;Signal&lt;/th&gt;
  2893. &lt;th&gt;Emitted&lt;/th&gt;
  2894. &lt;/tr&gt;
  2895. &lt;/thead&gt;
  2896. &lt;tbody&gt;
  2897. &lt;tr&gt;
  2898. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#textChanged"&gt;&lt;code&gt;textChanged(text)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2899. &lt;td&gt;Whenever the user changes the text either manually or programmatically. The &lt;code&gt;text&lt;/code&gt; argument is the new text.&lt;/td&gt;
  2900. &lt;/tr&gt;
  2901. &lt;tr&gt;
  2902. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#textEdited"&gt;&lt;code&gt;textEdited(text)&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2903. &lt;td&gt;Whenever the user edits the text manually. The &lt;code&gt;text&lt;/code&gt; argument is the new text.&lt;/td&gt;
  2904. &lt;/tr&gt;
  2905. &lt;tr&gt;
  2906. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#editingFinished"&gt;&lt;code&gt;editingFinished&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2907. &lt;td&gt;When the user presses the &lt;em&gt;Return&lt;/em&gt; or &lt;em&gt;Enter&lt;/em&gt; key, or when the line edit loses focus, and its contents have changed since the last time this signal was emitted.&lt;/td&gt;
  2908. &lt;/tr&gt;
  2909. &lt;tr&gt;
  2910. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#inputRejected"&gt;&lt;code&gt;inputRejected&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2911. &lt;td&gt;When the user presses a key that is an unacceptable input.&lt;/td&gt;
  2912. &lt;/tr&gt;
  2913. &lt;tr&gt;
  2914. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#returnPressed"&gt;&lt;code&gt;returnPressed&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2915. &lt;td&gt;When the user presses the &lt;em&gt;Return&lt;/em&gt; or &lt;em&gt;Enter&lt;/em&gt; key.&lt;/td&gt;
  2916. &lt;/tr&gt;
  2917. &lt;tr&gt;
  2918. &lt;td&gt;&lt;a href="https://doc.qt.io/qt-6/qlineedit.html#selectionChanged"&gt;&lt;code&gt;selectionChanged&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
  2919. &lt;td&gt;When the selection changes.&lt;/td&gt;
  2920. &lt;/tr&gt;
  2921. &lt;/tbody&gt;
  2922. &lt;/table&gt;
  2923. &lt;p&gt;We can connect either of these signals with any slot. A slot is a method or function that performs a concrete action in your application. We can connect a signal and a slot so that the slot gets called when the signal gets emitted. Here's the required syntax to do this:&lt;/p&gt;
  2924. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2925. &lt;pre&gt;
  2926. &lt;code class="python"&gt;line_edit.&lt;signal&gt;.connect(&lt;method&gt;)
  2927. &lt;/code&gt;
  2928. &lt;/pre&gt;&lt;/div&gt;
  2929. &lt;p&gt;In this construct, &lt;code&gt;line_edit&lt;/code&gt; is the &lt;code&gt;QLineEdit&lt;/code&gt; object that we need to connect with a given slot. The &lt;code&gt;&lt;signal&gt;&lt;/code&gt; placeholder can be any of the abovementioned signals. Finally, &lt;code&gt;&lt;method&gt;&lt;/code&gt; represents the target slot or method.&lt;/p&gt;
  2930. &lt;p&gt;Let's write an example that puts this syntax into action. For this example, we'll connect the &lt;code&gt;textEdited&lt;/code&gt; signal with a method that updates the text of a &lt;code&gt;QLabel&lt;/code&gt; to match the text of our line edit:&lt;/p&gt;
  2931. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  2932. &lt;pre&gt;
  2933. &lt;code class="python"&gt;from PyQt6.QtWidgets import (
  2934.    QApplication,
  2935.    QLabel,
  2936.    QLineEdit,
  2937.    QVBoxLayout,
  2938.    QWidget,
  2939. )
  2940.  
  2941. class Window(QWidget):
  2942.    def __init__(self, parent=None):
  2943.        super().__init__(parent)
  2944.        self.setWindowTitle("Signal and Slot")
  2945.        self.resize(300, 100)
  2946.  
  2947.        self.line_edit = QLineEdit(parent=self)
  2948.        self.label = QLabel(parent=self)
  2949.        self.line_edit.textEdited.connect(self.update_label)
  2950.  
  2951.        layout = QVBoxLayout()
  2952.        layout.addWidget(self.line_edit)
  2953.        layout.addWidget(self.label)
  2954.        self.setLayout(layout)
  2955.  
  2956.    def update_label(self):
  2957.        self.label.setText(self.line_edit.text())
  2958.  
  2959. app = QApplication([])
  2960. window = Window()
  2961. window.show()
  2962. app.exec()
  2963. &lt;/code&gt;
  2964. &lt;/pre&gt;&lt;/div&gt;
  2965. &lt;p&gt;In this example, we connect the line edit's &lt;code&gt;textEdited&lt;/code&gt; signal with the &lt;code&gt;update_label()&lt;/code&gt; method, which sets the label's text to match the text we enter in our line edit. Go ahead and run the app. Then, enter some text in the line edit and see what happens with the label at the bottom of the app's window.&lt;/p&gt;
  2966. &lt;h2 id="validating-input-in-line-edits"&gt;Validating Input in Line Edits&lt;/h2&gt;
  2967. &lt;p&gt;We can provide input validators to our line edits using the &lt;a href="https://doc.qt.io/qt-6/qlineedit.html#setValidator"&gt;&lt;code&gt;setValidator()&lt;/code&gt;&lt;/a&gt; method. This method takes a &lt;code&gt;QValidator&lt;/code&gt; object as an argument. PyQt has a few built-in validators that you can use directly on a line edit:&lt;/p&gt;
  2968. &lt;ul&gt;
  2969. &lt;li&gt;&lt;a href="https://doc.qt.io/qt-6/qintvalidator.html"&gt;QIntValidator&lt;/a&gt; for integer validation&lt;/li&gt;
  2970. &lt;li&gt;&lt;a href="https://doc.qt.io/qt-6/qdoublevalidator.html"&gt;QDoubleValidator&lt;/a&gt; for floating-point validation&lt;/li&gt;
  2971. &lt;li&gt;&lt;a href="https://doc.qt.io/qt-6/qregularexpressionvalidator.html"&gt;QRegularExpressionValidator&lt;/a&gt; for validation based on regular expressions&lt;/li&gt;
  2972. &lt;/ul&gt;
  2973. &lt;p&gt;Validator objects process the input to check whether it's valid. In general, validator object has three possible states:&lt;/p&gt;
  2974. &lt;table&gt;
  2975. &lt;thead&gt;
  2976. &lt;tr&gt;
  2977. &lt;th&gt;Constant&lt;/th&gt;
  2978. &lt;th&gt;Value&lt;/th&gt;
  2979. &lt;th&gt;Description&lt;/th&gt;
  2980. &lt;/tr&gt;
  2981. &lt;/thead&gt;
  2982. &lt;tbody&gt;
  2983. &lt;tr&gt;
  2984. &lt;td&gt;&lt;code&gt;QValidator.State.Invalid&lt;/code&gt;&lt;/td&gt;
  2985. &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
  2986. &lt;td&gt;The input is invalid.&lt;/td&gt;
  2987. &lt;/tr&gt;
  2988. &lt;tr&gt;
  2989. &lt;td&gt;&lt;code&gt;QValidator.State.Intermediate&lt;/code&gt;&lt;/td&gt;
  2990. &lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
  2991. &lt;td&gt;The input is a valid intermediate value.&lt;/td&gt;
  2992. &lt;/tr&gt;
  2993. &lt;tr&gt;
  2994. &lt;td&gt;&lt;code&gt;QValidator.State.Acceptable&lt;/code&gt;&lt;/td&gt;
  2995. &lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
  2996. &lt;td&gt;The input is acceptable as a final result.&lt;/td&gt;
  2997. &lt;/tr&gt;
  2998. &lt;/tbody&gt;
  2999. &lt;/table&gt;
  3000. &lt;p&gt;When you set a validator to a given line edit, the user may change the content to any &lt;a href="https://doc.qt.io/qt-6/qvalidator.html#State-enum"&gt;&lt;code&gt;Intermediate&lt;/code&gt;&lt;/a&gt; value during editing. However, they can't edit the text to a value that is &lt;a href="https://doc.qt.io/qt-6/qvalidator.html#State-enum"&gt;&lt;code&gt;Invalid&lt;/code&gt;&lt;/a&gt;. The line edit will emit the &lt;code&gt;returnPressed&lt;/code&gt; and &lt;code&gt;editingFinished&lt;/code&gt; signals only when the validator validates input as &lt;a href="https://doc.qt.io/qt-6/qvalidator.html#State-enum"&gt;&lt;code&gt;Acceptable&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
  3001. &lt;p&gt;Here's an example where we use a &lt;code&gt;QIntValidator&lt;/code&gt; and a &lt;code&gt;QRegularExpressionValidator&lt;/code&gt;&lt;/p&gt;
  3002. &lt;div class="code-block"&gt;&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
  3003. &lt;pre&gt;
  3004. &lt;code class="python"&gt;from PyQt6.QtCore import QRegularExpression
  3005. from PyQt6.QtGui import QIntValidator, QRegularExpressionValidator
  3006. from PyQt6.QtWidgets import (
  3007.    QApplication,
  3008.    QFormLayout,
  3009.    QLabel,
  3010.    QLineEdit,
  3011.    QWidget,
  3012. )
  3013.  
  3014. class Window(QWidget):
  3015.    def __init__(self, parent=None):
  3016.        super().__init__(parent)
  3017.        self.setWindowTitle("Input Validators")
  3018.        self.resize(300, 100)
  3019.  
  3020.        self.int_line_edit = QLineEdit(parent=self)
  3021.        self.int_line_edit.setValidator(QIntValidator())
  3022.  
  3023.        self.uppercase_line_edit = QLineEdit(parent=self)
  3024.        input_validator = QRegularExpressionValidator(
  3025.            QRegularExpression("[A-Z]+"), self.uppercase_line_edit
  3026.        )
  3027.        self.uppercase_line_edit.setValidator(input_validator)
  3028.        self.uppercase_line_edit.returnPressed.connect(self.update_label)
  3029.  
  3030.        self.signal_label = QLabel(parent=self)
  3031.  
  3032.        layout = QFormLayout()
  3033.        layout.addRow("Integers:", self.int_line_edit)
  3034.        layout.addRow("Uppercase letters:", self.uppercase_line_edit)
  3035.        layout.addRow("Signal:", self.signal_label)
  3036.        self.setLayout(layout)
  3037.  
  3038.    def update_label(self):
  3039.        self.signal_label.setText("Return pressed!")
  3040.  
  3041. if __name__ == "__main__":
  3042.    app = QApplication([])
  3043.    window = Window()
  3044.    window.show()
  3045.    app.exec()
  3046. &lt;/code&gt;
  3047. &lt;/pre&gt;&lt;/div&gt;
  3048. &lt;p&gt;In this example, we have two line edits. In the first line edit, we've used a &lt;code&gt;QIntValidator&lt;/code&gt; object. This way, the line edit will only accept valid integer numbers. If you try to type in something different, then the line edit won't accept your input.&lt;/p&gt;
  3049. &lt;p&gt;In the second line edit, we've used a &lt;code&gt;QRegularExpressionValidator&lt;/code&gt;. In this specific case, the regular expression accepts one or more uppercase letters. Again if you try to enter something else, then the line edit won't accept the input.&lt;/p&gt;
  3050. &lt;p&gt;The &lt;code&gt;QLabel&lt;/code&gt; will show the text &lt;code&gt;Return pressed!&lt;/code&gt; if the input in the second line edit is valid and you press the Enter key. Here's what the app looks like:&lt;/p&gt;
  3051. &lt;p&gt;&lt;img alt="QLineEdit with input validator" height="292" src="https://www.pythonguis.com/static/docs/qlineedit/qlineedit-input-validators.png" width="600"&gt; &lt;em&gt;QLineEdit with input validator.&lt;/em&gt;&lt;/p&gt;
  3052. &lt;p&gt;Validators provide a quick way to restrict the user input and set our own validation rules. This way, we can ensure valid user input in our applications.&lt;/p&gt;
  3053. &lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
  3054. &lt;p&gt;Line edits are pretty useful widgets in any GUI application. They allow text input through a single-line editor that has many cool features.&lt;/p&gt;
  3055. &lt;p&gt;In this tutorial, you've learned how to create, use, and customize your line edits while building a GUI application with PyQt/PySide.&lt;/p&gt;</description>
  3056.    </item>
  3057.    <item>
  3058.      <guid isPermaLink="false">https://blog.felgo.com/release-felgo-qml-hot-reload-for-qt-projects</guid>
  3059.      <title>Felgo: Felgo Hot Reload: Enhance your Qt Project Development with QML Code Reload</title>
  3060.      <pubDate>Thu, 25 Jan 2024 12:58:33 GMT</pubDate>
  3061.      <link>https://blog.felgo.com/release-felgo-qml-hot-reload-for-qt-projects</link>
  3062.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://blog.felgo.com/release-felgo-qml-hot-reload-for-qt-projects" title=""&gt;&lt;img alt="Felgo Hot Reload: Enhance your Qt Project Development with QML Code Reload" class="hs-featured-image" src="https://blog.felgo.com/hubfs/felgo-hot-reload-product-release.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  3063. &lt;p&gt;Felgo specializes in unique Qt products and tools to develop fast and efficiently. QML Hot Reload is one of them, and it transforms the way you develop Qt Quick applications.&lt;/p&gt;
  3064. &lt;p&gt;&lt;span style="font-weight: normal;"&gt;The&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;Felgo Hot Reload&lt;/span&gt; release now makes the tool available as a standalone product - independent from the Felgo SDK. This means that you can &lt;span style="font-weight: bold;"&gt;integrate code reloading to any Qt/QML project&lt;/span&gt; to enhance your development workflow. To do so, simply add the Felgo QML Hot Reload library to your project. No change to your production code is required.&lt;/p&gt;
  3065. &lt;p style="text-align: center;"&gt;&lt;a class="cta_button" href="https://hs.felgo.com/cs/ci/?pg=d3780ea5-44e6-4b22-a0b3-1875caeed7f4&amp;pid=6147417&amp;ecid=&amp;hseid=&amp;hsic="&gt;&lt;img alt="Get Felgo Hot Reload" class="hs-cta-img" src="https://no-cache.hubspot.com/cta/default/6147417/d3780ea5-44e6-4b22-a0b3-1875caeed7f4.png"&gt;&lt;/a&gt;&lt;br&gt;
  3066. &lt;br&gt;&lt;/p&gt;
  3067. &lt;p&gt;Read this post to learn why you should not miss QML Hot Reload in your development setup, and what benefits it brings to your project:&lt;/p&gt;
  3068. &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%2Frelease-felgo-qml-hot-reload-for-qt-projects&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
  3069.    </item>
  3070.    <item>
  3071.      <guid isPermaLink="false">https://www.kdab.com/?p=33409</guid>
  3072.      <title>KDAB on Qt: KDSoap 2.2.0 Released</title>
  3073.      <pubDate>Fri, 12 Jan 2024 12:30:35 GMT</pubDate>
  3074.      <link>https://www.kdab.com/kdsoap-2-2-0-released/</link>
  3075.      <description>&lt;p&gt;&lt;img align="right" alt="" class="alignleft size-full wp-image-1403" height="128" src="https://www.kdab.com/wp-content/uploads/stories/kdsoap128.png" width="128"&gt; We&#x2019;re pleased to announce the release of KDSoap version 2.2.0, an update that brings new enhancements to improve both the general build system and client-side functionality.&lt;/p&gt;
  3076. &lt;h4&gt;What is KDSoap?&lt;/h4&gt;
  3077. &lt;p&gt;KDSoap, a SOAP (&#x201C;Simple Object Access Protocol&#x201C;) component rooted in Qt, serves as an essential tool for both client-side and server-side operations. Tailored for C++ programmers using Qt, it not only facilitates the creation of client applications for web services but also empowers developers to seamlessly build web services without requiring additional components like dedicated web servers. For further details on KDSoap, visit &lt;a href="https://www.kdab.com/development-resources/qt-tools/kd-soap"&gt;here&lt;/a&gt;.&lt;/p&gt;
  3078. &lt;h4&gt;What&#x2019;s New in KDSoap Version 2.2.0?&lt;/h4&gt;
  3079. &lt;p&gt;&lt;strong&gt;Build System Co-installability:&lt;/strong&gt; The buildsystem now supports the co-installability of Qt 5 and Qt 6 headers. Qt 6 headers are installed into their dedicated subdirectory. This ensures compatibility with client code and allows co-installation with Qt 5.&lt;/p&gt;
  3080. &lt;p&gt;&lt;strong&gt;Client-Side:&lt;/strong&gt;&lt;/p&gt;
  3081. &lt;ul&gt;
  3082. &lt;li&gt;&lt;strong&gt;WS-Addressing Support:&lt;/strong&gt; The new release adds &lt;code&gt;KDSoapClientInterface::setMessageAddressingProperties()&lt;/code&gt;. This addition enables the use of WS-Addressing support specifically with WSDL-generated services.&lt;/li&gt;
  3083. &lt;li&gt;&lt;strong&gt;SOAP Action Requirement Removal:&lt;/strong&gt; KDSoap no longer requires a SOAP action for writing addressing properties.&lt;/li&gt;
  3084. &lt;/ul&gt;
  3085. &lt;p&gt;&lt;strong&gt;WSDL Parser / Code Generator Changes:&lt;/strong&gt;&lt;/p&gt;
  3086. &lt;p&gt;&lt;strong&gt;Enhanced &lt;code&gt;-import-path Support&lt;/code&gt;:&lt;/strong&gt; Notable changes have been made to the WSDL parser and code generator, impacting both client and server sides. The update improves &lt;code&gt;-import-path&lt;/code&gt; support by incorporating the import path in more areas within the code. This refinement enhances the overall functionality of the parser and code generator.&lt;/p&gt;
  3087. &lt;p&gt;These updates collectively contribute to a more streamlined and efficient experience for KDSoap users, addressing specific issues and introducing valuable features to facilitate seamless integration with Qt-based applications. For detailed information and to explore these enhancements, we refer to the KDSoap documentation accompanying version 2.2.0 on &lt;a href="https://github.com/KDAB/KDSoap/releases/tag/kdsoap-2.2.0"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
  3088. &lt;h4&gt;How to Get Started with KDSoap Version 2.2.0?&lt;/h4&gt;
  3089. &lt;p&gt;For existing users, upgrading to the latest version is as simple as downloading the new release from the &lt;a href="https://github.com/KDAB/KDSoap/releases/tag/kdsoap-2.2.0"&gt;GitHub page&lt;/a&gt;. If you are new to KDSoap, we &lt;a href="https://github.com/KDAB/KDSoap"&gt;invite you&lt;/a&gt; to explore its capabilities and discover how it can streamline your web service development process.&lt;/p&gt;
  3090. &lt;p&gt;As always, we appreciate your feedback and contributions to make KDSoap even better. Feel free to reach out to us with any questions, suggestions or bug reports on &lt;a href="https://github.com/KDAB/KDSoap"&gt;our GitHub repository&lt;/a&gt;.&lt;/p&gt;
  3091. &lt;p&gt;Thank you for choosing KDSoap, and happy coding!&lt;/p&gt;
  3092. &lt;div class="panel panel-info"&gt;
  3093. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  3094. &lt;div class="panel-body"&gt;
  3095. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  3096. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  3097. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  3098. &lt;/div&gt;
  3099. &lt;/div&gt;
  3100. &lt;p&gt;The post &lt;a href="https://www.kdab.com/kdsoap-2-2-0-released/"&gt;KDSoap 2.2.0 Released&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  3101.    </item>
  3102.    <item>
  3103.      <guid isPermaLink="false">https://blog.felgo.com/develop-qt-quick-apps-with-visual-studio-code-qml-extension</guid>
  3104.      <title>Felgo: QML Extension for Visual Studio Code: Develop Qt Quick with VS Code and QML Hot Reload</title>
  3105.      <pubDate>Thu, 11 Jan 2024 17:15:00 GMT</pubDate>
  3106.      <link>https://blog.felgo.com/develop-qt-quick-apps-with-visual-studio-code-qml-extension</link>
  3107.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://blog.felgo.com/develop-qt-quick-apps-with-visual-studio-code-qml-extension" title=""&gt;&lt;img alt="QML Extension for Visual Studio Code: Develop Qt Quick with VS Code and QML Hot Reload" class="hs-featured-image" src="https://blog.felgo.com/hubfs/develop-qt-quick-apps-with-vs-code-and-qml-hot-reload-2023.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  3108. &lt;p&gt;Visual Studio Code ranks &lt;strong&gt;#1 among the most popular development tools&lt;/strong&gt; in the annual developers survey of Stack Overflow. More than 70% of all participants use this code editor for development. And there&#x2019;s a reason why: It is fast, reliable, supports a wide range of languages and runs on Windows, macOS and Linux.&lt;/p&gt;
  3109. &lt;p&gt;With the right extensions and tools, you can set up and use Visual Studio Code to develop your Qt and QML projects. Watch the tutorial or read this guide to learn how:&lt;/p&gt;
  3110. &lt;div class="hs-embed-wrapper" style="overflow: hidden; width: 100%; height: auto; padding: 0px; display: block; margin: auto;"&gt;
  3111. &lt;div class="hs-embed-content-wrapper"&gt;
  3112. &lt;div style="overflow: hidden; padding-bottom: 56.5%; margin: 0px;"&gt;&lt;/div&gt;
  3113. &lt;/div&gt;
  3114. &lt;/div&gt;
  3115. &lt;p&gt;&#xA0;&lt;/p&gt;
  3116. &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%2Fdevelop-qt-quick-apps-with-visual-studio-code-qml-extension&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
  3117.    </item>
  3118.    <item>
  3119.      <guid isPermaLink="false">https://www.kdab.com/?p=33362</guid>
  3120.      <title>KDAB on Qt: Qt 6 WASM: Uploading &amp; Playing Back Audio Files</title>
  3121.      <pubDate>Thu, 11 Jan 2024 09:00:20 GMT</pubDate>
  3122.      <link>https://www.kdab.com/qt-6-wasm-uploading-playing-back-audio-files/</link>
  3123.      <description>&lt;div class="stackedit__html"&gt;
  3124. &lt;blockquote&gt;
  3125. &lt;p&gt;&lt;em&gt;This article walks through an implementation using C++11 or later, Qt 6.5 or later for WebAssembly (multithreaded), and CMake. The browser environment used was Mozilla Firefox 119.0.1 (64-bit) provided by the Mozilla Firefox snap package for Ubuntu.&lt;/em&gt;&lt;/p&gt;
  3126. &lt;/blockquote&gt;
  3127. &lt;h2 id="overview--motivation"&gt;Overview &amp; Motivation&lt;/h2&gt;
  3128. &lt;p&gt;Lately, I&#x2019;ve been working on a small Qt Widgets project to help manage some weekly poker games with my friends, and realized it would be much nicer to distribute copies by web instead of building binaries. This gave me the perfect excuse to test out Qt for WebAssembly, and see how much tinkering I&#x2019;d have to do with the original source code to make it work in Firefox!&lt;/p&gt;
  3129. &lt;p&gt;Everything looked and felt great on the web browser when just compiling the desktop code with a Qt WASM CMake kit, but one feature caused some issues. The program plays a notification sound with &lt;code&gt;QMediaPlayer&lt;/code&gt;, and allows the user to select any audio file on their computer to use as the sound. The original implementation for both getting a native file dialog and playing back audio files did not work in-browser. Using goofy audio is a must for our poker nights, so I quickly started rewriting.&lt;/p&gt;
  3130. &lt;p&gt;Fixing the implementation to get the file dialog was simple and required me to replace a very small amount of code, but &lt;code&gt;QMediaPlayer&lt;/code&gt; was unusable with file URLs. Firstly, browser code is sandboxed, so the &lt;code&gt;QMediaPlayer&lt;/code&gt; can&#x2019;t set its source to a file URL on the user&#x2019;s file system. The data would have to be stored in the browser&#x2019;s internal file system or on a server. Secondly, Qt Multimedia is pretty broken for WASM in general. It&#x2019;s listed as &lt;a href="https://doc.qt.io/qt-5/wasm.html#supported-qt-modules"&gt;not working in Qt 5&lt;/a&gt;, and &lt;a href="https://doc.qt.io/qt-6/wasm.html#supported-qt-modules"&gt;untested in Qt 6&lt;/a&gt;, with some Qt 6 limitations detailed &lt;a href="https://doc.qt.io/qt-6/qtmultimedia-wasm.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
  3131. &lt;p&gt;However, I noticed that the Qt WASM method for opening files provided the file contents as a &lt;code&gt;QByteArray&lt;/code&gt;.&lt;/p&gt;
  3132. &lt;p&gt;I thought, why not just try to play back the audio from the buffer of raw bytes?&lt;/p&gt;
  3133. &lt;blockquote&gt;
  3134. &lt;p&gt;&lt;em&gt;Please note that there are other (and usually better) ways to do this. The program I was working on was simple enough that storing a buffer as a DOM variable was sufficient enough. In many cases, it would be preferable to store audio persistently on a server and fetch the stream to play it back, or even in some cases write the file to the browser&#x2019;s IndexedDB. Either way, knowing how to use C++ to play audio in-browser from a buffer could be useful in these cases, so this simple example should cover a lot of the common ground without making it too complex. Additionally, note that cross-browser implementation may require a little bit more code, and production code should perform more checks than you&#x2019;ll see here.&lt;/em&gt;&lt;/p&gt;
  3135. &lt;/blockquote&gt;
  3136. &lt;h2 id="getting-file-contents"&gt;Getting File Contents&lt;/h2&gt;
  3137. &lt;p&gt;I&#x2019;ll start off this basic example by creating a regular Qt Widgets application, with a class that inherits from &lt;code&gt;QMainWindow&lt;/code&gt;.&lt;/p&gt;
  3138. &lt;pre&gt;
  3139. &lt;code class="prism lang-cpp"&gt;#pragma once
  3140.  
  3141. #include
  3142.  
  3143. class MainWindow : public QMainWindow {
  3144.    Q_OBJECT
  3145.  
  3146. public:
  3147.    explicit MainWindow(QWidget *parent = nullptr) noexcept;
  3148.    ~MainWindow() override;
  3149. };
  3150. &lt;/code&gt;
  3151. &lt;/pre&gt;
  3152. &lt;p&gt;In the constructor, I&#x2019;ll create a &lt;code&gt;QPushButton&lt;/code&gt; to open a file dialog (&lt;code&gt;dialogButton&lt;/code&gt;) and one to play the audio back (&lt;code&gt;playButton&lt;/code&gt;).&lt;/p&gt;
  3153. &lt;p&gt;Let&#x2019;s connect &lt;code&gt;dialogButton&lt;/code&gt;&#x2018;s &lt;code&gt;clicked&lt;/code&gt; signal to a lambda and get our file dialog.&lt;/p&gt;
  3154. &lt;p&gt;To do this in a Qt WASM project, we use &lt;code&gt;QFileDialog::getOpenFileContent&lt;/code&gt;.&lt;/p&gt;
  3155. &lt;pre&gt;
  3156. &lt;code class="prism language-cpp"&gt;connect(dialogButton, &amp;QPushButton::clicked, this, [this]() {
  3157.    QFileDialog::getOpenFileContent(
  3158.        tr("Audio files (*.mp3 *.flac *.wav *.aiff *.ogg)"),
  3159.        [this](const QString &amp;fileName, const QByteArray &amp;fileContent) {
  3160.            if (fileName.isEmpty()) {
  3161.                // no file selected
  3162.            } else {
  3163.                // do stuff with file data
  3164.            }
  3165.        });
  3166. });
  3167.  
  3168. &lt;/code&gt;
  3169. &lt;/pre&gt;
  3170. &lt;p&gt;Notice that, as I mentioned earlier, the file&#x2019;s contents are provided as a &lt;code&gt;QByteArray&lt;/code&gt;. To play the audio, we need our buffer to contain PCM data, while these bytes are the file&#x2019;s binary contents in a specific file format. We need to decode the bytes and transform them to PCM.&lt;/p&gt;
  3171. &lt;p&gt;How do we do that?&lt;/p&gt;
  3172. &lt;h2 id="finding-the-needed-decoding-method"&gt;Finding the Needed Decoding Method&lt;/h2&gt;
  3173. &lt;p&gt;Let&#x2019;s stick with the &lt;code&gt;QMediaPlayer&lt;/code&gt; idea for now to illustrate some basic concepts. We want to use a buffer of bytes rather than a file URL, so we can set the &lt;code&gt;QMediaPlayer&lt;/code&gt;&#x2018;s source device to a &lt;code&gt;QBuffer&lt;/code&gt; containing PCM data.&lt;/p&gt;
  3174. &lt;p&gt;To obtain this buffer, we need to create an initial &lt;code&gt;QBuffer&lt;/code&gt; from the &lt;code&gt;QByteArray&lt;/code&gt;, then give it to a &lt;code&gt;QAudioDecoder&lt;/code&gt;, read the decoded bytes as a &lt;code&gt;QAudioBuffer&lt;/code&gt;, then create another &lt;code&gt;QBuffer&lt;/code&gt; from the &lt;code&gt;QAudioBuffer&lt;/code&gt;&#x2018;s raw byte data and byte count. Now &lt;em&gt;this&lt;/em&gt; buffer can be given to a &lt;code&gt;QMediaPlayer&lt;/code&gt; by calling &lt;code&gt;setSourceDevice&lt;/code&gt;.&lt;/p&gt;
  3175. &lt;p&gt;Here&#x2019;s the problem: &lt;code&gt;QAudioDecoder&lt;/code&gt; needs a &lt;code&gt;QAudioFormat&lt;/code&gt; to know how to decode the data. This is not just file format &#x2013; we need to know about channels and bitrate as well. We want to be able to upload files in different formats, with different bitrates, and in both mono and stereo, so we would have to extract all this information manually somehow to decode correctly.&lt;/p&gt;
  3176. &lt;p&gt;On top of that, this limitation is mentioned in the &lt;a href="https://doc.qt.io/qt-6/qtmultimedia-wasm.html"&gt;Qt 6 WASM Multimedia page&lt;/a&gt;:&lt;/p&gt;
  3177. &lt;blockquote&gt;
  3178. &lt;p&gt;Playing streaming bytes instead of a url. e.g. setSource(QIOStream) is also not currently supported. Some advanced features may or may not work at this time.&lt;/p&gt;
  3179. &lt;/blockquote&gt;
  3180. &lt;p&gt;Even if we do all the decoding properly, we can&#x2019;t play from our buffer (by &lt;code&gt;setSource(QIOStream)&lt;/code&gt; they mean &lt;code&gt;setSourceDevice(QIODevice *)&lt;/code&gt;)! We need to find another way.&lt;/p&gt;
  3181. &lt;p&gt;Luckily, JavaScript&#x2019;s Web Audio API has a great solution. &lt;code&gt;BaseAudioContext&lt;/code&gt; has a nice &lt;code&gt;decodeAudioData&lt;/code&gt; method that takes an &lt;code&gt;ArrayBuffer&lt;/code&gt; of data in any kind of supported audio format and decodes it as an &lt;code&gt;AudioBuffer&lt;/code&gt;. This buffer can be played with an &lt;code&gt;AudioSourceNode&lt;/code&gt; connected to an &lt;code&gt;AudioContext&lt;/code&gt;&#x2018;s destination node.&lt;/p&gt;
  3182. &lt;p&gt;But wait, how do we get our &lt;code&gt;QByteArray&lt;/code&gt; data into a JavaScript &lt;code&gt;ArrayBuffer&lt;/code&gt;?&lt;/p&gt;
  3183. &lt;h2 id="using-the-emscripten-api"&gt;Using the Emscripten API&lt;/h2&gt;
  3184. &lt;p&gt;We need to use emscripten&#x2019;s C++ API for this. On Qt for WASM, it&#x2019;s already linked and you can include its headers out of the box.&lt;/p&gt;
  3185. &lt;p&gt;The idea is that we want to not only invoke JS functions and use JS &lt;code&gt;var&lt;/code&gt;s, but also have C++ objects representing JS objects. Then we can create them, perform other operations in our C++ context, and then invoke methods on the JS objects later, even passing data from C++ objects to JavaScript and vice-versa.&lt;/p&gt;
  3186. &lt;p&gt;Our best option for this is to use emscripten&#x2019;s embind, instead of writing inline JavaScript with something like &lt;code&gt;EM_JS&lt;/code&gt; or &lt;code&gt;EM_ASM&lt;/code&gt;. This way, our JS objects are accessible in whatever scope their corresponding C++ objects are defined in.&lt;/p&gt;
  3187. &lt;p&gt;To start, we need to &lt;code&gt;#include &lt;emscripten/bind.h&gt;&lt;/code&gt;.&lt;/p&gt;
  3188. &lt;p&gt;We&#x2019;ll be working with the C++ type &lt;code&gt;emscripten::val&lt;/code&gt;, essentially emscripten&#x2019;s wrapper for a JS &lt;code&gt;var&lt;/code&gt;, which additionally has a static member function to access global objects and functions.&lt;/p&gt;
  3189. &lt;p&gt;Since Qt 6.5, in Qt WASM, &lt;code&gt;QByteArray&lt;/code&gt; conveniently has a member function &lt;code&gt;toEcmaUint8Array()&lt;/code&gt; that represents its data in the layout of a JS &lt;code&gt;Uint8Array&lt;/code&gt; and returns it as an &lt;code&gt;emscripten::val&lt;/code&gt;. Since we receive &lt;code&gt;fileContent&lt;/code&gt; as a &lt;code&gt;const&lt;/code&gt; reference to a &lt;code&gt;QByteArray&lt;/code&gt; and &lt;code&gt;toEcmaUint8Array&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; a &lt;code&gt;const&lt;/code&gt; function, we&#x2019;ll copy &lt;code&gt;fileContent&lt;/code&gt; to a new &lt;code&gt;QByteArray&lt;/code&gt;:&lt;/p&gt;
  3190. &lt;pre&gt;
  3191. &lt;code class="prism language-cpp"&gt;QFileDialog::getOpenFileContent(
  3192.    tr("Audio files (*.mp3 *.flac *.wav *.aiff *.ogg)"),
  3193.    [this](const QString &amp;fileName, const QByteArray &amp;fileContent) {
  3194.        if (fileName.isEmpty()) {
  3195.            // no file selected
  3196.        } else {
  3197.            auto contentCopy = fileContent;
  3198.            auto buf = contentCopy.toEcmaUint8Array();
  3199.            // ...
  3200.            // ...
  3201.            // ...
  3202.        }
  3203.    });
  3204.  
  3205. &lt;/code&gt;
  3206. &lt;/pre&gt;
  3207. &lt;p&gt;Nice. Now we have to get the buffer property from our &lt;code&gt;buf&lt;/code&gt; object and call &lt;code&gt;decodeAudioData&lt;/code&gt;. For that, we need to initialize an &lt;code&gt;AudioContext&lt;/code&gt;.&lt;/p&gt;
  3208. &lt;p&gt;An easy way is to just give our &lt;code&gt;MainWindow&lt;/code&gt; class a private data member &lt;code&gt;emscripten::val mAudioContext&lt;/code&gt; and initialize it in the constructor. To get the embind equivalent of the JS expression &lt;code&gt;mAudioContext = new AudioContext()&lt;/code&gt; we do this:&lt;/p&gt;
  3209. &lt;pre&gt;
  3210. &lt;code class="prism language-cpp"&gt;mAudioContext = emscripten::val::global("AudioContext").new_();&lt;/code&gt;
  3211. &lt;/pre&gt;
  3212. &lt;p&gt;We can go ahead and initialize it in our constructor&#x2019;s initializer list:&lt;/p&gt;
  3213. &lt;pre&gt;
  3214. &lt;code class="prism language-cpp"&gt;MainWindow::MainWindow(QWidget *parent) noexcept
  3215.    : QMainWindow(parent)
  3216.    , mAudioContext(emscripten::val::global("AudioContext").new_())
  3217. {
  3218.    // ...
  3219.    // ...
  3220.    // ...
  3221. }
  3222. &lt;/code&gt;
  3223. &lt;/pre&gt;
  3224. &lt;p&gt;So why this syntax?&lt;/p&gt;
  3225. &lt;p&gt;In JavaScript, functions are first-class objects. For a browser that complies with the Web Audio API, the constructor &lt;code&gt;AudioContext&lt;/code&gt; is a property of &lt;code&gt;globalThis&lt;/code&gt;, so it can be accessed as a global object with &lt;code&gt;emscripten::val::global("AudioContext")&lt;/code&gt;. Then we can call &lt;code&gt;new_(Args&amp;&amp;... args)&lt;/code&gt; on it, which calls the constructor with &lt;code&gt;args&lt;/code&gt; using the &lt;code&gt;new&lt;/code&gt; keyword.&lt;/p&gt;
  3226. &lt;p&gt;Now let&#x2019;s get back to setting up our &lt;code&gt;AudioBuffer&lt;/code&gt;.&lt;/p&gt;
  3227. &lt;h2 id="finally-decoding-the-audio"&gt;Finally Decoding the Audio&lt;/h2&gt;
  3228. &lt;p&gt;Recall that we have this:&lt;/p&gt;
  3229. &lt;pre&gt;
  3230. &lt;code class="prism language-cpp"&gt;auto contentCopy = fileContent;
  3231. auto buf = contentCopy.toEcmaUint8Array();&lt;/code&gt;
  3232. &lt;/pre&gt;
  3233. &lt;p&gt;We need to access the property &lt;code&gt;buffer&lt;/code&gt; of &lt;code&gt;buf&lt;/code&gt; to get an &lt;code&gt;ArrayBuffer&lt;/code&gt; object that we can pass to &lt;code&gt;decodeAudioData&lt;/code&gt;. To get the property, we just use &lt;code&gt;operator[]&lt;/code&gt; like so: &lt;code&gt;buf["buffer"]&lt;/code&gt;. Easy.&lt;/p&gt;
  3234. &lt;p&gt;To call &lt;code&gt;decodeAudioData&lt;/code&gt;, we just invoke the template function &lt;code&gt;ReturnValue call(const char *name, Args&amp;&amp;... args) const&lt;/code&gt; like so:&lt;/p&gt;
  3235. &lt;pre&gt;
  3236. &lt;code class="prism language-cpp"&gt;auto decodedBuffer = mAudioContext.call&lt;emscripten::val&gt;("decodeAudioData", /* arguments */);&lt;/code&gt;
  3237. &lt;/pre&gt;
  3238. &lt;p&gt;But wait a second, &lt;code&gt;decodeAudioData&lt;/code&gt; is overloaded. There are two versions of this function with different arguments and return types. One involves a promise-await syntax where you just pass the buffer, which returns the decoded buffer. The other is void and involves passing both the buffer and a callback function that takes the decoded buffer as an argument. How can we do JS promise-await or pass JS callback functions as arguments in C++?&lt;/p&gt;
  3239. &lt;p&gt;Well, to do promise-await syntax, we can just call &lt;code&gt;await()&lt;/code&gt; on our return value.&lt;/p&gt;
  3240. &lt;pre&gt;
  3241. &lt;code class="prism language-cpp"&gt;auto decodedBuffer = mAudioContext.call&lt;emscripten::val&gt;("decodeAudioData", buf["buffer"]).await();&lt;/code&gt;
  3242. &lt;/pre&gt;
  3243. &lt;p&gt;Please keep in mind this &lt;code&gt;await()&lt;/code&gt; is &lt;strong&gt;only&lt;/strong&gt; available when Asyncify is enabled. If you&#x2019;re using the multithreaded version of Qt WASM, you can enable this. Just add the following to your &lt;code&gt;CMakeLists.txt&lt;/code&gt;:&lt;/p&gt;
  3244. &lt;pre&gt;
  3245. &lt;code class="prism language-cmake"&gt;target_link_options(&lt;target name&gt; PUBLIC -sASYNCIFY -O3)&lt;/code&gt;
  3246. &lt;/pre&gt;
  3247. &lt;p&gt;In C++20, you can also use coroutines to do promise-await syntax by placing a &lt;code&gt;co_await&lt;/code&gt; operator to the left of the function call.&lt;/p&gt;
  3248. &lt;p&gt;For the callback function, well, &lt;code&gt;Function&lt;/code&gt; is a global object. Thus, you can call the &lt;code&gt;Function&lt;/code&gt; constructor with &lt;code&gt;new_(Args&amp;&amp;... args)&lt;/code&gt;, passing the function body as a string, and store the returned function as an &lt;code&gt;emscripten::val&lt;/code&gt;.&lt;/p&gt;
  3249. &lt;p&gt;The problem is that the callback function takes the decoded buffer as an argument, so we get it in JS rather than C++. It &lt;strong&gt;is&lt;/strong&gt; possible to call a C++ function from the callback and forward the decoded buffer to it, which involves exposing the function to emscripten&#x2019;s &lt;code&gt;Module&lt;/code&gt; object using &lt;code&gt;EMSCRIPTEN_BINDINGS&lt;/code&gt;. However, if we need it to be a member function, we get type errors on the function pointer.&lt;/p&gt;
  3250. &lt;p&gt;I am still looking at how the callback syntax would work, but I believe it involves exposing the entire class to &lt;code&gt;Module&lt;/code&gt;.&lt;/p&gt;
  3251. &lt;p&gt;So, let&#x2019;s just go with the promise-await syntax for now.&lt;/p&gt;
  3252. &lt;p&gt;Since we will want to play from the buffer on a button press or some other event, let&#x2019;s make a data member &lt;code&gt;emscripten::val mDecodedBuffer&lt;/code&gt; so it&#x2019;s in the class scope.&lt;/p&gt;
  3253. &lt;p&gt;We now have this:&lt;/p&gt;
  3254. &lt;pre&gt;
  3255. &lt;code class="prism language-cpp"&gt;QFileDialog::getOpenFileContent(
  3256.    tr("Audio files (*.mp3 *.flac *.wav *.aiff *.ogg)"),
  3257.    [this](const QString &amp;fileName, const QByteArray &amp;fileContent) {
  3258.        if (fileName.isEmpty()) {
  3259.            // no file selected
  3260.        } else {
  3261.            auto contentCopy = fileContent;
  3262.            auto buf = contentCopy.toEcmaUint8Array();
  3263.  
  3264.            mDecodedBuffer = mAudioContext.call&lt;emscripten::val&gt;("decodeAudioData", buf["buffer"]).await();
  3265.        }
  3266.    });
  3267. &lt;/code&gt;
  3268. &lt;/pre&gt;
  3269. &lt;p&gt;Cool, we can store the data from an audio file in a buffer in PCM format!&lt;/p&gt;
  3270. &lt;p&gt;Let&#x2019;s move on to playing the audio from that buffer.&lt;/p&gt;
  3271. &lt;h2 id="playing-back-the-audio"&gt;Playing Back the Audio&lt;/h2&gt;
  3272. &lt;p&gt;When we want to play, we first need to create an &lt;code&gt;AudioBufferSourceNode&lt;/code&gt; from the &lt;code&gt;AudioContext&lt;/code&gt;, and set its buffer to &lt;code&gt;mDecodedBuffer&lt;/code&gt;. We then connect the source node to our audio context&#x2019;s destination node (our audio device). After this, we can call &lt;code&gt;start&lt;/code&gt; on the source node to play the sound!&lt;/p&gt;
  3273. &lt;p&gt;Here&#x2019;s what that looks like with embind:&lt;/p&gt;
  3274. &lt;pre&gt;
  3275. &lt;code class="prism language-cpp"&gt;auto source = mAudioContext.call&lt;emscripten::val&gt;("createBufferSource");
  3276. source.set("buffer", mDecodedBuffer);
  3277. source.call&lt;void&gt;("connect", mAudioContext["destination"]);
  3278. source.call&lt;void&gt;("start");
  3279. &lt;/code&gt;
  3280. &lt;/pre&gt;
  3281. &lt;p&gt;A new &lt;code&gt;AudioBufferSourceNode&lt;/code&gt; needs to be created every time you want to play the sound, but they are inexpensive to construct.&lt;/p&gt;
  3282. &lt;p&gt;I have this code to play on the &lt;code&gt;QPushButton&lt;/code&gt; click:&lt;/p&gt;
  3283. &lt;pre&gt;
  3284. &lt;code class="prism language-cpp"&gt;connect(playButton, &amp;QPushButton::clicked, this, [this]() {
  3285.    auto source = mAudioContext.call&lt;emscripten::val&gt;("createBufferSource");
  3286.    source.set("buffer", mDecodedBuffer);
  3287.    source.call&lt;void&gt;("connect", mAudioContext["destination"]);
  3288.    source.call&lt;void&gt;("start");
  3289. });
  3290. &lt;/code&gt;
  3291. &lt;/pre&gt;
  3292. &lt;p&gt;To make sure the buffer will be populated successfully before this code executes, I make the button initially disabled and use Qt signals &lt;code&gt;readyToPlay&lt;/code&gt; and &lt;code&gt;notReady&lt;/code&gt; to enable and disable the button respectively.&lt;/p&gt;
  3293. &lt;h2 id="complete-code--final-thoughts"&gt;Complete Code &amp; Final Thoughts&lt;/h2&gt;
  3294. &lt;p&gt;Here is my full header for this basic example:&lt;/p&gt;
  3295. &lt;pre&gt;
  3296. &lt;code class="prism language-cpp"&gt;#pragma once
  3297.  
  3298. #include &lt;QMainWindow&gt;
  3299. #include &lt;emscripten/bind.h&gt;
  3300.  
  3301. class MainWindow : public QMainWindow {
  3302.    Q_OBJECT
  3303.  
  3304. public:
  3305.    explicit MainWindow(QWidget *parent = nullptr) noexcept;
  3306.    ~MainWindow() override;
  3307.  
  3308. signals:
  3309.    void notReady();
  3310.    void readyToPlay();
  3311.  
  3312. private:
  3313.    emscripten::val mAudioContext;
  3314.    emscripten::val mDecodedBuffer;
  3315. };
  3316. &lt;/code&gt;
  3317. &lt;/pre&gt;
  3318. &lt;p&gt;and my entire implementation file (it&#x2019;s a very basic example so I just left everything in the constructor):&lt;/p&gt;
  3319. &lt;pre&gt;
  3320. &lt;code class="prism language-cpp"&gt;#include "mainwindow.h"
  3321.  
  3322. #include &lt;QFileDialog&gt;
  3323. #include &lt;QHBoxLayout&gt;
  3324. #include &lt;QPushButton&gt;
  3325.  
  3326. MainWindow::MainWindow(QWidget *parent) noexcept
  3327.    : QMainWindow(parent)
  3328.    , mAudioContext(emscripten::val::global("AudioContext").new_())
  3329. {
  3330.    auto *centerWidget = new QWidget(this);
  3331.    auto *layout = new QHBoxLayout(centerWidget);
  3332.  
  3333.    auto *dialogButton = new QPushButton(centerWidget);
  3334.    dialogButton-&gt;setText(tr("Choose file"));
  3335.  
  3336.    auto *playButton = new QPushButton(centerWidget);
  3337.    playButton-&gt;setText(tr("Play"));
  3338.    playButton-&gt;setEnabled(false);
  3339.  
  3340.    layout-&gt;addWidget(dialogButton);
  3341.    layout-&gt;addWidget(playButton);
  3342.    centerWidget-&gt;setLayout(layout);
  3343.    setCentralWidget(centerWidget);
  3344.  
  3345.    connect(dialogButton, &amp;QPushButton::clicked, this, [this]() {
  3346.        QFileDialog::getOpenFileContent(
  3347.            tr("Audio files (*.mp3 *.flac *.wav *.aiff *.ogg)"),
  3348.            [this](const QString &amp;fileName, const QByteArray &amp;fileContent) {
  3349.                if (fileName.isEmpty()) {
  3350.                    emscripten::val::global().call&lt;void&gt;(
  3351.                        "alert", std::string("no file selected"));
  3352.                } else {
  3353.                    emit notReady();
  3354.  
  3355.                    auto contentCopy = fileContent;
  3356.                    auto buf = contentCopy.toEcmaUint8Array();
  3357.  
  3358.                    mDecodedBuffer = mAudioContext.call&lt;emscripten::val&gt;("decodeAudioData", buf["buffer"]).await();
  3359.  
  3360.                    emit readyToPlay();
  3361.                }
  3362.            });
  3363.    });
  3364.  
  3365.    connect(playButton, &amp;QPushButton::clicked, this, [this]() {
  3366.        auto source = mAudioContext.call&lt;emscripten::val&gt;("createBufferSource");
  3367.        source.set("buffer", mDecodedBuffer);
  3368.        source.call&lt;void&gt;("connect", mAudioContext["destination"]);
  3369.        source.call&lt;void&gt;("start");
  3370.    });
  3371.  
  3372.    connect(this, &amp;MainWindow::notReady, this, [playButton]() {
  3373.        if (playButton-&gt;isEnabled())
  3374.            playButton-&gt;setEnabled(false);
  3375.    });
  3376.  
  3377.    connect(this, &amp;MainWindow::readyToPlay, this, [playButton]() {
  3378.        if (!playButton-&gt;isEnabled())
  3379.            playButton-&gt;setEnabled(true);
  3380.    });
  3381. }
  3382.  
  3383. MainWindow::~MainWindow() = default;
  3384. &lt;/code&gt;
  3385. &lt;/pre&gt;
  3386. &lt;p&gt;This example was simple, but I hope readers can use these building blocks in more complete codebases to work with audio in Qt WASM!&lt;/p&gt;
  3387. &lt;blockquote&gt;
  3388. &lt;p&gt;Note: if you want to stream your audio, look into the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API"&gt;Media Capture and Streams API&lt;/a&gt; and use a &lt;code&gt;MediaStreamAudioSourceNode&lt;/code&gt; instead of an &lt;code&gt;AudioBufferSourceNode&lt;/code&gt;.&lt;/p&gt;
  3389. &lt;/blockquote&gt;
  3390. &lt;div class="panel panel-info"&gt;
  3391. &lt;div class="panel-heading"&gt;About KDAB&lt;/div&gt;
  3392. &lt;div class="panel-body"&gt;
  3393. &lt;p&gt;If you like this article and want to read similar material, consider subscribing via &lt;a href="https://www.kdab.com/category/blogs/feed/"&gt;our RSS feed&lt;/a&gt;.&lt;/p&gt;
  3394. &lt;p&gt;Subscribe to &lt;a href="https://www.youtube.com/kdabtv"&gt;KDAB TV&lt;/a&gt; for similar informative short video content.&lt;/p&gt;
  3395. &lt;p&gt;KDAB provides market leading software consulting and development &lt;a href="https://www.kdab.com/software-services/"&gt;services&lt;/a&gt; and &lt;a href="https://training.kdab.com/"&gt;training&lt;/a&gt; in Qt, C++ and 3D/OpenGL. &lt;a href="https://www.kdab.com/about/contact/"&gt;Contact us&lt;/a&gt;.&lt;/p&gt;
  3396. &lt;/div&gt;
  3397. &lt;/div&gt;
  3398. &lt;/div&gt;
  3399. &lt;p&gt;The post &lt;a href="https://www.kdab.com/qt-6-wasm-uploading-playing-back-audio-files/"&gt;Qt 6 WASM: Uploading &amp; Playing Back Audio Files&lt;/a&gt; appeared first on &lt;a href="https://www.kdab.com"&gt;KDAB&lt;/a&gt;.&lt;/p&gt;</description>
  3400.    </item>
  3401.    <item>
  3402.      <guid isPermaLink="false">http://planet.qt.io/rss20.xml#id8a10ab52a5df2a23ab8c1d542cfa111805687424</guid>
  3403.      <title>Cutelyst Framework: Cutelyst v4 - 10 years &#x1F389;</title>
  3404.      <pubDate>Thu, 21 Dec 2023 21:49:36 GMT</pubDate>
  3405.      <link>https://cutelyst.org/2023/12/21/cutelyst-v4-10-years</link>
  3406.      <description>&lt;p&gt;Cutelyst the Qt web framework is now at v4.0.0 just a bit later for it's 10th anniversary.&lt;/p&gt;
  3407. &lt;p&gt;With 2.5k commits it has been steadly improving, and in production for many high traffic applications. With this release we say good bye to our old Qt5 friend, also dropped uWSGI support, clearsilver and Grantlee were also removed, many methods now take a QStringView and Cutelyst::Header class was heavly refactored to allow usage of QByteArrayView, and stopped storing QStrings internally in a QHash, they are QByteArray inside a vector.&lt;/p&gt;
  3408. &lt;p&gt;Before, all headers were uppercased and dashes replaced with underscores, this was quite some work, so that when searching the string had to be converted to this format to be searcheable, this had the advantage of allowing the use of QHash and in templates you could c.request.header.CONTENT_TYPE. Turns out both cases aren't so important, speed is more important for the wider use cases.&lt;/p&gt;
  3409. &lt;p&gt;With these changes Cutelyst managed to get 10 - 15% faster on TechEmpower benchmarks, which is great as we are still well positioned as a full stack framework there.&lt;/p&gt;
  3410. &lt;p&gt;https://github.com/cutelyst/cutelyst/releases/tag/v4.0.0&lt;/p&gt;
  3411. &lt;p&gt;Have fun, Merry Christmas and Happy New Year!&lt;/p&gt;</description>
  3412.    </item>
  3413.    <item>
  3414.      <guid isPermaLink="false">https://scythe-studio.com/en/blog/qt-for-mcu</guid>
  3415.      <title>Scythe Studio Qt Blog: Qt Embedded Programming &amp;#8211; First Steps with Qt for MCUs</title>
  3416.      <pubDate>Wed, 20 Dec 2023 14:27:26 GMT</pubDate>
  3417.      <link>https://scythe-studio.com/en/blog/qt-for-mcu</link>
  3418.      <description>&lt;p&gt;On our blog, we have repeatedly covered various &#x2018;branches&#x2019; of Qt-a such as 3D, Android, DBus, etc (the latter topic [&#x2026;]&lt;/p&gt;</description>
  3419.    </item>
  3420.    <item>
  3421.      <guid isPermaLink="false">https://blog.felgo.com/qt-world-summit-2023-highlights</guid>
  3422.      <title>Felgo: Qt World Summit 2023: Together We Shape the Future of Qt</title>
  3423.      <pubDate>Wed, 13 Dec 2023 12:00:00 GMT</pubDate>
  3424.      <link>https://blog.felgo.com/qt-world-summit-2023-highlights</link>
  3425.      <description>&lt;div class="hs-featured-image-wrapper"&gt;&lt;a class="hs-featured-image-link" href="https://blog.felgo.com/qt-world-summit-2023-highlights" title=""&gt;&lt;img alt="Qt World Summit 2023: Together We Shape the Future of Qt" class="hs-featured-image" src="https://blog.felgo.com/hubfs/qtws23-shape-the-future-of-qt-1.png" style="width: auto !important; float: left; margin: 0 15px 15px 0;"&gt;&lt;/a&gt;&lt;/div&gt;
  3426. &lt;p&gt;The Qt World Summit 2023 in Berlin was a huge success. After several years of virtual events, we once again had the chance to meet with industry experts and Qt enthusiasts from all around the world. We thus want to share our experiences, discuss the latest advancements, and strengthen our bonds with the Qt community!&#xA0;&lt;/p&gt;
  3427. &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%2Fqt-world-summit-2023-highlights&amp;bu=https%253A%252F%252Fblog.felgo.com&amp;bvt=rss" width="1"&gt;</description>
  3428.    </item>
  3429.  </channel>
  3430. </rss>
  3431.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.rssboard.org/rss-validator/check.cgi?url=http%3A//planet.qt-project.org/rss20.xml

Software created by Sam Ruby, Mark Pilgrim, Joseph Walton and Phil Ringnalda