web-dev-qa-db-fra.com

Comment ajouter du texte à QPlainTextEdit sans ajouter de nouvelle ligne et garder le défilement en bas?

Je dois ajouter du texte à QPlainTextEdit sans ajouter de nouvelle ligne au texte, mais les deux méthodes appendPlainText() et appendHtml() ajoutent un nouveau paragraphe.

Je peux le faire manuellement avec QTextCursor:

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

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

Cela fonctionne, mais je dois aussi garder le parchemin en bas s'il était en bas avant append.

J'ai essayé de copier la logique à partir des sources de Qt, mais je suis restée bloquée là-dessus, car la classe QPlainTextEditPrivate est utilisée et je ne trouve pas le moyen de faire la même chose sans elle: disons que je ne vois pas la méthode verticalOffset() dans QPlainTextEdit.

En fait, ces sources contiennent de nombreuses choses étranges (du moins au premier abord), et je ne sais pas du tout comment les mettre en œuvre.

Voici le code source de append(): http://code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763

26
Dmitry Frank

Ok, je ne suis pas sûr si ma solution est réellement "agréable", mais cela semble fonctionner pour moi: je viens de créer une nouvelle classe QPlainTextEdit_My héritée de QPlainTextEdit et d’ajouter de nouvelles méthodes appendPlainTextNoNL(), appendHtmlNoNL(), insertNL().

S'il vous plaît NOTE: lire les commentaires sur params check_nl et check_br avec soin, c'est important! J'ai passé plusieurs heures à comprendre pourquoi mon widget est si lent lorsque j'ajoute du texte sans nouveaux paragraphes.

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

Je suis confus parce que dans le code original, il existe des calculs beaucoup plus compliqués de atBottom:

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

et needScroll:

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

Mais ma solution facile semble fonctionner aussi.

4
Dmitry Frank

Je vais juste citer ce que j'ai trouvé ici:

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


Il suffit de déplacer le curseur à la fin du contenu de QTextEdit et d’utiliser insertPlainText. Dans mon code, cela ressemble à ceci:

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

Aussi simple que cela. Si votre application doit conserver le curseur où elle était avant d'ajouter le texte, vous pouvez utiliser les méthodes QTextCursor::position() et QTextCursor::setPosition(), ou

il suffit de copier le curseur avant de modifier sa position [QTextCursor QTextEdit::textCursor()], puis de le définir comme curseur [void QTextEdit::setTextCursor(const QTextCursor & cursor)]

Voici un exemple:

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

La réponse actuelle n'était pas une option pour moi. Il était beaucoup plus simple d'ajouter du code HTML sans nouvelles lignes avec la méthode suivante.

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

Comme n'importe quelle corde:

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

Je l'ai essayé et cela a fonctionné.

0
Nabil