Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Change color of part of the text in a QListWidgetItem
Forum Updated to NodeBB v4.3 + New Features

Change color of part of the text in a QListWidgetItem

Scheduled Pinned Locked Moved Solved Qt for Python
8 Posts 3 Posters 1.9k Views 2 Watching
  • 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
    Kekz
    wrote on last edited by Kekz
    #1

    Hello,

    I have the following scenario:
    I receive text data from an application, which uses ASCII control characters to change the color of the text (intended for terminals). I want to display this text in different widgets, while also keeping the coloring.
    I have a working setup for this using a QTextEdit widget, where I can simply set the font color whenever I encounter an ASCII control character before adding my actual text, which works as expected:

    tokens = gdb_output.split(b"\x1b[")
    ### ...loop through tokens...
    start = token[:3]
    # https://stackoverflow.com/a/33206814
    if start == b"30m":
        self.setTextColor(Qt.GlobalColor.black)
        # Remove the control character from the text and add it to the QTextEdit
        self.insertPlainText(token.strip(start).decode())
    

    Now I want to replicate the same using a QListWidget, since the text data I receive here are split into lines which I want to be able to interact with.
    Is there a way to do this with the QListWidgetItems? The advantage of the QTextEdit was that I can set the text color, and then all the text I insert afterwards will have these changes.
    The only option I see currently is using HTML, however it seems to me extremely difficult to translate the control characters into HTML.
    Alternatively, is there a better widget for my use case? I would want to be able to interact with each line of text individually (e.g. be able to right click on it) while also being able to change the text color like in a QTextEdit.

    The answer to this thread seems to be unavailable unfortunately.

    Thank you for your time.

    JonBJ 1 Reply Last reply
    1
    • SGaistS SGaist

      Hi,

      The original suggestion for a QStyledItemDelegate is the correct one.

      See this Stack Overflow answer that provides an example of html rendering delegate. It uses QTextDocument which is also used by QTextEdit.

      K Offline
      K Offline
      Kekz
      wrote on last edited by Kekz
      #8

      @SGaist
      Seems to work well enough, although I share the sentiment in the SO post that this seems a bit hacky for such an important functionality.
      There are many "solutions" provided in the post, I ended up using this answer, which worked for PySide6 after adapting some imports.

      Thank you both for your time :)

      Adapted solution (in case linked post gets lost)

      from PySide6.QtCore import QRectF, QSize
      from PySide6.QtGui import QTextDocument, QAbstractTextDocumentLayout
      from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QStyle
      
      
      # https://stackoverflow.com/a/66091713
      class HTMLDelegate(QStyledItemDelegate):
          def __init__(self):
              super().__init__()
              # probably better not to create new QTextDocuments every ms
              self.doc = QTextDocument()
      
          def paint(self, painter, option, index):
              options = QStyleOptionViewItem(option)
              self.initStyleOption(options, index)
              painter.save()
              self.doc.setTextWidth(options.rect.width())
              self.doc.setHtml(options.text)
              self.doc.setDefaultFont(options.font)
              options.text = ''
              options.widget.style().drawControl(QStyle.ControlElement.CE_ItemViewItem, options, painter)
              painter.translate(options.rect.left(), options.rect.top())
              clip = QRectF(0, 0, options.rect.width(), options.rect.height())
              painter.setClipRect(clip)
              ctx = QAbstractTextDocumentLayout.PaintContext()
              ctx.clip = clip
              self.doc.documentLayout().draw(painter, ctx)
              painter.restore()
      
          def sizeHint(self, option, index):
              options = QStyleOptionViewItem(option)
              self.initStyleOption(option, index)
              self.doc.setHtml(option.text)
              self.doc.setTextWidth(option.rect.width())
              return QSize(self.doc.idealWidth(), self.doc.size().height())
      
      1 Reply Last reply
      1
      • K Kekz

        Hello,

        I have the following scenario:
        I receive text data from an application, which uses ASCII control characters to change the color of the text (intended for terminals). I want to display this text in different widgets, while also keeping the coloring.
        I have a working setup for this using a QTextEdit widget, where I can simply set the font color whenever I encounter an ASCII control character before adding my actual text, which works as expected:

        tokens = gdb_output.split(b"\x1b[")
        ### ...loop through tokens...
        start = token[:3]
        # https://stackoverflow.com/a/33206814
        if start == b"30m":
            self.setTextColor(Qt.GlobalColor.black)
            # Remove the control character from the text and add it to the QTextEdit
            self.insertPlainText(token.strip(start).decode())
        

        Now I want to replicate the same using a QListWidget, since the text data I receive here are split into lines which I want to be able to interact with.
        Is there a way to do this with the QListWidgetItems? The advantage of the QTextEdit was that I can set the text color, and then all the text I insert afterwards will have these changes.
        The only option I see currently is using HTML, however it seems to me extremely difficult to translate the control characters into HTML.
        Alternatively, is there a better widget for my use case? I would want to be able to interact with each line of text individually (e.g. be able to right click on it) while also being able to change the text color like in a QTextEdit.

        The answer to this thread seems to be unavailable unfortunately.

        Thank you for your time.

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by
        #2

        @Kekz
        You will need a QStyledItemDelegate with whatever functionality. Yes it does not have the interface of QTextEdit. (You could put a QTextEdit in as a list item, but I think you want to deal with each line separately.) I would follow the approach of the SO post you linked to with HTML. I don't see that it is "extremely difficult to translate the control characters into HTML".

        K 2 Replies Last reply
        0
        • JonBJ JonB

          @Kekz
          You will need a QStyledItemDelegate with whatever functionality. Yes it does not have the interface of QTextEdit. (You could put a QTextEdit in as a list item, but I think you want to deal with each line separately.) I would follow the approach of the SO post you linked to with HTML. I don't see that it is "extremely difficult to translate the control characters into HTML".

          K Offline
          K Offline
          Kekz
          wrote on last edited by Kekz
          #3

          @JonB said in Change color of part of the text in a QListWidgetItem:

          You could put a QTextEdit in as a list item, but I think you want to deal with each line separately.).

          But making a QTextEdit for each line should work (one line would correspond to one list item)?
          And inside that item I could use the QTextEdit functionalities like in my example.
          Thanks for the idea, I will try that.

          @JonB said in Change color of part of the text in a QListWidgetItem:

          I don't see that it is "extremely difficult to translate the control characters into HTML"

          E.g. the following text:
          "These are a couple of different words as an example"
          Making words 1-5 red, 6-10 blue and words 3-7 underlined, is simple with ASCII control characters but more complicated when translating to HTML, as the tags would be nested and I can only close the last opened tag, i.e. when trying to close the red tag at word 6, it would instead close the last opened "underline" tag from word 3. I would always have to close all tags, and only reopen the ones I didn't want to close.

          JonBJ 1 Reply Last reply
          0
          • K Kekz

            @JonB said in Change color of part of the text in a QListWidgetItem:

            You could put a QTextEdit in as a list item, but I think you want to deal with each line separately.).

            But making a QTextEdit for each line should work (one line would correspond to one list item)?
            And inside that item I could use the QTextEdit functionalities like in my example.
            Thanks for the idea, I will try that.

            @JonB said in Change color of part of the text in a QListWidgetItem:

            I don't see that it is "extremely difficult to translate the control characters into HTML"

            E.g. the following text:
            "These are a couple of different words as an example"
            Making words 1-5 red, 6-10 blue and words 3-7 underlined, is simple with ASCII control characters but more complicated when translating to HTML, as the tags would be nested and I can only close the last opened tag, i.e. when trying to close the red tag at word 6, it would instead close the last opened "underline" tag from word 3. I would always have to close all tags, and only reopen the ones I didn't want to close.

            JonBJ Online
            JonBJ Online
            JonB
            wrote on last edited by JonB
            #4

            @Kekz said in Change color of part of the text in a QListWidgetItem:

            Making words 1-5 red, 6-10 blue and words 3-7 underlined, is simple with ASCII control characters but more complicated with HTML, as the tags would be nested and I can only close the last opened tag, i.e. when trying to close the red tag at word 6, it would instead close the last opened "underline" tag from word 3. I would always have to close all tags, and only reopen the ones I didn't want to close.

            Sorry, I just don't see what your issue is here. You do whatever opening/closing is necessary. Yes you would need to close and re-open the underlining at the color change boundary. Anyway it is what it is.

            Out of interest, with your original QTextEdit code try calling toHtml() to see what it has generated. It has managed to produce that HTML from the instructions you gave it.

            1 Reply Last reply
            0
            • JonBJ JonB

              @Kekz
              You will need a QStyledItemDelegate with whatever functionality. Yes it does not have the interface of QTextEdit. (You could put a QTextEdit in as a list item, but I think you want to deal with each line separately.) I would follow the approach of the SO post you linked to with HTML. I don't see that it is "extremely difficult to translate the control characters into HTML".

              K Offline
              K Offline
              Kekz
              wrote on last edited by Kekz
              #5

              @JonB said in Change color of part of the text in a QListWidgetItem:

              You could put a QTextEdit in as a list item

              How would that actually be possible?
              The way I see it, I can only add QListWidgetItems to the QListWidget, where the items hold simple text.
              How do I add a widget as a list item?

              @JonB said in Change color of part of the text in a QListWidgetItem:

              Out of interest, with your original QTextEdit code try calling toHtml() to see what it has generated. It has managed to produce that HTML from the instructions you gave it.

              That is true, unfortunately I don't have such a working example right now. But it gives the idea to use QTextEdit as my parser ^^

              JonBJ 1 Reply Last reply
              0
              • K Kekz

                @JonB said in Change color of part of the text in a QListWidgetItem:

                You could put a QTextEdit in as a list item

                How would that actually be possible?
                The way I see it, I can only add QListWidgetItems to the QListWidget, where the items hold simple text.
                How do I add a widget as a list item?

                @JonB said in Change color of part of the text in a QListWidgetItem:

                Out of interest, with your original QTextEdit code try calling toHtml() to see what it has generated. It has managed to produce that HTML from the instructions you gave it.

                That is true, unfortunately I don't have such a working example right now. But it gives the idea to use QTextEdit as my parser ^^

                JonBJ Online
                JonBJ Online
                JonB
                wrote on last edited by
                #6

                @Kekz
                I really just meant "QTextEdit in a list of widgets", rather than necessarily a QListWidget. For example, a QListView at a pinch you can use setIndexWidget() to place an actual widget (should work from QListWidget too, but just use a QListView). You're not supposed to have too many widgets in a list, but you could try it here maybe.

                SGaistS 1 Reply Last reply
                0
                • JonBJ JonB

                  @Kekz
                  I really just meant "QTextEdit in a list of widgets", rather than necessarily a QListWidget. For example, a QListView at a pinch you can use setIndexWidget() to place an actual widget (should work from QListWidget too, but just use a QListView). You're not supposed to have too many widgets in a list, but you could try it here maybe.

                  SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #7

                  Hi,

                  The original suggestion for a QStyledItemDelegate is the correct one.

                  See this Stack Overflow answer that provides an example of html rendering delegate. It uses QTextDocument which is also used by QTextEdit.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  K 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Hi,

                    The original suggestion for a QStyledItemDelegate is the correct one.

                    See this Stack Overflow answer that provides an example of html rendering delegate. It uses QTextDocument which is also used by QTextEdit.

                    K Offline
                    K Offline
                    Kekz
                    wrote on last edited by Kekz
                    #8

                    @SGaist
                    Seems to work well enough, although I share the sentiment in the SO post that this seems a bit hacky for such an important functionality.
                    There are many "solutions" provided in the post, I ended up using this answer, which worked for PySide6 after adapting some imports.

                    Thank you both for your time :)

                    Adapted solution (in case linked post gets lost)

                    from PySide6.QtCore import QRectF, QSize
                    from PySide6.QtGui import QTextDocument, QAbstractTextDocumentLayout
                    from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QStyle
                    
                    
                    # https://stackoverflow.com/a/66091713
                    class HTMLDelegate(QStyledItemDelegate):
                        def __init__(self):
                            super().__init__()
                            # probably better not to create new QTextDocuments every ms
                            self.doc = QTextDocument()
                    
                        def paint(self, painter, option, index):
                            options = QStyleOptionViewItem(option)
                            self.initStyleOption(options, index)
                            painter.save()
                            self.doc.setTextWidth(options.rect.width())
                            self.doc.setHtml(options.text)
                            self.doc.setDefaultFont(options.font)
                            options.text = ''
                            options.widget.style().drawControl(QStyle.ControlElement.CE_ItemViewItem, options, painter)
                            painter.translate(options.rect.left(), options.rect.top())
                            clip = QRectF(0, 0, options.rect.width(), options.rect.height())
                            painter.setClipRect(clip)
                            ctx = QAbstractTextDocumentLayout.PaintContext()
                            ctx.clip = clip
                            self.doc.documentLayout().draw(painter, ctx)
                            painter.restore()
                    
                        def sizeHint(self, option, index):
                            options = QStyleOptionViewItem(option)
                            self.initStyleOption(option, index)
                            self.doc.setHtml(option.text)
                            self.doc.setTextWidth(option.rect.width())
                            return QSize(self.doc.idealWidth(), self.doc.size().height())
                    
                    1 Reply Last reply
                    1
                    • K Kekz has marked this topic as solved on
                    • K Kekz has marked this topic as unsolved on
                    • K Kekz has marked this topic as solved on

                    • Login

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