#python-3.8 #qtextedit #pyside6 #pyqt6 #qtextcursor
#python-3.8 #qtextedit #pyside6 #pyqt6 #qtextcursor
Вопрос:
Я работаю над редактором расширенного текста и столкнулся с небольшой проблемой, которую я решил с помощью того, что кажется «взломом».
Итак, я хотел проверить, имеет ли выделенный текст или текст в позиции курсора какое-либо форматирование, жирный шрифт, курсив и т. Д., И проверить соответствующую кнопку, которая выполняет соответствующую работу, но это становится странным.
если я сделаю что-то вроде
if self.ed.fontItalic() is True:
self.italic.setChecked(True)
else:
self.italic.setChecked(False)
if self.ed.fontUnderline() is True:
self.uline.setChecked(True)
else:
self.uline.setChecked(False)
где «self.italic» и «self.uline» являются проверяемыми QPushButtons;
Проверяется только формат под курсором, но не обе кнопки для курсива и подчеркивания, т. Е. Если выделенный текст имеет форматирование бота.
По сути, он игнорирует выделенный текст и ищет форматирование текста под курсором.
Итак, я сейчас анализирую html, чтобы узнать, имеет ли он форматирование;
def check_formatting(self):
if self.ed.textCursor().hasSelection():
print(self.ed.textCursor().selection().toHtml())
if "font-style:italic;" in self.ed.textCursor().selection().toHtml():
self.italic.setChecked(True)
else:
self.italic.setChecked(False)
if "text-decoration: underline;" in self.ed.textCursor().selection().toHtml():
self.uline.setChecked(True)
else:
self.uline.setChecked(False)
else:
if self.ed.fontItalic() is True:
self.italic.setChecked(True)
else:
self.italic.setChecked(False)
if self.ed.fontUnderline() is True:
self.uline.setChecked(True)
else:
self.uline.setChecked(False)
и код для форматирования выделенного текста или текста под курсором при нажатии кнопки выглядит следующим образом
def set_italic(self):
if self.italic.isChecked():
self.ed.setFontItalic(True)
if self.ed.textCursor().hasSelection():
if self.ed.fontItalic() != QTextFormat.FontItalic:
self.ed.setFontItalic(True)
else:
self.ed.setFontItalic(False)
else:
self.ed.setFontItalic(False)
Все это работает почти так, как задумано, но все это кажется супер хакерским. И при синтаксическом анализе html, очевидно, если пользователь вводит «font-style: italic;» в редактировании текста и выбирает введенный текст, кнопка для курсива проверяется.
Я просматривал много материалов в Интернете, но ни один из них не помогает мне достичь того, чего достигает приведенный выше код.
Комментарии:
1. Это ожидаемое поведение: по умолчанию для проверки формата используется только позиция курсора, что имеет смысл; если выделение содержит несколько форматов (или даже несколько весов шрифта, поскольку существуют другие веса, отличные от «нормального» и «жирного»), что должна возвращать функция? Вас может заинтересовать тот факт, что выделенный текст содержит жирный / курсивный / подчеркнутый текст, но другие могут захотеть узнать, содержит ли выделенный текст только жирный (или курсивный или подчеркнутый) текст. Ваш подход также ошибочен, так как если вы выделите текст внутри формата, вы вообще не получите никакой информации о формате.
2. Предположим, что у вас есть большой выбор с одним символом в другом формате, при вашем подходе весь выбор приведет к этому формату, и это было бы нелогично. В любом случае, если это то, что вы хотите, это все равно можно сделать, но вы все равно не можете использовать html, но вам нужно работать с QTextCursor и перебирать все форматы в выборе (если таковые имеются). Кроме того, ваша логика для кнопок излишне сложна, поскольку и функция форматирования, и функции переключения кнопок являются логическими, просто сделайте
self.italic.setChecked(self.ed.fontItalic())
.
Ответ №1:
Поведение по умолчанию ожидается, с точки зрения программирования невозможно узнать, заинтересован ли разработчик в том, чтобы узнать, имеет ли выбор формат, установленный в любой точке, или они хотят знать, не содержит ли он этот формат.
Кроме того, проверка html документа концептуально неверна, поскольку формат может быть установлен вне выделения (включая использование таблицы стилей по умолчанию), и также важно помнить, что toHtml()
функция возвращает «перевод» базового QTextDocument, а не сам объект document .
Единственный правильный способ проверить формат в указанной позиции — получить QTextCharFormat текстового курсора для заданной позиции символа.
Если вы действительно хотите проверить, содержит ли выделение какое-либо изменение формата в любой позиции, независимо от положения курсора, тогда вам нужно перебрать все символы в выделении и проверить их формат.
Обратите внимание, что в этом случае вам необходимо подключиться к обоим cursorPositionChanged
selectionChanged
сигналам and , так как пользователь может щелкнуть редактор в позиции курсора, что приведет к удалению выделения, но не изменит положение курсора.
С помощью следующего кода check_formatting
функция автоматически переключает кнопки, так что вам не нужно проверять текущий формат в функции кнопки, но вы можете напрямую подключиться к функциям редактирования текста, поскольку они будут переключать формат исключительно на основе состояния, установленного check_formatting
, таким образом, переопределяя поведение по умолчанию.
class Editor(QtWidgets.QWidget):
def __init__(self):
# ...
self.ed.cursorPositionChanged.connect(self.check_formatting)
self.ed.selectionChanged.connect(self.check_formatting)
self.bold.toggled.connect(self.toggle_bold)
self.italic.toggled.connect(self.ed.setFontItalic)
self.underline.toggled.connect(self.ed.setFontUnderline)
def toggle_bold(self, bold):
self.ed.setFontWeight(QtGui.QFont.Bold if bold else QtGui.QFont.Normal)
def check_formatting(self):
# assume no format by default
bold = italic = underline = False
cursor = self.ed.textCursor()
if cursor.hasSelection():
rangeEnd = cursor.selectionEnd() 1
else:
rangeEnd = cursor.selectionStart() 1
for pos in range(cursor.selectionStart(), rangeEnd):
cursor.setPosition(pos)
fmt = cursor.charFormat()
if fmt.fontWeight() >= QtGui.QFont.Bold:
bold = True
if fmt.fontItalic():
italic = True
if fmt.fontUnderline():
underline = True
if all((bold, italic, underline)):
# all formats are set, no need for further checking
break
# set check states of buttons but block their signals to avoid
# unnecessary calls and unwanted behavior when using keyboard
# navigation for selection (eg: shift arrows)
with QtCore.QSignalBlocker(self.bold):
self.bold.setChecked(bold)
with QtCore.QSignalBlocker(self.italic):
self.italic.setChecked(italic)
with QtCore.QSignalBlocker(self.underline):
self.underline.setChecked(underline)
Комментарии:
1. Я уже решил это с помощью аналогичного метода, но с циклом while. Но ваше решение намного надежнее. Спасибо.