tckraomuqnt
tckraomuqnt

Reputation: 492

How to fix hover effect for multi QFrame in PyQt5?

My intention is to make a Hover effect for multiple frames at a time. For Example, Below is my code, I have three frames. Two inner frames and one outer frame. If the mouse enters where ever, that is, either in an outer frame or in the inner frames, I need a hover effect for three frames, at a time.

import sys

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

class Dynamic_Widgets(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Dynamic Widget")
        self.lbl = QLabel("this is text")
        self.btn = QPushButton("Button")
        self.lbl_1 = QLabel("-----------")

        self.lbl_r = QLabel("My text ")
        self.btn_r = QPushButton("Button888888")
        self.lbl_1r = QLabel(('\u2261' * 60))

        my_font_1 = QFont("Arial", 10, QFont.Bold)
        my_font_1.setLetterSpacing(QFont.AbsoluteSpacing, -6)
        self.lbl_1r.setFont(my_font_1)

        self.vbox = QHBoxLayout()
        self.frame = QFrame()
        self.frame_right = QFrame()
        self.frame_all = QFrame()
        self.frame.setObjectName("ob_frame")
        self.frame_right.setObjectName("ob_frame_right")
        self.frame_all.setObjectName("ob_frame_all")
        self.frame.setProperty("type", "2")
        self.frame_right.setProperty("type", "2")
        self.frame_all.setProperty("type", "2")

        self.framebox = QVBoxLayout(self.frame)
        self.framebox_right = QVBoxLayout(self.frame_right)
        self.framebox_all = QHBoxLayout(self.frame_all)
        self.framebox_all.setContentsMargins(0, 0, 0, 0)

        self.framebox_all.setSpacing(0)
        self.framebox_all.addWidget(self.frame)
        self.framebox_all.addWidget(self.frame_right)
        self.vbox.addWidget(self.frame_all)
        self.setLayout(self.vbox)

        self.frame.setFixedSize(100, 100)
        self.frame_right.setFixedSize(100, 100)
        self.frame_all.setFixedSize(220, 120)

        self.frame.setStyleSheet(f"QFrame#ob_frame{{background-color: lightgreen;}}")
        self.frame_right.setStyleSheet(f"QFrame#ob_frame_right{{background-color: lightgreen;}}")
        self.frame_all.setStyleSheet(f"QFrame#ob_frame_all{{background-color: green;}}")
        #self.frame_all.setStyleSheet('QFrame:hover { background: yellow; }')

        self.framebox.addWidget(self.lbl)
        self.framebox.addWidget(self.btn)
        self.framebox.addWidget(self.lbl_1)

        self.framebox_right.addWidget(self.lbl_r)
        self.framebox_right.addWidget(self.btn_r)
        self.framebox_right.addWidget(self.lbl_1r)


def main():
    app = QApplication(sys.argv)
    ex = Dynamic_Widgets()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Upvotes: 1

Views: 339

Answers (1)

musicamante
musicamante

Reputation: 48509

Setting individual stylesheets can be useful for very specific and relatively static styling, but, in general, it's usually better to have a centralized QSS or, at least, different QSS set for common parents.

In normal situations, a single Class:hover selector would suffice, but if the children have properties that need to be overridden by a change in the parent, it is necessary to install an event filter on the parent.

Considering that the event filter will match Enter and Leave events, the hover selector doesn't make a lot of sense anymore: we can create a "default" style sheet stored as instance attribute and set/override it depending on those events:

class Dynamic_Widgets(QWidget):
    def __init__(self):
        # ...
        self.frame_all_qss = '''
            QFrame#ob_frame_all {
                background-color: green;
            }
            QFrame#ob_frame {
                background-color: lightgreen;
            }
            QFrame#ob_frame_right {
                background-color: lightgreen;
            }
        '''
        self.frame_all.setStyleSheet(self.frame_all_qss)
        self.frame_all.installEventFilter(self)

    def eventFilter(self, obj, event):
        if obj == self.frame_all:
            if event.type() == event.Enter:
                res = obj.event(event)
                self.frame_all.setStyleSheet(
                    'QFrame#ob_frame_all { background: yellow; }')
                return res
            elif event.type() == event.Leave:
                res = obj.event(event)
                self.frame_all.setStyleSheet(self.frame_all_qss)
                return res
        return super().eventFilter(obj, event)

Upvotes: 1

Related Questions