<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Python GUIs</title><link>https://www.pythonguis.com/</link><description>Create GUI applications with Python and Qt</description><atom:link href="https://www.pythonguis.com/feeds/all.rss.xml" rel="self"/><lastBuildDate>Wed, 07 Oct 2026 06:00:00 +0000</lastBuildDate><item><title>Change the color of the ProgressBar indicator text when it exceeds 50%</title><link>https://www.pythonguis.com/faq/change-the-color-of-the-progressbar-indicator-text-when-it-exceeds-50/</link><description>How can I change the text color from black to white of the percentage indicator inside the &lt;code&gt;QProgressBar&lt;/code&gt; when it exceeds the value of 50?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 07 Oct 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-10-07:/faq/change-the-color-of-the-progressbar-indicator-text-when-it-exceeds-50/</guid><category>pyqt5</category><category>pyqt</category><category>qprogressbar</category><category>stylesheets</category><category>python</category><category>qt</category><category>qt5</category></item><item><title>Using Complex Data Sources with PyQt6 Model/View Architecture — How to use JSON, nested data, and other complex structures in your Qt table and list views</title><link>https://www.pythonguis.com/faq/complex-data-in-pyqt-models/</link><description>I have a complex data set in a JSON file. Is it possible to use this as my model's data in PyQt6 views, or do I need to simplify it to a basic table?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 07 Oct 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-10-07:/faq/complex-data-in-pyqt-models/</guid><category>pyqt6</category><category>python</category><category>model-view</category><category>qtableview</category><category>json</category><category>qt</category><category>qt6</category></item><item><title>Changing Ticks in PyQtGraph Objects to Strings — How to replace numeric axis ticks with custom labels like month names or dates in PyQtGraph</title><link>https://www.pythonguis.com/faq/changing-ticks-in-pyqtgraph-objects-to-strings/</link><description>How do I replace the numeric tick labels on a PyQtGraph axis with custom strings, like month names or category labels?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 30 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-30:/faq/changing-ticks-in-pyqtgraph-objects-to-strings/</guid><category>pyqt6</category><category>pyqt</category><category>pyqtgraph</category><category>plotting</category><category>python</category><category>qt</category><category>qt6</category><category>data-science</category><category>pyqt6-data-science</category></item><item><title>Dynamically Adding Rows of Widgets in PyQt6 — How to use QGridLayout to add multiple widgets per row at runtime</title><link>https://www.pythonguis.com/faq/creating-dynamic-textboxes/</link><description>I have a GUI where I dynamically add a QLineEdit for each image a user selects. That part works. But now I want to extend it so that each image gets a &lt;em&gt;row&lt;/em&gt; of three text boxes &amp;mdash; one for the filename, one for the width, and one for the height. How do I dynamically add multiple widgets horizontally for each new entry?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 23 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-23:/faq/creating-dynamic-textboxes/</guid><category>pyqt6</category><category>pyqt</category><category>layouts</category><category>widgets</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Clean up on exit — Stopping threads when closing a PyQt6 application — How to properly shut down background threads and workers when your application window is closed</title><link>https://www.pythonguis.com/faq/clean-up-on-exit-application/</link><description>I'm using QThreadPool and worker threads in my PyQt application. When I click the X button to close the window, the threads keep running in the background. What's the best way to clean everything up on application exit?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 09 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-09:/faq/clean-up-on-exit-application/</guid><category>pyqt6</category><category>python</category><category>threads</category><category>qthread</category><category>qt</category><category>qt6</category></item><item><title>Fixing Crashes When Using NumPy Arrays with QImage in Qt Threads — How to safely pass image data between threads when streaming video or updating displays</title><link>https://www.pythonguis.com/faq/crashing-in-qrunner-threads-with-numpy/</link><description>I'm using a threaded runner to stream a live video feed by converting a NumPy array to a &lt;code&gt;QImage&lt;/code&gt;, then to a &lt;code&gt;QPixmap&lt;/code&gt;, and displaying it on a &lt;code&gt;QLabel&lt;/code&gt;. But I'm frequently encountering crashes when the label is resized too quickly or the scroll area is scrolled. Could this be a problem with the &lt;code&gt;QImage&lt;/code&gt; memory buffer getting cleared before the &lt;code&gt;QPixmap&lt;/code&gt; can update? Is this fixable, or is it a fundamental issue with threads in Python/Qt?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 09 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-09:/faq/crashing-in-qrunner-threads-with-numpy/</guid><category>python</category><category>pyqg6</category><category>pyside6</category><category>threads</category><category>numpy</category><category>qimage</category><category>concurrency</category><category>qt</category><category>qt6</category><category>data-science</category><category>pyside6-data-science</category><category>pyside6-concurrency</category></item><item><title>How to Check if a QLineEdit is Empty in Python — Empty strings are falsey in Python</title><link>https://www.pythonguis.com/faq/check-qlineedit-empty-pyqt/</link><description>A reader asked:</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 09 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-09:/faq/check-qlineedit-empty-pyqt/</guid><category>qlineedit</category><category>widgets</category><category>pyqt</category><category>pyside</category><category>python</category><category>qt</category></item><item><title>Are there any built-in QIcons? — Using built-in icons for your apps.</title><link>https://www.pythonguis.com/faq/built-in-qicons-pyqt/</link><description>In the tutorials on this site and in &lt;a href="/books/"&gt;my books&lt;/a&gt; I recommend using the &lt;a href="https://p.yusukekamiyamane.com/"&gt;fugue icons set&lt;/a&gt;. This is a &lt;em&gt;free&lt;/em&gt; set of icons from Yusuke Kamiyamane, a freelance designer from Tokyo. The set contains 3,570 icons and is a great way to add some nice visual touches to your application without much hassle.</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 02 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-02:/faq/built-in-qicons-pyqt/</guid><category>pyqt</category><category>pyqt6</category><category>pyside</category><category>pyside6</category><category>icons</category><category>theme</category><category>qt-designer</category><category>qstyle</category><category>qicon</category><category>python</category><category>qt</category><category>qt6</category><category>pyqt6-qt-designer</category><category>pyside6-qt-designer</category></item><item><title>Understanding QPainter Coordinates in PyQt6 — How the coordinate system works for drawing on canvases in PyQt6</title><link>https://www.pythonguis.com/faq/coordinates-on-qpainter/</link><description>I really having trouble understanding the coordinate system used in &lt;code&gt;QPainter&lt;/code&gt;. Can you explain how this works?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 02 Sep 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-09-02:/faq/coordinates-on-qpainter/</guid><category>pyqt6</category><category>pyqt</category><category>python</category><category>qpainter</category><category>drawing</category><category>coordinates</category><category>qt</category><category>qt6</category></item><item><title>Creating PySide6 UI without .ui / Qt Designer — Build your entire GUI in pure Python code, no .ui files required</title><link>https://www.pythonguis.com/faq/creating-pyside2-ui-without-ui-qt-designer/</link><description>Is it possible to write a PySide6 application without using .ui files or Qt Designer? How can I create widgets and lay out a window entirely in Python code?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 19 Aug 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-08-19:/faq/creating-pyside2-ui-without-ui-qt-designer/</guid><category>pyside6</category><category>pyside</category><category>python</category><category>gui</category><category>qt</category><category>qt6</category></item><item><title>Adding QTabWidget to a Layout Alongside Other Widgets in PyQt6 — How to combine QTabWidget with other layouts without it taking over your entire window</title><link>https://www.pythonguis.com/faq/cant-integrate-qtabwidget-into-a-layout/</link><description>I'm trying to create a layout in PyQt and implement different layouts into one QHBoxLayout. Everything works fine, but when I add a QTabWidget alongside other layouts, it becomes the only visible widget &amp;mdash; as if everything else disappears. Isn't it possible to have a QTabWidget in a layout beside other layouts?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 12 Aug 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-08-12:/faq/cant-integrate-qtabwidget-into-a-layout/</guid><category>pyqt6</category><category>layout</category><category>qtabwidget</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Handling Image Drag and Drop from Web Browsers in PyQt6 — Why toLocalFile() returns an empty string and how to handle remote image drops correctly</title><link>https://www.pythonguis.com/faq/dragging-and-dropping-in-rich-text-example-app/</link><description>&lt;blockquote&gt;
&lt;p&gt;When dragging and dropping images from a web browser into a PyQt6 rich text editor, &lt;code&gt;toLocalFile()&lt;/code&gt; sometimes returns a blank string. It works for some images (like Google image search results) but fails for others (like images embedded directly on a webpage). Why does this happen, and how can I handle it?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you've added drag and drop support to your application, you may have noticed something frustrating: dragging an image from a browser sometimes works perfectly, and other times gives you nothing at all. The &lt;code&gt;toLocalFile()&lt;/code&gt; method returns an empty string, and your image never appears.&lt;/p&gt;
&lt;p&gt;This comes down to how browsers package image data when you start a drag operation, and what your application expects to receive. Let's walk through what's happening and how to fix it.&lt;/p&gt;
&lt;h2 id="how-drag-and-drop-mime-data-works"&gt;How drag and drop MIME data works&lt;/h2&gt;
&lt;p&gt;When you drag something &amp;mdash; a file, an image, some text &amp;mdash; the source application bundles that data into a &lt;code&gt;QMimeData&lt;/code&gt; object. This object can contain several different formats at once. For example, dragging an image might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A file URL (&lt;code&gt;text/uri-list&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Raw image data (&lt;code&gt;image/png&lt;/code&gt; or &lt;code&gt;image/jpeg&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;An HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag (&lt;code&gt;text/html&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A plain text URL (&lt;code&gt;text/plain&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Which of these formats are included depends entirely on the source application. Different browsers, and even different types of images within the same browser, behave differently.&lt;/p&gt;
&lt;h2 id="why-tolocalfile-returns-an-empty-string"&gt;Why toLocalFile() returns an empty string&lt;/h2&gt;
&lt;p&gt;The method &lt;code&gt;QUrl.toLocalFile()&lt;/code&gt; converts a URL into a local filesystem path. It only works when the URL uses the &lt;code&gt;file://&lt;/code&gt; scheme &amp;mdash; meaning the file actually exists on your computer.&lt;/p&gt;
&lt;p&gt;When you drag an image from a Google image search, the browser often creates a temporary local file and provides a &lt;code&gt;file://&lt;/code&gt; URL. That's why &lt;code&gt;toLocalFile()&lt;/code&gt; works in that case.&lt;/p&gt;
&lt;p&gt;But when you drag an image that's embedded directly in a webpage (like a screenshot in a blog post), the browser typically provides a remote &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt; URL instead. There's no local file, so &lt;code&gt;toLocalFile()&lt;/code&gt; returns an empty string. Some browsers may also provide the image as inline data or an HTML fragment with no URL at all.&lt;/p&gt;
&lt;h2 id="inspecting-what-the-browser-actually-sends"&gt;Inspecting what the browser actually sends&lt;/h2&gt;
&lt;p&gt;A good first step is to look at exactly what MIME data arrives when you drop something. This small example creates a drop target that prints out all available MIME formats and their contents:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget


class DropInspector(QLabel):
    def __init__(self):
        super().__init__("Drop something here")
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.setMinimumSize(400, 300)
        self.setStyleSheet(
            "background-color: #f0f0f0; border: 2px dashed #aaa; font-size: 16px;"
        )
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        event.acceptProposedAction()

    def dropEvent(self, event):
        mime_data = event.mimeData()
        print("=== Drop received ===")
        for fmt in mime_data.formats():
            data = mime_data.data(fmt)
            print(f"\nFormat: {fmt}")
            # Show first 200 bytes as text for readability.
            try:
                print(f"  Data: {bytes(data[:200]).decode('utf-8', errors='replace')}")
            except Exception:
                print(f"  Data: ({len(data)} bytes, binary)")

        if mime_data.hasUrls():
            for url in mime_data.urls():
                print(f"\nURL: {url.toString()}")
                print(f"  toLocalFile: '{url.toLocalFile()}'")
                print(f"  scheme: '{url.scheme()}'")

        event.acceptProposedAction()
        self.setText("Check console output!")


app = QApplication(sys.argv)
window = DropInspector()
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Try dragging different images from your browser into this window. You'll see that some drops include &lt;code&gt;file://&lt;/code&gt; URLs while others include &lt;code&gt;https://&lt;/code&gt; URLs or even raw image data with no URL at all.&lt;/p&gt;
&lt;h2 id="handling-all-cases-in-your-drop-event"&gt;Handling all cases in your drop event&lt;/h2&gt;
&lt;p&gt;To make your application work reliably with images dragged from any source, you need to handle multiple scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Local file URL&lt;/strong&gt; &amp;mdash; use the file path directly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote URL&lt;/strong&gt; &amp;mdash; download the image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raw image data&lt;/strong&gt; &amp;mdash; use it directly from the MIME data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML with an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag&lt;/strong&gt; &amp;mdash; extract the image URL from the HTML&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here's how to implement this step by step.&lt;/p&gt;
&lt;h3&gt;Checking for local files first&lt;/h3&gt;
&lt;p&gt;This is the simplest case and the one you likely already have working:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def dropEvent(self, event):
    mime_data = event.mimeData()

    if mime_data.hasUrls():
        for url in mime_data.urls():
            local_path = url.toLocalFile()
            if local_path:
                # It's a local file &amp;mdash; use it directly.
                self.insert_image_from_path(local_path)
                event.acceptProposedAction()
                return
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3&gt;Handling remote URLs&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;toLocalFile()&lt;/code&gt; returns an empty string but you still have a URL, it's likely a remote image. You can download it using Python's &lt;code&gt;urllib&lt;/code&gt; (or &lt;code&gt;requests&lt;/code&gt; if you prefer):&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import os
import tempfile
import urllib.request


def download_image(url_string):
    """Download an image from a URL and return the local file path."""
    try:
        # Create a temporary file to store the downloaded image.
        suffix = os.path.splitext(url_string)[-1].split("?")[0]
        if suffix not in (".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"):
            suffix = ".png"
        tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
        urllib.request.urlretrieve(url_string, tmp_file.name)
        return tmp_file.name
    except Exception as e:
        print(f"Failed to download image: {e}")
        return None
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then extend your drop handler:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;if mime_data.hasUrls():
    for url in mime_data.urls():
        local_path = url.toLocalFile()
        if local_path:
            self.insert_image_from_path(local_path)
            event.acceptProposedAction()
            return

        # No local file &amp;mdash; try downloading the remote URL.
        url_string = url.toString()
        if url_string:
            local_path = download_image(url_string)
            if local_path:
                self.insert_image_from_path(local_path)
                event.acceptProposedAction()
                return
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3&gt;Handling raw image data&lt;/h3&gt;
&lt;p&gt;Sometimes the browser sends the image data directly, without any URL. You can check for this using &lt;code&gt;hasImage()&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;if mime_data.hasImage():
    image = mime_data.imageData()
    if image and not image.isNull():
        # Save the image to a temp file and insert it.
        tmp_path = tempfile.NamedTemporaryFile(
            delete=False, suffix=".png"
        ).name
        image.save(tmp_path)
        self.insert_image_from_path(tmp_path)
        event.acceptProposedAction()
        return
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3&gt;Extracting URLs from HTML&lt;/h3&gt;
&lt;p&gt;As a fallback, some drops include an HTML fragment with an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag. You can parse out the &lt;code&gt;src&lt;/code&gt; attribute:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import re


def extract_image_url_from_html(html):
    """Extract the first image URL from an HTML string."""
    match = re.search(r'&amp;lt;img[^&amp;gt;]+src=["\']([^"\']+)["\']', html)
    if match:
        return match.group(1)
    return None
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then add this as a final fallback:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;if mime_data.hasHtml():
    html = mime_data.html()
    image_url = extract_image_url_from_html(html)
    if image_url:
        local_path = download_image(image_url)
        if local_path:
            self.insert_image_from_path(local_path)
            event.acceptProposedAction()
            return
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="complete-working-example"&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's a full, working rich text editor with robust image drag and drop support. You can copy this and run it directly:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import os
import re
import sys
import tempfile
import urllib.request

from PyQt6.QtCore import Qt
from PyQt6.QtGui import QImage, QTextCursor
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget


def download_image(url_string):
    """Download an image from a URL and return the local file path."""
    try:
        suffix = os.path.splitext(url_string.split("?")[0])[-1]
        if suffix.lower() not in (".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"):
            suffix = ".png"
        tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
        urllib.request.urlretrieve(url_string, tmp_file.name)
        return tmp_file.name
    except Exception as e:
        print(f"Failed to download image: {e}")
        return None


def extract_image_url_from_html(html):
    """Extract the first image URL from an HTML string."""
    match = re.search(r'&amp;lt;img[^&amp;gt;]+src=["\']([^"\']+)["\']', html)
    if match:
        return match.group(1)
    return None


class ImageDropTextEdit(QTextEdit):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)

    def canInsertFromMimeData(self, source):
        if source.hasImage() or source.hasUrls() or source.hasHtml():
            return True
        return super().canInsertFromMimeData(source)

    def insertFromMimeData(self, source):
        """Handle paste and drop events with image support."""
        # Try each method in order of reliability.

        # 1. Check for direct image data.
        if source.hasImage():
            image = source.imageData()
            if isinstance(image, QImage) and not image.isNull():
                self.insert_image(image)
                return

        # 2. Check for URLs (local or remote).
        if source.hasUrls():
            for url in source.urls():
                local_path = url.toLocalFile()
                if local_path and self.is_image_file(local_path):
                    self.insert_image_from_path(local_path)
                    return

                # Try downloading remote URL.
                url_string = url.toString()
                if url_string and self.looks_like_image_url(url_string):
                    local_path = download_image(url_string)
                    if local_path:
                        self.insert_image_from_path(local_path)
                        return

        # 3. Check for HTML with embedded image tags.
        if source.hasHtml():
            image_url = extract_image_url_from_html(source.html())
            if image_url:
                if image_url.startswith("data:"):
                    # Data URI &amp;mdash; decode and insert.
                    image = self.image_from_data_uri(image_url)
                    if image and not image.isNull():
                        self.insert_image(image)
                        return
                else:
                    local_path = download_image(image_url)
                    if local_path:
                        self.insert_image_from_path(local_path)
                        return

        # Fall back to default behavior for plain text, etc.
        super().insertFromMimeData(source)

    def insert_image_from_path(self, file_path):
        """Insert an image from a local file path into the editor."""
        image = QImage(file_path)
        if image.isNull():
            print(f"Could not load image: {file_path}")
            return
        self.insert_image(image)

    def insert_image(self, image):
        """Insert a QImage into the editor at the current cursor position."""
        cursor = self.textCursor()
        document = self.document()

        # Add the image as a resource in the document.
        image_name = f"dropped_image_{id(image)}"
        document.addResource(
            document.ResourceType.ImageResource.value,
            self.create_url(image_name),
            image,
        )

        # Insert the image at the cursor.
        image_format = cursor.charFormat()
        from PyQt6.QtGui import QTextImageFormat

        img_fmt = QTextImageFormat()
        img_fmt.setName(image_name)
        img_fmt.setWidth(min(image.width(), 600))
        img_fmt.setHeight(
            int(image.height() * min(image.width(), 600) / max(image.width(), 1))
        )
        cursor.insertImage(img_fmt)

    @staticmethod
    def create_url(name):
        from PyQt6.QtCore import QUrl

        return QUrl(name)

    @staticmethod
    def is_image_file(path):
        extensions = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".svg"}
        return os.path.splitext(path.lower())[-1] in extensions

    @staticmethod
    def looks_like_image_url(url_string):
        """Check if a URL looks like it points to an image."""
        clean_url = url_string.split("?")[0].lower()
        extensions = {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp", ".svg"}
        return any(clean_url.endswith(ext) for ext in extensions)

    @staticmethod
    def image_from_data_uri(data_uri):
        """Decode a data: URI and return a QImage."""
        import base64

        try:
            # data:image/png;base64,iVBOR...
            header, data = data_uri.split(",", 1)
            image_data = base64.b64decode(data)
            image = QImage()
            image.loadFromData(image_data)
            return image
        except Exception as e:
            print(f"Failed to decode data URI: {e}")
            return None


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Rich Text Editor &amp;mdash; Image Drop Demo")
        self.setMinimumSize(700, 500)

        self.editor = ImageDropTextEdit()
        self.editor.setPlaceholderText(
            "Try dragging an image from your web browser into this editor..."
        )

        layout = QVBoxLayout()
        layout.addWidget(self.editor)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="whats-happening-in-the-complete-example"&gt;What's happening in the complete example&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;ImageDropTextEdit&lt;/code&gt; class overrides &lt;code&gt;insertFromMimeData&lt;/code&gt;, which Qt calls for both paste (Ctrl+V) and drag-and-drop operations. This gives you a single place to handle all image insertion.&lt;/p&gt;
&lt;p&gt;The method tries each data source in order:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Direct image data&lt;/strong&gt; &amp;mdash; the fastest and most reliable, when available.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URLs&lt;/strong&gt; &amp;mdash; first checking for local files, then attempting to download remote URLs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTML fragments&lt;/strong&gt; &amp;mdash; parsing out &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags and fetching the referenced image, including support for &lt;code&gt;data:&lt;/code&gt; URIs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fallback&lt;/strong&gt; &amp;mdash; if none of the above match, it passes control to the default &lt;code&gt;QTextEdit&lt;/code&gt; behavior, so normal text paste and drop still work.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By overriding &lt;code&gt;canInsertFromMimeData&lt;/code&gt; as well, we tell Qt's drag and drop system that our editor accepts these additional formats, which ensures the correct cursor icon appears when hovering over the editor.&lt;/p&gt;
&lt;p&gt;This approach handles the differences between browsers &amp;mdash; Chrome, Firefox, Edge &amp;mdash; and between different types of images on the web, making your rich text editor's drag and drop support much more resilient.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 05 Aug 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-08-05:/faq/dragging-and-dropping-in-rich-text-example-app/</guid><category>pyqt6</category><category>pyqt</category><category>drag-and-drop</category><category>rich-text</category><category>python</category><category>mime-data</category><category>qt</category><category>qt6</category></item><item><title>Constantly Print Subprocess Output While Process is Running — How to stream live output from a subprocess into your PyQt6 GUI without freezing the interface</title><link>https://www.pythonguis.com/faq/constantly-print-subprocess-output-while-process-is-running/</link><description>I need to call a legacy Bash program and display the results in a Qt window. The problem is the subprocess doesn't return each output line as it happens &amp;mdash; it waits until the entire command is finished, then dumps everything to the window at once. If the command takes a long time, the user thinks the system is frozen. How can I get live, line-by-line output from a subprocess into my Qt application?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 22 Jul 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-07-22:/faq/constantly-print-subprocess-output-while-process-is-running/</guid><category>pyqt6</category><category>python</category><category>subprocess</category><category>qprocess</category><category>qthread</category><category>gui</category><category>qt</category><category>qt6</category></item><item><title>Why Widgets Appear as Separate Windows — Understanding widget parenting in Qt and how to fix widgets that float outside your main window</title><link>https://www.pythonguis.com/faq/adding-new-tabs-in-tabwidget-appears-as-a-seperate-window-when-tab-is-selected/</link><description>Sometimes when I dynamically add widgets to tabs in my PyQt6 application, they pop out as windows instead. What's going on?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 08 Jul 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-07-08:/faq/adding-new-tabs-in-tabwidget-appears-as-a-seperate-window-when-tab-is-selected/</guid><category>pyqt6</category><category>pyqt</category><category>widgets</category><category>troubleshooting</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>How to Set Row Background Colors in a QTableView — Use Qt's BackgroundRole to color entire rows based on your data</title><link>https://www.pythonguis.com/faq/backgroundcolor-for-row-in-qtableview/</link><description>I have a QTableView table showing some data about connected devices. How can I highlight rows to give a visual indicator of the current status of the device?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 10 Jun 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-06-10:/faq/backgroundcolor-for-row-in-qtableview/</guid><category>pyqt6</category><category>pyqt</category><category>qtableview</category><category>model-view</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Authentication and Authorization with PyQt6 or PySide6 — Secure your desktop applications with login flows, token-based auth, and role-based access control</title><link>https://www.pythonguis.com/faq/authentication-and-authorization-with-pyqt6-or-pyside6/</link><description>How can I add authentication and authorization to a PyQt6 application? Is there something built into Qt to make this easier?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 03 Jun 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-06-03:/faq/authentication-and-authorization-with-pyqt6-or-pyside6/</guid><category>pyqt6</category><category>pyqt</category><category>pyside6</category><category>pyside</category><category>authentication</category><category>authorization</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Fixing Missing Icons in PyInstaller-Packaged PyQt6 Applications on Windows — Why your app icon disappears after packaging and how to fix it</title><link>https://www.pythonguis.com/faq/always-the-default-icon/</link><description>&lt;blockquote&gt;
&lt;p&gt;I've packaged my PyQt application with PyInstaller, but the icon isn't showing up &amp;mdash; both the executable icon and the running application icon are just the default Python/Windows icon. What's going on?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a common issue when &lt;a href="https://www.pythonguis.com/tutorials/packaging-pyqt6-applications-windows-pyinstaller/"&gt;packaging PyQt6 apps with PyInstaller on Windows&lt;/a&gt;. The good news is that it usually comes down to one of two straightforward causes: Windows icon caching, and missing resource files in your packaged output.&lt;/p&gt;
&lt;h2 id="setting-the-executable-icon-with-pyinstaller"&gt;Setting the executable icon with PyInstaller&lt;/h2&gt;
&lt;p&gt;When you run PyInstaller, you can set the icon for the &lt;code&gt;.exe&lt;/code&gt; file itself using the &lt;code&gt;--icon&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;pyinstaller --windowed --icon=myicon.ico myapp.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This embeds the icon into the executable, so it shows up in File Explorer and on the desktop. The icon file needs to be in &lt;code&gt;.ico&lt;/code&gt; format &amp;mdash; &lt;code&gt;.png&lt;/code&gt; or &lt;code&gt;.svg&lt;/code&gt; won't work here.&lt;/p&gt;
&lt;p&gt;After building, check the &lt;code&gt;dist/&lt;/code&gt; folder. Your &lt;code&gt;.exe&lt;/code&gt; should display the custom icon. But sometimes... it doesn't.&lt;/p&gt;
&lt;h2 id="windows-icon-caching"&gt;Windows icon caching&lt;/h2&gt;
&lt;p&gt;Windows caches icons aggressively. If you've previously built your app without a custom icon, Windows may continue to show the old default icon even after you've rebuilt the app with the correct one.&lt;/p&gt;
&lt;p class="admonition admonition-note"&gt;&lt;span class="admonition-kind"&gt;&lt;i class="fas fa-sticky-note"&gt;&lt;/i&gt;&lt;/span&gt;  This still catches me out, even though I know this. You'll reflexively start checking the config assuming something is wrong, and think you're going mad.&lt;/p&gt;
&lt;p&gt;There are a few ways to deal with this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rename the executable.&lt;/strong&gt; Changing the filename forces Windows to look up the icon fresh. This is the quickest way to confirm that your icon &lt;em&gt;is&lt;/em&gt; actually embedded correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear the Windows icon cache.&lt;/strong&gt; You can do this by restarting Windows Explorer or by deleting the icon cache files manually. To manually clear the Windows icon cache open a Command Prompt and run:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;ie4uinit.exe -show
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After clearing the cache, the correct icon should appear.&lt;/p&gt;
&lt;p&gt;You can also try turning your computer off and on again, or rather restarting Windows. That will also trigger the icon cache to rebuild.&lt;/p&gt;
&lt;h2 id="missing-icon-file-at-runtime"&gt;Missing icon file at runtime&lt;/h2&gt;
&lt;p&gt;Setting the executable icon with &lt;code&gt;--icon&lt;/code&gt; only affects what shows up in File Explorer. If your application &lt;em&gt;also&lt;/em&gt; sets a window icon in code (using &lt;code&gt;setWindowIcon&lt;/code&gt;), that icon file needs to be available at runtime too.&lt;/p&gt;
&lt;p&gt;For example, if your code does this:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QIcon
import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("My Application")


app = QApplication(sys.argv)
app.setWindowIcon(QIcon("myicon.ico"))

window = MainWindow()
window.show()

app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then &lt;code&gt;myicon.ico&lt;/code&gt; needs to exist in the working directory when the packaged app runs. By default, PyInstaller doesn't include data files like &lt;code&gt;.ico&lt;/code&gt; images unless you tell it to.&lt;/p&gt;
&lt;p&gt;You can add the icon file to your build using the &lt;code&gt;--add-data&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;pyinstaller --windowed --icon=myicon.ico --add-data "myicon.ico;." myapp.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;On Linux or macOS, use &lt;code&gt;:&lt;/code&gt; instead of &lt;code&gt;;&lt;/code&gt; as the separator:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;pyinstaller --windowed --icon=myicon.ico --add-data "myicon.ico:." myapp.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This copies &lt;code&gt;myicon.ico&lt;/code&gt; into the output directory alongside your executable (or into the temporary directory if you're using &lt;code&gt;--onefile&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;An alternative approach (not available on PyQt6) is to use the &lt;a href="https://www.pythonguis.com/tutorials/pyside6-qresource-system/"&gt;Qt Resource System&lt;/a&gt; to embed your icon directly into your application, which avoids the need to bundle separate icon files entirely.&lt;/p&gt;
&lt;h3&gt;Handling &lt;code&gt;--onefile&lt;/code&gt; builds&lt;/h3&gt;
&lt;p&gt;When you use &lt;code&gt;--onefile&lt;/code&gt;, PyInstaller extracts everything to a temporary folder at runtime. Your code needs to know how to find files relative to that temporary folder. You can handle this by detecting the base path:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys
import os

if getattr(sys, 'frozen', False):
    # Running as a PyInstaller bundle
    basedir = sys._MEIPASS
else:
    # Running as a normal script
    basedir = os.path.dirname(__file__)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then use &lt;code&gt;basedir&lt;/code&gt; when constructing file paths:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;app.setWindowIcon(QIcon(os.path.join(basedir, "myicon.ico")))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="taskbar-grouping-with-an-application-user-model-id"&gt;Taskbar grouping with an Application User Model ID&lt;/h2&gt;
&lt;p&gt;On Windows, the taskbar groups windows by their application identity. Without an explicit identity, Windows guesses &amp;mdash; and sometimes guesses wrong. This can cause your app to show the Python icon in the taskbar, or to group instances inconsistently depending on where they were launched from.&lt;/p&gt;
&lt;p&gt;You can fix this by setting an &lt;em&gt;Application User Model ID&lt;/em&gt; before creating your &lt;code&gt;QApplication&lt;/code&gt;. This tells Windows exactly which application this is:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import ctypes

myappid = "com.mycompany.myapp.1.0"
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The string can be anything, but it's conventional to use a reverse-domain format. The value just needs to be unique to your application.&lt;/p&gt;
&lt;p&gt;With an explicit app ID set, all instances of your app will group together in the taskbar regardless of where they were launched from &amp;mdash; whether that's your IDE, the &lt;code&gt;dist/&lt;/code&gt; folder, or a &lt;code&gt;--onefile&lt;/code&gt; build.&lt;/p&gt;
&lt;h2 id="complete-working-example"&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's a complete example that handles all of the above &amp;mdash; the runtime base path, the window icon, and the application user model ID. If you're new to building PyQt6 applications, you may want to start with &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-creating-your-first-window/"&gt;creating your first window&lt;/a&gt; before tackling packaging.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import sys
import os
import ctypes

from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt


# Set the app user model ID before creating QApplication (Windows only)
if sys.platform == "win32":
    myappid = "com.mycompany.myapp.1.0"
    ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)

# Determine the base directory for resource files
if getattr(sys, "frozen", False):
    basedir = sys._MEIPASS
else:
    basedir = os.path.dirname(__file__)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("My Application")
        label = QLabel("Hello, world!")
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.setCentralWidget(label)


app = QApplication(sys.argv)
app.setWindowIcon(QIcon(os.path.join(basedir, "myicon.ico")))

window = MainWindow()
window.show()

app.exec()
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To package this with PyInstaller:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;pyinstaller --windowed --icon=myicon.ico --add-data "myicon.ico;." myapp.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 27 May 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-05-27:/faq/always-the-default-icon/</guid><category>pyqt6</category><category>pyinstaller</category><category>windows</category><category>icons</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Adding QComboBox to a QTableView and getting/setting values after creation — Use QItemDelegate to embed combo boxes in your table views, with per-row data and value tracking</title><link>https://www.pythonguis.com/faq/adding-qcombobox-to-a-qtableview-and-getting-setting-values-after-creation/</link><description>I'm using a QTableView to display data, and would like to limit the choices in some of the fields using a drop-down. I can use &lt;code&gt;QComboBox&lt;/code&gt; to provide a list of choices in a normal UI, but how can I do that in a table view?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 20 May 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-05-20:/faq/adding-qcombobox-to-a-qtableview-and-getting-setting-values-after-creation/</guid><category>pyqt6</category><category>pyqt</category><category>qtableview</category><category>qcombobox</category><category>delegate</category><category>model-view</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>How to Add Custom Widgets to Qt Designer — Use widget promotion to integrate your own Python widgets into Qt Designer layouts</title><link>https://www.pythonguis.com/faq/add-widgets-in-a-kind-of-library-show-in-the-qt-designer/</link><description>Can I use custom widgets in Qt Designer?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 13 May 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-05-13:/faq/add-widgets-in-a-kind-of-library-show-in-the-qt-designer/</guid><category>pyqt6</category><category>pyqt</category><category>qtdesigner</category><category>custom-widgets</category><category>widget-promotion</category><category>python</category><category>qt</category><category>qt6</category><category>pyqt6-custom-widgets</category></item><item><title>Sorting and Filtering a QTableView with QSortFilterProxyModel — Learn how to add interactive sorting and filtering to your PyQt/PySide table views without touching your underlying data</title><link>https://www.pythonguis.com/faq/add-some-explanation-on-sorting-a-qtableview/</link><description>I'm using QTableView to show some data, which works well. But I would like to be able to sort the data by different columns. How can I do this without sorting the data manually?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 06 May 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-05-06:/faq/add-some-explanation-on-sorting-a-qtableview/</guid><category>PyQt5</category><category>PyQt6</category><category>PySide2</category><category>PySide6</category><category>QTableView</category><category>QSortFilterProxyModel</category><category>Model-View</category></item><item><title>Streamlit Buttons — Making things happen with Streamlit buttons</title><link>https://www.pythonguis.com/tutorials/streamlit-buttons/</link><description>Streamlit is a popular choice for creating interactive web applications in Python. With its simple syntax and intuitive interface, developers can quickly create visually appealing dashboards.</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Fri, 01 May 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-05-01:/tutorials/streamlit-buttons/</guid><category>streamlit</category><category>foundation</category><category>buttons</category><category>streamlit-foundation</category></item><item><title>Actions in one thread changing data in another — How to communicate between threads and windows in PyQt6</title><link>https://www.pythonguis.com/faq/actions-in-one-thread-changing-data-in-another/</link><description>I have a main window that starts background threads (e.g., handling GPIO data). From the main window I open secondary windows using buttons. When I press a button in a secondary window, I can't change anything in the background threads. But if I press a button in the main window, everything works. How do I communicate between a secondary window and a thread that was started from the main window?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 29 Apr 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-04-29:/faq/actions-in-one-thread-changing-data-in-another/</guid><category>pyqt6</category><category>multithreading</category><category>signals</category><category>qthread</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>Streamlit Widgets — An Overview of Commonly Used Widgets in Streamlit</title><link>https://www.pythonguis.com/tutorials/streamlit-widgets/</link><description>Streamlit is a powerful Python library designed to build interactive web apps with minimal code. One of its core features is an extensive collection of widgets that allow users to interact with the app in various ways, such as providing inputs, triggering actions, or visualizing data. Streamlit makes it easy to create these elements with simple, intuitive syntax.</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Fri, 24 Apr 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-04-24:/tutorials/streamlit-widgets/</guid><category>streamlit</category><category>foundation</category><category>streamlit-foundation</category></item><item><title>Checkboxes in Table Views with a Custom Model — Show checkboxes for boolean values in PyQt/PySide table views</title><link>https://www.pythonguis.com/faq/abstract-table-model-question/</link><description>I have a QTableView with a custom QAbstractTableModel, and I want to add a column of checkboxes. Should I create a custom delegate class for the checkbox, or is there a simpler way to do this?</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Wed, 22 Apr 2026 09:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-04-22:/faq/abstract-table-model-question/</guid><category>pyqt6</category><category>pyqt</category><category>pyside6</category><category>pyside</category><category>qtableview</category><category>qabstracttablemodel</category><category>checkbox</category><category>python</category><category>qt</category><category>qt6</category></item><item><title>What does @pyqtSlot() do? — Is the pyqtSlot decorator even necessary?</title><link>https://www.pythonguis.com/faq/what-does-pyqtslot-do/</link><description>When working with Qt slots and signals in PyQt6 you will discover the &lt;code&gt;@pyqtSlot&lt;/code&gt; decorator. This decorator is used to &lt;em&gt;mark&lt;/em&gt; a Python function or method as a &lt;em&gt;slot&lt;/em&gt; to which a Qt signal can be connected. However, as you can see in our &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-signals-slots-events/"&gt;signals and slots tutorials&lt;/a&gt; you don't &lt;em&gt;have&lt;/em&gt; to use this. Any Python function or method can be used, normally, as a slot for Qt signals. But elsewhere, in our &lt;a href="https://www.pythonguis.com/tutorials/multithreading-pyqt6-applications-qthreadpool/"&gt;threading tutorials&lt;/a&gt; we &lt;em&gt;do&lt;/em&gt; use it.</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Martin Fitzpatrick</dc:creator><pubDate>Mon, 12 Jan 2026 06:00:00 +0000</pubDate><guid>tag:www.pythonguis.com,2026-01-12:/faq/what-does-pyqtslot-do/</guid><category>pyqt6</category><category>pyqt5</category><category>pyqt</category><category>threading</category><category>threads</category><category>signals</category><category>slots</category><category>python</category><category>qt</category><category>qt6</category><category>qt5</category></item></channel></rss>