在 PyQt 中将鼠标悬停在 link 上时更改文本颜色

Change Text color when hovered over a link in PyQt

我试图在 QLabel 中将鼠标悬停在 link 上时更改文本的颜色。我无法使用PyQt提供的标签来实现,所以我尝试通过继承QLabel来创建自定义标签。

这是我试过的代码,但这不能正常工作:


from PyQt5 import QtGui, QtCore, QtWidgets
import sys


class LinkLabel(QtWidgets.QLabel):

    def __init__(self, link=""):
        super(LinkLabel, self).__init__()

        self.setText('<a href="http://whosebug.com/" style="color: black; font: 14px; text-decoration: None;">'
                                 'Whosebug</a>')

        self.setFixedSize(100, 50)
        # self.linkHovered.connect(lambda : print("Hovered"))
        self.linkActivated.connect(self.reDirect)
        #self.setMouseTracking(True)

    def reDirect(self, linkStr):
        QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))

    def mouseMoveEvent(self, event):
        print(self.fontMetrics().boundingRect("Whosebug"), event.pos())
        if self.fontMetrics().boundingRect("Whosebug").contains(event.pos()):
            print("Hovered")
            self.setText('<a href="http://whosebug.com/" style="color: blue; font: 14px; text-decoration: None;">'
                      'Whosebug</a>')

        else:
            self.setText('<a href="http://whosebug.com/" style="color: black; font: 14px; text-decoration: None;">'
                         'Whosebug</a>')

        super(LinkLabel, self).mouseMoveEvent(event)

    # def enterEvent(self, event):
    #     print("YES", self.fontMetrics().boundingRect(self.text()))
    #     if self.fontMetrics().boundingRect(self.text()).contains(event.pos()):
    #         print("Hovered")
    #         self.setText('<a href="http://whosebug.com/" style="color: blue; font: 14px;">'
    #                   'SignUp</a>')
    #         # self.fontMetrics().tightBoundingRect()
    #     super(LinkLabel, self).enterEvent(event)
    #
    # def leaveEvent(self, event):
    #     if not self.fontMetrics().boundingRect(self.text()).contains():
    #         self.setText('<a href="http://whosebug.com/" style="color: black; font: 14px;">'
    #                      'SignUp</a>')
    #
    #     super(LinkLabel, self).leaveEvent(event)


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.layout().addWidget(LinkLabel())


def main():
    app = QtWidgets.QApplication(sys.argv)
    win =MainWindow()
    win.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

我试过 QLabel.linkHovered.connect() 但问题是一旦悬停它就会改变颜色并且不会重置回原来的颜色。评论部分都是我试过的。

它不能正常工作,因为标签居中,而你对 boundingRect() 的调用显然不是:

Returns the rectangle that is covered by ink if character ch were to be drawn at the origin of the coordinate system.

此外,您正在使用更大的字体,而 fontMetrics 对此一无所知,因为它基于小部件的 font()

解决方案是使用正确的 boundingRect() 实现,并根据您要使用的字体构造字体指标:

    def checkHover(self, pos=None):
        if pos is None:
            pos = self.mapFromGlobal(QtGui.QCursor.pos())
        font = self.font()
        font.setPixelSize(14)
        fm = QtGui.QFontMetrics(font)
        textRect = fm.boundingRect(self.rect(), self.alignment(), "Whosebug")
        self.setText('''
            <a href="{link}" style="color: {color}; font: 14px; text-decoration: None;">
            {alias}</a>'''.format(
                link='https://whosebug.com', 
                alias='Whosebug', 
                color='blue' if pos in textRect else 'black', 
            ))

    def enterEvent(self, event):
        self.checkHover()
        super(LinkLabel, self).enterEvent(event)

    def mouseMoveEvent(self, event):
        self.checkHover(event.pos())
        super(LinkLabel, self).mouseMoveEvent(event)

    def leaveEvent(self, event):
        self.checkHover()
        super(LinkLabel, self).leaveEvent(event)

请注意,我使用 setPixelSize() 是因为您以像素为单位设置字体大小,而您最好使用点代替,因为它们与设备无关(这是字体渲染的首选做法)。