Border of a Frame is not shown - qt

This is the relevant code of the frame
self.frame = QtWidgets.QFrame(self)
self.frame.setFrameShape(QtWidgets.QFrame.Box)
self.frame.setGeometry(QtCore.QRect(20, 710, 381, 121))
self.frame.setLineWidth(2)
self.frame.setMidLineWidth(0)
self.frame.setStyleSheet("border-color:white")
self.frame.setObjectName("frame")
Problem is that the border of the frame is not shown in the window

You should add it in one layout like QVBoxLayout, You created a frame but never add it to any layout, so it doesn't show.
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget,QFrame,QVBoxLayout
from PySide6 import QtGui
from PySide6 import QtCore
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
self.setGeometry(0,0,600,400)
self.frame = QFrame(self)
self.frame.setFrameShape(QFrame.Box)
self.frame.setGeometry(QtCore.QRect(20, 710, 381, 121))
self.frame.setLineWidth(2)
self.frame.setMidLineWidth(0)
self.frame.setStyleSheet("border-color:white")
self.frame.setObjectName("frame")
layout=QVBoxLayout()
layout.addWidget(self.frame)
self.setLayout(layout)
app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()
output:
you can also use self.setCentralWidget(self.frame) if you use QMainwindow.

Setting the border color is insufficient, as you need to specify all border properties: width, style and color.
You should also always use selectors for widgets that can be containers.
The correct stylesheet would be:
QFrame#frame {
border: 2px solid white;
}
Note: you should always use layout managers, even in Designer.

Related

How to add dynamically stretching gap between widgets in Qt?

I want to add spaces between the widgets, dynamically, so that, as i resize the window, the widgets get their gaps adjusted accordingly, so that the widgets will be evenly spread over the available window space.
#!/usr/bin/python3
import sys
import random
try:
from PySide6 import QtCore, QtWidgets
except ModuleNotFoundError:
from PySide2 import QtCore, QtWidgets
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout(self)
for i in range(0, 10):
self.text = QtWidgets.QLabel("Hello World",
alignment=QtCore.Qt.AlignCenter,
styleSheet = f'''
background-color: '#999999';
color : '#000000';
'''
)
self.layout.addWidget(self.text)
self.layout.addStretch()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MyWidget()
widget.resize(800, 600)
widget.show()
sys.exit(app.exec_())
If you set labels' vertical size policy to QtWidgets.QSizePolicy.Maximum or QtWidgets.QSizePolicy.Fixed and remove self.layout.addStretch() you'll get evenly spread stretch.
self.text.setSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
Alternatively you can add self.layout.addStretch() after every label to achieve same thing.

Qt: Understanding QScrollArea::widgetResizable property

I am experimenting with Qt 5 QScrollArea (in Python and PyQt, but I believe the question applies just as well in C++ Qt).
The Qt documentation for QScrollArea::widgetResizable says that "If this property is set to false (the default), the scroll area honors the size of its widget." By "its widget", I assume it means the widget being viewed in the scroll area.
However, in the program below I show an image label inside the scroll area, but the scroll area does not seem to "honor the size of its widget", because the image is partly hidden from the start.
The documentation also says "Regardless of this property, you can programmatically resize the widget using widget()->resize(), and the scroll area will automatically adjust itself to the new size." However, I do invoke resize for the viewed widget, but nothing happens.
The documentation also says "If this property is set to true, the scroll area will automatically resize the widget in order to avoid scroll bars where they can be avoided, or to take advantage of extra space." However, I don't see any resizing, even though if the widget were resized then it would be possible to avoid the scroll bars.
This is what I see whether I set the property to True or False, and whether I invoke widget().resize() or not:
Clearly I must be missing something quite fundamental here; what is it?
Edit: the main purpose of the question is understanding how widgetResizable works and what it does. Fitting the image into the window is a secondary goal.
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QImage, QPalette, QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QScrollArea
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
image = QImage("happyguy.png")
imageLabel = QLabel()
imageLabel.setPixmap(QPixmap.fromImage(image))
scrollArea = QScrollArea()
scrollArea.setBackgroundRole(QPalette.Dark)
scrollArea.setWidget(imageLabel)
scrollArea.setWidgetResizable(True)
scrollArea.widget().resize(QSize(10, 10))
self.setCentralWidget(scrollArea)
app = QApplication([])
w = MainWindow()
w.show()
app.exec_()
And here's the happyguy.pgn file:
scrollArea.setWidgetResizable(True) give the resize control of imageLabel to scrollArea. So the next line scrollArea.widget().resize(QSize(10, 10)) will be overrode by system.
A solution worked on windows (resize main window to fit image size).
from PyQt5.QtGui import QImage, QPalette, QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QScrollArea, QFrame
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
image = QImage("happyguy.png")
imageLabel = QLabel()
imageLabel.setPixmap(QPixmap.fromImage(image))
scrollArea = QScrollArea()
scrollArea.setFrameShape(QFrame.NoFrame)
scrollArea.setBackgroundRole(QPalette.Dark)
scrollArea.setWidget(imageLabel)
self.setCentralWidget(scrollArea)
self.resize(image.size())
app = QApplication([])
w = MainWindow()
w.show()
app.exec_()
Or use QScrollArea.setMinimumSize
from PyQt5.QtGui import QImage, QPalette, QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QScrollArea, QFrame
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
image = QImage("happyguy.png")
imageLabel = QLabel()
imageLabel.setPixmap(QPixmap.fromImage(image))
scrollArea = QScrollArea()
scrollArea.setFrameShape(QFrame.NoFrame)
scrollArea.setBackgroundRole(QPalette.Dark)
scrollArea.setWidget(imageLabel)
scrollArea.setMinimumSize(image.size())
self.setCentralWidget(scrollArea)
app = QApplication([])
w = MainWindow()
w.show()
app.exec_()
Resizable IS NOT Scrollable ...

How to build a flat groupbox in PyQt5?

I found the flat property of the QGroupbox Class in the Qt-docs, where it says:
A group box usually consists of a surrounding frame with a title at the top. If this property is enabled, only the top part of the frame is drawn in most styles; otherwise, the whole frame is drawn.
I'm trying to build such a flat QGroupBox, but it doesn't seem to work, as you can see in this picture. In the docs it also says:
Note: In some styles, flat and non-flat group boxes have similar representations and may not be as distinguishable as they are in other styles.
That leads me to the QStyle Class, which overstrains me a little, as I have no idea how to change the Style of the QGroupBox. I'm not even sure, if this is the real problem here. As you can see in my code below, I don't assign a specific style to the QGroupBox. So, it should use some sort of standard style, i guess...
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox,
QVBoxLayout, QLabel
class WidgetWithFlatGroupBox(QWidget):
def __init__(self):
QWidget.__init__(self, flags=Qt.Widget)
self.init_ui()
def init_ui(self):
self.setGeometry(300, 300, 300, 100)
self.setWindowTitle('PyQt5 Window')
layout = QVBoxLayout()
layout.addWidget(self.create_groupbox(), alignment=Qt.AlignCenter)
self.setLayout(layout)
def create_groupbox(self):
groupbox = QGroupBox('Flat Groupbox')
layout = QVBoxLayout()
label = QLabel('This Groupbox should be flat.')
layout.addWidget(label, alignment=Qt.AlignCenter)
groupbox.setLayout(layout)
groupbox.setFlat(True)
return groupbox
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = WidgetWithFlatGroupBox()
ex.show()
sys.exit(app.exec_())
I had a look at the internet, also here at stackoverflow of course, but were not able to find something useful. Is there anyone who knows how to use the flat property of the QGroupBox Class properly?
Sorry, but I do not understand how you need to do:
border: None;
border: 1px solid #76797C;
Try it:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QWidget, QGroupBox,
QVBoxLayout, QLabel, QPushButton)
class WidgetWithFlatGroupBox(QWidget):
def __init__(self):
QWidget.__init__(self, flags=Qt.Widget)
self.init_ui()
def init_ui(self):
self.setGeometry(300, 300, 300, 100)
self.setWindowTitle('PyQt5 Window')
layout = QVBoxLayout()
layout.addWidget(self.create_groupbox(), alignment=Qt.AlignCenter)
self.setLayout(layout)
def create_groupbox(self):
groupbox = QGroupBox('Flat Groupbox')
layout = QVBoxLayout()
label = QLabel('This Groupbox should be flat.')
button = QPushButton("This Button !!!")
button.setFlat(True)
layout.addWidget(label, alignment=Qt.AlignCenter)
layout.addWidget(button, alignment=Qt.AlignCenter)
groupbox.setLayout(layout)
# groupbox.setFlat(True)
return groupbox
style = '''
QGroupBox {
border: None; /*<----- None */
/* border: 1px solid #76797C; <----- 1px solid #76797C */
border-radius: 2px;
margin-top: 20px;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding-left: 10px;
padding-right: 10px;
padding-top: 10px;
}
'''
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyleSheet(style)
ex = WidgetWithFlatGroupBox()
ex.show()
sys.exit(app.exec_())
self.groupBox_33.setFlat(True)

How to set background color to entire widget with stylesheet in PySide

I am trying to set a background color of a widget, but it only applies to widget's children. The code below is a simple representation of the real app structure. I'd like testWidget to be entirely red, which is 100x100 pixel rectangle due to it's size, but for some reason only the button is red.
from PySide import QtGui
class Widget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
mainLayout = QtGui.QVBoxLayout(self)
testWidget = QtGui.QWidget()
testWidget.setFixedSize(100,100)
testWidget.setStyleSheet('background-color: red;')
testLayout = QtGui.QVBoxLayout()
testWidget.setLayout(testLayout)
but = QtGui.QPushButton('TEST')
but.setFixedSize(20,20)
testLayout.addWidget(but)
mainLayout.addWidget(testWidget)
w = Widget()
w.show()
By default, a QWidget does not fill its background. You can either use a QFrame instead or setting the WA_StyledBackground attribute of the QWidget to True as said here : PySide: QWidget does not draw background color.
To apply the style sheet only to the container, and not to its children, the container widget can be named and the style sheet can specifically be applied to it by referring to its name.
Below is a MWE, derived from your code, that shows how it can be done using a QFrame instead of a QWidget :
from PySide import QtGui
import sys
class Widget(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
mainLayout = QtGui.QVBoxLayout(self)
testWidget = QtGui.QFrame()
testWidget.setFixedSize(100,100)
testWidget.setObjectName("myWidget")
testWidget.setStyleSheet("#myWidget {background-color:red;}")
testLayout = QtGui.QVBoxLayout()
testWidget.setLayout(testLayout)
but = QtGui.QPushButton('TEST')
testLayout.addWidget(but)
mainLayout.addWidget(testWidget)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
instance_1 = Widget()
instance_1.show()
sys.exit(app.exec_())
which results in:

QSplitter - change the color of the grabbable area to make it more visible

With QSplitter it is sometimes difficult to see whether there is a "grabbable" area and where to click in order to grab it.
I'd like to set the color of the grabbale area to something different to the background so it is visible.
Is this possible?
Sure, use handle selector:
QSplitter::handle {
background: red;
}
Method one: use palette
from PySide2 import QtWidgets, QtGui
app = QtWidgets.QApplication()
window = QtWidgets.QMainWindow()
splitter = QtWidgets.QSplitter(window)
splitter.addWidget(QtWidgets.QLabel("Hello", splitter))
splitter.addWidget(QtWidgets.QLabel("World", splitter))
window.setCentralWidget(splitter)
palette = window.palette()
palette.setColor(QtGui.QPalette.ColorRole.Window, QtGui.QColor("gray"))
window.setPalette(palette)
for handle in window.findChildren(QtWidgets.QSplitterHandle):
palette = handle.palette()
palette.setColor(QtGui.QPalette.ColorRole.Window, QtGui.QColor("yellow"))
handle.setPalette(palette)
window.show()
app.exec_()
Method two: use stylesheet
from PySide2 import QtWidgets, QtGui
app = QtWidgets.QApplication()
window = QtWidgets.QMainWindow()
splitter = QtWidgets.QSplitter(window)
splitter.addWidget(QtWidgets.QLabel("Hello", splitter))
splitter.addWidget(QtWidgets.QLabel("World", splitter))
window.setCentralWidget(splitter)
palette = window.palette()
palette.setColor(QtGui.QPalette.ColorRole.Window, QtGui.QColor("gray"))
window.setPalette(palette)
window.setStyleSheet("QSplitterHandle { background: red }")
window.show()
app.exec_()
Note: do not use QSplitter::handle if you are using QPalette
QSplitter::handle will invalidate all QSplitter's palette settings, and all children in QSplitter

Resources