askqest
askqest

Reputation: 47

Can I blur the background behind qwidget “menu_pos_”?

I need to make the background of the "menu_pos_" block translucent and blur everything on the back. And leave the text clear. This effect is usually called the frosted glass effect.

image

But unfortunately I could only blur the whole widget

image

import sys


from PyQt5.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint,
    QRect, QSize, QUrl, Qt)
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtCore import QPropertyAnimation, QPoint

from PyQt5.QtWidgets import QGraphicsEffect

#Or

'''
from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint,
    QRect, QSize, QUrl, Qt)
from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from PySide2.QtCore import QPropertyAnimation, QPoint

from PySide2.QtWidgets import QGraphicsEffect
'''



class test_mynu(QtWidgets.QWidget):
    def __init__(self, arr="", parent=None):
        super(test_mynu, self).__init__(parent)
        self._expand = False                                # - self.__expand ; + self._expand  !!!
        #------menu_pos_block------
        self.menu_pos_block = QtWidgets.QWidget()

        blur = QtWidgets.QGraphicsBlurEffect(blurRadius=5)
        self.menu_pos_block.setGraphicsEffect(blur)


        #------menu_pos_block_layout------
        self.menu_pos_block_layout = QtWidgets.QHBoxLayout(self.menu_pos_block)
        self.menu_pos_block_layout.setObjectName(u"menu_pos_block_layout")
        #------menu_pos_label------
        self.menu_pos_label = QtWidgets.QLabel()
        self.menu_pos_label.setText(arr)
        self.menu_pos_block_layout.addWidget(self.menu_pos_label)
        #------ADD------
        lay = QtWidgets.QHBoxLayout(self)
        lay.addWidget(self.menu_pos_block)



class MainWindow(QtWidgets.QMainWindow):
    # number of radio
    def num(self):
        return 3
    def __init__(self, parent=None):
        super().__init__(parent)

        self.toggle_animations = QtCore.QSequentialAnimationGroup(self)

        #------centralwidget------
        centralwidget = QtWidgets.QWidget()
        centralwidget.setObjectName(u"centralwidget")
        self.setCentralWidget(centralwidget)
        #------layout------
        central_w_layout = QtWidgets.QGridLayout(centralwidget)
        central_w_layout.setObjectName(u"central_w_layout")
        #------Spacer------
        vs_up = QtWidgets.QSpacerItem(17, 105, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        central_w_layout.addItem(vs_up, 0, 1, 1, 1)
        hs_left = QtWidgets.QSpacerItem(327, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        central_w_layout.addItem(hs_left, 1, 0, 1, 1)
        hs_right = QtWidgets.QSpacerItem(326, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        central_w_layout.addItem(hs_right, 1, 2, 1, 1)
        vs_down = QtWidgets.QSpacerItem(20, 105, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        central_w_layout.addItem(vs_down, 2, 1, 1, 1)
        #------block------
        block = QtWidgets.QWidget()
        block.setObjectName(u"block")
        central_w_layout.addWidget(block, 1, 1, 1, 1)             ######
        #------layout------
        layout_block = QtWidgets.QVBoxLayout(block)
        layout_block.setObjectName(u"layout_block")
        #------menu_block------
        menu_block = QtWidgets.QWidget()
        menu_block.setObjectName(u"menu_block")
        layout_block.addWidget(menu_block)             ######
        #------menu_layout------
        menu_layout = QtWidgets.QHBoxLayout(menu_block)
        menu_layout.setObjectName(u"menu_layout")

        self.menu_but = []
        self.menu_pos = []
        self.menu_by_pos = None

        for i in range(self.num()):
            menu_pos_block = test_mynu("menu_{}".format(i))
            menu_pos_block.setObjectName("menu_pos_{}".format(i))

            self.menu_pos.append(menu_pos_block)
            self.menu_pos[i].setGeometry(QRect(menu_pos_block.width(), menu_pos_block.height(), 151, 181))
            menu_layout.addWidget(self.menu_pos[i])

        #------menu_block_but------
        self.menu_block_but = QtWidgets.QWidget()
        self.menu_block_but.setObjectName(u"menu_block_but")
        menu_layout.addWidget(self.menu_block_but)             ######
        #------menu_block_but_layout------
        menu_block_but_layout = QtWidgets.QVBoxLayout(self.menu_block_but)
        menu_block_but_layout.setObjectName(u"menu_block_but_layout")
        #------menu_but_radio------
        for i in range(self.num()):
            menu_but_radio = QtWidgets.QRadioButton('{}'.format(i))
            menu_but_radio.setObjectName("{}".format(i))
            menu_but_radio.toggled.connect(self.menu_animation)

            self.menu_but.append(menu_but_radio)
            menu_block_but_layout.addWidget(menu_but_radio)

        # Связывание меню к кнопкам и наоборот
        self.menu_by_but = dict()
        self.but_by_menu = dict()
        for i in range(self.num()):
            but = self.menu_but[i]
            menu = self.menu_pos[i]

            self.menu_by_but[menu] = but
            self.but_by_menu[but] = menu

        menu_block_content = QtWidgets.QWidget()
        menu_block_content.setObjectName(u"menu_block_content")
        menu_layout.addWidget(menu_block_content)             ######
        #------menu_content_layout------
        menu_content_layout = QtWidgets.QHBoxLayout(menu_block_content)
        menu_content_layout.setObjectName(u"menu_content_layout")
        #------menu_label------
        menu_label = QtWidgets.QLabel()
        menu_label.setText('text, text text, text')
        menu_content_layout.addWidget(menu_label)

        self.num = 0
        self.menu_pos_ter = []

    def menu_animation(self):
        self.num =self.num+1
        self.toggle_animations.clear()

        num = int(self.sender().objectName())
        self.menu_pos_ter.append(self.menu_pos[num])

        # Хитрая сортировка, что сначала вернет элемент с _expand = True
        for menu in sorted(self.menu_pos_ter, key=lambda x: x._expand):
            pos1 = QPoint(self.menu_block_but.x() - menu.width(), menu.y())
            pos2 = QPoint(self.menu_block_but.x() +self.menu_block_but.width(), menu.y())

            but = self.menu_by_but[menu]
            menu.raise_()
            self.menu_block_but.raise_()
            if but.isChecked():

                start_pos = pos1
                end_pos = pos2
            else:
                start_pos = menu.pos()
                end_pos = pos1

            anim = QPropertyAnimation(menu, b"pos")
            anim.setDuration(1000)
            anim.setStartValue(start_pos)
            anim.setEndValue(end_pos)

            self.toggle_animations.addAnimation(anim)


        if (self.num == 1) or (self.num == 3):
            self.toggle_animations.start()
            self.menu_pos_ter.clear()

        if self.num == 3 :
            self.num = 1
        print("--x--")


StyleSheet = """
#centralwidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget{
background:#000;
color:#fff;
}
#centralwidget QWidget,
#centralwidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget,
#centralwidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget QWidget{
background:#fff;
color:#000;
}
#click_me{
background:#000;
color:#fff;
}
"""

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyleSheet(StyleSheet)
    w = MainWindow()
    w.resize(640, 570) #Size window
    w.show()
    sys.exit(app.exec_())

I want the widget to look like this html template.

$(".menu-btn input").change(function() {
$('.menu_1').removeClass('menu_1_active');
$('.menu_2').removeClass('menu_2_active'); $('.menu_3').removeClass('menu_3_active');
 
 $('.sidebar_menu_1').removeClass('sidebar_menu_1_active');
 $('.frame_menu_1').removeClass('frame_menu_1_active'); 
 
  $('.sidebar_menu_2').removeClass('sidebar_menu_2_active');
 $('.frame_menu_2').removeClass('frame_menu_2_active'); 
  
  $('.sidebar_menu_3').removeClass('sidebar_menu_3_active');
 $('.frame_menu_3').removeClass('frame_menu_3_active'); 
  
  
var name = $(this).val();

setTimeout(function(){ 

$('.menu_'+name).toggleClass('menu_'+name+'_active'); 
$('.sidebar_menu_'+name).toggleClass('sidebar_menu_'+name+'_active'); 
$('.frame_menu_'+name).toggleClass('frame_menu_'+name+'_active');  
}, 1000);


  
  
  
});


/*return*/
$("#block_blur").append('<div class="frame_menu_1" ><div class="full sidebar_menu_1"></div></div>');

$("#block_blur").append('<div class="frame_menu_2" ><div class="full sidebar_menu_2"></div></div>');

$("#block_blur").append('<div class="frame_menu_3" ><div class="full sidebar_menu_3"></div></div>');





/*copy menu */
$('.copy').clone().appendTo('.full');
.content > h3{
  padding:10px;
  margin:2px;
}

.title_1{
 background:red;
}
.title_2{
 background:blue;
}
.title_3{
 background:green;
}

.title_4{
 background:url('https://i.ytimg.com/vi/slZdLNewXrE/maxresdefault.jpg');
}

.title_5{
 background:yellow;
}


.menu-btn {
 display: flex;
  flex-direction: column;
  background-color: #333;
  position: absolute;
  left: 10px;
  top: 10px;
  z-index:110;
}

.menu-btn > input{
 margin:2px;
}

.menu > div{
   width: 200px;
  height: 200px;
  background-color:#18182178;
  position: absolute;
  left: 0px;
  top: 0px;
text-align: center;
  color:white;
transition:  1s;
  transform: translateX(-100%);
   z-index:100;
}

.menu .menu_1_active,
.menu .menu_2_active,
.menu .menu_3_active{
 transform: translateX(0%);
}


/*blur*/
.frame_menu_1,
.frame_menu_2,
.frame_menu_3{
z-index: 10;
overflow: hidden;
position: absolute;
width: 200px !important;
height:  200px !important;
top: 200px !important;
left: 0px !important;
transition:  1s;
transform: translate(0%, -100%);

 transform: translate(-100%, -100%); 
  
  
}




 .frame_menu_1_active,
 .frame_menu_2_active,
 .frame_menu_3_active{
transition:  1s; 
transform: translate(-100%, -100%);
   
   
   transform: translate(0%, -100%);
   
   
 }   









/*copy*/
.sidebar_menu_1,
.sidebar_menu_2,
.sidebar_menu_3{
width: 100% !important;
height: 100% !important;
position: absolute;
filter:blur(8px);
-webkit-filter:blur(8px);
top:  -200px;
left: 0px;
transition:  1s;
transform: translate(0%, 100%);
  
transform: translate(100%, 100% );  
  
}




 






/*active*/
.sidebar_menu_1_active,
.sidebar_menu_2_active,
.sidebar_menu_3_active{
transition:  1s; 
transform: translate(100%, 100% );
  
  
  transform: translate(0%, 100%);
  
}

 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="copy">


<div class="menu-btn">
<input type="radio" id="rad_men" name="red" value="1"/>
    <input type="radio" id="rad_men" name="red" value="2"/>
    <input type="radio" id="rad_men" name="red" value="3"/>
  
  
</div>
  
<div class="menu">
<div class="menu_1">menu 1</div>
<div class="menu_2">menu 2</div>
<div class="menu_3">menu 3</div>  
</div>
  
  


  <div class="content">
  <h3  class="title_1" >text text text</h3>
  <h3  class="title_2" >text text text</h3>
  <h3  class="title_3" >text text text</h3>
  <h3  class="title_4" >text text text</h3>
  <h3  class="title_5" >text text text</h3>
   </div>

     
     
</div>

  
 <div id="block_blur"></div>

I had to use JS to copy all the HTML code, frame overflow: hidden; and synchronize movements with buttons.

If possible, I would like to avoid this method, because it is the wildest horror.

Upvotes: 0

Views: 4476

Answers (2)

leonid gvozdev
leonid gvozdev

Reputation: 1

You can find the answer here.

I have created graphical effects and animation that can be applied to any PyQt / PySide widget to display blurred content under widget. Also you can add many translucent backgrounds to widget (color or gradient)

Shine animation can be adjusted in angle, color, width and duration.

Move animation can be adjusted in offset and duration.

This effect only works with child widgets. If it is applied to the main widget, then it will not work. https://github.com/GvozdevLeonid/BackDrop-in-PyQt-PySide

Upvotes: 0

eyllanesc
eyllanesc

Reputation: 243965

The QGraphicsEffect affects the widget and the children of the widget therefore the QLabel is also affected. To avoid this, a possible solution is to use a QWidget where another QWidget is established through a layout, and to that last widget apply the effect, and add a QLabel to the initial QWidget so that the QLabel and the QWidget will effectively have the same parent , raise_() must also be used so that the QLabel is on top of all:

from PyQt5 import QtCore, QtGui, QtWidgets


class BlurLabel(QtWidgets.QWidget):
    def __init__(self, text, parent=None):
        super().__init__(parent)
        self.setAttribute(QtCore.Qt.WA_StyledBackground)
        widget = QtWidgets.QWidget()
        widget.setStyleSheet("""QWidget{ background:#fff; color:#000;}""")
        blur_effect = QtWidgets.QGraphicsBlurEffect(blurRadius=5)
        widget.setGraphicsEffect(blur_effect)

        self._label = QtWidgets.QLabel(
            text=text, alignment=QtCore.Qt.AlignCenter, parent=self
        )
        self.label.setStyleSheet(""" background-color : transparent; color : black""")
        self.label.setContentsMargins(10, 0, 10, 0)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(widget)

    @property
    def label(self):
        return self._label

    def sizeHint(self):
        return self._label.sizeHint()

    def resizeEvent(self, event):
        self._label.resize(self.size())
        self._label.raise_()
        return super().resizeEvent(event)


class ButtonWidget(QtWidgets.QWidget):
    clicked = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAttribute(QtCore.Qt.WA_StyledBackground)
        self.setStyleSheet("""background:#fff;""")

        vlay = QtWidgets.QVBoxLayout(self)

        group = QtWidgets.QButtonGroup(self)
        group.buttonClicked[int].connect(self.clicked)

        for i in range(3):
            radiobutton = QtWidgets.QRadioButton(str(i))
            radiobutton.setStyleSheet("""background:#000; color:#fff;""")
            group.addButton(radiobutton, i)
            vlay.addWidget(radiobutton)


class LabelWidget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAttribute(QtCore.Qt.WA_StyledBackground)
        self.setStyleSheet("""background:#fff;""")

        vlay = QtWidgets.QVBoxLayout(self)

        label = QtWidgets.QLabel("text, text, text, text")
        label.setStyleSheet("""background:#000; color:#fff;""")
        vlay.addWidget(label)


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

        container = QtWidgets.QWidget()
        container.setStyleSheet("""QWidget{ background:#000;}""")

        hlay_menus = QtWidgets.QHBoxLayout()
        hlay_menus.setContentsMargins(0, 6, 0, 6)

        self.menus = []

        for i in range(3):
            menu = BlurLabel("menu-{}".format(i))
            hlay_menus.addWidget(menu)
            self.menus.append(menu)

        self.button_widget = ButtonWidget()
        self.button_widget.clicked.connect(self.onClicked)
        self.label_widget = LabelWidget()

        lay = QtWidgets.QHBoxLayout(container)
        lay.addLayout(hlay_menus)
        lay.addWidget(self.button_widget)
        lay.addWidget(self.label_widget)
        container.setFixedSize(container.sizeHint())

        hlay = QtWidgets.QHBoxLayout()
        hlay.addStretch(0)
        hlay.addWidget(container)
        hlay.addStretch(0)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        vlay = QtWidgets.QVBoxLayout(central_widget)
        vlay.addStretch(0)
        vlay.addLayout(hlay)
        vlay.addStretch(0)

        self.last_id = -1

    @QtCore.pyqtSlot(int)
    def onClicked(self, id_):
        menu = self.menus[id_]
        if not hasattr(menu, "animation"):
            animation = QtCore.QPropertyAnimation(menu, b"pos", duration=1000)
            animation.setStartValue(menu.pos())
            animation.setEndValue(
                QtCore.QPoint(self.label_widget.pos().x() + 5, menu.pos().y())
            )
            animation.start()
            menu.animation = animation

        if self.last_id != -1:
            last_menu = self.menus[self.last_id]
            last_menu.animation.setDirection(QtCore.QAbstractAnimation.Backward)
            last_menu.animation.start()
            last_menu.raise_()
        menu.animation.setDirection(QtCore.QAbstractAnimation.Forward)
        menu.animation.start()
        menu.raise_()
        self.button_widget.raise_()
        self.last_id = id_


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

enter image description here

Upvotes: 2

Related Questions