Как добавить текст в QPlainTextEdit без добавления новой строки и держать прокрутку внизу?

Мне нужно добавить текст к QPlainTextEdit без добавления новой строки в текст, но оба метода appendPlainText() а также appendHtml() добавляет фактически новый абзац.

Я могу сделать это вручную с QTextCursor:

QTextCursor text_cursor = QTextCursor(my_plain_text_edit->document());
text_cursor.movePosition(QTextCursor::End);

text_cursor.insertText("string to append. ");

Это работает, но мне также нужно держать прокрутку внизу, если она была внизу перед добавлением.

Я пытался скопировать логику из источников Qt, но я застрял на ней, потому что там на самом деле QPlainTextEditPrivate класс используется, и я не могу найти способ сделать то же самое без него: скажем, я не вижу метод verticalOffset() в QPlainTextEdit,

На самом деле, эти источники содержат много странных (на первый взгляд, по крайней мере) вещей, и я понятия не имею, как это реализовать.

Вот исходный код append(): http://code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763

26

Решение

Я просто процитирую то, что я нашел здесь:

http://www.jcjc-dev.com/2013/03/qt-48-appending-text-to-qtextedit.html


Нам просто нужно переместить курсор в конец содержимого в QTextEdit и использовать insertPlainText. В моем коде это выглядит так:

myTextEdit->moveCursor (QTextCursor::End);
myTextEdit->insertPlainText (myString);
myTextEdit->moveCursor (QTextCursor::End);

Так просто. Если ваше приложение должно держать курсор там, где оно было до добавления текста, вы можете использовать QTextCursor::position() а также QTextCursor::setPosition() методы или

просто скопировать курсор перед изменением его положения [QTextCursor QTextEdit::textCursor()] а затем установить его в качестве курсора [void QTextEdit::setTextCursor(const QTextCursor & cursor)],

Вот пример:

QTextCursor prev_cursor = myTextEdit->textCursor();
myTextEdit->moveCursor (QTextCursor::End);
myTextEdit->insertPlainText (myString);
myTextEdit->setTextCursor (&prev_cursor);
23

Другие решения

Текущий ответ не был вариант для меня. Намного проще было добавить html без новых строк следующим способом.

//logs is a QPlainTextEdit object
ui.logs->moveCursor(QTextCursor::End);
ui.logs->textCursor().insertHtml(out);
ui.logs->moveCursor(QTextCursor::End);
10

Хорошо, я не уверен, что мое решение на самом деле «хорошее», но мне кажется, оно работает: я только что создал новый класс QPlainTextEdit_My унаследованный от QPlainTextEditи добавил новые методы appendPlainTextNoNL(), appendHtmlNoNL(), insertNL(),

Пожалуйста, обратите внимание: читать комментарии о параметрах check_nl а также check_br осторожно, это важно! Я потратил несколько часов, чтобы понять, почему мой виджет такой медленный, когда я добавляю текст без новых абзацев.

/******************************************************************************************
* INCLUDED FILES
*****************************************************************************************/

#include "qplaintextedit_my.h"#include <QScrollBar>
#include <QTextCursor>
#include <QStringList>
#include <QRegExp>/******************************************************************************************
* CONSTRUCTOR, DESTRUCTOR
*****************************************************************************************/

QPlainTextEdit_My::QPlainTextEdit_My(QWidget *parent) :
QPlainTextEdit(parent)
{

}

QPlainTextEdit_My::QPlainTextEdit_My(const QString &text, QWidget *parent) :
QPlainTextEdit(text, parent)
{

}

/******************************************************************************************
* METHODS
*****************************************************************************************/

/* private      */

/* protected    */

/* public       */

/**
* append html without adding new line (new paragraph)
*
* @param html       html text to append
* @param check_nl   if true, then text will be splitted by \n char,
*                   and each substring will be added as separate QTextBlock.
*                   NOTE: this important: if you set this to false,
*                   then you should append new blocks manually (say, by calling appendNL() )
*                   because one huge block will significantly slow down your widget.
*/
void QPlainTextEdit_My::appendPlainTextNoNL(const QString &text, bool check_nl)
{
QScrollBar *p_scroll_bar = this->verticalScrollBar();
bool bool_at_bottom = (p_scroll_bar->value() == p_scroll_bar->maximum());

if (!check_nl){
QTextCursor text_cursor = QTextCursor(this->document());
text_cursor.movePosition(QTextCursor::End);
text_cursor.insertText(text);
} else {
QTextCursor text_cursor = QTextCursor(this->document());
text_cursor.beginEditBlock();

text_cursor.movePosition(QTextCursor::End);

QStringList string_list = text.split('\n');

for (int i = 0; i < string_list.size(); i++){
text_cursor.insertText(string_list.at(i));
if ((i + 1) < string_list.size()){
text_cursor.insertBlock();
}
}text_cursor.endEditBlock();
}

if (bool_at_bottom){
p_scroll_bar->setValue(p_scroll_bar->maximum());
}
}

/**
* append html without adding new line (new paragraph)
*
* @param html       html text to append
* @param check_br   if true, then text will be splitted by "<br>" tag,
*                   and each substring will be added as separate QTextBlock.
*                   NOTE: this important: if you set this to false,
*                   then you should append new blocks manually (say, by calling appendNL() )
*                   because one huge block will significantly slow down your widget.
*/
void QPlainTextEdit_My::appendHtmlNoNL(const QString &html, bool check_br)
{
QScrollBar *p_scroll_bar = this->verticalScrollBar();
bool bool_at_bottom = (p_scroll_bar->value() == p_scroll_bar->maximum());

if (!check_br){
QTextCursor text_cursor = QTextCursor(this->document());
text_cursor.movePosition(QTextCursor::End);
text_cursor.insertHtml(html);
} else {

QTextCursor text_cursor = QTextCursor(this->document());
text_cursor.beginEditBlock();

text_cursor.movePosition(QTextCursor::End);

QStringList string_list = html.split(QRegExp("\\<br\\s*\\/?\\>", Qt::CaseInsensitive));

for (int i = 0; i < string_list.size(); i++){
text_cursor.insertHtml( string_list.at(i) );
if ((i + 1) < string_list.size()){
text_cursor.insertBlock();
}
}

text_cursor.endEditBlock();
}

if (bool_at_bottom){
p_scroll_bar->setValue(p_scroll_bar->maximum());
}
}

/**
* Just insert new QTextBlock to the text.
* (in fact, adds new paragraph)
*/
void QPlainTextEdit_My::insertNL()
{
QScrollBar *p_scroll_bar = this->verticalScrollBar();
bool bool_at_bottom = (p_scroll_bar->value() == p_scroll_bar->maximum());

QTextCursor text_cursor = QTextCursor(this->document());
text_cursor.movePosition(QTextCursor::End);
text_cursor.insertBlock();

if (bool_at_bottom){
p_scroll_bar->setValue(p_scroll_bar->maximum());
}
}

Я запутался, потому что в оригинальном коде есть гораздо более сложные вычисления atBottom:

const bool atBottom =  q->isVisible()
&& (control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
<= viewport->rect().bottom());

а также needScroll:

if (atBottom) {
const bool needScroll =  !centerOnScroll
|| control->blockBoundingRect(document->lastBlock()).bottom() - verticalOffset()
> viewport->rect().bottom();
if (needScroll)
vbar->setValue(vbar->maximum());
}

Но мое простое решение, похоже, тоже работает.

4

Как и любая строка:

    QTextEdit *myTextEdit = ui->textEdit;
myTextEdit->moveCursor (QTextCursor::End);
myTextEdit->insertPlainText (myString+"\n");

Я попробовал это, и это сработало.

0
По вопросам рекламы [email protected]