Layout doesn’t expand more than initial size it was set using designer
Posted By: Anonymous
I’m trying to resize my widgets proportional to GUI window size but got stuck.
First, I put some widgets, including QVBoxLayout
, using designer and load it using PyQt5.uic.loadUi()
.
After that I tried to resize some of the widgets via resizeEvent
:
def resizeEvent(self, event):
print("Resized")
QtWidgets.QMainWindow.resizeEvent(self, event)
self.resize_widget(self.label, 'both', self.ratio_label)
self.resize_widget(self.slider_cv2, 'width', self.ratio_slider_cv2)
self.resize_widget(self.graph_layout, 'both', self.ratio_graph_layout)
def resize_widget(self, widget, mode, ratio):
if mode == 'width':
widget.resize(int(self.size().width() * ratio), widget.geometry().height())
elif mode == 'height':
widget.resize(widget.geometry().width(), int(self.size().height() * ratio))
else:
try:
widget.resize(int(self.size().width() * ratio[0]), int(self.size().height() * ratio[1]))
except AttributeError:
widget.setGeometry(QtCore.QRect(widget.geometry().left(), widget.geometry().top(), int(self.geometry().width() * ratio[0]), int(self.geometry().height() * ratio[1])))
self.label
, self.slider_cv2
, and self.graph_layout
are instances of Qlabel
, QSlider
, and QVBoxLayout
, respectively.
Sizes of self.label
and self.slider_cv2
change dynamically as I expected, but self.graph_layout
doesn’t. It gets smaller when the GUI window gets smaller, yet does not grow bigger than its initial size.
Added minimal reproducible code:
from PyQt5 import QtWidgets, uic, QtCore
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QVideoFrame
from PyQt5.QtCore import QUrl, QTimer
from PyQt5.QtGui import QPixmap, QImage
import sys
import os
import threading
app = QtWidgets.QApplication(sys.argv)
import cv2
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from time import sleep
import numpy as np
class UI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi('/workspace/demo_cv2_load_entire_layout.ui', self)
self.fig = plt.Figure()
self.canvas = FigureCanvas(self.fig)
self.graph_layout.addWidget(self.canvas)
#---------For resizeing widget-----------
w, h = self.size().width(), self.size().height()
self.graph_layout.activate()
self.ratio_graph_layout = (self.graph_layout.geometry().width() / w, self.graph_layout.geometry().height() / h)
self.ratio_label = (self.label.size().width() / w, self.label.size().height() / h)
self.ratio_slider_cv2 = self.slider_cv2.size().width() / w
self.initial_wh = (w, h)
#----------------------------------------
self.show()
def resizeEvent(self, event):
print("Resized")
QtWidgets.QMainWindow.resizeEvent(self, event)
self.resize_widget(self.label, 'both', self.ratio_label)
self.resize_widget(self.slider_cv2, 'width', self.ratio_slider_cv2)
self.resize_widget(self.graph_layout, 'both', self.ratio_graph_layout)
def resize_widget(self, widget, mode, ratio):
if mode == 'width':
widget.resize(int(self.size().width() * ratio), widget.geometry().height())
elif mode == 'height':
widget.resize(widget.geometry().width(), int(self.size().height() * ratio))
else:
try:
widget.resize(int(self.size().width() * ratio[0]), int(self.size().height() * ratio[1]))
except AttributeError:
widget.setGeometry(QtCore.QRect(widget.geometry().left(), widget.geometry().top(), int(self.geometry().width() * ratio[0]), int(self.geometry().height() * ratio[1])))
print(widget.geometry())
if __name__ == "__main__":
window = UI()
app.exec_()
And .UI file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1018</width>
<height>814</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
<rect>
<x>240</x>
<y>410</y>
<width>291</width>
<height>151</height>
</rect>
</property>
<layout class="QVBoxLayout" name="graph_layout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
</layout>
</widget>
<widget class="QSlider" name="slider_cv2">
<property name="geometry">
<rect>
<x>220</x>
<y>620</y>
<width>349</width>
<height>15</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>90</x>
<y>0</y>
<width>711</width>
<height>371</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string>Video</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1018</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
Solution
If you want to resize an element manually then you shouldn’t use a layout. In this you must use a QWidget as a container and then place the FigureCanvas in that container using a layout.
On the other hand, I have implemented a logic that simplifies and allows easy handling of the resize functionality without the need for resizeEvent override.
*.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1018</width>
<height>814</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QSlider" name="slider_cv2">
<property name="geometry">
<rect>
<x>220</x>
<y>620</y>
<width>349</width>
<height>15</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>90</x>
<y>0</y>
<width>711</width>
<height>371</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string>Video</string>
</property>
</widget>
<widget class="QWidget" name="graph_container" native="true">
<property name="geometry">
<rect>
<x>240</x>
<y>390</y>
<width>291</width>
<height>151</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1018</width>
<height>28</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
*.py
import os
import sys
from dataclasses import dataclass
from enum import IntFlag, auto
from pathlib import Path
from PyQt5 import QtWidgets, uic, QtCore
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class ModeRatio(IntFlag):
NONE = auto()
WIDTH = auto()
HEIGHT = auto()
BOTH = WIDTH | HEIGHT
@dataclass
class SizeManager(QtCore.QObject):
widget: QtWidgets.QWidget
mode: ModeRatio
def __post_init__(self):
super().__init__(self.widget)
self.widget.window().installEventFilter(self)
self._width_ratio = self.widget.width() * 1.0 / self.widget.window().width()
self._height_ratio = self.widget.height() * 1.0 / self.widget.window().height()
def eventFilter(self, obj, event):
if obj is self.widget.window():
if event.type() == QtCore.QEvent.Resize:
self.apply_resize()
return super().eventFilter(obj, event)
def apply_resize(self):
width = self.widget.width()
height = self.widget.height()
if self.mode & ModeRatio.WIDTH:
width = self.widget.window().width() * self._width_ratio
if self.mode & ModeRatio.HEIGHT:
height = self.widget.window().height() * self._height_ratio
self.widget.resize(QtCore.QSizeF(width, height).toSize())
class UI(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
filename = os.fspath(
Path(__file__).resolve().parent / "demo_cv2_load_entire_layout.ui"
)
uic.loadUi(filename, self)
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
lay = QtWidgets.QVBoxLayout(self.graph_container)
lay.addWidget(self.canvas)
self.label_size_manager = SizeManager(widget=self.label, mode=ModeRatio.BOTH)
self.slider_size_manager = SizeManager(
widget=self.slider_cv2, mode=ModeRatio.WIDTH
)
self.graph_size_manager = SizeManager(
widget=self.graph_container, mode=ModeRatio.BOTH
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = UI()
window.show()
app.exec_()
├── demo_cv2_load_entire_layout.ui
└── main.py
Answered By: Anonymous
Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.