1

I'm trying to draw a long cursor in Qt.

enter image description here

I already have a function to edit many lines of a QPlainTextEdit at the same time (<-> alt edition in Notepad++), and my current goal is to display the cursor.


---- old version -------

I wasn't the simplest way, but I planned on drawing the cursor in a QGraphicsScene on top of the QPlainTextEdit (could'nt think of another way). I had a QGraphicsView and Scene transparent on top of my QPlainTextEdit, the QPlainTextEdit is the one that catches the users's events. My current problem was that I didn't manage to scroll the QGraphicsScene.

I know it can work because of this old question : QGraphicsView inside QPlainTextEdit (scrollable widget) but they don't precise how they achieved that...

So at the moment I have my editor (a QPlainTextEdit)

class Editor(QPlainTextEdit):

    def __init__(self):
        super().__init__()

        self.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.setCenterOnScroll(True)
        
        # for the cursor
        self.graphicScene = QGraphicsScene()
        self.graphicScene.addText("Hello world")

        self.view = AltGraphicsView(self.graphicScene, self)
        self.view.show()

        self.horizontalScrollBar().valueChanged.connect(self.view.scrollH)
        self.verticalScrollBar().valueChanged.connect(self.view.scrollV)

and the AltGraphicsView is like this :

class AltGraphicsView(QGraphicsView):
    def __init__(self, scene, parent):
        super().__init__(scene, parent)
        self.parent = parent
        self.setSceneRect(parent.rect())

        # Transparent so that we see the text behind
        transparentBrush = QBrush()
        transparentBrush.setColor(QColor(255, 255, 255, 0))
        self.setBackgroundBrush(transparentBrush)
        self.viewport().setAutoFillBackground(False)

    # Functions to connect the scrolling ... doesn't work
    def scrollV(self, value):
        self.verticalScrollBar().setValue(value)
        self.viewport().scroll(0,-value)
        self.invalidateScene()

    def scrollH(self, value):
        self.horizontalScrollBar().setValue(value)
        self.scrollContentsBy(-value,0)
    
    # Do not catch anything -> "function-transparent"
    def dragEnterEvent(self, event):
        self.parent.dragEnterEvent(event)
        return True
    #...
    def wheelEvent(self, event):
        self.parent.wheelEvent(event)
        return True

When I do not set self.setSceneRect(parent.rect()), the view is the size of Hello world at the top-left of the editor, but the scrolling works (must debug, but works a bit). When I set it, the view has a correct size... but does not scroll with the editor.

I think there's a problem with the size of the QGraphicsScene, but when I tried giving it a larger size than the QGraphicsView with self.graphicScene.setSceneRect(0,0,10000,10000), nothing changed (no scroll).

Does somebody has an idea about how to solve this scrolling problem?


----- new version -----------

Following musicamante's advice, I'm looking into the paintEvent function of QPlainTextEdit. Trying to understand how to draw the cursor so that it remains at the same place when scrolling.

10
  • 1
    You should not try to use functions such as scroll() and even scrollContentsBy() on your own (the documentation of the latter also explicitly says that you should not use it to scroll programmatically). In theory, you should set the scene rect based on the extent of the scrollable area of the plain text edit, and also resize the view so that it fits the editor; in reality, embedding a QGraphicsView just to paint the cursor is completely inappropriate, other than an unnecessary complication. You should override paintEvent(), call the base implementation, and draw the cursor. Commented May 20 at 20:08
  • Further notes: your question begins with a request about drawing "a large cursor". If you just want to show a larger caret (the vertical line at the text cursor position when the editor is focused) QPlainTextEdit provides the setCursorWidth(), did you try it? If that's not what you want, are you trying to show a "block cursor" that includes the current character, similarly to some IDEs or terminals? In this case, this becomes an XY problem, which is asking the wrong question for the wrong problem. Commented May 21 at 2:25
  • 1
    Hello, no I don't want a thick cursor but a cursor on different lines at the same time. I add an image in the question. Commented May 21 at 8:16
  • Thank you for the recommendation! I'll try the paintEvent() way. Commented May 21 at 8:19
  • 1
    @Clem Be aware that there is the QScintilla module (available for PyQt as well) which is a full Qt port of the Scintilla library, specifically intended for advanced text editing, and already including such features among others (code folding, autocompletion, syntax highlighting...). Unfortunately, docs are a bit scarce, but since it's mostly based on Scintilla, that documentation may normally be used as well. Considering the difficulties of implementing such features, it's still better to struggle with the docs than trying to do it from scratch. Commented May 21 at 22:45

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.