TextEdit Example¶
The Text Edit example shows Qt’s rich text editing facilities in action.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
"""PySide6 port of the widgets/richtext/textedit example from Qt v6.x"""
import sys
from argparse import ArgumentParser, RawTextHelpFormatter
from PySide6.QtCore import QCoreApplication, qVersion
from PySide6.QtWidgets import QApplication
from textedit import TextEdit
import textedit_rc # noqa: F401
if __name__ == '__main__':
argument_parser = ArgumentParser(description='Rich Text Example',
formatter_class=RawTextHelpFormatter)
argument_parser.add_argument("file", help="File",
nargs='?', type=str)
options = argument_parser.parse_args()
app = QApplication(sys.argv)
QCoreApplication.setOrganizationName("QtProject")
QCoreApplication.setApplicationName("Rich Text")
QCoreApplication.setApplicationVersion(qVersion())
mw = TextEdit()
available_geometry = mw.screen().availableGeometry()
mw.resize((available_geometry.width() * 2) / 3,
(available_geometry.height() * 2) / 3)
mw.move((available_geometry.width() - mw.width()) / 2,
(available_geometry.height() - mw.height()) / 2)
file = options.file if options.file else ":/example.html"
if not mw.load(file):
mw.file_new()
mw.show()
sys.exit(app.exec())
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations
import sys
from PySide6.QtCore import (QCoreApplication, QDir, QFile, QFileInfo,
QMimeDatabase, QUrl, Qt, Slot)
from PySide6.QtGui import (QAction, QActionGroup, QColor, QGuiApplication,
QFont, QFontDatabase, QFontInfo, QIcon,
QKeySequence, QPalette, QPixmap, QTextBlockFormat,
QTextCharFormat, QTextCursor, QTextDocumentWriter,
QTextFormat, QTextListFormat)
from PySide6.QtWidgets import (QApplication, QMainWindow, QColorDialog, QComboBox,
QDialog, QFileDialog, QFontComboBox,
QTextEdit, QMessageBox)
from PySide6.QtPrintSupport import (QAbstractPrintDialog, QPrinter,
QPrintDialog, QPrintPreviewDialog)
ABOUT = """This example demonstrates Qt's
rich text editing facilities in self.action, providing an example
document for you to experiment with."""
MIME_TYPES = ["text/html", "text/markdown", "text/plain"]
RSRC_PATH = ":/images/mac" if sys.platform == 'darwin' else ":/images/win"
STYLES = ["Standard", "Bullet List (Disc)", "Bullet List (Circle)",
"Bullet List (Square)", "Task List (Unchecked)",
"Task List (Checked)", "Ordered List (Decimal)",
"Ordered List (Alpha lower)", "Ordered List (Alpha upper)",
"Ordered List (Roman lower)", "Ordered List (Roman upper)",
"Heading 1", "Heading 2", "Heading 3", "Heading 4", "Heading 5",
"Heading 6"]
class TextEdit(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
if sys.platform == 'darwin':
self.setUnifiedTitleAndToolBarOnMac(True)
self.setWindowTitle(QCoreApplication.applicationName())
self._text_edit = QTextEdit(self)
self._text_edit.currentCharFormatChanged.connect(self.current_char_format_changed)
self._text_edit.cursorPositionChanged.connect(self.cursor_position_changed)
self.setCentralWidget(self._text_edit)
self.setToolButtonStyle(Qt.ToolButtonFollowStyle)
self.setup_file_actions()
self.setup_edit_actions()
self.setup_text_actions()
help_menu = self.menuBar().addMenu("Help")
help_menu.addAction("About", self.about)
help_menu.addAction("About &Qt", qApp.aboutQt) # noqa: F821
text_font = QFont("Helvetica")
text_font.setStyleHint(QFont.SansSerif)
self._text_edit.setFont(text_font)
self.font_changed(self._text_edit.font())
self.color_changed(self._text_edit.textColor())
self.alignment_changed(self._text_edit.alignment())
document = self._text_edit.document()
document.modificationChanged.connect(self._action_save.setEnabled)
document.modificationChanged.connect(self.setWindowModified)
document.undoAvailable.connect(self._action_undo.setEnabled)
document.redoAvailable.connect(self._action_redo.setEnabled)
self.setWindowModified(document.isModified())
self._action_save.setEnabled(document.isModified())
self._action_undo.setEnabled(document.isUndoAvailable())
self._action_redo.setEnabled(document.isRedoAvailable())
self._action_cut.setEnabled(False)
self._text_edit.copyAvailable.connect(self._action_cut.setEnabled)
self._action_copy.setEnabled(False)
self._text_edit.copyAvailable.connect(self._action_copy.setEnabled)
QGuiApplication.clipboard().dataChanged.connect(self.clipboard_data_changed)
self._text_edit.setFocus()
self.set_current_file_name('')
# Use dark text on light background on macOS, also in dark mode.
if sys.platform == 'darwin':
pal = self._text_edit.palette()
pal.setColor(QPalette.Base, QColor(Qt.white))
pal.setColor(QPalette.Text, QColor(Qt.black))
self._text_edit.setPalette(pal)
def closeEvent(self, e):
if self.maybe_save():
e.accept()
else:
e.ignore()
def setup_file_actions(self):
tb = self.addToolBar("File self.actions")
menu = self.menuBar().addMenu("&File")
icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentNew,
QIcon(RSRC_PATH + "/filenew.png"))
a = menu.addAction(icon, "&New", self.file_new)
tb.addAction(a)
a.setPriority(QAction.LowPriority)
a.setShortcut(QKeySequence.New)
icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentOpen,
QIcon(RSRC_PATH + "/fileopen.png"))
a = menu.addAction(icon, "&Open...", self.file_open)
a.setShortcut(QKeySequence.Open)
tb.addAction(a)
menu.addSeparator()
icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentSave,
QIcon(RSRC_PATH + "/filesave.png"))
self._action_save = menu.addAction(icon, "&Save", self.file_save)
self._action_save.setShortcut(QKeySequence.Save)
self._action_save.setEnabled(False)
tb.addAction(self._action_save)
a = menu.addAction("Save &As...", self.file_save_as)
a.setPriority(QAction.LowPriority)
menu.addSeparator()
icon = QIcon.fromTheme(QIcon.ThemeIcon.DocumentPrint,
QIcon(RSRC_PATH + "/fileprint.png"))
a = menu.addAction(icon, "&Print...", self.file_print)
a.setPriority(QAction.LowPriority)
a.setShortcut(QKeySequence.Print)
tb.addAction(a)
icon = QIcon.fromTheme("fileprint", QIcon(RSRC_PATH + "/fileprint.png"))
menu.addAction(icon, "Print Preview...", self.file_print_preview)
icon = QIcon.fromTheme("exportpdf", QIcon(RSRC_PATH + "/exportpdf.png"))
a = menu.addAction(icon, "&Export PDF...", self.file_print_pdf)
a.setPriority(QAction.LowPriority)
a.setShortcut(Qt.CTRL | Qt.Key_D)
tb.addAction(a)
menu.addSeparator()
a = menu.addAction("&Quit", self.close)
a.setShortcut(Qt.CTRL | Qt.Key_Q)
def setup_edit_actions(self):
tb = self.addToolBar("Edit self.actions")
menu = self.menuBar().addMenu("&Edit")
icon = QIcon.fromTheme(QIcon.ThemeIcon.EditUndo,
QIcon(RSRC_PATH + "/editundo.png"))
self._action_undo = menu.addAction(icon, "&Undo", self._text_edit.undo)
self._action_undo.setShortcut(QKeySequence.Undo)
tb.addAction(self._action_undo)
icon = QIcon.fromTheme(QIcon.ThemeIcon.EditRedo,
QIcon(RSRC_PATH + "/editredo.png"))
self._action_redo = menu.addAction(icon, "&Redo", self._text_edit.redo)
self._action_redo.setPriority(QAction.LowPriority)
self._action_redo.setShortcut(QKeySequence.Redo)
tb.addAction(self._action_redo)
menu.addSeparator()
icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCut,
QIcon(RSRC_PATH + "/editcut.png"))
self._action_cut = menu.addAction(icon, "Cu&t", self._text_edit.cut)
self._action_cut.setPriority(QAction.LowPriority)
self._action_cut.setShortcut(QKeySequence.Cut)
tb.addAction(self._action_cut)
icon = QIcon.fromTheme(QIcon.ThemeIcon.EditCopy,
QIcon(RSRC_PATH + "/editcopy.png"))
self._action_copy = menu.addAction(icon, "&Copy", self._text_edit.copy)
self._action_copy.setPriority(QAction.LowPriority)
self._action_copy.setShortcut(QKeySequence.Copy)
tb.addAction(self._action_copy)
icon = QIcon.fromTheme(QIcon.ThemeIcon.EditPaste,
QIcon(RSRC_PATH + "/editpaste.png"))
self._action_paste = menu.addAction(icon, "&Paste", self._text_edit.paste)
self._action_paste.setPriority(QAction.LowPriority)
self._action_paste.setShortcut(QKeySequence.Paste)
tb.addAction(self._action_paste)
md = QGuiApplication.clipboard().mimeData()
if md:
self._action_paste.setEnabled(md.hasText())
def setup_text_actions(self):
tb = self.addToolBar("Format self.actions")
menu = self.menuBar().addMenu("F&ormat")
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextBold,
QIcon(RSRC_PATH + "/textbold.png"))
self._action_text_bold = menu.addAction(icon, "&Bold", self.text_bold)
self._action_text_bold.setShortcut(Qt.CTRL | Qt.Key_B)
self._action_text_bold.setPriority(QAction.LowPriority)
bold = QFont()
bold.setBold(True)
self._action_text_bold.setFont(bold)
tb.addAction(self._action_text_bold)
self._action_text_bold.setCheckable(True)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextItalic,
QIcon(RSRC_PATH + "/textitalic.png"))
self._action_text_italic = menu.addAction(icon, "&Italic", self.text_italic)
self._action_text_italic.setPriority(QAction.LowPriority)
self._action_text_italic.setShortcut(Qt.CTRL | Qt.Key_I)
italic = QFont()
italic.setItalic(True)
self._action_text_italic.setFont(italic)
tb.addAction(self._action_text_italic)
self._action_text_italic.setCheckable(True)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatTextUnderline,
QIcon(RSRC_PATH + "/textunder.png"))
self._action_text_underline = menu.addAction(icon, "&Underline",
self.text_underline)
self._action_text_underline.setShortcut(Qt.CTRL | Qt.Key_U)
self._action_text_underline.setPriority(QAction.LowPriority)
underline = QFont()
underline.setUnderline(True)
self._action_text_underline.setFont(underline)
tb.addAction(self._action_text_underline)
self._action_text_underline.setCheckable(True)
menu.addSeparator()
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyLeft,
QIcon(RSRC_PATH + "/textleft.png"))
self._action_align_left = QAction(icon, "&Left", self)
self._action_align_left.setShortcut(Qt.CTRL | Qt.Key_L)
self._action_align_left.setCheckable(True)
self._action_align_left.setPriority(QAction.LowPriority)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyCenter,
QIcon(RSRC_PATH + "/textcenter.png"))
self._action_align_center = QAction(icon, "C&enter", self)
self._action_align_center.setShortcut(Qt.CTRL | Qt.Key_E)
self._action_align_center.setCheckable(True)
self._action_align_center.setPriority(QAction.LowPriority)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyRight,
QIcon(RSRC_PATH + "/textright.png"))
self._action_align_right = QAction(icon, "&Right", self)
self._action_align_right.setShortcut(Qt.CTRL | Qt.Key_R)
self._action_align_right.setCheckable(True)
self._action_align_right.setPriority(QAction.LowPriority)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatJustifyFill,
QIcon(RSRC_PATH + "/textjustify.png"))
self._action_align_justify = QAction(icon, "&Justify", self)
self._action_align_justify.setShortcut(Qt.CTRL | Qt.Key_J)
self._action_align_justify.setCheckable(True)
self._action_align_justify.setPriority(QAction.LowPriority)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatIndentMore,
QIcon(RSRC_PATH + "/format-indent-more.png"))
self._action_indent_more = menu.addAction(icon, "&Indent", self.indent)
self._action_indent_more.setShortcut(Qt.CTRL | Qt.Key_BracketRight)
self._action_indent_more.setPriority(QAction.LowPriority)
icon = QIcon.fromTheme(QIcon.ThemeIcon.FormatIndentLess,
QIcon(RSRC_PATH + "/format-indent-less.png"))
self._action_indent_less = menu.addAction(icon, "&Unindent",
self.unindent)
self._action_indent_less.setShortcut(Qt.CTRL | Qt.Key_BracketLeft)
self._action_indent_less.setPriority(QAction.LowPriority)
# Make sure the alignLeft is always left of the alignRight
align_group = QActionGroup(self)
align_group.triggered.connect(self.text_align)
if QGuiApplication.isLeftToRight():
align_group.addAction(self._action_align_left)
align_group.addAction(self._action_align_center)
align_group.addAction(self._action_align_right)
else:
align_group.addAction(self._action_align_right)
align_group.addAction(self._action_align_center)
align_group.addAction(self._action_align_left)
align_group.addAction(self._action_align_justify)
tb.addActions(align_group.actions())
menu.addActions(align_group.actions())
tb.addAction(self._action_indent_more)
tb.addAction(self._action_indent_less)
menu.addAction(self._action_indent_more)
menu.addAction(self._action_indent_less)
menu.addSeparator()
pix = QPixmap(16, 16)
pix.fill(Qt.black)
self._action_text_color = menu.addAction(pix, "&Color...", self.text_color)
tb.addAction(self._action_text_color)
icon = QIcon(RSRC_PATH + "/textundercolor.png")
self._action_underline_color = menu.addAction(icon, "Underline color...",
self.underline_color)
tb.addAction(self._action_underline_color)
menu.addSeparator()
icon = QIcon.fromTheme("status-checkbox-checked",
QIcon(RSRC_PATH + "/checkbox-checked.png"))
self._action_toggle_check_state = menu.addAction(icon, "Chec&ked")
self._action_toggle_check_state.toggled.connect(self.set_checked)
self._action_toggle_check_state.setShortcut(Qt.CTRL | Qt.Key_K)
self._action_toggle_check_state.setCheckable(True)
self._action_toggle_check_state.setPriority(QAction.LowPriority)
tb.addAction(self._action_toggle_check_state)
tb = self.addToolBar("Format self.actions")
tb.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
self.addToolBarBreak(Qt.TopToolBarArea)
self.addToolBar(tb)
self._combo_style = QComboBox(tb)
tb.addWidget(self._combo_style)
self._combo_style.addItems(STYLES)
self._combo_style.activated.connect(self.text_style)
self._combo_font = QFontComboBox(tb)
tb.addWidget(self._combo_font)
self._combo_font.textActivated.connect(self.text_family)
self._combo_size = QComboBox(tb)
self._combo_size.setObjectName("comboSize")
tb.addWidget(self._combo_size)
self._combo_size.setEditable(True)
standard_sizes = QFontDatabase.standardSizes()
for size in standard_sizes:
self._combo_size.addItem(str(size))
index = standard_sizes.index(QApplication.font().pointSize())
self._combo_size.setCurrentIndex(index)
self._combo_size.textActivated.connect(self.text_size)
def load(self, f):
if not QFile.exists(f):
return False
file = QFile(f)
if not file.open(QFile.ReadOnly):
return False
data = file.readAll()
db = QMimeDatabase()
mime_type_name = db.mimeTypeForFileNameAndData(f, data).name()
text = data.data().decode('utf8')
if mime_type_name == "text/html":
file_url = QUrl(f) if f[0] == ':' else QUrl.fromLocalFile(f)
options = QUrl.FormattingOptions(QUrl.RemoveFilename)
self._text_edit.document().setBaseUrl(file_url.adjusted(options))
self._text_edit.setHtml(text)
elif mime_type_name == "text/markdown":
self._text_edit.setMarkdown(text)
else:
self._text_edit.setPlainText(text)
self.set_current_file_name(f)
return True
def maybe_save(self):
if not self._text_edit.document().isModified():
return True
ret = QMessageBox.warning(self, QCoreApplication.applicationName(),
"The document has been modified.\n"
"Do you want to save your changes?",
QMessageBox.Save | QMessageBox.Discard
| QMessageBox.Cancel)
if ret == QMessageBox.Save:
return self.file_save()
if ret == QMessageBox.Cancel:
return False
return True
def set_current_file_name(self, fileName):
self._file_name = fileName
self._text_edit.document().setModified(False)
shown_name = QFileInfo(fileName).fileName() if fileName else "untitled.txt"
app_name = QCoreApplication.applicationName()
self.setWindowTitle(f"{shown_name}[*] - {app_name}")
self.setWindowModified(False)
@Slot()
def file_new(self):
if self.maybe_save():
self._text_edit.clear()
self.set_current_file_name("")
@Slot()
def file_open(self):
file_dialog = QFileDialog(self, "Open File...")
file_dialog.setAcceptMode(QFileDialog.AcceptOpen)
file_dialog.setFileMode(QFileDialog.ExistingFile)
file_dialog.setMimeTypeFilters(MIME_TYPES)
if file_dialog.exec() != QDialog.Accepted:
return
fn = file_dialog.selectedFiles()[0]
native_fn = QDir.toNativeSeparators(fn)
if self.load(fn):
self.statusBar().showMessage(f'Opened "{native_fn}"')
else:
self.statusBar().showMessage(f'Could not open "{native_fn}"')
@Slot()
def file_save(self):
if not self._file_name or self._file_name.startswith(":/"):
return self.file_save_as()
writer = QTextDocumentWriter(self._file_name)
document = self._text_edit.document()
success = writer.write(document)
native_fn = QDir.toNativeSeparators(self._file_name)
if success:
document.setModified(False)
self.statusBar().showMessage(f'Wrote "{native_fn}"')
else:
self.statusBar().showMessage(f'Could not write to file "{native_fn}"')
return success
@Slot()
def file_save_as(self):
file_dialog = QFileDialog(self, "Save as...")
file_dialog.setAcceptMode(QFileDialog.AcceptSave)
mime_types = MIME_TYPES
mime_types.insert(1, "application/vnd.oasis.opendocument.text")
file_dialog.setMimeTypeFilters(mime_types)
file_dialog.setDefaultSuffix("odt")
if file_dialog.exec() != QDialog.Accepted:
return False
fn = file_dialog.selectedFiles()[0]
self.set_current_file_name(fn)
return self.file_save()
@Slot()
def file_print(self):
printer = QPrinter(QPrinter.HighResolution)
dlg = QPrintDialog(printer, self)
if self._text_edit.textCursor().hasSelection():
dlg.setOption(QAbstractPrintDialog.PrintSelection)
dlg.setWindowTitle("Print Document")
if dlg.exec() == QDialog.Accepted:
self._text_edit.print_(printer)
@Slot()
def file_print_preview(self):
printer = QPrinter(QPrinter.HighResolution)
preview = QPrintPreviewDialog(printer, self)
preview.paintRequested.connect(self._text_edit.print_)
preview.exec()
@Slot()
def file_print_pdf(self):
file_dialog = QFileDialog(self, "Export PDF")
file_dialog.setAcceptMode(QFileDialog.AcceptSave)
file_dialog.setMimeTypeFilters(["application/pdf"])
file_dialog.setDefaultSuffix("pdf")
if file_dialog.exec() != QDialog.Accepted:
return
pdf_file_name = file_dialog.selectedFiles()[0]
printer = QPrinter(QPrinter.HighResolution)
printer.setOutputFormat(QPrinter.PdfFormat)
printer.setOutputFileName(pdf_file_name)
self._text_edit.document().print_(printer)
native_fn = QDir.toNativeSeparators(pdf_file_name)
self.statusBar().showMessage(f'Exported "{native_fn}"')
@Slot()
def text_bold(self):
fmt = QTextCharFormat()
weight = QFont.Bold if self._action_text_bold.isChecked() else QFont.Normal
fmt.setFontWeight(weight)
self.merge_format_on_word_or_selection(fmt)
@Slot()
def text_underline(self):
fmt = QTextCharFormat()
fmt.setFontUnderline(self._action_text_underline.isChecked())
self.merge_format_on_word_or_selection(fmt)
@Slot()
def text_italic(self):
fmt = QTextCharFormat()
fmt.setFontItalic(self._action_text_italic.isChecked())
self.merge_format_on_word_or_selection(fmt)
@Slot(str)
def text_family(self, f):
fmt = QTextCharFormat()
fmt.setFontFamilies({f})
self.merge_format_on_word_or_selection(fmt)
@Slot(str)
def text_size(self, p):
point_size = float(p)
if point_size > 0:
fmt = QTextCharFormat()
fmt.setFontPointSize(point_size)
self.merge_format_on_word_or_selection(fmt)
@Slot(int)
def text_style(self, styleIndex):
cursor = self._text_edit.textCursor()
style = QTextListFormat.ListStyleUndefined
marker = QTextBlockFormat.MarkerType.NoMarker
if styleIndex == 1:
style = QTextListFormat.ListDisc
elif styleIndex == 2:
style = QTextListFormat.ListCircle
elif styleIndex == 3:
style = QTextListFormat.ListSquare
elif styleIndex == 4:
if cursor.currentList():
style = cursor.currentList().format().style()
else:
style = QTextListFormat.ListDisc
marker = QTextBlockFormat.MarkerType.Unchecked
elif styleIndex == 5:
if cursor.currentList():
style = cursor.currentList().format().style()
else:
style = QTextListFormat.ListDisc
marker = QTextBlockFormat.MarkerType.Checked
elif styleIndex == 6:
style = QTextListFormat.ListDecimal
elif styleIndex == 7:
style = QTextListFormat.ListLowerAlpha
elif styleIndex == 8:
style = QTextListFormat.ListUpperAlpha
elif styleIndex == 9:
style = QTextListFormat.ListLowerRoman
elif styleIndex == 10:
style = QTextListFormat.ListUpperRoman
cursor.beginEditBlock()
block_fmt = cursor.blockFormat()
if style == QTextListFormat.ListStyleUndefined:
block_fmt.setObjectIndex(-1)
# H1 to H6, or Standard
heading_level = styleIndex - 11 + 1 if styleIndex >= 11 else 0
block_fmt.setHeadingLevel(heading_level)
cursor.setBlockFormat(block_fmt)
# H1 to H6: +3 to -2
size_adjustment = 4 - heading_level if heading_level != 0 else 0
fmt = QTextCharFormat()
fmt.setFontWeight(QFont.Bold if heading_level else QFont.Normal)
fmt.setProperty(QTextFormat.FontSizeAdjustment, size_adjustment)
cursor.select(QTextCursor.LineUnderCursor)
cursor.mergeCharFormat(fmt)
self._text_edit.mergeCurrentCharFormat(fmt)
else:
block_fmt.setMarker(marker)
cursor.setBlockFormat(block_fmt)
list_fmt = QTextListFormat()
if cursor.currentList():
list_fmt = cursor.currentList().format()
else:
list_fmt.setIndent(block_fmt.indent() + 1)
block_fmt.setIndent(0)
cursor.setBlockFormat(block_fmt)
list_fmt.setStyle(style)
cursor.createList(list_fmt)
cursor.endEditBlock()
@Slot()
def text_color(self):
col = QColorDialog.getColor(self._text_edit.textColor(), self)
if not col.isValid():
return
fmt = QTextCharFormat()
fmt.setForeground(col)
self.merge_format_on_word_or_selection(fmt)
self.color_changed(col)
@Slot()
def underline_color(self):
col = QColorDialog.getColor(Qt.black, self)
if not col.isValid():
return
fmt = QTextCharFormat()
fmt.setUnderlineColor(col)
self.merge_format_on_word_or_selection(fmt)
self.color_changed(col)
@Slot(QAction)
def text_align(self, a):
if a == self._action_align_left:
self._text_edit.setAlignment(Qt.AlignLeft | Qt.AlignAbsolute)
elif a == self._action_align_center:
self._text_edit.setAlignment(Qt.AlignHCenter)
elif a == self._action_align_right:
self._text_edit.setAlignment(Qt.AlignRight | Qt.AlignAbsolute)
elif a == self._action_align_justify:
self._text_edit.setAlignment(Qt.AlignJustify)
@Slot(bool)
def set_checked(self, checked):
self.text_style(5 if checked else 4)
@Slot()
def indent(self):
self.modify_indentation(1)
@Slot()
def unindent(self):
self.modify_indentation(-1)
def modify_indentation(self, amount):
cursor = self._text_edit.textCursor()
cursor.beginEditBlock()
if cursor.currentList():
list_fmt = cursor.currentList().format()
# See whether the line above is the list we want to move self item
# into, or whether we need a new list.
above = QTextCursor(cursor)
above.movePosition(QTextCursor.Up)
if (above.currentList()
and list_fmt.indent() + amount == above.currentList().format().indent()):
above.currentList().add(cursor.block())
else:
list_fmt.setIndent(list_fmt.indent() + amount)
cursor.createList(list_fmt)
else:
block_fmt = cursor.blockFormat()
block_fmt.setIndent(block_fmt.indent() + amount)
cursor.setBlockFormat(block_fmt)
cursor.endEditBlock()
@Slot(QTextCharFormat)
def current_char_format_changed(self, format):
self.font_changed(format.font())
self.color_changed(format.foreground().color())
@Slot()
def cursor_position_changed(self):
self.alignment_changed(self._text_edit.alignment())
list = self._text_edit.textCursor().currentList()
if list:
style = list.format().style()
if style == QTextListFormat.ListDisc:
self._combo_style.setCurrentIndex(1)
elif style == QTextListFormat.ListCircle:
self._combo_style.setCurrentIndex(2)
elif style == QTextListFormat.ListSquare:
self._combo_style.setCurrentIndex(3)
elif style == QTextListFormat.ListDecimal:
self._combo_style.setCurrentIndex(6)
elif style == QTextListFormat.ListLowerAlpha:
self._combo_style.setCurrentIndex(7)
elif style == QTextListFormat.ListUpperAlpha:
self._combo_style.setCurrentIndex(8)
elif style == QTextListFormat.ListLowerRoman:
self._combo_style.setCurrentIndex(9)
elif style == QTextListFormat.ListUpperRoman:
self._combo_style.setCurrentIndex(10)
else:
self._combo_style.setCurrentIndex(-1)
marker = self._text_edit.textCursor().block().blockFormat().marker()
if marker == QTextBlockFormat.MarkerType.NoMarker:
self._action_toggle_check_state.setChecked(False)
elif marker == QTextBlockFormat.MarkerType.Unchecked:
self._combo_style.setCurrentIndex(4)
self._action_toggle_check_state.setChecked(False)
elif marker == QTextBlockFormat.MarkerType.Checked:
self._combo_style.setCurrentIndex(5)
self._action_toggle_check_state.setChecked(True)
else:
heading_level = self._text_edit.textCursor().blockFormat().headingLevel()
new_level = heading_level + 10 if heading_level != 0 else 0
self._combo_style.setCurrentIndex(new_level)
@Slot()
def clipboard_data_changed(self):
md = QGuiApplication.clipboard().mimeData()
self._action_paste.setEnabled(md and md.hasText())
@Slot()
def about(self):
QMessageBox.about(self, "About", ABOUT)
def merge_format_on_word_or_selection(self, format):
cursor = self._text_edit.textCursor()
if not cursor.hasSelection():
cursor.select(QTextCursor.WordUnderCursor)
cursor.mergeCharFormat(format)
self._text_edit.mergeCurrentCharFormat(format)
def font_changed(self, f):
index = self._combo_font.findText(QFontInfo(f).family())
self._combo_font.setCurrentIndex(index)
index = self._combo_size.findText(str(f.pointSize()))
self._combo_size.setCurrentIndex(index)
self._action_text_bold.setChecked(f.bold())
self._action_text_italic.setChecked(f.italic())
self._action_text_underline.setChecked(f.underline())
def color_changed(self, c):
pix = QPixmap(16, 16)
pix.fill(c)
self._action_text_color.setIcon(pix)
def alignment_changed(self, a):
if a & Qt.AlignLeft:
self._action_align_left.setChecked(True)
elif a & Qt.AlignHCenter:
self._action_align_center.setChecked(True)
elif a & Qt.AlignRight:
self._action_align_right.setChecked(True)
elif a & Qt.AlignJustify:
self._action_align_justify.setChecked(True)
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>images/logo32.png</file>
<file>images/mac/checkbox.png</file>
<file>images/mac/checkbox-checked.png</file>
<file>images/mac/editcopy.png</file>
<file>images/mac/editcut.png</file>
<file>images/mac/editpaste.png</file>
<file>images/mac/editredo.png</file>
<file>images/mac/editundo.png</file>
<file>images/mac/exportpdf.png</file>
<file>images/mac/filenew.png</file>
<file>images/mac/fileopen.png</file>
<file>images/mac/fileprint.png</file>
<file>images/mac/filesave.png</file>
<file>images/mac/format-indent-less.png</file>
<file>images/mac/format-indent-more.png</file>
<file>images/mac/textbold.png</file>
<file>images/mac/textcenter.png</file>
<file>images/mac/textitalic.png</file>
<file>images/mac/textjustify.png</file>
<file>images/mac/textleft.png</file>
<file>images/mac/textright.png</file>
<file>images/mac/textunder.png</file>
<file>images/mac/textundercolor.png</file>
<file>images/mac/zoomin.png</file>
<file>images/mac/zoomout.png</file>
<file>images/win/checkbox.png</file>
<file>images/win/checkbox-checked.png</file>
<file>images/win/editcopy.png</file>
<file>images/win/editcut.png</file>
<file>images/win/editpaste.png</file>
<file>images/win/editredo.png</file>
<file>images/win/editundo.png</file>
<file>images/win/exportpdf.png</file>
<file>images/win/filenew.png</file>
<file>images/win/fileopen.png</file>
<file>images/win/fileprint.png</file>
<file>images/win/filesave.png</file>
<file>images/win/format-indent-less.png</file>
<file>images/win/format-indent-more.png</file>
<file>images/win/textbold.png</file>
<file>images/win/textcenter.png</file>
<file>images/win/textitalic.png</file>
<file>images/win/textjustify.png</file>
<file>images/win/textleft.png</file>
<file>images/win/textright.png</file>
<file>images/win/textunder.png</file>
<file>images/win/textundercolor.png</file>
<file>images/win/zoomin.png</file>
<file>images/win/zoomout.png</file>
<file>example.html</file>
</qresource>
</RCC>
<html><head><meta name="qrichtext" content="1" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>QTextEdit Example</title><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body style=" font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;">
<h1 align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:20pt; font-weight:600;">QTextEdit</span></h1>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">The QTextEdit widget is an advanced editor that supports formatted rich text. It can be used to display HTML and other rich document formats. Internally, QTextEdit uses the QTextDocument class to describe both the high-level structure of each document and the low-level formatting of paragraphs.</span></p>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">If you are viewing this document in the <span style=" font-style:italic;">textedit</span> example, you can edit this document to explore Qt's rich text editing features. We have included some comments in each of the following sections to encourage you to experiment. </p>
<h2 style=" margin-top:16px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:18pt; font-weight:600;"><span style=" font-size:16pt;">Font and Paragraph Styles</span></h2>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">QTextEdit supports </span><span style=" font-size:11pt; font-weight:600;">bold</span><span style=" font-size:11pt;">, </span><span style=" font-size:11pt; font-style:italic;">italic</span><span style=" font-size:11pt;">, and </span><span style=" font-size:11pt; text-decoration: underline;">underlined</span><span style=" font-size:11pt;"> font styles, and can display </span><span style=" font-size:11pt; font-weight:600; color:#00007f;">multicolored</span><span style=" font-size:11pt;"> </span><span style=" font-size:11pt; font-weight:600; color:#aa0000;">text</span><span style=" font-size:11pt;">. Font families such as </span><span style=" font-family:'Times New Roman'; font-size:11pt; font-weight:600;">Times New Roman</span><span style=" font-size:11pt;"> and </span><span style=" font-family:'Courier'; font-size:11pt; font-weight:600;">Courier</span><span style=" font-size:11pt;"> can also be used directly. </span><span style=" font-size:11pt; font-style:italic;">If you place the cursor in a region of styled text, the controls in the tool bars will change to reflect the current style.</span></p>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Paragraphs can be formatted so that the text is left-aligned, right-aligned, centered, or fully justified.</p>
<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-style:italic;">Try changing the alignment of some text and resize the editor to see how the text layout changes.</span> </p>
<h2 align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:16pt; font-weight:600;">Lists</span></h2>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">Different kinds of lists can be included in rich text documents. Standard bullet lists can be nested, using different symbols for each level of the list: </span></p>
<ul style="-qt-list-indent: 1;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disc symbols are typically used for top-level list items. </li></ul>
<ul type=circle style="-qt-list-indent: 2;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Circle symbols can be used to distinguish between items in lower-level lists.</li></ul>
<ul type=square style="-qt-list-indent: 3;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Square symbols provide a reasonable alternative to discs and circles. </li></ul>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Ordered lists can be created that can be used for tables of contents. Different characters can be used to enumerate items, and we can use both Roman and Arabic numerals in the same list structure: </p>
<ol style="-qt-list-indent: 1;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Introduction</li>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Tools </li></ol>
<ol type=a style="-qt-list-indent: 2;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Assistant</li>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Designer</li>
<ol type=A style="-qt-list-indent: 3;"><li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Form Editor</li>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Component Architecture</li></ol>
<li style=" font-size:11pt;" style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qt Linguist</li></ol>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">The list will automatically be renumbered if you add or remove items. <span style=" font-style:italic;">Try adding new sections to the above list or removing existing item to see the numbers change.</span> </p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
<h2 style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Images</span></h2>
<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">Inline images are treated like ordinary ranges of characters in the text editor, so they flow with the surrounding text. Images can also be selected in the same way as text, making it easy to cut, copy, and paste them. </span></p>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><img src=":/images/logo32.png" /><span style=" font-style:italic;"> Try to select this image by clicking and dragging over it with the mouse, or use the text cursor to select it by holding down Shift and using the arrow keys. You can then cut or copy it, and paste it into different parts of this document.</span></p>
<h2 align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Tables</span></h2>
<p align="justify" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:16pt; font-weight:600;"><span style=" font-size:11pt; font-weight:400;">QTextEdit can arrange and format tables, supporting features such as row and column spans, text formatting within cells, and size constraints for columns. </span></p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
<table border="1" align="center" width="90%" cellspacing="0" cellpadding="4">
<tr>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Development Tools </span></p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Programming Techniques </span></p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Graphical User Interfaces </span></p></td></tr>
<tr>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">9:00 - 11:00 </span></p></td>
<td colspan="3">
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Introduction to <span style=" font-style:italic;">Qt </span></p></td></tr>
<tr>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">11:00 - 13:00 </span></p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Using <span style=" font-style:italic;">qmake</span> </p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Object-oriented Programming </p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Layouts in <span style=" font-style:italic;">Qt</span> </p></td></tr>
<tr>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">13:00 - 15:00 </span></p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Designer</span> Tutorial </p></td>
<td rowspan="2">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extreme Programming </p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Writing Custom Styles </p></td></tr>
<tr>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">15:00 - 17:00 </span></p></td>
<td>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Qt Linguist</span> and Internationalization </p></td>
<td></td></tr></table>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"></p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt; font-style:italic;">Try adding text to the cells in the table and experiment with the alignment of the paragraphs.</p>
<h2 style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Hyperlinks</span></h2>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">QTextEdit is designed to support hyperlinks between documents, and this feature is used extensively in </span><span style=" font-size:11pt; font-style:italic;">Qt Assistant</span><span style=" font-size:11pt;">. Hyperlinks are automatically created when an HTML file is imported into an editor. Since the rich text framework supports hyperlinks natively, they can also be created programatically.</span></p>
<h2 style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-size:16pt; font-weight:600;">Undo and Redo</span></h2>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;">Full support for undo and redo operations is built into QTextEdit and the underlying rich text framework. Operations on a document can be packaged together to make editing a more comfortable experience for the user.</p>
<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><span style=" font-style:italic;">Try making changes to this document and press Ctrl+Z to undo them. You can always recover the original contents of the document.</span> </p></body></html>