I was reading the work of cursorposition of qlineedit in documentation it was written that
This property holds the current cursor position of this lineedit.
setting the cursor position causes a repaint when appropriate.
By default, this property contains a value of 0.
what does this lines mean.
The cursor position is the index of the character in the displayed string that will be changed if you type something. Usually, it is indicated by a (blinking) vertical bar and advances as you type.
If the string is Hello World, and the cursor position is 3, then the line edit will look like Hel|lo World, and when you type, e.g., x, it will change to
Helx|lo World.
By default, the cursor is placed at the beginning of the string, i.e., at position zero (0).
If the cursor position changed, a repaint is usually required, since the line edit is supposed to look differently (the vertical bar has moved).
I'm not sure when a repaint would not be appropriate. Maybe if the cursor is not visible.
Related
I am trying to create something similiar like MS paint and I need a feature where I can click on the scene and immediately being able to write where I clicked. I took the the entire code example from this Anwser to solve how to switch between canvas and textarea. In other word how to switch between "drawing" and "writing" mode. So currently I can draw and write Current progress , but my problem is I want to write text where ever I click on the textarea and not at the beginning of the row.
This is how I imagine it (Goal).
So I wanted to add a handler, which can give the mouse coordinates and set the Caret to that positon:
textarea.setOnMouseClicked(event->{
textarea.positionCaret();
});
To only realise that positionCaret() only takes 1 parameter.
So I am not able to position my "Caret" to the x,y position of my mouse click.
So the question is how do I move the "Caret"/cursor to any given positon within my textarea?
Explaining Caret positioning and why it is irrelevant for your purposes
You are misunderstanding the concept of the caret position-related APIs for JavaFX text input. The APIs have nothing to do with screen coordinates. They are referring to the position of the caret with respect to the text in the text input field.
Let's say you have the following word:
happy
Caret position 0 positions the caret before the h.
Caret position 3 positions the caret in-between the two ps.
Once the caret is positioned. If somebody starts typing, the new text will be inserted at the caret.
So if you do:
setCaretPositon(3)
Then you type haphap, then the text will become:
haphaphappy
If somebody clicks in an editable text field, the JavaFX system is smart enough to handle the click by default to position the caret next to the closest letter to the click (and also handle selection and other tasks). You don't need to write any code to get the functionality.
So the caret API has nothing to do with the task you want to accomplish.
Absolute positioning for Text (or any other Node)
If you want to define an absolute position for a text input field on mouse click, then you do it in the exact same way you position any node in JavaFX, i.e. you use the node layout functions. Specifically, you set the x and y coordinates of the node. The co-ordinate system and relevant APIs are explained in the Node javadoc. To set both the x and y values at once, you call the relocate method.
Example for positioning editable text in a pane on mouse click
Here is an example, which generates a new text area and positions the top left corner of the new text area at the position a mouse was clicked.
Pane pane = new Pane();
pane.setOnMouseClicked(event -> {
if (event.getTarget() == pane) {
TextArea newTextArea = new TextArea();
newTextArea.relocate(
event.getX(),
event.getY()
);
pane.getChildren().add(
newTextArea
);
}
});
The example uses a Pane because that is a parent node which does not apply layout positioning to its children (unlike a StackPane which will overwrite any layout values you set and apply its own layout algorithm, which, by default, will center a node in its parent node).
You can see a more comprehensive example in context in the answer to:
How do I create an editable Label in javafx 2.2
That example will convert the text between a Label and TextField on click to allow the label value to be edited. You could choose to use such functionality in your paint program, or you could do it the way MS Paint does it.
How to emulate MS Paint
What MS Paint does is allow you to initially edit the text, but once you hit return to commit the edit, it snapshots the text and paints it as an image on the canvas, converting it from a node-type object to a bit on the canvas. Thereafter you can't edit the text directly anymore. If you want to do things that way you can use a combination of the node snapshot function and the graphics context drawImage function. If you do a snapshot, make sure you set the background correctly in the SnapshotParameters, so that it is transparent, that way the text background won't overwrite your drawing (or do set a background to the appropriate color, if you wanted an overwrite).
I won't provide full code for such functionality here at this time.
Styling text input
You probably want to style (using CSS) the text input field to get the look you want. The editable label example gives some hints on how to do this, but you probably want a different style for your app. Specifically, the default style for text input will have a box and background, which you may or may not want.
When the user scrolls in a QTextBrowser in my application, I want to retrieve the position in the document that they've scrolled to (offset in the document, not the GUI position.)
If I can make the cursor jump to that location, I can get QTextCursor.position(). But I don't see a way to make the cursor jump to the visible location in the browser. The cursor stays where it is when I scroll.
I do not completely understand the description of your problem, but maybe you can determine the cursor (i.e. the position in text document) of the beginning and the end of the visible area by calling https://doc.qt.io/qt-5/qtextedit.html#cursorForPosition
QRect rect = textBrowser->rect();
QTextCursor firstVisible = textBrowser->cursorForPosition(rect.topLeft());
QTextCursor lastVisible = textBrowser->cursorForPosition(rect.bottomRight());
I have not tested it, but I think you get the idea. Maybe you will need to use the rect of textBrowser->viewport() instead of the rect of textBrowser. You need to experiment a bit with this to find what works for you.
Based on V.K.'s answer, here is my solution in Python:
browserRect = self.mainText.rect()
newCursor = self.mainText.cursorForPosition(browserRect.topLeft())
self.mainText.setTextCursor(newCursor)
textPos = mainText.textCursor().position()
Actually, just using QPoint(0,0) probably would work just as well, since the upper left of the browser's rectangle is pretty close to (0,0).
I've added QLabel widgets to my QTreeWidget to work around the word wrapping issue in QTreeWidget. (see how to word wrap a QTreeWidgetItem). The QLabel widgets appear to have spacing around the text which for some reason disappears when the text wraps. It also does not show up when the Label text is blank.
I tried setting setContentsMargin(0,0,0,0) on the QLabel but that didn't work. I also tried setStyleSheet("border: 0px; margin: 0px; padding: 0px;") which also didn't help.
Screenshot:
You can see that it depends on the length of the description whether QT decides to put that spacing buffer around the words. It only happens when the word wrap is enabled. Further playing around seems to indicate its dependent on spaces in the description string. No spaces in the string prevents the additional space around the words. Probably something to do with what the QLabel is doing with its word wrap property.
# This code is Ruby because I'm using the qtbindings gem
tree = Qt::TreeWidget.new
tree.setColumnCount(2)
tree.setHeaderLabels(["Name", "Description"])
top_node = Qt::TreeWidgetItem.new(["top"])
top_node.setCheckState(0, Qt::Unchecked)
tree.addTopLevelItem(top_node)
desc_label = Qt::Label.new("description")
desc_label.setWordWrap(true) # Remove and it works
tree.setItemWidget(top_node, 1, desc_label)
node = Qt::TreeWidgetItem.new(["test1"])
node.setCheckState(0, Qt::Unchecked)
top_node.addChild(node)
desc_label = Qt::Label.new("description1 is long and very interesting")
desc_label.setWordWrap(true) # Remove and it works
tree.setItemWidget(node, 1, desc_label)
What you see is effect of layouting logic for drawing/positioning of QLabel (you may see these routines in https://qt.gitorious.org/qt/qt/source/f7b3072924fb57b3979ff4d536eb213270be1047:src/gui/widgets/qlabel.cpp#sizeForWidth, see sizeForWidth() method).
What you may do is:
You may change the behavior little by trying to set setTextFormat() and use PlainText or RichText for all custom items explicitly. But it may not help.
My recommendation is to subclass used QItemDelegate or QStyledItemDelegate and reimplement the sizeHint( const QStyleOptionViewItem & option, const QModelIndex & index ) for returning desired size, height for you customized item. Then to use setItemDelegate() to view.
My workaround was to set the label's minimum height as follows:
desc_label.setMinimumHeight(desc_label.fontMetrics.height * 2)
This matches what the Label is doing automatically with some of the strings and prevents the inconsistenly sized labels with blank or one-word strings.
I solved the problem by setting the fixed height or maximum height:
label.setMaximumHeight(label.fontMetrics().height() * n);
or
label.setFixedHeight(label.fontMetrics().height() * n);
where n is max considered/estimated lines of the label content.
Unfortunately, setting the minimum height, label.setMinimumHeight(...) does not work, otherwise it was more rational since it is not clear that the wrapped text may have how much lines. Also label.setContentMargin(0,0,0,0) does not work.
Is there any way to control the keyboard cursor in QTextEdit? For instance move the cursor one line up, or two positions back. I have looked at the QCursor class, but is this only for the mouse cursor? Thanks!
QTextCursor::movePosition(MoveOperation operation, MoveMode mode=MoveAnchor, int n=1)
This method allows you to move the cursor in various ways, such as one word to the right or up one line.
You can use it like this:
QTextCursor c = textEdit->textCursor();
c.movePosition(QTextCursor::Up);
textEdit->setTextCursor(c);
If you need to select some text, not just move the cursor, specify the MoveMode as KeepAnchor.
Yes there is:
http://doc.qt.nokia.com/4.7-snapshot/qtextedit.html#moveCursor
Take a look at this demo, how do they accomplish the Inline Changes feature? To me it looks like they are floating a movieclip over the textarea.
What I can't figure out is how they anchored the movieclip to stay in the correct position. If you type something before the movieclip it moves position along with the text, the movieclips even move to the next line when the text word wraps. Does anyone have an idea?
What I think they're doing is keeping track of the index the sprite is representing. Then they have a nice function that moves the sprite to the correct position given the size of the textbox and font. All you need to do after that is bind the positioning function to changes made to the textbox and you've got that effect. Doesn't seem too complicated, as there are already font size/position functions available.
EDIT: Notice how you cannot type code in between the overlapping regions.