I am trying to set the width height of a QWidget percentage wise. But since we cannot do something like min-height:20% using QSS. I tried to use setGeometry function and recall this function on window resize event, but somehow it don't work, below is my code:
class mainwindow(QMainWindow):
def __init__(self):
super().__init__()
stylesheet = """
#mainwindow{
border: 0px;
background-color: #222;
}
"""
scanelestylesheet = """
#scanelecontainer{
border: 1px solid #1a1a1a;
background-color: #222;
}
"""
scanstusconstylesheet = """
#scanstuscon{
border: 1px solid #1a1a1a;
background-color: #fff;
}
"""
container = QWidget()
container.setObjectName("mainwindow")
container.setContentsMargins(100, 100, 100, 100)
self.setCentralWidget(container)
self.setStyleSheet(stylesheet)
self.setWindowTitle("Neehack")
widget = QWidget()
widget.setObjectName("scanelecontainer")
widget.setAutoFillBackground(True)
lay = QVBoxLayout(container)
lay.addWidget(widget)
effect = QGraphicsDropShadowEffect(
offset=QPoint(3, 3), blurRadius=25, color=QColor("#1a1a1a")
)
widget.setGraphicsEffect(effect)
widget.setGeometry(0, 0,200, 20)
widget.setStyleSheet(scanelestylesheet)
scanstuscon = QWidget()
scanstuscon.setObjectName("scanstuscon")
scanstuscon.setAutoFillBackground(False)
scanstusconlay = QVBoxLayout(widget)
scanstusconlay.addWidget(scanstuscon)
scanstuscon.setGeometry(10,10, 200,200)
scanstuscon.setStyleSheet(scanstusconstylesheet)
self.resize(1200, 800)
How do I set a QWidget size based on its parent's percentage or why isn't setGeomtry not working here?
The objective of the layouts is to handle the geometry of the widgets so setGeometry will not work. On the other hand, using setGeometry to modify the size together with resizeEvent to establish a percentage of the size is unnecessary since it is enough to set the stretch factor in the layout:
class Mainwindow(QMainWindow):
def __init__(self):
super().__init__()
stylesheet = """
#mainwindow{
border: 0px;
background-color: #222;
}
"""
scanelestylesheet = """
#scanelecontainer{
border: 1px solid #1a1a1a;
background-color: #222;
}
"""
scanstusconstylesheet = """
#scanstuscon{
border: 1px solid #1a1a1a;
background-color: #fff;
}
"""
container = QWidget()
container.setObjectName("mainwindow")
container.setContentsMargins(100, 100, 100, 100)
self.setCentralWidget(container)
self.setStyleSheet(stylesheet)
self.setWindowTitle("Neehack")
widget = QWidget()
widget.setObjectName("scanelecontainer")
widget.setAutoFillBackground(True)
lay = QVBoxLayout(container)
lay.addWidget(widget)
effect = QGraphicsDropShadowEffect(
offset=QPoint(3, 3), blurRadius=25, color=QColor("#1a1a1a")
)
widget.setGraphicsEffect(effect)
widget.setStyleSheet(scanelestylesheet)
scanstuscon = QWidget()
scanstuscon.setObjectName("scanstuscon")
scanstuscon.setAutoFillBackground(False)
scanstuscon.setStyleSheet(scanstusconstylesheet)
# 20% = 20/(20 + 80)
lay = QVBoxLayout(widget)
lay.addWidget(scanstuscon, stretch=20)
lay.addStretch(80)
self.resize(1200, 800)
Related
I'm doing an addon for Blender and I'm using PySide2. I was able to remove the Window Title and appear only the content of the window. I inserted an animated gif inside a QFrame and changed the border of it. The problem is that the container still have its sharp borders appearing.
Is there any way to change a QLayout style?
I wish to add corners to the QLayout or set it to transparent instead of white.
Here is my code:
def __init__(self, parent=None):
super(Ui_Form, self).__init__(parent)
#size of the container of gif
self.size = QtCore.QSize(160, 100)
self.pixel = QtGui.QMovie(
'/home/mateus/Documents/Blender Projects/blender_pyside2_example-master/gui/img.gif')
self.pixel.setScaledSize(self.size)
#size of the window
self.setFixedSize(160, 100)
#style of with rounded corners
self.setStyleSheet("""
QFrame{
border-style: solid;
border-color: rgba(55, 55, 55, 255);
border-width: 3px;
border-radius: 10px;
background-color: rgba(55, 55, 55, 255);
}
""")
self.label = QtWidgets.QLabel()
self.label.setMovie(self.pixel)
self.pixel.start()
self.label.show()
layout = QtWidgets.QVBoxLayout()
layout.setMargin(0)
#attach gif to layout
layout.addWidget(self.label)
self.unsetCursor()
self.setLayout(layout)
You have to make the window transparent:
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setStyleSheet("""
QWidget{
background: transparent;
}
QFrame{
border-style: solid;
border-color: rgba(55, 55, 55, 255);
border-width: 3px;
border-radius: 30px;
background-color: rgba(55, 55, 55, 255);
}
""")
Note: The layout is not a graphic element so it cannot be made transparent, what has to be made transparent is the container.
1. Problem explained
I'm experimenting with Qt's QSplitter() widget. I've built a very simple sample project in PyQt5 showing a QSplitter() encapsulating a QScrollArea() on the left and a QFrame() on the right:
I've given both the QScrollArea() and QFrame() equal stretch factors, but the QSplitter() doesn't treat them equally. The QScrollArea() always gets most space. I have no idea why.
Minimal, Reproducible Example
Simply copy-paste the code below in a .py script and run it. I've got Python 3.7 with PyQt5 running on a Windows 10 machine.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Scroller(QScrollArea):
'''
The Scroller(), will be first widget in the Splitter().
'''
def __init__(self):
super().__init__()
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
self.setStyleSheet("""
QScrollArea {
background-color:#fce94f;
border-color:#c4a000;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
""")
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 1. FRAME
self.__frm = QFrame()
self.__frm.setStyleSheet("QFrame { background: #ff25292d; border: none; }")
self.__frm.setMinimumHeight(100)
# 2. LAYOUT
self.__lyt = QVBoxLayout()
self.__frm.setLayout(self.__lyt)
# 3. SELF
self.setWidget(self.__frm)
self.setWidgetResizable(True)
return
class Frame(QFrame):
'''
The Frame(), will be second widget in the Splitter()
'''
def __init__(self):
super().__init__()
self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
# 1. FRAME
self.setStyleSheet("""
QFrame {
background-color:#fcaf3e;
border-color:#ce5c00;
padding: 0px 0px 0px 0px;
margin: 0px 0px 0px 0px;
}
""")
self.__lyt = QVBoxLayout()
self.__lyt.setAlignment(Qt.AlignTop)
self.__lyt.setSpacing(0)
self.__lyt.setContentsMargins(10, 10, 10, 10)
self.setLayout(self.__lyt)
return
class Splitter(QSplitter):
'''
The Splitter().
'''
def __init__(self, widg1, widg2):
super().__init__()
self.setOrientation(Qt.Horizontal)
self.addWidget(widg1)
self.addWidget(widg2)
self.setStretchFactor(0, 5)
self.setStretchFactor(1, 5)
return
def createHandle(self):
return QSplitterHandle(self.orientation(), self)
class CustomMainWindow(QMainWindow):
'''
CustomMainWindow(), a QMainWindow() to start the whole setup.
'''
def __init__(self):
super().__init__()
self.setGeometry(100, 100, 600, 300)
self.setWindowTitle("QSPLITTER TEST")
# 1. OUTER FRAME
self.__frm = QFrame()
self.__frm.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.__frm.setStyleSheet("""
QFrame {
background-color: #eeeeec;
border-color: #2e3436;
}
""")
self.__lyt = QVBoxLayout()
self.__frm.setLayout(self.__lyt)
self.setCentralWidget(self.__frm)
self.show()
# 2. WIDGETS TO BE PUT IN SPLITTER
self.__widg1 = Scroller()
self.__widg2 = Frame()
# 3. SPLITTER
self.__splitter = Splitter(self.__widg1, self.__widg2)
self.__lyt.addWidget(self.__splitter)
return
if __name__== '__main__':
app = QApplication(sys.argv)
QApplication.setStyle(QStyleFactory.create('Plastique'))
myGUI = CustomMainWindow()
sys.exit(app.exec_())
QSplitter not only takes the stretch factor as a reference, it also takes into account the sizeHint(). If the following is added:
# ...
# 3. SPLITTER
self.__splitter = Splitter(self.__widg1, self.__widg2)
self.__lyt.addWidget(self.__splitter)
print(self.__widg1.sizeHint(), self.__widg2.sizeHint())
return
You get the following:
PyQt5.QtCore.QSize(38, 22) PyQt5.QtCore.QSize(20, 20)
Where we see that the QScrollArea has a greater width in the sizeHint() than the QFrame, and that explains why the observed behavior.
The solution is to establish the same width of sizeHint(), that is, not depend on what it contains.
class Scroller(QScrollArea):
# ...
def sizeHint(self):
s = super().sizeHint()
s.setWidth(20) # same width
return s
class Frame(QFrame):
# ...
def sizeHint(self):
s = super().sizeHint()
s.setWidth(20) # same width
return s
# ...
Output:
I'm trying to change the height of the inner bar.
I already tried to change the height of the chunk, but the hole bar just vanished.
I also tried to change the chunks padding, but nothing happend.
from PySide2 import QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.setStyleSheet("""
QProgressBar {
background-color: #C0C6CA;
border: 0px;
padding-top: 11px;
padding-bottom: 10px;
}
QProgressBar::chunk {
background: #7D94B0;
}
""")
self.progress_bar()
def progress_bar(self):
layout = QtWidgets.QHBoxLayout()
progress = QtWidgets.QProgressBar()
progress.setTextVisible(False)
progress.setValue(35)
layout.addWidget(progress)
self.setLayout(layout)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I want a chunk with the same height of the progressbar itself.
The ::chunk subcontrol is used to change the chunk progress (i.e. the rectangles in the progress bar).
If you want to have a progress bar with the same size of its background, remove the padding:
self.setStyleSheet("""
QProgressBar {
background-color: #C0C6CA;
border: 0px;
padding: 0px;
// height: 100px; // To change the progress bar height
}
QProgressBar::chunk {
background: #7D94B0;
width:5px
}
""")
It will display:
I am developing an application in Python using PyQt5. Here is the code in question:
class Dialog(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout()
self.main = QtWidgets.QWidget()
self.main.setLayout(self.layout)
self.setStyleSheet(QMainWindowStyle)
self.setCentralWidget(self.main)
self.show()
class AppearanceTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
class SettingsDialog(Dialog):
def __init__(self):
super().__init__()
self.tabs = QtWidgets.QTabWidget(self)
self.tabs.setStyleSheet(QTabWidgetStyle)
self.layout.addWidget(self.tabs)
self.tab_appearance = AppearanceTab()
self.tab_appearance.setStyleSheet(QWidgetStyle)
self.tab_appearance_layout = QtWidgets.QGridLayout()
self.tab_appearance.setLayout(self.tab_appearance_layout)
self.tabs.addTab(self.tab_appearance, "Appearance")
self.tab_server = QtWidgets.QWidget()
self.tab_server.setStyleSheet(QWidgetStyle)
self.tab_server_layout = QtWidgets.QGridLayout()
self.tab_server.setLayout(self.tab_server_layout)
self.tabs.addTab(self.tab_server, "Server")
Why is it that when self.tab_appearance is an AppearanceTab instance (which should be a copy of QWidget) it has a different style to self.tab_server (i.e. background colour changes) when self.tab_server is an instance of QWidget?
The stylesheet just defines background-color: #333333 and color: #dddddd.
Thanks in advance.
EDIT:
I believe that the stylesheet is not being properly applied to AppearanceTab, however I don;t know why that would be seeing as it just inherits from QWidget.
EDIT 2:
A MCVE (along with the rest of my project) can be found on github.
In the documentation, there is a paragraph the paragraph about inheritance and style:
Inheritance
In classic CSS, when font and color of an item is not explicitly set, it gets automatically inherited from the parent. When using Qt Style Sheets, a widget does not automatically inherit its font and color setting from its parent widget.
If we want to set the color on a QGroupBox and its children, we can write:
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
So you probably want to to change
QMainWindowStyle = QMainWindow {color: #dddddd; background-color: #333333;}
to
QMainWindowStyle = QMainWindow, QMainWindow * {color: #dddddd; background-color: #333333;}
so that all the child widgets of the main window have the same style.
Try it:
from PyQt5 import QtWidgets
class Dialog(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout()
self.main = QtWidgets.QWidget()
self.main.setLayout(self.layout)
# self.setStyleSheet(QMainWindowStyle)
self.setCentralWidget(self.main)
self.show()
class AppearanceTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
class SettingsDialog(Dialog):
def __init__(self):
super().__init__()
self.tabs = QtWidgets.QTabWidget(self)
# self.tabs.setStyleSheet(QTabWidgetStyle)
self.layout.addWidget(self.tabs)
self.tab_appearance = AppearanceTab()
# self.tab_appearance.setStyleSheet(QWidgetStyle)
## self.tab_appearance.setStyleSheet("QWidget, QWidget * {color: #dddddd; background-color: #333333;}") #note: Tried this however it didn't work.
self.tab_appearance_layout = QtWidgets.QGridLayout()
self.tab_appearance.setLayout(self.tab_appearance_layout)
self.tabs.addTab(self.tab_appearance, "Appearance")
self.tab_server = QtWidgets.QWidget()
# self.tab_server.setStyleSheet(QWidgetStyle)
self.tab_server_layout = QtWidgets.QGridLayout()
self.tab_server.setLayout(self.tab_server_layout)
self.tabs.addTab(self.tab_server, "Server")
style = """
QWidget {
color: #dddddd;
background-color: #333333;
}
QMainWindow {
color: #dddddd;
background-color: #333333;
}
QTabWidget {
background-color: #333333;
color: #dddddd;
}
QTabBar {
color: #dddddd;
background-color: #333333;
}
"""
if __name__ == "__main__":
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("Fusion"))
app = QtWidgets.QApplication([])
app.setStyleSheet(style) # < ---
d = SettingsDialog()
print(app.exec_())
I am having an issue with PyQt4. I have a class which inherits from QWidget. This class uses a layout to store a QLabel and a QLineEdit. Here is the code:
class SearchBar(QtGui.QWidget):
def __init__(self, parent=None):
super(SearchBar, self).__init__(parent)
self.setStyleSheet(SEARCHBAR_STYLE)
layout = QtGui.QHBoxLayout()
layout.setSpacing(0)
layout.setMargin(0)
layout.addStrut(SEARCHAR_HEIGHT)
lbl_notification = QtGui.QLabel('Hi')
lbl_notification.setStyleSheet(SEARCHBAR_NOTIFICATION_STYLE)
layout.addSpacing(10)
layout.addWidget(lbl_notification)
searchbox = QLineEdit('Search')
layout.addStretch()
layout.addWidget(searchbox)
layout.addSpacing(10)
self.setLayout(layout)
and here is the stylesheet:
SEARCHBAR_STYLE = """
QWidget {
background: #424a7d;
}
.QWidget {
border: 1px solid grey;
}
QLabel {
border-top: 1px solid grey;
border-bottom: 1px solid grey;
}
"""
Now, my problem is that the stylesheet does not apply the way I would like it to. It only applies on my QLabel when the border should be around the whole object:
When I had a function creating my search bar as a QWidget, it worked perfectly, but now that I changed that to a class it does not work. What am I doing wrong?
EDIT: I am trying to achieve this:
EDIT 2: The previous code, before I change it to a class, was this:
def create_bar():
layout = QtGui.QHBoxLayout()
layout.setSpacing(0)
layout.setMargin(0)
layout.addStrut(SEARCHAR_HEIGHT)
lbl_notification = QtGui.QLabel('Hi')
lbl_notification.setStyleSheet(SEARCHBAR_NOTIFICATION_STYLE)
layout.addSpacing(10)
layout.addWidget(lbl_notification)
search_bar = QtGui.QLineEdit('Search')
search_bar.setMinimumSize(200, 25)
search_bar.setMaximumSize(200, 25)
search_bar.setStyleSheet(SEARCHBOX_STYLE)
layout.addStretch()
layout.addWidget(search_bar)
layout.addSpacing(10)
widget = QtGui.QWidget()
widget.setStyleSheet(SEARCHBAR_STYLE)
widget.setLayout(layout)
return widget
Change the base class of SearchBar from QWidget to QFrame, or alternatively implement a style sheet aware paintEvent:
def paintEvent(self, event):
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
Then change the style sheet to
SEARCHBAR_STYLE = """
SearchBar {
background: #424a7d;
border: 1px solid grey;
}
"""