Comment ajouter du texte à QPlainTextEdit sans ajouter newline, et garder scroll en bas?
j'ai besoin d'ajouter du texte à QPlainTextEdit
sans ajouter de nouvelle ligne au texte, mais les deux méthodes appendPlainText()
et appendHtml()
ajoute en fait 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 j'ai aussi besoin de garder le rouleau en bas s'il était en bas avant l'ajout.
j'ai essayé de copier la logique des sources de Qt, mais je suis resté dessus, parce qu'il y a en fait QPlainTextEditPrivate
classe est utilisé, et je ne trouve pas le moyen de faire la même sans elle: dire, je ne vois pas de méthode verticalOffset()
QPlainTextEdit
.
en fait, ces sources contiennent beaucoup de choses bizarres (au premier coup d'oeil, au moins), et je n'ai aucune idée de comment mettre en œuvre cela.
voici le code source de append()
: http://code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763
4 réponses
je vais juste citer ce que j'ai trouvé ici:
http://www.jcjc-dev.com/2013/03/qt-48-appending-text-to-qtextedit.html
nous avons juste besoin de déplacer le curseur à la fin du contenu dans QTextEdit et d'utiliser insertPlainText. Dans mon code, il ressemble à ceci:
myTextEdit->moveCursor (QTextCursor::End);
myTextEdit->insertPlainText (myString);
myTextEdit->moveCursor (QTextCursor::End);
Aussi simple que cela. Si votre application doit garder le curseur à l'endroit où il se trouvait avant d'ajouter le texte, vous pouvez utiliser le QTextCursor::position()
et QTextCursor::setPosition()
méthodes, ou
copier le curseur avant de modifier sa position [QTextCursor QTextEdit::textCursor()]
et ensuite paramétrer cela comme le 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);
La Réponse actuelle n'était pas une option pour moi. Il était beaucoup plus simple d'ajouter 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);
Ok, je ne suis pas sûr que ma solution soit vraiment "sympa", mais elle semble fonctionner pour moi: je viens de faire une nouvelle classe QPlainTextEdit_My
hérité de QPlainTextEdit
, et ajouté de nouvelles méthodes appendPlainTextNoNL()
,appendHtmlNoNL()
,insertNL()
.
REMARQUE: lire les commentaires sur params check_nl
et check_br
attention, c'est important! J'ai passé plusieurs heures à comprendre pourquoi mon widget est si lent quand je 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 y a 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.
Comme toute chaîne de caractères:
QTextEdit *myTextEdit = ui->textEdit;
myTextEdit->moveCursor (QTextCursor::End);
myTextEdit->insertPlainText (myString+"\n");
je l'ai essayé et cela a fonctionné.