PyQt5 - QTextBrowser клик по тексту меняет шрифт - PullRequest
2 голосов
/ 26 февраля 2020

У меня странный вопрос, я создаю GUI для чат-бота, и я выбрал PyQt5 Designer для этого. Все работало отлично, но теперь я реализовал несколько гиперссылок и понял, что когда я щелкаю строку с другим шрифтом в QTextBrowser, все ответы чат-бота меняются на этот шрифт. Так, например, если я нажму на ссылку, каждый отдельный ответ после этого будет гиперссылкой.

enter image description here

Фрагменты кода:

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_())

Любая помощь будет принята с благодарностью. PS Если бы я щелкнул по вводу пользователя (красным шрифтом), то и все последующие ответы чат-бота тоже стали бы красными. Единственное найденное мной половинное решение - это использование QTextCursor.Start, но оно прокручивалось вверх после каждого вопроса.

1 Ответ

2 голосов
/ 26 февраля 2020

Проблема в том, что когда вы нажимаете на ссылку, этот формат установлен как текущий формат, поэтому при добавлении текста будет использоваться этот формат, возможное решение состоит в том, чтобы сбросить формат до значения, которое было до нажатия ссылки (у меня есть нашли время, чтобы улучшить свой пример с помощью макета).

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_())
...