PDA

View Full Version : How do I set a QTextEdit to a specific line by line number?



Coolname007
27th December 2012, 23:11
Hello.
In my application I'm writing in Qt, I am trying to implement a "Go to Line" dialog which will set the central widget (a QTextEdit) to a specific line that the user enters, using a line number.

However, I have searched the docs for such a function will allow one to easily do this, and have not found one. Is this because it does not exist? Or maybe I missed it?

I also need to display the line numbers in the QTextEdit like many text editors do (i.e. displaying the line numbers on the left side of each line), but have also failed to find such existing functionality.

Any suggestions??

Thanks.

EDIT:

Here is what I have so far:



void C_MainWindow::goToLineAction() {

bool ok;
int line_number = QInputDialog::getInt(this, tr("Go to Line"),
tr("Enter a line number to go to: "), 1, 1, central_widget_TextDocument->blockCount(), 1, &ok);
if (ok) {
}

}


This creates the "Go to Line" dialog with the default value being the first line's number (1) and the minimal value also being 1, and the maximal value being the number of "blocks" (which I understand is really lines, I believe) that the text editor's document currently has. But it does not (yet) actually go to the line in the QTextEdit, since I don't know how to do that yet (hence this thread).

airglide
28th December 2012, 04:04
Well I would try to set the QTextCursor to this position, something like:



QTextCursor txtCursor = edit->textCursor();
//position where you want it
txtCursor.setPosition(...);
edit->setTextCursor(txtCursor);

Coolname007
28th December 2012, 05:28
Well I would try to set the QTextCursor to this position, something like:



QTextCursor txtCursor = edit->textCursor();
//position where you want it
txtCursor.setPosition(...);
edit->setTextCursor(txtCursor);

Well, how would I convert a line number to an absolute position inside of a document (which is what that setPosition() function requires)?

Also, assuming I could get that to work, I don't think a text cursor principle would work on a QTextEdit which has had its setReadOnly(true) function called (since setting it to read-only mode means you can no longer use the cursor in it), which is what I do for "Standard Mode" in my application...

Added after 52 minutes:

Hmm...
I have tried the following code to see if it might work, but it did not perform as expected. In the "Go to Line" dialog, I entered line 14 for a document that contains 14 lines, but instead of selecting line 14, it selected line 1, proving it does not work.



void C_MainWindow::goToLineAction() {

bool ok;
int line_number = QInputDialog::getInt(this, tr("Go to Line"),
tr("Enter a line number to go to: "), 1, 1, central_widget_TextDocument->blockCount(), 1, &ok);
if (ok) {
QTextCursor text_cursor(central_widget_TextDocument->findBlockByLineNumber(line_number));
text_cursor.select(QTextCursor::BlockUnderCursor);
central_widget_TextEdit->setTextCursor(text_cursor);
}

}

lanz
28th December 2012, 07:30
I have tried the following code to see if it might work, but it did not perform as expected. In the "Go to Line" dialog, I entered line 14 for a document that contains 14 lines, but instead of selecting line 14, it selected line 1, proving it does not work.

Use findBlockByLineNumber (line_number -1), since findBlockByNumber works on zero-based line numbers.
After that you can set position of the cursor (rather than selecting whole block):


QTextBlock text_block = central_widget_TextDocument->findBlockByLineNumber(line_number-1);

QTextCursor text_cursor = central_widget_TextEdit->textCursor ();
text_cursor.setPosition (text_block.position ());
central_widget_TextEdit->setFocus ();
central_widget_TextEdit->setTextCursor (text_cursor);


BUT, I don't think i fully understand concept of a block. Can it contain multiple lines?
Can anyone clarify on that?
If this is the case, this method will not work. Then you can simply have a list of the absolute positions of strings inside your text edit and set up cursor accordingly to this list.


To display line numbers you can subclass text edit and do custom painting in paint event using drawText and QFontMetrics (first thing that comes to mind).
What is unclear for me is how you get what lines are displayed.

Coolname007
28th December 2012, 19:26
Use findBlockByLineNumber (line_number -1), since findBlockByNumber works on zero-based line numbers.

Hey, thanks for that. I wasn't aware that the findBlockByNumber() function uses 0-based line numbers, and it doesn't mention it in the docs.
I just assumed it used 1-based numbers.
I tried modifying the code in my last post to use line_number - 1 instead of just line_number, and that appears to have fixed it. :D It now selects
the right line that I enter in. However, I have noticed something a bit strange in its behavior: Instead of just selecting the line that I entered, it also appears to select a
one-character-width space before the line as well (even if the line before is empty). And if I enter in a line number corresponding to a line that does not follow an empty line,
it does not select any of the characters of the previous line, but appears to select a one-character-width space after the previous line's characters. I do not know why this is.
I suspect it has something to do with Qt's concept of a "block".



After that you can set position of the cursor (rather than selecting whole block):

Thanks, but I'd rather keep selecting the whole block, reason being when the text edit is in read-only mode (which is true in my application when the text editor mode is in "Standard mode", meaning you can only edit the document with the GUI controls,
and can not directly modify the document), it does not show the cursor, and you can only select the text.




QTextBlock text_block = central_widget_TextDocument->findBlockByLineNumber(line_number-1);

QTextCursor text_cursor = central_widget_TextEdit->textCursor ();
text_cursor.setPosition (text_block.position ());
central_widget_TextEdit->setFocus ();
central_widget_TextEdit->setTextCursor (text_cursor);


Thanks for the example code. I didn't even think of looking at the QTextBlock class for a function to get the position.
However, since "text_block.position()" refers to a position corresponding to that of the first character of the block in the document, wouldn't that position be different in terms of cursor positions (since the cursor is always in between characters, and not on the same space)? Maybe it should be "text_block.position() - 1"?


BUT, I don't think i fully understand concept of a block. Can it contain multiple lines?
Can anyone clarify on that?

Good question. I'm wondering the same thing myself, especially after the results I just got.
I will wait for an answer...



If this is the case, this method will not work. Then you can simply have a list of the absolute positions of strings inside your text edit and set up cursor accordingly to this list.


To display line numbers you can subclass text edit and do custom painting in paint event using drawText and QFontMetrics (first thing that comes to mind).
What is unclear for me is how you get what lines are displayed.
Keep in mind, I'm still relatively new to Qt, and don't quite understand how to do "custom painting in paint event".
I would appreciate it if you could give some example code demonstrating this.

Thanks.

Added after 47 minutes:

Ok, I guess not (about the cursor position thing)...
I just tried the following code, and the cursor (in "Hand-Editing" mode) shows up on the right position on the right line when I enter a line to go to.
But, as before, the selection problem still exists.



void C_MainWindow::goToLineAction() {

bool ok;
int line_number = QInputDialog::getInt(this, tr("Go to Line"),
tr("Enter a line number to go to: "), 1, 1, central_widget_TextDocument->blockCount(), 1, &ok);
if (ok) {
/*
QTextCursor text_cursor(central_widget_TextDocument->findBlockByLineNumber(line_number - 1));
text_cursor.select(QTextCursor::BlockUnderCursor);
central_widget_TextEdit->setTextCursor(text_cursor);
*/
QTextBlock text_block = central_widget_TextDocument->findBlockByLineNumber(line_number - 1);
QTextCursor text_cursor = central_widget_TextEdit->textCursor ();
text_cursor.setPosition (text_block.position());
central_widget_TextEdit->setFocus();
text_cursor.select(QTextCursor::BlockUnderCursor);
central_widget_TextEdit->setTextCursor (text_cursor);
}

}


EDIT:

Nevemind about the selection problem. FIXED! :D





void C_MainWindow::goToLineAction() {

bool ok;
int line_number = QInputDialog::getInt(this, tr("Go to Line"),
tr("Enter a line number to go to: "), 1, 1, central_widget_TextDocument->blockCount(), 1, &ok);
if (ok) {
QTextCursor text_cursor(central_widget_TextDocument->findBlockByLineNumber(line_number - 1));
text_cursor.select(QTextCursor::LineUnderCursor);
central_widget_TextEdit->setTextCursor(text_cursor);

/*
QTextBlock text_block = central_widget_TextDocument->findBlockByLineNumber(line_number - 1);
QTextCursor text_cursor = central_widget_TextEdit->textCursor ();
text_cursor.setPosition (text_block.position());
central_widget_TextEdit->setFocus();
text_cursor.select(QTextCursor::LineUnderCursor);
central_widget_TextEdit->setTextCursor(text_cursor);
*/
}

}

amleto
28th December 2012, 22:46
Hey, thanks for that. I wasn't aware that the findBlockByNumber() function uses 0-based line numbers, and it doesn't mention it in the docs.
I just assumed it used 1-based numbers.
Why? EVERYTHING in c/c++ is 0-based.

Coolname007
31st December 2012, 19:47
Why? EVERYTHING in c/c++ is 0-based.
Not everything. Size functions and size parameters in functions always use 1-based numbers.
Granted, findBlockByLineNumber() is a find function, and find functions in the C++ standard library use 0-based numbers to represent positions.
But, line numbers and indexes are two separate things. Since line numbers are often displayed (and always in the 1-based format), I just assumed
that a function which takes a line number as a parameter would count the line number in a 1-based way, and not a 0-based way.

lanz
29th January 2013, 07:22
Keep in mind, I'm still relatively new to Qt, and don't quite understand how to do "custom painting in paint event".
I would appreciate it if you could give some example code demonstrating this.


There's very good example:
http://doc.qt.digia.com/qt/widgets-codeeditor.html

Coolname007
1st February 2013, 06:18
There's very good example:
http://doc.qt.digia.com/qt/widgets-codeeditor.html

Awesome. That example looks exactly like what I'm looking for.
I haven't had time yet to look over it in any depth, but I'm certain I'll find the information that I need in there.

Thanks a ton. I really appreciate it. :D