PyQt5 - QTextBrowser click on text changes font

Alexandru Petrea :

I have a weird question, I am creating a GUI for a chatbot and I've chosen PyQt5 Designer to do so. Everything has been working perfectly but now I've implemented some hyperlinks and realized that when I click a line with different font in QTextBrowser, all the chatbot responses change to that font. So for example, if I click a link, every single answer after that will be hyperlinked.

enter image description here

Code snippets:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_mainWindow(object):
    def setupUi(self, mainWindow):
        mainWindow.setObjectName("mainWindow")
        mainWindow.resize(812, 577)
        self.centralwidget = QtWidgets.QWidget(mainWindow)
        self.centralwidget.setObjectName("centralwidget")

        #Browse Button
        self.browseButton = QtWidgets.QPushButton(self.centralwidget)
        self.browseButton.setGeometry(QtCore.QRect(690, 480, 101, 61))
        self.browseButton.setObjectName("browseButton")

        #TextBrowser (big window)
        self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser.setGeometry(QtCore.QRect(20, 20, 581, 471))
        self.textBrowser.setObjectName("textBrowser")
        self.textBrowser.setFontFamily("monospace")
        self.textBrowser.setFont(QtGui.QFont("monospace",11))
        self.textBrowser.setOpenExternalLinks(True)

        #Line Edit - small line for user input
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(20, 500, 581, 41))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit.returnPressed.connect(self.run)
        self.lineEdit.setPlaceholderText("Ask me anything...")

        #Anton's Avatar
        self.avatarLabel = QtWidgets.QLabel(self.centralwidget)
        self.avatarLabel.setGeometry(QtCore.QRect(610, 20, 191, 251))
        self.avatarLabel.setFrameShape(QtWidgets.QFrame.Box)
        self.avatarLabel.setText("")
        self.avatarLabel.setPixmap(QtGui.QPixmap("Anton.jpg"))
        self.avatarLabel.setObjectName("avatarLabel")

        #Send button and Yes/No Dialog
        self.buttonBox = QtWidgets.QDialogButtonBox(self.centralwidget)
        self.buttonBox.setGeometry(QtCore.QRect(400, 440, 193, 28))
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.sendButton = QtWidgets.QPushButton(self.centralwidget)
        self.sendButton.setGeometry(QtCore.QRect(610, 480, 71, 61))
        self.sendButton.setObjectName("sendButton")
        self.sendButton.clicked.connect(self.run)
        self.sendButton.clicked.connect(self.lineEdit.clear)

        self.buttonBox.raise_()
        self.browseButton.raise_()
        self.textBrowser.raise_()
        self.lineEdit.raise_()
        self.avatarLabel.raise_()
        self.sendButton.raise_()

        mainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(mainWindow)
        self.statusbar.setObjectName("statusbar")
        mainWindow.setStatusBar(self.statusbar)


        self.retranslateUi(mainWindow)
        self.lineEdit.returnPressed.connect(self.lineEdit.clear)
        self.sendButton.clicked.connect(self.lineEdit.copy)
        QtCore.QMetaObject.connectSlotsByName(mainWindow)

    def retranslateUi(self, mainWindow):
        _translate = QtCore.QCoreApplication.translate
        mainWindow.setWindowTitle(_translate("mainWindow", "Chatbot"))
        self.textBrowser.setHtml(_translate("mainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
        "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
        "p, li { white-space: pre-wrap; }\n"
        "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:7.8pt; font-weight:400; font-style:normal;\">\n"
        "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>"))
        self.sendButton.setText(_translate("mainWindow", "Send"))

    def gettext(self): # Get text from user input text line
        text = self.lineEdit.text()
        return text

    def answerr(self,text): # Print result to text browser
        self.textBrowser.append(str(text))

    def run(self):
    #get user input
        try:
            userInput = self.gettext()
            user = '<span style=\" color: #ff0000;\">%s</span>' % userInput
            self.answerr("> "+user)
        except (KeyboardInterrupt, EOFError) as e:
            answerr("Bye!")

        rec_video="https://www.youtube.com/watch?v=Z6MqOw2y744"
        self.textBrowser.append("\nYou can find a video with the instructions on the link below.")
        self.textBrowser.append(str("<a href=\""+rec_video+"\">'Youtube Link'</a>"))



if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = QtWidgets.QMainWindow()
    ui = Ui_mainWindow()
    ui.setupUi(mainWindow)
    mainWindow.show()


    sys.exit(app.exec_())

Any help would be greatly appreciated. P.S. If I would click the user input (red font) it would make all the upcoming chatbot responses red too. The only half-solution I have found was using QTextCursor.Start but that would scroll up after each question.

eyllanesc :

The problem is that when you click on the link that format is set as the current format so adding text will use that format, a possible solution is to reset the format to the value it had before the link is pressed (I have taken the time to improve your example using layout).

import sys

from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.textbrowser = QtWidgets.QTextBrowser(openExternalLinks=True)
        self.lineedit = QtWidgets.QLineEdit(
            placeholderText=self.tr("Ask me anything...")
        )
        self.sendbutton = QtWidgets.QPushButton(self.tr("Send"))
        self.browsebutton = QtWidgets.QPushButton()
        self.avatarlabel = QtWidgets.QLabel(
            frameShape=QtWidgets.QFrame.Box, pixmap=QtGui.QPixmap("Anton.jpg")
        )

        self.lineedit.setFixedHeight(40)
        self.avatarlabel.setFixedSize(190, 250)
        self.sendbutton.setFixedHeight(60)
        self.browsebutton.setFixedHeight(60)

        vlay_left = QtWidgets.QVBoxLayout()
        vlay_right = QtWidgets.QVBoxLayout()

        central_widget = QtWidgets.QWidget()
        central_widget.setContentsMargins(10, 10, 10, 10)
        self.setCentralWidget(central_widget)

        hlay = QtWidgets.QHBoxLayout(central_widget)
        hlay.addLayout(vlay_left)
        hlay.addLayout(vlay_right)

        vlay_left.addWidget(self.textbrowser)
        vlay_left.addWidget(self.lineedit)

        bottom_hlay = QtWidgets.QHBoxLayout()
        bottom_hlay.addWidget(self.sendbutton)
        bottom_hlay.addWidget(self.browsebutton)

        vlay_right.addWidget(self.avatarlabel)
        vlay_right.addStretch()
        vlay_right.addLayout(bottom_hlay)

        self.resize(640, 480)

        self._text_format = self.textbrowser.currentCharFormat()
        self.lineedit.returnPressed.connect(self.execute)
        self.sendbutton.clicked.connect(self.lineedit.copy)
        self.sendbutton.clicked.connect(self.execute)

        self.textbrowser.setFontFamily("monospace")
        self.textbrowser.setFont(QtGui.QFont("monospace", 11))

    @property
    def text_format(self):
        return self._text_format

    @text_format.setter
    def text_format(self, fmt):
        self._text_format = fmt
        self.reset_format()

    def reset_format(self):
        self.textbrowser.setCurrentCharFormat(self.text_format)

    @QtCore.pyqtSlot()
    def execute(self):
        self.reset_format()
        text = self.lineedit.text()
        user = '<span style=" color: #ff0000;">%s</span>' % text
        self.answer("> " + user)
        rec_video = "https://www.youtube.com/watch?v=Z6MqOw2y744"
        self.textbrowser.append(
            "\nYou can find a video with the instructions on the link below."
        )
        self.textbrowser.append('<a href="' + rec_video + "\">'Youtube Link'</a>")
        self.lineedit.clear()

    def answer(self, text):
        self.textbrowser.append(text)


if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=12462&siteId=1