【问题标题】:How to append text to QPlainTextEdit without adding newline, and keep scroll at the bottom?如何在不添加换行符的情况下将文本附加到 QPlainTextEdit,并将滚动保持在底部?
【发布时间】:2012-11-13 15:25:57
【问题描述】:

我需要将文本附加到 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 类,没有它我找不到做同样事情的方法:说,我看不到QPlainTextEdit 中的方法 verticalOffset()

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

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

【问题讨论】:

    标签: c++ qt newline qplaintextedit


    【解决方案1】:

    像任何字符串一样:

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

    我试过了,效果很好。

    【讨论】:

    • 请在代码前使用4个空格将其格式化为代码。
    【解决方案2】:

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

    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);
    

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这个答案对我来说不是一个选项,因为:(1)即使当前滚动位置不在底部,它也会继续向下滚动新数据。这很烦人:当新数据到达时,用户无法检查之前添加的数据; (2)当新数据到来时,清除用户的选择。可能在某些情况下这种行为是可以接受的,但在我的情况下,它对用户非常不友好。
    【解决方案4】:

    好的,我不确定我的解决方案是否真的“不错”,但它似乎对我有用:我刚刚创建了继承自 QPlainTextEdit 的新类 QPlainTextEdit_My,并添加了新方法 appendPlainTextNoNL()、@ 987654324@, insertNL().

    请注意:仔细阅读有关参数check_nlcheck_br 的cmets,这很重要!我花了几个小时来弄清楚为什么当我在没有新段落的情况下附加文本时,我的小部件会这么慢。

    /******************************************************************************************
     * 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());
    }
    

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

    【讨论】:

    • 至少在 Qt 5.2.1 insertPlainText() / text_cursor.insertText() 遇到换行符时似乎会自动插入块。
    猜你喜欢
    • 1970-01-01
    • 2019-03-06
    • 1970-01-01
    • 2011-09-25
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多