Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Changing "CodeEditor" example code.
QtWS25 Last Chance

Changing "CodeEditor" example code.

Scheduled Pinned Locked Moved General and Desktop
c++qtwidgetsqtextedit
6 Posts 3 Posters 493 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Khamza
    wrote on 17 Dec 2024, 17:32 last edited by Khamza
    #1

    There is example from code editor.
    I want to draw both numbers and text from my CodeEditor::paintEvent() without calling QTextEdit::paintEvent() from it because it will draw text twice. Also i don't want to use additional LineNumberArea class.
    The problem is that i can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent().
    How can i do that?
    Or should i use another approach?
    P.S I use QTextEdit instead of QPlainTextEdit because of rich text support.

    J I 2 Replies Last reply 17 Dec 2024, 18:24
    0
    • K Khamza
      17 Dec 2024, 17:32

      There is example from code editor.
      I want to draw both numbers and text from my CodeEditor::paintEvent() without calling QTextEdit::paintEvent() from it because it will draw text twice. Also i don't want to use additional LineNumberArea class.
      The problem is that i can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent().
      How can i do that?
      Or should i use another approach?
      P.S I use QTextEdit instead of QPlainTextEdit because of rich text support.

      J Offline
      J Offline
      JonB
      wrote on 17 Dec 2024, 18:24 last edited by
      #2

      @Khamza said in Changing "CodeEditor" example code.:

      from my CodeEditor::paintEvent() without calling QTextEdit::paintEvent() from it because it will draw text twice.

      Why would anything draw twice. If you call the base paintEvent() from a derived class don't have the overrider paint stuff the base is doing.

      can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent()

      That does not sound like something you should want or need to do.

      If you have a working example why do you want to change it with things like "Also i don't want to use additional LineNumberArea class."? Aren't you overcomplicating?

      K 1 Reply Last reply 17 Dec 2024, 18:37
      1
      • J JonB
        17 Dec 2024, 18:24

        @Khamza said in Changing "CodeEditor" example code.:

        from my CodeEditor::paintEvent() without calling QTextEdit::paintEvent() from it because it will draw text twice.

        Why would anything draw twice. If you call the base paintEvent() from a derived class don't have the overrider paint stuff the base is doing.

        can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent()

        That does not sound like something you should want or need to do.

        If you have a working example why do you want to change it with things like "Also i don't want to use additional LineNumberArea class."? Aren't you overcomplicating?

        K Offline
        K Offline
        Khamza
        wrote on 17 Dec 2024, 18:37 last edited by
        #3

        @JonB Thank you for your reply.
        I want to use my own paintEvent because additionally i want to draw lines between strings as here:
        Screenshot_20241209_150710.png
        So i thought it would be much easier to maintain code in future with this approach and to draw all three parts(line numbers, strings, lines between) in one place. Also i don't need some extra functionality for my line numbers.
        And if i use two classes i have to draw in two functions: one for line numbers and other for "underlines".
        Despite all the above you think that using two separate classes is good approach and not overkill for my case?

        Thank you!

        1 Reply Last reply
        0
        • K Khamza
          17 Dec 2024, 17:32

          There is example from code editor.
          I want to draw both numbers and text from my CodeEditor::paintEvent() without calling QTextEdit::paintEvent() from it because it will draw text twice. Also i don't want to use additional LineNumberArea class.
          The problem is that i can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent().
          How can i do that?
          Or should i use another approach?
          P.S I use QTextEdit instead of QPlainTextEdit because of rich text support.

          I Offline
          I Offline
          IgKh
          wrote on 18 Dec 2024, 14:35 last edited by
          #4

          @Khamza said in Changing "CodeEditor" example code.:

          The problem is that i can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent().

          The data structure backing QTextEdit (and QPlainTextEdit) isn't a simple QString, it is a QTextDocument. Logically, a text document is a collection of text blocks (with associated formats); the blocks are also arranged in various rich text structures like frames, tables, lists etc. Make sure you understand the relevant documentation.

          When you call convenience methods like QTextEdit::insertPlainText, they just use the text cursor interface under the hood to create the requisite elements in the editor's backing QTextDocument. So if you want programmatic access to the editor's text, you need to get the document with QTextEdit::document and iterate over it using whatever strategy is appropriate for your needs.

          @Khamza said in Changing "CodeEditor" example code.:

          I want to use my own paintEvent because additionally i want to draw lines between strings as here:

          You can draw extra stuff directly on the editor in its' paintEvent for sure if that's what you feel is easier for you to write and maintain. The Code Editor example uses a separate widget for the line number area as it is probably somewhat easier to reason about managing its' size and position by having it in the the scroll view's viewport margin area (and it being a sink for input events intersecting with it is probably the more expected UX) but it is absolutely not essential. You can take another approach to ensuring that there is sufficient space left, and draw the line numbers (and any other decorations) directly into that space.

          What I don't suggest doing is to try to draw the text itself yourself. If you change anything about the text positioning relative to how the default layout will do it things like selecting text by mouse, caret movements and scrolling will break. There are multiple things that you need to tell QTextEdit about where the text exactly is and how big is it for all the text interaction behavior to be correct. This is abstracted by the QAbstractTextDocumentLayout interface, and if you want custom text positioning the "correct" thing to do is to implement it. However it is rather hard to get right.

          What you really should do if you can is to use custom block and character formats to ensure that the default text layout will leave sufficient space (e.g look at the setLeftMargin, setBottomMargin etc methods of QTextBlockFormat). In your paintEvent override, first call the parent for it to draw the text, and then draw the horizontal lines, line numbers and everything else you'd like, using the default text document layout to give you the bounding rectangles of text blocks to guide you.

          K 1 Reply Last reply 18 Dec 2024, 17:51
          3
          • I IgKh
            18 Dec 2024, 14:35

            @Khamza said in Changing "CodeEditor" example code.:

            The problem is that i can't pass text from QTextEdit::insertPlainText() to my CodeEditor::paintEvent().

            The data structure backing QTextEdit (and QPlainTextEdit) isn't a simple QString, it is a QTextDocument. Logically, a text document is a collection of text blocks (with associated formats); the blocks are also arranged in various rich text structures like frames, tables, lists etc. Make sure you understand the relevant documentation.

            When you call convenience methods like QTextEdit::insertPlainText, they just use the text cursor interface under the hood to create the requisite elements in the editor's backing QTextDocument. So if you want programmatic access to the editor's text, you need to get the document with QTextEdit::document and iterate over it using whatever strategy is appropriate for your needs.

            @Khamza said in Changing "CodeEditor" example code.:

            I want to use my own paintEvent because additionally i want to draw lines between strings as here:

            You can draw extra stuff directly on the editor in its' paintEvent for sure if that's what you feel is easier for you to write and maintain. The Code Editor example uses a separate widget for the line number area as it is probably somewhat easier to reason about managing its' size and position by having it in the the scroll view's viewport margin area (and it being a sink for input events intersecting with it is probably the more expected UX) but it is absolutely not essential. You can take another approach to ensuring that there is sufficient space left, and draw the line numbers (and any other decorations) directly into that space.

            What I don't suggest doing is to try to draw the text itself yourself. If you change anything about the text positioning relative to how the default layout will do it things like selecting text by mouse, caret movements and scrolling will break. There are multiple things that you need to tell QTextEdit about where the text exactly is and how big is it for all the text interaction behavior to be correct. This is abstracted by the QAbstractTextDocumentLayout interface, and if you want custom text positioning the "correct" thing to do is to implement it. However it is rather hard to get right.

            What you really should do if you can is to use custom block and character formats to ensure that the default text layout will leave sufficient space (e.g look at the setLeftMargin, setBottomMargin etc methods of QTextBlockFormat). In your paintEvent override, first call the parent for it to draw the text, and then draw the horizontal lines, line numbers and everything else you'd like, using the default text document layout to give you the bounding rectangles of text blocks to guide you.

            K Offline
            K Offline
            Khamza
            wrote on 18 Dec 2024, 17:51 last edited by Khamza
            #5

            Thank you for your response.
            So finally i used only one class and thy to draw everything in it. And i came to this paintEvent() which looks better and i think much more easy to understand

            void PasswordShowArea::paintEvent(QPaintEvent *event)
            {
                QTextEdit::paintEvent(event);
                QPainter painter(viewport());
            
                fillLineNumberArea(&painter);
            
                QTextDocument *doc = document();
                QAbstractTextDocumentLayout *lay = doc->documentLayout();
            
                // custom firstVisibleBlock() works fine.
                for (QTextBlock block = firstVisibleBlock(); block.isValid() && block.isVisible(); block = block.next()) {
            
                    painter.drawText(0, cursorRect(QTextCursor(block)).y(), 40, lay->blockBoundingRect(block).height()
                                     , Qt::AlignRight, QString::number(block.blockNumber() + 1));
            
                    int pointBetweenTwoStrings = lay->blockBoundingRect(block).top()
                            + lay->blockBoundingRect(block).height()
                            + block.blockFormat().lineHeight() / 2;
            
                    painter.drawLine(0, pointBetweenTwoStrings,
                                     event->rect().width(), pointBetweenTwoStrings);
                }
            }
            

            But there are some bugs which appear as i think because of scroll.
            No scroll:
            Screenshot_20241218_204912.png
            After some scroll:
            Screenshot_20241218_205138.png
            Screenshot_20241218_205831.png
            How do you think this problem can be solved? I really want to use this approach.
            Thank you!

            I 1 Reply Last reply 21 Dec 2024, 14:07
            0
            • K Khamza marked this topic as a regular topic on 19 Dec 2024, 19:49
            • K Khamza
              18 Dec 2024, 17:51

              Thank you for your response.
              So finally i used only one class and thy to draw everything in it. And i came to this paintEvent() which looks better and i think much more easy to understand

              void PasswordShowArea::paintEvent(QPaintEvent *event)
              {
                  QTextEdit::paintEvent(event);
                  QPainter painter(viewport());
              
                  fillLineNumberArea(&painter);
              
                  QTextDocument *doc = document();
                  QAbstractTextDocumentLayout *lay = doc->documentLayout();
              
                  // custom firstVisibleBlock() works fine.
                  for (QTextBlock block = firstVisibleBlock(); block.isValid() && block.isVisible(); block = block.next()) {
              
                      painter.drawText(0, cursorRect(QTextCursor(block)).y(), 40, lay->blockBoundingRect(block).height()
                                       , Qt::AlignRight, QString::number(block.blockNumber() + 1));
              
                      int pointBetweenTwoStrings = lay->blockBoundingRect(block).top()
                              + lay->blockBoundingRect(block).height()
                              + block.blockFormat().lineHeight() / 2;
              
                      painter.drawLine(0, pointBetweenTwoStrings,
                                       event->rect().width(), pointBetweenTwoStrings);
                  }
              }
              

              But there are some bugs which appear as i think because of scroll.
              No scroll:
              Screenshot_20241218_204912.png
              After some scroll:
              Screenshot_20241218_205138.png
              Screenshot_20241218_205831.png
              How do you think this problem can be solved? I really want to use this approach.
              Thank you!

              I Offline
              I Offline
              IgKh
              wrote on 21 Dec 2024, 14:07 last edited by
              #6

              @Khamza It is quite hard to tell. The piece of code you pasted has several issues unfortunately, and it would very hard to say what the exact cause it without the whole thing to reproduce.

              I'll say that the most pressing problem in the code is that you are using values that are in document coordinates (which is what the rectangle that QAbstractTextDocumentLayout::blockBoundingRect returns is in) to calculate parameters for a QPainter which works in viewport coordinates. These are not the same, especially when there are scroll bars shown, and in my experience the main cause of issues around scrolling.

              That said, it wouldn't explain the text itself just disappearing when scrolling back up; I'd expect it to just be garbled. First try to comment out your paintEvent to see if text is drawn correctly at the expected positions when scrolling back and forth - perhaps something in the formats isn't right. Otherwise, please post a complete yet minimal project that reproduces the problems you see.

              1 Reply Last reply
              1

              5/6

              18 Dec 2024, 17:51

              • Login

              • Login or register to search.
              5 out of 6
              • First post
                5/6
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved