SetTextCursor in PyQt4 - python

Every time textChanged() is emitted, the text of QTextBrowser is processed and then re-inserted in that QTextBrowser.
That causes trouble with the current Cursor.
How do I do that after typing something at | and re-inserting the text, the cursor is behind the newly inserted character (here: X) ?
Hello| World
Where it should be:
HelloX| World
Where it is:
|HelloX World
I need some help because I don't understand the according part of the QT documentation.

If you're inserting text after the cursor, as yor example suggests, you, you should use the text cursor's insertText method instead of replacing the whole content of the editor - should save you some trouble:
editor.textCursor().insertText('X')
Otherwise you should be able to restore the previous position like this:
old_position = editor.textCursor().position()
# ...
new_cursor = editor.textCursor()
new_cursor.setPosition(old_position)
editor.setTextCursor(cursor)

Related

Python Getting cursor position in WordApplication with win32

I would like to add some text after the current position of the cursor in an active word document.
The code I need would have to be something like this:
import win32com.client as win32
word = win32.gencache.EnsureDispatch('Word.Application')
def InsertTextAfterCursor(text,document):
document.Range(0,document.GETCURSORPOSITION).InsertAfter(text) #GETCURSORPOSITION is what I don't know how to implement
word.Documents().Open("TheDocI'mWorkingOn.docx")
doc = word.Documents().Item("TheDocI'mWorkingOn.docx")
InsertTextAfterCursor(doc,'The text I want to insert')
The only idea I've come up with is to constantly check for changes of the entire Range of the document, so I can get where I'm writing, but:
this is useless if I just click anywhere in the document without changing anything.
this becomes expensive and slow if I'm dealing with a, say, 200 pages document.
I've been reading the official documentation for a while now but I can't figure this out. Would appreciate any indication

Adding new line in the cursor position in QTextEdit

I want to add new line in the given cursor position in QTextEdit.
I tried what's below.
Here new line is added to the end:
self.textEdit.moveCursor(QTextCursor.PreviousWord)
self.textEdit.moveCursor(QTextCursor.PreviousWord)
self.textEdit.append()
This has no effects at all:
self.textEdit.moveCursor(QTextCursor.PreviousWord)
self.textEdit.moveCursor(QTextCursor.PreviousWord)
self.textEdit.insertHtml('<br>')
Calling setHtml or insertHtml with no actual content (text, resource, table, etc) will usually be ignored.
In this specific case, it's enough to add a blank space before or after the break:
self.textEdit.insertHtml('<br/> ')
Using append() will not work for a given position of the cursor, as the documentation explains:
Appends a new paragraph with text to the end of the text edit.
(emphasis mine)

Why are my charFormat styles only working on selections, and only those made in a specific direction?

I've been trying to be more explicit in my assignment of character formats for a text editor so that I can understand what I might be able to customize with my current skill range. While the basic copy-paste versions of my format methods worked pretty well, the version below keeps working and then not working in frustrating ways and need help figuring out what might be causing it.
The editor was originally intended to be a WYSIWYG editor styled via tags for documentation. Qt's confusing use of Html hasn't made that easy.
My basic flow is to extract a copy of the current format, check its current state, invert it, and reapply the format to the position or selection it was extracted from.
# textEdit is a QTextEdit with a loaded document.
# This function is one of several related pairs called by a switchboard.
# It's intent is to invert the italic state of the current position/selection.
def toggle_italic_text(textEdit):
# Get the cursor, and the format's state at its current selection/position.
cursor = textEdit.textCursor()
charFormat = cursor.charFormat()
currentState = charFormat.fontItalic()
# Invert the state within the format.
print(currentState)
charFormat.setFontItalic(not currentState)
print(charFormat.fontItalic())
# Reapply the format to the cursor's current selection/position.
cursor.mergeCharFormat(charFormat)
When I first implemented it, this worked find. Now, it only works on selections, and even then it seems to identify the wrong state depending which direction I make a selection. After experimenting with it, it appears that if I make a selection to the right, it inverts correctly. If I make a selection to the left, it doesn't.
When trying to assign it to a position without a selection, the printed state changes from False to True, which is desired, yet the effect doesn't apply as I type. If I run it repeatedly in place, it continues to change from False to True, meaning the change is being lost.
The function is being called consistently and running through completely. The stored state of the charFormat copy does change.
Why has this pattern stopped working? Am I using charFormats wrong? Why does the direction of selection change the results?
As far as what changed on my end, I had been getting lost in my styling efforts after needing to apply styles through QFonts, QCharFormats, QPalette, and CSS stylesheets (and doc.defaultStylesheet) targeting both widgets and html tags. I desperately wanted my styles to be controlled through one approach, but couldn't figure out the hierarchy or find an approach that applied widely enough. In the end, I stripped out everything except for the stylesheet assigned to the window.
If there's no issue with the code itself, I'm really hoping for hints at what might be disrupting things. It took me awhile to get used to the idea that cursors and formats are copies meant to be changed and reapplied, while the document and its blocks are the real structure.
The important thing that must be considered about QTextCursor.charFormat() is this:
Returns the format of the character immediately before the cursor position().
So, not only this doesn't work very well with selections that include multiple character formats, but you also have to consider the cursor position, which might change in a selection: it could be at the beginning (so it would return the format of the character before the selection), or at the end (returning the format of the last character in the selection).
If you want to invert the state based on the current cursor position (if at the beginning, use the first character, if at the end, use the last), then you can use the following:
def toggle_italic_text(self):
cursor = self.textEdit.textCursor()
if not cursor.hasSelection():
charFormat = cursor.charFormat()
charFormat.setFontItalic(not charFormat.fontItalic())
cursor.setCharFormat(charFormat)
# in this case, the cursor has to be applied to the textEdit to ensure
# that the following typed characters use the new format
self.textEdit.setTextCursor(cursor)
return
start = cursor.selectionStart()
end = cursor.selectionEnd()
newCursor = QtGui.QTextCursor(self.textEdit.document())
newCursor.setPosition(start)
if cursor.position() == start:
cursor.setPosition(start + 1)
charFormat = cursor.charFormat()
charFormat.setFontItalic(not charFormat.fontItalic())
newCursor.setPosition(end, cursor.KeepAnchor)
newCursor.mergeCharFormat(charFormat)
If you want to invert all states in the selection, you need to cycle through all characters.
While you could just change the char format for each character, that wouldn't be a very good thing for very large selections, so the solution is to apply the italic only when the char format actually changes from the previous state, and when at the end of the selection.
def toggle_italic_text(self):
# ...
start = cursor.selectionStart()
end = cursor.selectionEnd()
newCursor = QtGui.QTextCursor(self.textEdit.document())
newCursor.setPosition(start)
cursor.setPosition(start)
prevState = cursor.charFormat().fontItalic()
while cursor.position() < end:
cursor.movePosition(cursor.Right)
charFormat = cursor.charFormat()
if charFormat.fontItalic() != prevState or cursor.position() >= end:
newPos = cursor.position()
if cursor.position() < end:
newPos -= 1
newCursor.setPosition(newPos, cursor.KeepAnchor)
charFormat.setFontItalic(not prevState)
newCursor.mergeCharFormat(charFormat)
prevState = not prevState
newCursor.setPosition(cursor.position() - 1)

Pyqt: Get text under cursor

How can I get the text under the cursor? So if I hover over it and the word was "hi" I could read it? I think I need to do something with QTextCursor.WordUnderCursor but I am not really sure what. Any help?
This is what I am trying to work with right now:
textCursor = text.cursorForPosition(event.pos());
textCursor.select(QTextCursor.WordUnderCursor);
text.setTextCursor(textCursor);
word = textCursor.selectedText();
I have it selecting the text right now just so I can see it.
Edit 2:
What I am really trying to do is display a tooltip over certain words in the text.
Unfortunately, I can't test this at the moment, so this is a best guess at what you need. This is based on some code I wrote that had a textfield that showed errors in a tooltip as you typed, but should work.
You've already got code to select the word under the hover over, you just need the tooltip in the right spot.
textCursor = text.cursorForPosition(event.pos())
textCursor.select(QTextCursor.WordUnderCursor)
text.setTextCursor(textCursor)
word = textCursor.selectedText()
if meetsSomeCondition(word):
toolTipText = toolTipFromWord(word)
# Put the hover over in an easy to read spot
pos = text.cursorRect(text.textCursor()).bottomRight()
# The pos could also be set to event.pos() if you want it directly under the mouse
pos = text.mapToGlobal(pos)
QtGui.QToolTip.showText(pos,toolTipText)
I've left meetsSomeCondition() and toolTipFromWord() up to you to fill in as you don't describe those, but they are pretty descriptive in what needs to go there.
Regarding your comment on doing it without selecting the word, the easiest way to do this is to cache the cursor before you select a new one and then set it back. You can do this by calling QTextEdit.textCursor() and then setting it like you did previously.
Like so:
oldCur = text.textCursor()
textCursor.select(QTextCursor.WordUnderCursor) # line from above
text.setTextCursor(textCursor) # line from above
word = textCursor.selectedText() # line from above
text.setTextCursor(oldCur)
# if condition as above

Select text of textEdit object with QTextCursor, QTextEdit

I have a textEdit field and I want to process some selected text within this field (but not the format of it).
So far, I connect the button with:
QtCore.QObject.connect(self.ui.mytext_button,QtCore.SIGNAL("clicked()"), self.mytext)
The method:
def mytext(s):
return s.upper()
But how do I tell Python that s is the selected text? I know that is something with selectionStart(), selectionEnd(). And how to change it to what mytext returns? I think is something with insertText(), but here I am also lost at the details.
Answering my own question. Posting here for fellow Python noobs:
Get the selected text:
cursor = self.ui.editor_window.textCursor()
textSelected = cursor.selectedText()
insert back the text into your editor.
self.ui.editor_window.append(s)
There are also alternatives to append(), for inserting the text into the original text.
So, to put a selected text into uppercase:
def mytext(self):
cursor = self.ui.editor_window.textCursor()
textSelected = cursor.selectedText()
s = textSelected.upper()
self.ui.editor_window.append(s)

Categories

Resources