Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved How can I do something when the user clicks on a particular span/frame/block/fragment/whatever of text in a QTextEdit?

    General and Desktop
    3
    10
    168
    Loading More Posts
    • 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.
    • I
      Inhahe last edited by

      I'm writing an IRC client, and I have message/channel windows update with lines like

      <from_nick> message

      and I want to be able to bring up a context menu when the user right clicks on a nick (like the "from_nick" part above) and to know what the nick they clicked on is. I've tried numerous things, can't figure it out.

      Thanks.

      1 Reply Last reply Reply Quote 0
      • Kent-Dorfman
        Kent-Dorfman last edited by Kent-Dorfman

        Well, since it is a text-edit field the widget sees what is in it is text, so if you are not satisifed with cut-n-paste text operations then you'd need to subclass the widget and get the mouse coordinates of the click in the widget, and then you would need to use the font metrics information to calculate the boundaries of each character and react accordingly. ps - this only seems possible if the font is monospaced.

        Or ditch text-edit and parse the incoming messages into separate widgets, the nickname containing one being a pushbutton.

        1 Reply Last reply Reply Quote 1
        • jeremy_k
          jeremy_k last edited by

          If using rich text is acceptable, there's QTextEdit::anchorAt(). Handle the context menu event, and use anchorAt to retrieve the anchor embedded in the nick text.

          Asking a question about code? http://eel.is/iso-c++/testcase/

          1 Reply Last reply Reply Quote 2
          • I
            Inhahe last edited by

            Thanks for the lead, @jeremy_k, though I'm having some trouble making it work...

            I tried two different ways of making an anchor, one with insertHtml, inserting something like '<a href="nick">nick</a>', and one with QTextFormat, setAnchorHref, and insertText... in both cases, the link extends to the end of the line, e.g. in my original example of

            <from_nick> message

            the whole 'from_nick> message' would be the link, instead of the link starting and ending with 'some_nick' like I want.

            I haven't posted my code because it's in PyQt and I don't know if that would annoy some people because this isn't the Qt for Python forum. I posted the question here, assuming that I'd be able to adapt any advice I get to PyQt, because I didn't get any response in the Qt for Python forum which I think is a less popular forum..

            1 Reply Last reply Reply Quote 0
            • jeremy_k
              jeremy_k last edited by

              import PyQt5.QtCore as QtCore
              import PyQt5.QtWidgets as QtWidgets
              
              class MyTextEdit(QtWidgets.QTextEdit):
                  def contextMenuEvent(self, event):
                      anchor = self.anchorAt(event.pos())
                      if len(anchor) > 0:
                          QtWidgets.QMessageBox.information(self, "Anchor Found", "The anchor {} was found".format(anchor))
              
              app = QtWidgets.QApplication([])
              textEdit = MyTextEdit()
              textEdit.setHtml('<a href="first">&lt;user1&gt;</a> first user<br><a href="second">&lt;second&gt;</a> second user')
              textEdit.show()
              app.exec()
              

              Asking a question about code? http://eel.is/iso-c++/testcase/

              1 Reply Last reply Reply Quote 0
              • I
                Inhahe last edited by

                here's my code:

                def addmsg(textedit, nick, message):
                  if config.show_timestamp:
                    obj_now = datetime.now()
                    textedit.insertPlainText(f"[{obj_now.hour: >2}:{obj_now.minute: >2}] ")
                  textedit.insertPlainText("<")
                  #textedit.insertHtml(f'<a href="{nick}">{nick}</a>') #doesn't work right, bug in qt
                  charFormat = QTextCharFormat()
                  charFormat.setAnchorHref(nick)
                  textedit.textCursor().insertText(nick, charFormat)
                  textedit.insertPlainText("> ")
                  colorify(textedit, message)
                  textedit.insertHtml("<br>")
                

                both the QTextCharFormat approach and the insertHtml approach (commented out in the above) result in the link extending all the way to the end of the line, which it seems it shouldn't. Just posting it in case you happen to have any insight; I expect I'll have to figure this out myself ;/

                jeremy_k 1 Reply Last reply Reply Quote 0
                • I
                  Inhahe last edited by

                  I verified that the problem isn't in my colorify function, I've temporarily replaced that with a simple insertPlainText:

                  def addmsg(textedit, nick, message):
                    if config.show_timestamp:
                      obj_now = datetime.now()
                      textedit.insertPlainText(f"[{obj_now.hour: >2}:{obj_now.minute: >2}] ")
                    textedit.insertPlainText("<")
                    textedit.insertHtml(f'<a href="{nick}">{nick}</a>') #doesn't work right, bug in qt
                    textedit.insertPlainText("> ")
                    textedit.insertPlainText(message.decode('utf-8'))
                    textedit.insertHtml("<br>")
                  
                  1 Reply Last reply Reply Quote 0
                  • I
                    Inhahe last edited by

                    @jeremy_k said in How can I do something when the user clicks on a particular span/frame/block/fragment/whatever of text in a QTextEdit?:

                    import PyQt5.QtCore as QtCore
                    import PyQt5.QtWidgets as QtWidgets

                    class MyTextEdit(QtWidgets.QTextEdit):
                    def contextMenuEvent(self, event):
                    anchor = self.anchorAt(event.pos())
                    if len(anchor) > 0:
                    QtWidgets.QMessageBox.information(self, "Anchor Found", "The anchor {} was found".format(anchor))

                    app = QtWidgets.QApplication([])
                    textEdit = MyTextEdit()
                    textEdit.setHtml('<a href="first"><user1></a> first user<br><a href="second"><second></a> second user')
                    textEdit.show()
                    app.exec()

                    Here's a minimal example that does the wrong thing:

                    import PyQt5.QtCore as QtCore
                    import PyQt5.QtWidgets as QtWidgets
                    
                    class MyTextEdit(QtWidgets.QTextEdit):
                        def contextMenuEvent(self, event):
                            anchor = self.anchorAt(event.pos())
                            if len(anchor) > 0:
                                QtWidgets.QMessageBox.information(self, "Anchor Found", "The anchor {} was found".format(anchor))
                    
                    app = QtWidgets.QApplication([])
                    textEdit = MyTextEdit()
                    textEdit.insertHtml('<a href="test1">test1</a>')
                    textEdit.insertPlainText("test2")
                    textEdit.show()
                    app.exec()
                    

                    both test1 and test2 in the textEdit window are underlined and in blue.

                    1 Reply Last reply Reply Quote 0
                    • I
                      Inhahe last edited by

                      I figured it out. Thanks for your help.

                      def addmsg(textedit, nick, message):
                        if config.show_timestamp:
                          obj_now = datetime.now()
                          textedit.insertPlainText(f"[{obj_now.hour: >2}:{obj_now.minute: >2}] ")
                        textedit.insertHtml(f'&lt;<a style="text-decoration: none; color: inherit" href="{nick}">{nick}</a>&gt; ')
                        colorify(textedit, message)
                        textedit.insertHtml("<br>")
                      
                      1 Reply Last reply Reply Quote 0
                      • jeremy_k
                        jeremy_k @Inhahe last edited by

                        @Inhahe said in How can I do something when the user clicks on a particular span/frame/block/fragment/whatever of text in a QTextEdit?:

                        here's my code:

                        def addmsg(textedit, nick, message):
                          if config.show_timestamp:
                            obj_now = datetime.now()
                            textedit.insertPlainText(f"[{obj_now.hour: >2}:{obj_now.minute: >2}] ")
                          textedit.insertPlainText("<")
                          #textedit.insertHtml(f'<a href="{nick}">{nick}</a>') #doesn't work right, bug in qt
                          charFormat = QTextCharFormat()
                          charFormat.setAnchorHref(nick)
                          textedit.textCursor().insertText(nick, charFormat)
                          textedit.insertPlainText("> ")
                          colorify(textedit, message)
                          textedit.insertHtml("<br>")
                        

                        both the QTextCharFormat approach and the insertHtml approach (commented out in the above) result in the link extending all the way to the end of the line, which it seems it shouldn't. Just posting it in case you happen to have any insight; I expect I'll have to figure this out myself ;/

                        Using textedit.insertHtml(f'<a href="{nick}">{nick}</a>&gt;') rather than adding > as plain text fixes the issue for me with Qt 5.15.2 and PyQt 5.15.3. I haven't tried using the QTextCharFormat method.

                        Asking a question about code? http://eel.is/iso-c++/testcase/

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post