Pyside/Pyqt5 dynamically adding and sorting items

Question:

I have a simple user interface where I want to dynamically add frames and labels in a widget (as I will use these labels to transmit a video feed from my webcams).

In the following code I set a function where the user selects an integer which represents the number of labels(webcams) they want to see and then dynamically adds these labels& frames to the widget:

def loopCamFeed(self,n):
    if (n % 2) == 0:
        dividnd = n / 2
        for i in range(2):
            self.frame_12 = QFrame(self.ui.webcamWidget)
            self.frame_12.setObjectName(u"frame_12")
            self.frame_12.setFrameShape(QFrame.StyledPanel)
            self.frame_12.setFrameShadow(QFrame.Raised)
            self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
            self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
            for i in range(int(dividnd)):
                self.label_5 = QLabel("hello",self.frame_12)
                self.label_5.setObjectName(u"label_5")
                self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
                self.ui.verticalLayout_15.addWidget(self.frame_12)
    

Which displays the labels as in the image below:

–By adding a value of 2:
enter image description here

–By adding a value of 4):

enter image description here

By adding a value of 8:
enter image description here

The challenge that I am facing is how to handle an odd number selection. For example, if a user selects 3 or 7 webcams/labels.

If a user selects 3 labels/webcams, I’d want to show one on the top frame and two at the bottom.

MAIN.PY (Where this piece of code was written):

from ui_interface import *
import sys
from Custom_Widgets.Widgets import *
import cv2
import numpy as np
from PyQt5.QtCore import pyqtSignal, QObject, QThread

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        loadJsonStyle(self, self.ui)
        self.show()

        

        #Expand Center Menu Widget
        self.ui.settingsBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
        self.ui.infoBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
        self.ui.helpBtn.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())

        #Close Center Menu Widget
        self.ui.closeCenterMenuButton.clicked.connect(lambda: self.ui.centerMenuContainer.collapseMenu())

        #Close Notification Menu Widget
        self.ui.closeNotificationBtn.clicked.connect(lambda: self.ui.popUpNotificationContainer.collapseMenu())

        self.loopCamFeed(4)
    

    def ImageUpdateSlot(self, Image):
        self.ui.label_5.setPixmap(QPixmap.fromImage(Image))

    def CancelFeed(self):
        self.worker1.stop()
    
    def startVideo(self):
        self.worker1 = Worker1()
        self.worker1.start()
        self.worker1.ImageUpdate.connect(self.ImageUpdateSlot)
    
    def loopCamFeed(self,n):
        if (n % 2) == 0:
            dividnd = n / 2
            for i in range(2):
                self.frame_12 = QFrame(self.ui.webcamWidget)
                self.frame_12.setObjectName(u"frame_12")
                self.frame_12.setFrameShape(QFrame.StyledPanel)
                self.frame_12.setFrameShadow(QFrame.Raised)
                self.horizontalLayout_14 = QHBoxLayout(self.frame_12)
                self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
                for i in range(int(dividnd)):
                    self.label_5 = QLabel("hello",self.frame_12)
                    self.label_5.setObjectName(u"label_5")
                    self.horizontalLayout_14.addWidget(self.label_5, 0, Qt.AlignHCenter)
                    self.ui.verticalLayout_15.addWidget(self.frame_12)
        
 
class Worker1(QThread):
    ImageUpdate = pyqtSignal(QImage)
    def __init__(self):
        super().__init__()

    def run(self):
        self.ThreadActive = True
        Capture = cv2.VideoCapture(0)
        while self.ThreadActive:
            ret, frame = Capture.read()
            if ret:
                Image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                FlippedImage = cv2.flip(Image, 1)
                ConvertToQtFormat = QImage(FlippedImage.data, FlippedImage.shape[1], FlippedImage.shape[0], QImage.Format_RGB888)
                Pic = ConvertToQtFormat.scaled(1200, 900, Qt.KeepAspectRatio)
                self.ImageUpdate.emit(Pic)

    def stop(self):
        self.ThreadActive = False
        self.quit()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Answers:

use a grid layout instead of a horizontal Layout

    def loopCamFeed(self,n):
    self.frame_12 = QFrame(self.ui.webcamWidget)
    self.frame_12.setObjectName(u"frame_12")
    self.frame_12.setFrameShape(QFrame.StyledPanel)
    self.frame_12.setFrameShadow(QFrame.Raised)
    self.grid_layout = QGridLayout(self.frame_12)
    self.grid_layout.setObjectName(u"grid_layout")
    for i in range(int(n)):
        self.label_5 = QLabel("hello",self.frame_12)
        self.label_5.setObjectName(u"label_5")
        self.grid_layout.addWidget(self.label_5, 0, Qt.AlignHCenter)
    self.ui.verticalLayout_15.addWidget(self.frame_12)
Answered By: Medhat Ashour

As Medhat mentioned, applying the GridLayout was the best solution.

I applied the following code:

def loopCamFeed(self,n):
    w = 0
    if n > 0:
        # if ( n % 2) == 0:
            
        for i in range(int(n)):
            if (i%2) == 0:
                w +=1                
            print(int(w / 2), (i%2))
            self.label = QtWidgets.QLabel()
            self.label.setText("Screen " +str(i))
            self.label.setStyleSheet("background-color: black5;")

            self.label.setObjectName(u"label")
            self.gridLayout.addWidget(self.label, (i%2) ,int(w),Qt.AlignHCenter )

This works perfectly! Thanks @Medhat

Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.