Конвертация формата текста при вставке из буффера обмена, Часть 2
Кто-то может сказать, что можно использовать `insert`, который есть у `TextArea`, но это не сработает в сценарии, когда вы выделили часть текста и хотите заменить его данными из буффера.
Почему так происходит? Да потому что в момент вызова `insert` Qt в `QTextDocument` создает еще один `QTextCursor` по указанной позиции и говорит ему вставить текст. То есть у нас в какой-то момент времени в документе присутствуют два текстовых курсора. Нам же нужно использовать текущий экземпляр курсора, поэтому дальше только хардкор.
Дело в том, что до текущего экземпляра курсора просто так не достучаться, но если захотеть... То можно в проект добавить зависимость от `Qt6::QuickPrivate` и с ней же слинковаться в `target_link_libraries`. Дальше нам понадобятся следующие заголовочные файлы, порядок которых важен из-за особенности `QQuickTextControl`:
cpp
#include <QtQuick/private/qquicktextcontrol_p.h>
#include <QtQuick/private/qquicktextcontrol_p_p.h>
#include <QtQuick/private/qquicktextedit_p_p.h>
Дело в том, что все текстовые редакторы в QML так или иначе унаследованы от `QQuickTextEdit`. Поэтому передав из QML в C++ указатель на наш редактор, его можно попробовать скастовать в `QQuickTextEdit` используя `qobject_cast`, послеле этого достаем приватную часть `QQuickTextEditPrivate`, в ней достаем `QQuickTextControl` -- объект "управления текстом" и уже в его приватной части можно достучаться до заветного курсора:
cpp
QQuickTextEdit* editor = qobject_cast<QQuickTextEdit*>(mEditor);
if (editor != nullptr) {
QQuickTextEditPrivate* editorPrivate = QQuickTextEditPrivate::get(editor);
// Интересно то, что у QQuickTextControl нет стандартного статичного метода 'get' для
// приватной части, поэтому тут небольшой трюк с кастом и QObjectPrivate
QObjectPrivate* objPrivate = QQuickTextControlPrivate::get(editorPrivate->control);
if (objPrivate != nullptr) {
QQuickTextControlPrivate* controlPrivate = static_cast<QQuickTextControlPrivate*>(objPrivate);
}
}
Теперь дело за малым: получаем курсор приватного контрола и вставляем текст и не забываем, что нам нужно предотвратить дальнейшую обработку события, так что помечаем его как обработанное:
cpp
controlPrivate->cursor.insertFragment(QTextDocumentFragment::fromPlainText(someText));
event->setAccepted(true);
return true;
Нужно понимать, что использование приватного API Qt имеет свои риски, и никто не гарантирует стабильность этого API между разными версиями Qt. Указанное решение актуально для Qt 6.9. Что думаете?
Полный код можно посмотреть в телеграм-канале по хэштегу #PlainText