How to control the proportions of a QFrame in a layout? - python

It's My Code. My Requirement: if the Window Grows the frame also expands as per ratio in both directions. I am trying with SetSize Policy, but nothing will happen. How to achieve it?
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class FrameExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Frame Example")
self.setGeometry(100,100,600,600)
self.frame = QFrame()
self.frame.setFixedSize(200,200)
# self.frame.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Fixed)
self.frame.setStyleSheet("background-color:skyblue")
self.frame1 = QFrame()
self.frame1.setGeometry(QRect(10,10,600,600))
self.frame1.resize(600,600)
self.frame1.setStyleSheet("background-color:lightgreen")
layout = QVBoxLayout()
layout.addWidget(self.frame)
layout.addWidget(self.frame1)
self.setLayout(layout)
if __name__=="__main__":
app = QApplication(sys.argv)
countrywin =FrameExample()
countrywin.show()
sys.exit(app.exec_())

From the comments, it appears you want the top frame to get a third of the width (i.e. 200/600 == 1/3), with the height remaining fixed - but it should not resize smaller than the minimum in either direction. Meanwhile, the bottom frame should just take up whatever space is left over.
This can be achieved by firstly setting the minimum-size and an appropriate size-policy on the top frame. Its proportions can then be controlled by putting it in a horizontal layout and adding stretchers with appropriate stretch factors (depending on how the frame should be aligned).
Here is a working example based on your code:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class FrameExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Frame Example")
self.setGeometry(100, 100, 600, 600)
self.frame = QFrame()
self.frame.setStyleSheet("background-color:skyblue")
self.frame.setMinimumSize(QSize(200, 200))
self.frame.setSizePolicy(
QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
hbox = QHBoxLayout()
# align left
hbox.addWidget(self.frame, 1)
hbox.addStretch(2)
# align centre
# hbox.addStretch()
# hbox.addWidget(self.frame)
# hbox.addStretch()
self.frame1 = QFrame()
self.frame1.setStyleSheet("background-color:lightgreen")
layout = QVBoxLayout()
layout.addLayout(hbox)
layout.addWidget(self.frame1)
self.setLayout(layout)
if __name__=="__main__":
app = QApplication(sys.argv)
countrywin =FrameExample()
countrywin.show()
sys.exit(app.exec_())

Related

How to display Qframe as actual size in PyQt5?

Here is My program. My Requirement: Display frame as mentioned size. But in my code its occupies the entire area. How to resolve it?
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class FrameExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Frame Example")
self.setGeometry(100,100,1500,900)
self.frame = QFrame()
self.frame.resize(300, 300)
self.frame.setStyleSheet("background-color:skyblue")
self.frame1 = QFrame()
self.frame1.setGeometry(QRect(10,10,600,600))
self.frame1.resize(600,600)
self.frame1.setStyleSheet("background-color:lightgreen")
layout = QVBoxLayout()
layout.addWidget(self.frame)
layout.addWidget(self.frame1)
self.setLayout(layout)
if __name__=="__main__":
app = QApplication(sys.argv)
countrywin =FrameExample()
countrywin.show()
sys.exit(app.exec_())
With resize() you are managing the size of the widget but after setting the layouts it will handle the size. One possible solution is to use setFixedSize():
class FrameExample(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Frame Example")
self.setGeometry(100, 100, 1500, 900)
self.frame = QFrame()
self.frame.setFixedSize(300, 300)
self.frame.setStyleSheet("background-color:skyblue")
self.frame1 = QFrame()
self.frame1.setFixedSize(600, 600)
self.frame1.setStyleSheet("background-color:lightgreen")
layout = QVBoxLayout(self)
layout.addWidget(self.frame)
layout.addWidget(self.frame1)

QT: stretch factor in QSplitter does not work

I am using QSplitter in my project, and I want to set the stretch factor for two widget. The following code is recommanded:
splitter.setStretchFactor(0, 1)
splitter.setStretchFactor(1, 5)
And I need to firstly hide one widget, then show it after I click a button. I find the stretch factor does not work. The whole code is:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
class MainWindow(QWidget):
def __init__(self):
super().__init__()
mainLayout = QVBoxLayout()
self.setLayout(mainLayout)
self.btn = QPushButton('show')
self.btn.clicked.connect(self.btnSlot)
mainLayout.addWidget(self.btn)
layout = QHBoxLayout()
mainLayout.addLayout(layout)
self.w1 = QWidget()
self.w1.setStyleSheet('border: 2px solid #777;')
self.w1.hide()
self.lay1 = QVBoxLayout()
self.lay1.addWidget(QLabel('label 1'))
self.w1.setLayout(self.lay1)
w2 = QWidget()
w2.setStyleSheet('border: 2px solid red;')
self.lay2 = QVBoxLayout()
w2.setLayout(self.lay2)
splitter = QSplitter()
splitter.addWidget(self.w1)
splitter.addWidget(w2)
splitter.setStretchFactor(0, 1)
splitter.setStretchFactor(1, 5)
layout.addWidget(splitter)
def btnSlot(self, check=False):
self.w1.show()
self.lay2.addWidget(QLabel('label 2'))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
After clicked the 'show' button, the result is:
From the above figure, we can see the stretch factor for widget 1/2 is not 1:5. How can I make the strech factor to be 1:5?
Any suggestion is appreciated!
void QSplitter::setStretchFactor(int index, int stretch)
Updates the size policy of the widget at position index to have a stretch factor of stretch.
stretch is not the effective stretch factor; the effective stretch factor is calculated by taking the initial size of the widget and multiplying it with stretch.
void QSplitter::setSizes(const QList &list)
Sets the child widgets' respective sizes to the values given in the list.
If the splitter is horizontal, the values set the width of each widget in pixels, from left to right. If the splitter is vertical, the height of each widget is set, from top to bottom.
Extra values in the list are ignored. If list contains too few values, the result is undefined, but the program will still be well-behaved.
The overall size of the splitter widget is not affected. Instead, any additional/missing space is distributed amongst the widgets according to the relative weight of the sizes.
If you specify a size of 0, the widget will be invisible. The size policies of the widgets are preserved. That is, a value smaller than the minimal size hint of the respective widget will be replaced by the value of the hint.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
mainLayout = QVBoxLayout()
self.setLayout(mainLayout)
self.btn = QPushButton('show')
self.btn.clicked.connect(self.btnSlot)
mainLayout.addWidget(self.btn)
layout = QHBoxLayout()
mainLayout.addLayout(layout)
self.w1 = QWidget()
self.w1.setStyleSheet('border: 2px solid #777;')
self.w1.hide()
self.lay1 = QVBoxLayout()
self.lay1.addWidget(QLabel('label 1'))
self.w1.setLayout(self.lay1)
self.w2 = QWidget()
self.w2.setStyleSheet('border: 2px solid red;')
self.lay2 = QVBoxLayout()
self.w2.setLayout(self.lay2)
splitter = QSplitter(Qt.Horizontal)
splitter.addWidget(self.w1)
splitter.addWidget(self.w2)
splitter.setStretchFactor(0, 1)
splitter.setStretchFactor(1, 5)
splitter.setSizes([100,500]) # +++
layout.addWidget(splitter)
def btnSlot(self, check=False):
self.w1.show()
self.lay2.addWidget(QLabel('label 2'))
QTimer.singleShot(0, self._print)
def _print(self):
print(f'{self.size()}')
print(f'{self.w1.size()}')
print(f'{self.w2.size()}')
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.resize(628, 280) # +++
w.show()
app.exec_()

How to overlay widgets in PyQt5?

I would like to render some layouts - that groups some widgets - over a background layout that contains an image widget.
Let me explain myself with an image. The following image shows the desired output:
However, all I haven't find the way to overlay the two image widgets, and they show like this:
And this is the Python code I wrote:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5 import QtCore, Qt
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setGeometry(0, 0, self.windowsize.width(), self.windowsize.height())
self.setMaximumSize(self.windowsize.width(), self.windowsize.height())
self.setMinimumSize(self.windowsize.width(), self.windowsize.height())
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint)
widget = QWidget()
self.setCentralWidget(widget)
# Picture 1's widget
pixmap = QPixmap('picture_1.jpg')
pixmap = pixmap.scaledToWidth(self.windowsize.width())
self.image = QLabel()
self.image.setPixmap(pixmap)
left_box = QVBoxLayout()
left_box.setContentsMargins(0,0,0,0)
left_box.setSpacing(0)
left_box.setAlignment(Qt.Qt.AlignLeft)
left_box.addWidget(self.image, 0, Qt.Qt.AlignLeft | Qt.Qt.AlignTop)
# Picture 2's widget
pixmap = QPixmap('picture_2.jpg')
pixmap = pixmap.scaledToWidth(400)
self.image2 = QLabel()
self.image2.setPixmap(pixmap)
right_box = QVBoxLayout()
right_box.setContentsMargins(0, 0, 0, 0)
right_box.setSpacing(0)
right_box.setAlignment(Qt.Qt.AlignLeft)
right_box.addWidget(self.image2, 0, Qt.Qt.AlignLeft | Qt.Qt.AlignBottom)
layout_box = QHBoxLayout()
layout_box.addLayout(left_box)
layout_box.addLayout(right_box)
widget.setLayout(layout_box)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())
Could you please help me to modify my code in order to get the widgets overlaid as shown on first image?
Layouts are elements that manage the geometry of widgets, in your case both layouts try to occupy the largest available space. For a widget to be part of another widget there are 2 possibilities, the first is to use a layout, and the second is that the main widget is the father of the new widget, in the case of the first image we will use the first one, and for the second one we will use the second method.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setFixedSize(self.windowsize)
self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint)
widget = QWidget()
self.setCentralWidget(widget)
pixmap1 = QPixmap('picture_1.jpg')
pixmap1 = pixmap1.scaledToWidth(self.windowsize.width())
self.image = QLabel()
self.image.setPixmap(pixmap1)
layout_box = QHBoxLayout(widget)
layout_box.setContentsMargins(0, 0, 0, 0)
layout_box.addWidget(self.image)
pixmap2 = QPixmap('picture_2.jpg')
self.image2 = QLabel(widget)
self.image2.setPixmap(pixmap2)
self.image2.setFixedSize(pixmap2.size())
p = self.geometry().bottomRight() - self.image2.geometry().bottomRight() - QPoint(100, 100)
self.image2.move(p)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry().size()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())

PyQt QVBoxLayout adding elements at bottom

I'm a beginner learning Python/PyQt.
I'm trying to add QLabel and QLineEdits to a QVBoxLayout however all the widgets get added at the bottom of the screen.
I've tried using vbox.setAlignment(Qt.AlignTop) but that does not seem to work either.
Any pointers are appreciated!
main.py
import sys
import os
from PyQt4.QtGui import *
from PyQt4.QtCore import *
app = QApplication(sys.argv)
class m_Window(QWidget):
def __init__(self, scale = 1):
QWidget.__init__(self)
self.initUI(scale)
def initUI(self, scale):
#initialize window sizes
win_width = app.desktop().screenGeometry().width() * scale
win_height = app.desktop().screenGeometry().height() * scale
#init widgets
project_name_lbl = QLabel('<b>Project Name</b>', self)
project_name_inp = QLineEdit(self)
frameworks = ['Skeleton CSS','Bootstrap','UIKit','Foundation','JQuery']
framework_cmbx = QComboBox(self)
framework_cmbx.addItems(frameworks)
#add items to layout
vbox = QVBoxLayout()
vbox.addStretch()
vbox.addWidget(project_name_lbl)
vbox.addWidget(project_name_inp)
vbox.addWidget(framework_cmbx)
#self settings
self.setLayout(vbox)
self.setWindowTitle('Website Template Maker')
self.setMinimumSize(QSize(win_width, win_height))
def run(self):
self.show()
sys.exit(app.exec_())
m_Window(.5).run()
pic:
Move the line
vbox.addStretch()
To after you've added your widgets:
vbox = QVBoxLayout()
vbox.addWidget(project_name_lbl)
vbox.addWidget(project_name_inp)
vbox.addWidget(framework_cmbx)
vbox.addStretch()
This will make the layout push your widgets up instead of down.

PyQt QScrollArea within QScrollArea

I am trying to use multiple horizontal sub QScrollAreas with text and one vertical container QScrollArea. The idea being that the text area in the horizontal sub QScrollAreas will always have equivalent vertical heights and I would like to have one vertical QScrollArea to control the data within them.
The code below shows that the horizontal sub QScrollAreas work, but the vertical QScrollArea doesn't detect that the line edits within the widget inside it don't fit vertically. If I change
scroll.setWidgetResizable(True)
for the vertical QScrollArea to False, the vertical QScrollArea detects the widget inside doesn't fit but I want to be able to scroll all the lineEdits up and down not the parent widget. Also I would like all scrollbars to be always visible. Is this possible?
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Widget(QWidget):
def __init__(self, parent= None):
super(Widget, self).__init__()
self.setGeometry(100, 100, 400, 400)
baseWidget = QWidget()
hBox = QHBoxLayout()
hBox.addWidget(self.getWidget())
hBox.addWidget(self.getWidget())
baseWidget.setLayout(hBox)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
#when set to False all scrolls are not visible and can only scroll parent widget not the data areas
scroll.setWidgetResizable(True)
scroll.setWidget(baseWidget)
vBox = QHBoxLayout()
vBox.addWidget(scroll)
self.setLayout(vBox)
def getWidget(self):
widget = QWidget()
layout = QVBoxLayout()
for i in range(20):
lineEdit = QLineEdit("row: "+str(i)+" data: "+str(list(range(10))))
lineEdit.setMinimumWidth(250)
layout.addWidget(lineEdit)
widget.setLayout(layout)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(False)
scroll.setWidget(widget)
return scroll
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Widget()
dialog.show()
The answer could be found here:
PyQt4 : is there any signal related to scrollbar?
Just needed to sync vertical scrollbars and hide all but one:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Widget(QWidget):
def __init__(self, parent= None):
super(Widget, self).__init__()
self.setGeometry(100, 100, 200, 200)
baseWidget = QWidget()
hBox = QHBoxLayout()
lscrollArea = self.getWidget(False)
rScrollArea = self.getWidget(True)
rScrollArea.verticalScrollBar().valueChanged.connect(
lscrollArea.verticalScrollBar().setValue)
hBox.addWidget(lscrollArea)
hBox.addWidget(rScrollArea)
baseWidget.setLayout(hBox)
vBox = QHBoxLayout()
vBox.addWidget(baseWidget)
self.setLayout(vBox)
def getWidget(self, vScrollOn):
widget = QWidget()
layout = QVBoxLayout()
for i in range(20):
lineEdit = QLineEdit("row: "+str(i)+" data: "+str(list(range(10))))
lineEdit.setMinimumWidth(250)
layout.addWidget(lineEdit)
widget.setLayout(layout)
scroll = QScrollArea()
if vScrollOn:
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
else:
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setWidgetResizable(False)
scroll.setWidget(widget)
return scroll
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Widget()
dialog.show()
app.exec_()

Categories