If I have a QTextEdit box, how can I align different pieces of text within the box in different ways? For example, I would like to have one sentence be aligned-left, and the next sentence in the box be aligned-right. Is this possible? If not, how might I achieve this effect in Qt?
As documentation said:
void QTextEdit::setAlignment(Qt::Alignment a) [slot]
Sets the alignment of the current paragraph to a. Valid alignments are Qt::AlignLeft, Qt::AlignRight, Qt::AlignJustify and Qt::AlignCenter (which centers horizontally).
Link: http://qt-project.org/doc/qt-5/qtextedit.html#setAlignment
So as you can see you should provide some alignment to each paragraph.
Little example:
QTextCursor cursor = ui->textEdit->textCursor();
QTextBlockFormat textBlockFormat = cursor.blockFormat();
textBlockFormat.setAlignment(Qt::AlignRight);//or another alignment
cursor.mergeBlockFormat(textBlockFormat);
ui->textEdit->setTextCursor(cursor);
Which result I get on my computer?
Or something closer to your question:
ui->textEdit->clear();
ui->textEdit->append("example");
ui->textEdit->append("example");
QTextCursor cursor = ui->textEdit->textCursor();
QTextBlockFormat textBlockFormat = cursor.blockFormat();
textBlockFormat.setAlignment(Qt::AlignRight);
cursor.mergeBlockFormat(textBlockFormat);
ui->textEdit->setTextCursor(cursor);
ui->textEdit->append("example");
cursor = ui->textEdit->textCursor();
textBlockFormat = cursor.blockFormat();
textBlockFormat.setAlignment(Qt::AlignCenter);
cursor.mergeBlockFormat(textBlockFormat);
ui->textEdit->setTextCursor(cursor);
Result:
To left align to a textbox "TerminalOutput":
string Wibble="wibble";
TerminalOutput->append(QString::fromStdString(Wibble));
TerminalOutput->setAlignment(Qt::AlignLeft);
To right align to a textbox:
string Wobble="wobble";
TerminalOutput->append(QString::fromStdString(Wobble));
TerminalOutput->setAlignment(Qt::AlignRight);
Now, sometimes, and this happens with Kosovan's answer too, the alignment in my code sets the previous line instead of the current. This is inexplicable to me. I cannot work out why this is. If anyone knows why this is, please leave a comment because it's driving me nuts.
Edit, I found the problem. So the alignment works fine, until you select some text with the cursor. The instant you do that, the alignment stops aligning the previous line and then decides to affect the following line instead of the previous and this affects all other append formats henceforth. In fact clicking anywhere inside the textbox, will do this, it must be that it's interfering with qt's internal notion of cursor position.
I fixed this problem by doing the following before appending to the textbox:
QTextCursor newCursor = TerminalOutput->textCursor();
newCursor.movePosition(QTextCursor::End);
TerminalOutput->setTextCursor(newCursor);
And what that does is just moves the cursor to the end of the textbuffer so that when you append, it clears out any cursor position of a user clicking anywhere within the textbox, and this solves my strange little problem.
Related
I will start by saying: I am already aware that I can use '\b' and ansi escape codes to get the cursor position, move the cursor, and get the terminal size.
However, once the-text-I-am-interested-in has scrolled past the terminal's view, it seems impossible to modify said text.
For instance, imagine that the terminal has the following displayed on it:
first line [...]
a
b
c
...
last line
And when printing a new line, let's imagine that "first line [...]" scrolls out of screen, disappearing above "a":
a
b
c
...
last line
inserted line
Would it still be possible to modify the line ('first line [...]'), perhaps using the terminal's own buffer, in C++?
The idea would be to modify the line, such that if you do scroll back up, you would see the modified version (bonus points if you can also still print ansi codes for formatting out-of-screen).
I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)
I'm currently designing a CLI interface for linux, and for various reasons I am not able to use ncurses. I am using exclusively C++ and the Qt framework.
Therefore, in order to have a user-friendly interface, I have to run this getch loop in a separate thread:
https://stackoverflow.com/a/912796/3605689
Which basically means I have to implement all basic functionalities (such as backspace) by myself. I have already implemented command completion and command history(like when you press tab or uparrow/downarrow in linux), but I can't figure out how to implement leftarrow/rightarrow (aka seeking through the typeahead).
Normally, I implement it like this: upon every gech which is not equal to -1, I check whether the user has pressed a special key (one that modifies the typeahead somehow). I then clear the stdout using the following function:
void inputobject::clear_line(int nletters)
{
QTextStream(stdout) << "\033[2K";
for(int i = 0; i < nletters;i++){
QTextStream(stdout) << "\b";
}
rewind(stdout);
}
And replace it with something else, effectively simulating the typeahead. For example, in the case of backspace, I would save the command call clear_line, and print the command out again, just with one less letter, behaving exactly as a normal console application would.
My real problem is with the cursor, in the case of left/rightarrow, I need to move the cursor visual in order to be able to indicate where in the text is the user seeking:
Because of the nature of how I rewrite the given stdout line to simulate the typeahead, it does not really matter where the cursor REALLY is, as long as it stays on the same line - it is just the visual that matters. How can I achieve moving the cursor visual on linux?
The answer was provided in the comment by Evilruff:
Cursor Movement
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
Position the Cursor:
\033[;H
Or
\033[L;Cf
puts the cursor at line L and column C.
Move the cursor up N lines:
\033[NA
Move the cursor down N lines:
\033[NB
Move the cursor forward N columns:
\033[NC
Move the cursor backward N columns:
\033[ND
Clear the screen, move to (0,0):
\033[2J
Erase to end of line:
\033[K
Save cursor position:
\033[s
Restore cursor position:
\033[u
Not using ncurses and co is a serious limitation.
It is hell to make correct input/output on shell for displaying anything.
The only others real solutions (I can't think as a solution to reimplement a ncurse-like library) I think of are:
making call to dialog (for some example www.linuxjournal.com/article/2807 and for the doc: http://linux.die.net/man/1/dialog)
using the framebuffer mecanism with Qt4 (here)
I need to delete a specific line from QTextEdit (NoWrap option is active) manualy from the program. I found a solution which explains how to remove first line, but i wonder how can I remove whole line at specific index.
I've also found a solution here Remove a line/block from QTextEdit , but I don't know what these blocks are. Do they represent single lines or not? Should i iterate through these blocks and if i reach block at given index, then delete it?
You can remove the line at lineNumer with :
QTextCursor cursor = textEdit->textCursor();
cursor.movePosition(QTextCursor::Start);
cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, lineNumer);
cursor.select(QTextCursor::LineUnderCursor);
cursor.removeSelectedText();
cursor.deleteChar(); // clean up new line
textEdit->setTextCursor(cursor);
Here you put the cursor at the beginning of the document, move down lineNumer times, select the specific line and remove it.
You can do the following:
QTextEdit te;
// Three lines in the text edit
te.setText("Line 1\nLine 2\nLine 3");
const int lineToDelete = 1; // To delete the second line.
QTextBlock b = te.document()->findBlockByLineNumber(lineToDelete);
if (b.isValid()) {
QTextCursor cursor(b);
cursor.select(QTextCursor::BlockUnderCursor);
cursor.removeSelectedText();
}
I know that this question has been accepted and that it's fairly dead here, but I'm going to posit my experiences with QTextEdit as a caution to those that follow.
My problem space was similar to OP's in that I wanted to remove a single line from a text edit. I following the given solution here, improving upon it slightly, and ultimately believed that I had found success.
That success, however, was only realized while the text edit was being viewed, or if it had appeared on screen at least once throughout the course of the program. While I cannot confirm this, I believe that it has to do with cursor manipulation.
Here's a more in-depth explanation:
I desired to create a message history between a UI and the remote unit to which it was conversing. The messages would be color-coded, one for the UI's sent messages, the other for the received messages. In order to prevent a massive memory impact, the idea is to limit the number of lines to a specific amount, say 1000.
My original code was much like the accepted answer:
If the number of lines exceeded my setpoint, move cursor to the beginning and delete the first line.
After some time, however, I began to notice a slowdown in the runtime execution of the program. After adding debug in, I found that, so long as I had not actually viewed the location to which the text was sent, the line-limiter never actually erased the lines. The QTextEdit to which the text was sent was in a tabbed widget. This means that I had to cycle through to that tab, otherwise the algorithm wouldn't work.
Here is a working solution for my problem space:
void ScrollingEdit::append(QString text, QColor color)
{
QString pc = QString("<body style=\"color:rgb(%1,%2,%3);\">").
arg(color.red()).arg(color.green()).arg(color.blue());
QString ac = QString("</body>");
text.prepend( pc );
text.append( ac );
mText.append( text );
QString delim = "</body>";
if ( mText.count( delim ) > mMaxLine )
{
mText.remove(0, mText.indexOf( delim ) + delim.size() );
}
mEdit->clear();
mEdit->setHtml( mText );
QTextCursor cursor = mEdit->textCursor();
cursor.movePosition( QTextCursor::End );
mEdit->setTextCursor(cursor);
mEdit->ensureCursorVisible();
}
Where mText is a member variable QString that acts as the "model" for the text edit, mMaxLine is a user-configurable int that sets the maximum number of allowable lines, and mEdit is the UI QTextEdit. Note that cursor manipulation still exists, but where it matters, which is when the user is viewing the element.
I'm using a QPlainTextEdit control with word-wrapping active and I'm wondering how can I detect, in order to update a line counter, when a block of text gets wrapped (causing the number of lines to be incremented).
The underlying QTextDocument has a signal to detect when the block count changes, but not the corresponding one for line count changes.
Is it possible to detect word-wrapping and line count increase for a QTextDocument?
It's a little bit late but perhaps my answer can help somebody.
I had almost the same need in my company and I solved it like this:
// This example show how to get the visual number of lines
QPlainTextEdit *pte = new QPlainTextEdit();
pte->setAttribute(Qt::WA_DontShowOnScreen);
pte->show();
pte->setFixedWidth(50);
pte->setPlainText("Hello world!");
/* The next line return the number of necessary line
to display the text "Hello World!" with width of 50px */
int lineCount = pte->document()->documentLayout()->documentSize().height();
Best regards
I solved by using QAbstractTextDocument's signal documentSizeChanged:
void QAbstractTextDocumentLayout::documentSizeChanged ( const QSizeF &
newSize ) [signal]
This signal is emitted when the size of the
document layout changes to newSize. Subclasses of
QAbstractTextDocumentLayout should emit this signal when the
document's entire layout size changes. This signal is useful for
widgets that display text documents since it enables them to update
their scroll bars correctly.
I know the size of my font and getting the precise size of the new underlying document allowed me to count the lines (wrapped or not) of my text document.