<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hedi bettaieb </title>
    <description>The latest articles on DEV Community by Hedi bettaieb  (@hedi_douz).</description>
    <link>https://dev.to/hedi_douz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3974677%2Fc0319af3-f857-4cfe-b5b0-d8fc22de6cd2.png</url>
      <title>DEV Community: Hedi bettaieb </title>
      <link>https://dev.to/hedi_douz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hedi_douz"/>
    <language>en</language>
    <item>
      <title>QTextEdit is Finally Accessible in Qt (PyQt6 &amp; PySide6)</title>
      <dc:creator>Hedi bettaieb </dc:creator>
      <pubDate>Mon, 08 Jun 2026 18:28:48 +0000</pubDate>
      <link>https://dev.to/hedi_douz/qtextedit-is-finally-accessible-in-qt-pyqt6-pyside6-270e</link>
      <guid>https://dev.to/hedi_douz/qtextedit-is-finally-accessible-in-qt-pyqt6-pyside6-270e</guid>
      <description>&lt;h1&gt;
  
  
  Blind Python Developers: QTextEdit is Finally Accessible in Qt (PyQt6 &amp;amp; PySide6)
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;cwidgets is a specialized Python library that enhances NVDA accessibility&lt;br&gt;
for PyQt6 and PySide6 interfaces.&lt;/p&gt;

&lt;p&gt;It provides a complete alternative to QTextEdit — natively inaccessible with NVDA —&lt;br&gt;
allowing blind Python developers to build interfaces containing multi-line text editors&lt;br&gt;
with full NVDA compatibility.&lt;/p&gt;

&lt;p&gt;The library supports both Qt environments:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
# PySide6
from cwidgets.pyside6 import CTextEdit

# PyQt6
from cwidgets.pyqt6 import CTextEdit
The Problem
QTextEdit, Qt's native multi-line text editor, has serious limitations with NVDA:
Content is announced twice during navigation
Impossible to distinguish the current line from a new line
Unpredictable behavior during editing
No reliable feedback on cursor position
These limitations make QTextEdit unusable in practice for a blind developer. QLineEdit is accessible but single-line — it cannot replace QTextEdit.
Result: blind developers using PyQt6 or PySide6 had no reliable solution for integrating a multi-line text editor into their applications.
The Solution — CTextEdit
cwidgets is a Python library that solves this problem by directly integrating the native Win32 RICHEDIT20W control inside a Qt window.
RichEdit is the engine used by WordPad and many Windows applications. It is natively and fully compatible with NVDA — correct reading, precise navigation, reliable line-by-line announcement.
The complex part was integrating it into Qt while maintaining:
Full NVDA accessibility
Standard Qt API (setText, toPlainText, append, clear...)
PyQt6 and PySide6 compatibility
Tab navigation between Qt widgets
Focus restoration after Alt+Tab
All of this is handled internally by cwidgets. You use it exactly like QTextEdit.
Installation
pip install cwidgets
Requirements:
Python 3.10+
Windows (Win32 RichEdit dependency)
PyQt6 or PySide6
pywin32 (installed automatically)
Help and Documentation
After installation, explore the library directly from your code:
import cwidgets

# List all available components
cwidgets.widgets()

# List all available documentation sections
cwidgets.sections()

# Open the full guide in the browser
cwidgets.show_help()
cwidgets.show_help(lang="fr")   # French
cwidgets.show_help(lang="ar")   # Arabic

# Open CTextEdit documentation directly
cwidgets.show_help(lang="en", goto="CTextEdit")

# Explore CTextEdit API from code
cwidgets.ctextedit.show()          # method names only
cwidgets.ctextedit.show_details()  # names + descriptions
Using CTextEdit
# PySide6
from cwidgets.pyside6 import CTextEdit, CLabel

# PyQt6
from cwidgets.pyqt6 import CTextEdit, CLabel
Creation
self.editor = CTextEdit(self, accessible_name="Notes")
layout.addWidget(self.editor)
Content
# Set content
self.editor.setText("Hello from cwidgets!")

# Get content
text = self.editor.toPlainText()
text = self.editor.text()           # alias for toPlainText()

# Append text at the end
self.editor.append("New line.")

# Insert at cursor position
self.editor.insertPlainText("Inserted text\n")

# Insert HTML — tags are stripped
self.editor.insertHtml("&amp;lt;p&amp;gt;Hello &amp;lt;b&amp;gt;world&amp;lt;/b&amp;gt;&amp;lt;/p&amp;gt;")

# Clear content
self.editor.clear()
Selection
self.editor.selectAll()
text = self.editor.selectedText()   # returns "" if no selection
count = self.editor.lineCount()
Properties
self.editor.setReadOnly(True)
self.editor.setReadOnly(False)
state = self.editor.isReadOnly()
Formatting
# Font
self.editor.setFont("Arial", 12, True, False)   # name, size, bold, italic

# Text color — name or (R, G, B)
self.editor.setTextColor("blue")
self.editor.setTextColor((0, 0, 255))

# Background color
self.editor.setBackgroundColor("yellow")

# Alignment
self.editor.setAlignment("left")
self.editor.setAlignment("center")
self.editor.setAlignment("right")
Clipboard
# Ctrl+C/X/V/Z/Y shortcuts work natively via keyboard.
# These methods allow programmatic use, e.g. via a button.

self.editor.copy()
self.editor.cut()
self.editor.paste()
self.editor.undo()
self.editor.redo()
Signals
self.editor.textChanged.connect(self.on_text_changed)
self.editor.cursorPositionChanged.connect(self.on_cursor_changed)
self.editor.selectionChanged.connect(self.on_selection_changed)

def on_text_changed(self):
    print(self.editor.toPlainText())

def on_cursor_changed(self):
    print("Cursor moved")

def on_selection_changed(self):
    print(self.editor.selectedText())
Visual Title with CLabel
self.editor = CTextEdit(self, accessible_name="Description")
self.lbl    = CLabel("Text area:", self, self.editor)
layout.addWidget(self.lbl)
layout.addWidget(self.editor)
Behavior in Layouts
CTextEdit has a minimum size of 50x50 pixels. When sharing a QHBoxLayout with other widgets, use stretch=1:
layout = QHBoxLayout()
layout.addWidget(self.list_widget, 1)
layout.addWidget(self.editor, 1)
Other Widgets
cwidgets also enhances NVDA accessibility for six additional Qt widgets: CButton, CLabel, CLineEdit, CComboBox, CListWidget and CMessageBox. These widgets preserve the complete native Qt API while fixing known NVDA accessibility issues.
Links
PyPI: https://pypi.org/project/cwidgets/
GitHub: https://github.com/hedi-bettaieb/cwidgets
Install: pip install cwidgets

About the Author
Mohamed Hédi Bettaieb — Tunisia
A blind developer who built this library because he needed it himself.
All widgets and all APIs have been personally tested by the developer and by a group of blind Python developers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>algorithms</category>
      <category>python</category>
    </item>
  </channel>
</rss>
