Название: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 12, 2012, 17:32
Здраствуйте! Кому не лень, помогите :) делаю панельку форматирования текста, связанную с textEdit, в качестве основы, взял пример Text EditЗахотелось добавить возможность поменять регистр выделенных символов, для этого использую функции: QString UTextEdit::makeCaseSensitiveUpper(QString InputString) { return InputString.toUpper(); } QString UTextEdit::makeCaseSensitiveLower(QString InputString) { return InputString.toLower(); } QString UTextEdit::makeCaseSensitiveNegative(QString InputString) { for (int i = 0; i < InputString.size(); i++) { if(InputString[i].isLower()) InputString[i] = InputString[i].toUpper(); else InputString[i] = InputString[i].toLower(); } return InputString; }
для изменения выделенных символов делаю следующее: enum UTypesOfCaseSensitive { UpperCaseSensitive, LowerCaseSensitive, NegativeCaseSensitive };
void UTextEdit::textCaseSensitiveEdit(UTypesOfCaseSensitive typeOfCaseSensitive) { QTextCursor cursor = this->textCursor();
if(!cursor.selectedText().isEmpty()) { cursor.beginEditBlock();
if(typeOfCaseSensitive == UpperCaseSensitive) { QTextDocumentFragment textFragment = cursor.selection(); QString text = textFragment.toPlainText(); QString changeText = makeCaseSensitiveUpper(text); this->setText(this->toPlainText().replace(QString(text), QString(changeText));
}else if(typeOfCaseSensitive == LowerCaseSensitive) { QTextDocumentFragment textFragment = cursor.selection(); QString text = textFragment.toPlainText(); QString changeText = makeCaseSensitiveLower(text); this->setText(this->toHtml().replace(QString(text), QString(changeText)); }else if(typeOfCaseSensitive == NegativeCaseSensitive) { QTextDocumentFragment textFragment = cursor.selection(); QString text = textFragment.toPlainText(); QString changeText = makeCaseSensitiveNegative(text); this->setText(this->toHtml().replace(QString(text), QString(changeText)); }
cursor.endEditBlock(); } }
Вот до этого смог додуматься, но есть проблемы: this->setText(this->toHtml().replace(QString(text), QString(changeText)); - такой код не годится - будет весело, если в тексте будет что то повторяться
- при таком коде, если среди выделенных символов есть отличающиеся шрифтом, то замены не будет
можно замену делать вот так: [/list] this->setText(this->toPlainText().replace(QString(text), QString(changeText)); тогда: - после замены, если текст располагался на нескольких строках, все они окажутся на первой
- форматирование текста (цвет, выделение, подчеркивания) пропадает
Можно вместо QString & QString::replace ( const QString & before, const QString & after, Qt::CaseSensitivity cs = Qt::CaseSensitive ), использовать QString & QString::replace ( int position, int n, const QString & after ), тогда проблема в том что указание позиции курсора текста, в качестве параметра не катит, ведь мне нужно чтобы была поддержка rich text, а это html текст, а курсор в тексте не подходит для использования в html тексте, т.е. что то вроде этого не прокатит: QTextDocumentFragment textFragment = cursor.selection(); QString text = textFragment.toPlainText(); QString changeText = makeCaseSensitiveNegative(text); this->setText(this->toHtml().replace(cursor.position(), text.size(), changeText);
Помогите с написанием кода, который бы заменял выделенный текст в TextEdit, на тот который с измененным регистром, и при этом изменяемый текст сохранял бы свой шрифт: до: H ello World! после: H ELLO WORLD! Спасибо :)
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: Swa от Август 13, 2012, 10:14
Во-первых: QTextDocumentFragment textFragment = cursor.selection(); QString text = textFragment.toPlainText(); - для этого есть метод QString QTextCursor::selectedText () constВо-вторых: Зачем это? this->setText(this->toPlainText().replace(QString(text),QString(changeText)); Вы уже нашли валидный курсор с выделенным текстом, а затем выполняете поиск по всему документу. Чтобы изменить выделенный текст используйте void QTextCursor::insertText ( const QString & text )Он заменит выделенный текст на text.
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 10:52
Я выбрал cursor.selection() потому что в документации было написано что это в отличии от selectedText() используется для работы с rich text, потом использовал textFragment.toHTML(), но оно не прокатило, поэтому перешел на toPlainText(). Сделал с insertText(), оно работает, только не годится оно для rich text - если например использую следующий код: QString text = cursor.selectedText(); QString changeText = makeCaseSensitiveUpper(text); cursor.insertText(changeText);
только есть проблемка с QTextCharFormat: cursor.insertText(), использует тот QTextCharFormat, который находится перед позицией курсора, например: до: helloo выделяем "llo", теперь в зависимости от того с какого края выделяли: слева-направо или наоборот будет разный результат: слева-направо: llo справо-налево: llo Ну как то так=)
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 11:11
вот если бы можно было получить QTextCharFormat для каждого символа выделенного текста и скажем сохранить их например в контейнер, то: QString text = cursor.selectedText(); QString changeText = makeCaseSensitiveUpper(text); for(int i = 0; i < changeText.size(); i++) cursor.insertText(changeText.data()[i]);
и в функции insertText(), в качестве второго параметра передавать QTextCharFormat данного символа, то что это сработает показывает код снизу: QTextCharFormat charFormat; charFormat.setForeground(Qt::yellow); cursor.insertText(changeText.data()[0], charFormat);
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: Swa от Август 13, 2012, 12:09
Вот держите: QTextCursor cursor = this->textCursor(); int start = cursor.selectionStart(); int end = cursor.selectionEnd(); int cStart = 0; int cEnd = 0; QTextBlock block = document()->findBlock(start);
while (true) { if (!block.isValid()) {break;} if (block.position() > end) {break;} QTextBlock::iterator it; for(it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); if (!currentFragment.isValid()) {continue;} int fs = currentFragment.position(); int fe = currentFragment.position() + currentFragment.length();
if (end < fs || start > fe) {continue;}
QTextCursor temp(document());
if (start < fs) { cStart = fs; } else { cStart = start; }
if (end < fe) { cEnd = end; } else { cEnd = fe; }
temp.setPosition(cStart); temp.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cEnd - cStart); QString text = temp.selectedText(); text = text.toUpper(); temp.beginEditBlock(); temp.insertText(text); temp.endEditBlock(); } block = block.next(); }
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 13:47
даааа...вот так работать с text edit и курсором я пока не умею... :( Спасибо, Swa за рабочий пример, буду изучать :)
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 14:50
Кое что конечно не понятно: :) QTextCursor cursor = this->textCursor();
int start = cursor.selectionStart(); int end = cursor.selectionEnd(); int cStart = 0; int cEnd = 0; // получем текстовый блок используя позицию курсора QTextBlock block = document()->findBlock(start);
while (true) { if (!block.isValid()) {break;} // если блок не существует if (block.position() > end) {break;} // если позиция первого символа в блоке > end (а это может быть??) QTextBlock::iterator it;
// перебираем символы блока с начала до конца for(it = block.begin(); !(it.atEnd()); ++it) { // текстовый фрагмент - это ведь слова, символы, отделенные друг от друга разделителем (пробел например)? QTextFragment currentFragment = it.fragment(); if (!currentFragment.isValid()) {continue;} // если не существует int fs = currentFragment.position(); // нач позиция int fe = currentFragment.position() + currentFragment.length(); // конечная
if (end < fs || start > fe) {continue;} // еще одна проверка
QTextCursor temp(document()); // а почему получаем именно от документа курсор, а не от text edit?
// определяем нач и кон позицию // передвижения курсора по документу if (start < fs) { cStart = fs; } else { cStart = start; }
if (end < fe) { cEnd = end; } else { cEnd = fe; }
// курсор будет находиться в позиции cStart temp.setPosition(cStart); // сдвигаем вправо, выделяя пройденные символы temp.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cEnd - cStart);
QString text = temp.selectedText();
text = text.toUpper();
//помещаем вставку в этот блок, чтобы можно было использовать после //undo и redo temp.beginEditBlock(); temp.insertText(text); temp.endEditBlock(); } // смотрим следующий блок block = block.next(); }
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: Bepec от Август 13, 2012, 14:52
QTextEdit - это представление. Данные/цвет/позиции курсора/шрифт, всё это хранится в QDocument - модели.
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 15:01
А можно будет облегчить код, не используя блоки текста и фрагменты, а получая курсор от документа, и у выделенных курсором символов поменять регистр, при этом не потеряв форматирования символов (шрифт, выделение, почеркивание, цвет)?
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: Swa от Август 13, 2012, 15:19
Насколько я понимаю, это - минимальный код для этой задачи. Тут дело немного сложнее, чем кажется. Если вы повнимательнее почитаете документацию, то узнаете, что формат текста хранится в QTextFragment, то есть фрагмент - это кусок текста с одинаковым форматированием. Формат не хранится для каждого символа. Например, в тексте "раз два три" находятся три фрагмента. Чтобы изменить текст фрагмента, не потеряв его форматирования, нужно установить курсор внутри фрагмента.
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 13, 2012, 15:25
Swa, спасибо за такой ясный и понятный ответ :) все, вопросов нет :)
Название: Re: QTextEdit + Изменение регистра символов
Отправлено: gil9red от Август 14, 2012, 13:47
Наткнулся на ошибку :( для моего случая, изменил добавил немного код: void UTextEdit::textCaseSensitiveEdit(UTypesOfCaseSensitive typeOfCaseSensitive) { QTextCursor cursor = this->textCursor();
int startPosition = cursor.selectionStart(); int endPosition = cursor.selectionEnd(); int cursorStart = 0; int cursorEnd = 0;
QTextBlock block = document()->findBlock(startPosition);
while(true) { if(!block.isValid()) break;
if(block.position() > endPosition) break;
QTextBlock::iterator it;
for(it = block.begin(); !(it.atEnd()); ++it) { QTextFragment currentFragment = it.fragment(); if (!currentFragment.isValid()) continue;
int fragmentLength = currentFragment.length();
int fragmentStart = currentFragment.position(); int fragmentEnd = fragmentStart + fragmentLength;
if (endPosition < fragmentStart || startPosition > fragmentEnd) continue;
QTextCursor temp(document());
if(startPosition < fragmentStart) cursorStart = fragmentStart; else cursorStart = startPosition;
if(endPosition < fragmentEnd) cursorEnd = endPosition; else cursorEnd = fragmentEnd;
temp.setPosition(cursorStart); temp.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, cursorEnd - cursorStart); QString text = temp.selectedText();
if(typeOfCaseSensitive == UpperCaseSensitive) { text = makeCaseSensitiveUpper(text); }else if(typeOfCaseSensitive == LowerCaseSensitive) { text = makeCaseSensitiveLower(text); }else if(typeOfCaseSensitive == NegativeCaseSensitive) { text = makeCaseSensitiveNegative(text); }
temp.beginEditBlock(); temp.insertText(text); temp.endEditBlock(); } block = block.next(); } }
Если при выделении текста началом выделения будет первый символ абзаца, то при повторном использовании функции программа падает, посмотрел в отладке, и он указывает на строку с циклом for, и похоже проблема именно в ++it Помогите исправить это :)
|