C++ 如何在不添加换行符的情况下将文本附加到 QPlainTextEdit,并在底部保持滚动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13559990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:29:13  来源:igfitidea点击:

How to append text to QPlainTextEdit without adding newline, and keep scroll at the bottom?

c++qtnewlineqplaintextedit

提问by Dmitry Frank

I need to append text to QPlainTextEditwithout adding a newline to the text, but both methods appendPlainText()and appendHtml()adds actually new paragraph.

我需要将文本追加到QPlainTextEdit不添加新行的文本,但是这两种方法appendPlainText(),并appendHtml()实际上增加了新的段落。

I can do that manually with QTextCursor:

我可以使用QTextCursor以下方法手动执行此操作:

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

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

That works, but I also need to keep scroll at bottom if it was at bottom before append.

那行得通,但如果在追加之前它位于底部,我还需要将滚动保持在底部。

I tried to copy logic from Qt's sources, but I stuck on it, because there actually QPlainTextEditPrivateclass is used, and I can't find the way to do the same without it: say, I don't see method verticalOffset()in QPlainTextEdit.

我试图从 Qt 的源代码中复制逻辑,但我坚持使用它,因为实际上使用了QPlainTextEditPrivate类,并且没有它我找不到做同样事情的方法:比如说,我verticalOffset()QPlainTextEdit.

Actually, these sources contain many weird (at the first look, at least) things, and I have no idea how to implement this.

实际上,这些来源包含许多奇怪的(至少乍一看)的东西,我不知道如何实现这一点。

Here's the source code of append(): http://code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763

这里的源代码append()http: //code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763

采纳答案by Dmitry Frank

Ok, I'm not sure if my solution is actually "nice", but it seems to work for me: I just made new class QPlainTextEdit_Myinherited from QPlainTextEdit, and added new methods appendPlainTextNoNL(), appendHtmlNoNL(), insertNL().

好的,我不确定我的解决方案是否真的“不错”,但它似乎对我有用:我只是QPlainTextEdit_My从 继承了新类QPlainTextEdit,并添加了新方法appendPlainTextNoNL(), appendHtmlNoNL(), insertNL()

Please NOTE:read comments about params check_nland check_brcarefully, this is important! I spent several hours to figure out why is my widget so slow when I append text without new paragraphs.

请注意:阅读有关参数的评论check_nlcheck_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());
   }
}

I'm confused because in original code there are much more complicated calculations of atBottom:

我很困惑,因为在原始代码中有更复杂的计算atBottom

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

and needScroll:

needScroll

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

But my easy solution seems to work too.

但我的简单解决方案似乎也有效。

回答by david

I'll just quote what I found here:

我将引用我在这里找到的内容:

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

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



We just need to move the cursor to the end of the contents in the QTextEdit and use insertPlainText. In my code, it looks like this:

我们只需要将光标移动到 QTextEdit 中内容的末尾并使用 insertPlainText。在我的代码中,它看起来像这样:

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

As simple as that. If your application needs to keep the cursor where it was before appending the text, you can use the QTextCursor::position()and QTextCursor::setPosition()methods, or

就如此容易。如果您的应用程序需要在追加文本之前将光标保持在原来的位置,您可以使用QTextCursor::position()QTextCursor::setPosition()方法,或者

just copying the cursor before modifying its position [QTextCursor QTextEdit::textCursor()]and then setting that as the cursor [void QTextEdit::setTextCursor(const QTextCursor & cursor)].

只需在修改光标位置之前复制光标,然后将其[QTextCursor QTextEdit::textCursor()]设置为光标[void QTextEdit::setTextCursor(const QTextCursor & cursor)]

Here's an example:

下面是一个例子:

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

回答by andre

The current Answer was not an option for me. It was much simplier to add html with no new lines with the following method.

当前的答案对我来说不是一个选择。使用以下方法添加没有新行的html要简单得多。

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

回答by Nabil

Like any string:

像任何字符串一样:

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

I tried it and it worked.

我试过了,它奏效了。