2012-11-26 9 views
23

Devo aggiungere il testo a QPlainTextEdit senza aggiungere una nuova riga al testo, ma entrambi i metodi appendPlainText() e appendHtml() aggiungono effettivamente un nuovo paragrafo.Come aggiungere testo a QPlainTextEdit senza aggiungere una nuova riga e mantenere lo scroll in basso?

posso farlo manualmente con QTextCursor:

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

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

Che funziona, ma ho anche bisogno di tenere scorrimento nella parte inferiore se fosse, in fondo, prima di accodamento.

Ho provato a copiare la logica dalle sorgenti di Qt, ma mi sono bloccato, perché in realtà viene utilizzata la classe QPlainTextEditPrivate e non riesco a trovare il modo di fare lo stesso senza: diciamo, non vedo il metodo verticalOffset() in QPlainTextEdit.

In realtà, queste fonti contengono molte cose strane (al primo sguardo, almeno), e non ho idea di come implementarlo.

Ecco il codice sorgente di append(): http://code.qt.io/cgit/qt/qt.git/tree/src/gui/widgets/qplaintextedit.cpp#n2763

risposta

2

Ok, io non sono sicuro se la mia soluzione è in realtà "bello", ma sembra funzionare per me: ho appena fatto nuova classe QPlainTextEdit_My ereditato da QPlainTextEdit, e ha aggiunto nuovi metodi appendPlainTextNoNL(), appendHtmlNoNL(), insertNL().

Nota: leggi i commenti sui parametri check_nl e check_br attentamente, questo è importante! Ho trascorso diverse ore a capire perché il mio widget è così lento quando aggiungo il testo senza nuovi paragrafi.

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

Sono confuso perché nel codice originale ci sono molto più complicati calcoli di atBottom:

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

e needScroll:

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

Ma la mia soluzione facile sembra funzionare troppo.

+1

Almeno su Qt 5.2.1 insertPlainText()/text_cursor.insertText() sembra inserire automaticamente i blocchi quando incontra una nuova riga. – iliis

19

mi limiterò a citare quello che ho trovato qui:

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


abbiamo solo bisogno di spostare il cursore alla fine dei contenuti del QTextEdit e utilizzare insertPlainText. Nel mio codice, appare così:

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

Semplice. Se l'applicazione ha bisogno di mantenere il cursore in cui era prima di aggiungere il testo, è possibile utilizzare le QTextCursor::position() e QTextCursor::setPosition() metodi, o

semplicemente copiando il cursore prima di modificare la sua posizione [QTextCursor QTextEdit::textCursor()] e quindi impostando che, come il cursore [void QTextEdit::setTextCursor(const QTextCursor & cursor)].

Ecco un esempio:

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

Una correzione minore, setTextCursor accetta un QTextCursor, non un puntatore. Fonte: http://doc.qt.io/qt-4.8/qplaintextedit.html#setTextCursor. Anche il tuo link è giù. – awakenDeepBlue

8

La risposta attuale non era un'opzione per me. È stato molto più semplice aggiungere html senza nuove righe con il seguente metodo.

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

Questa risposta non è un'opzione per me, perché: (1) Continua a scorrere verso il basso sui nuovi dati anche se la posizione di scorrimento corrente non è in fondo. Questo è molto fastidioso: mentre arrivano nuovi dati, l'utente non è in grado di esaminare i dati che sono stati aggiunti prima; e (2) quando arrivano nuovi dati, cancella la selezione dell'utente. Probabilmente, in alcuni casi questo comportamento è accettabile, ma nel mio caso è molto ostico all'utente. –

-2

Come ogni stringa:

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

ho provato e ha funzionato.

+0

Utilizzare 4 spazi davanti al codice per formattarlo come codice. –

+0

Questa risposta è già stata data. –