Issue
Pretty sure I've looked everywhere on the whole internet for why this is happening so I've resorted to asking a question for once.
Anyway, I'm trying to make a transparent (apart from the borders) QSlider lay on top of a QLabel with a QPixmap set on it.
This is so I can have this hue gradient underneath the transparent parts of this slider (so that I can select a hue, I'm creating a rough image editor)
But the problem is, no matter how transparent it knows it is (it's literally displaying the background colour of the whole window behind it) it just seems to really not want to let the QLabel show up beneath it
I know I could save the hue gradient and use .setStyleSheet('background-image:url('gradient.png')
and avoid using a QLabel altogether, but I don't want to have to save the gradient as a file, I want it in main memory when the program is running.
Currently this is my code:
# hue background
self.hueBGData = Image.new('RGBA', (40, 256), (0, 0, 0, 0)) # background hue gradient
self.drawHueSlider() # here i'm just generating the hue gradient, but I don't want to save it as an actual file
self.QtHueBG = ImageQt.ImageQt(self.hueBGData)
self.hueBG = QLabel(self)
self.hueBGPixmap = QPixmap.fromImage(self.QtHueBG)
self.hueBG.setPixmap(self.hueBGPixmap)
self.hueBG.setGeometry(604, 255, 40, 256) # set to same position (40, 256)
# actual slider
self.hueSlider = QSlider(Qt.Vertical, self) # actual slider
self.hueSlider.setRange(1, 1530)
self.hueSlider.setValue(600)
self.hueSlider.setGeometry(604, 255, 40, 256) # set to same position (40, 256)
self.hueSlider.setStyleSheet('''QSlider::groove:vertical {border-radius:4px;
border:1px solid #88888f;}
QSlider::handle:vertical {border-radius:4px; margin:-5px 0px;
border:1px solid #88888f;}''')
I have tried using:
.setAttribute(Qt.WA_TranslucentBackground)
for the sliderbackground-color:(0, 0, 0, 0);
for the slider- defining the hueSlider first, then using
.stackUnder(self.hueSider)
on hueBG.
I've also made the slider sit behind the gradient and made the gradient have 0.5 opacity and it layers them perfectly, but obviously the slider is behind the gradient and I can't use it and I don't want the gradient to be on 0.5 opacity.
Any help would be greatly appreciated.
Edit for minimal reproducible example:
from PIL import Image, ImageQt, ImageColor
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QSlider, QStyleFactory, QStyle
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import sys
class Interface(QMainWindow):
def __init__(self):
super(Interface, self).__init__()
self.setWindowTitle('slider test')
self.setStyleSheet('background-color: #d8d8df;')
self.background = Image.new('RGBA', (40, 256), (255, 0, 0, 255))
self.label = QLabel(self)
self.backgroundQt = ImageQt.ImageQt(self.background)
self.backgroundPixmap = QPixmap.fromImage(self.backgroundQt)
self.label.setPixmap(self.backgroundPixmap)
self.label.setGeometry(100, 100, 40, 256)
self.slider = QSlider(Qt.Vertical, self)
self.slider.setStyle(QStyleFactory.create('fusion'))
self.slider.setStyleSheet('''QSlider::groove:vertical {border-radius:4px; border:1px solid #88888f;}
QSlider::handle:vertical {border-radius:4px; margin:-5px 0px;
border:1px solid #88888f;}''')
self.slider.setGeometry(100, 100, 40, 256)
self.showMaximized()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('fusion')
print(app.style().objectName())
ex = Interface()
sys.exit(app.exec_())
this example just shows the slider with the overall background behind it:
Solution
The problem resides in the usage of a generic stylesheet definition for the parent (the main window). This is one of the reasons for which generic stylesheet should be avoided, and selectors should always be preferred.
Stylesheets are cascading by nature, so, setting the background for the parent widget sets the background for all its children.
To avoid this you can simply override the background:
self.slider.setStyleSheet('''
QSlider:vertical {
background: transparent;
}
QSlider::groove:vertical {
border-radius: 4px;
border: 1px solid #88888f;
}
QSlider::handle:vertical {
border-radius: 4px;
margin: -5px 0px;
border: 1px solid #88888f;}
''')
But remember that generic properties should be avoided for parent widgets, as it can also result in unexpected problems with complex widgets like combo boxes and scroll bars in scroll areas, so I strongly suggest you to change the main stylesheet by properly using selectors.
Also note that Qt stylesheets support all three Qt gradients, so you don't even need to create an image for that as you can build a Hue-like gradient very easily; try with the following stylesheet
QSlider::groove:vertical {
border: none;
}
QSlider::handle:vertical {
margin: -5px 0px;
border-radius: 4px;
border: 1px solid #88888f;
}
QSlider:vertical {
border-radius: 4px;
border: 1px solid #88888f;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 rgba(255, 0, 0, 255),
stop:0.166 rgba(255, 0, 255, 255),
stop:0.333 rgba(0, 0, 255, 255),
stop:0.5 rgba(0, 255, 255, 255),
stop:0.666 rgba(0, 255, 0, 255),
stop:0.833 rgba(255, 255, 0, 255),
stop:1 rgba(255, 0, 0, 255))
}
Finally, remember that adding direct children to a QMainWindow is unsupported and discouraged, and a central widget (possibly with proper layout managers) should always be used instead.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.