pyqt5qvboxlayout

PyQt Frame for BoxLayout


I've now been stucked more than 2 hours, trying to put a frame/border around my Boxlayout.

This is main minimal Main.py

from PyQt5 import QtGui
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import circle


class fenster(QWidget):

    def __init__(self):
        super().__init__()

        self.top = 100
        self.left = 100
        self.width = 900
        self.height = 1200

        self.initMe()

    def DisplayMainWindowBox(self):

        maingrahpic = QVBoxLayout()

        topgraphicbox = QFormLayout()
        circle1 = circle.circle()
        topgraphicbox.addWidget(circle1)

        BottomGraphicBox = QFormLayout()
        circle2 = circle.circle()
        BottomGraphicBox.addWidget(circle2)

        maingrahpic.addLayout(topgraphicbox)
        maingrahpic.addLayout(BottomGraphicBox)

        return (maingrahpic)

    def initMe(self):

        # define boxes for boxLayout
        horizontalmainbox = QHBoxLayout()

        rbtnrow = QVBoxLayout()
        rlabelrow = QVBoxLayout()

        lbtnrow = QVBoxLayout()
        llabelrow = QVBoxLayout()

        bottombtnrow = QHBoxLayout()
        bottomlabelrow = QHBoxLayout()

        maingraphicbox = self.DisplayMainWindowBox()

        middlebox = QHBoxLayout()
        middlebox.addLayout(llabelrow)
        middlebox.addLayout(maingraphicbox)
        middlebox.addLayout(rlabelrow)

        mainmiddlebox = QVBoxLayout()
        displayvbox = QVBoxLayout()

        frame = QFrame()
        frame.setFrameShape(QFrame.StyledPanel)
        frame.setStyleSheet("background-color: blue")
        frame.setLineWidth(3)

        displayvbox.addWidget(frame)
        displayvbox.addLayout(middlebox)
        displayvbox.addLayout(bottomlabelrow)

        mainmiddlebox.addLayout(displayvbox)
        mainmiddlebox.addLayout(bottombtnrow)

        horizontalmainbox.addLayout(lbtnrow)
        horizontalmainbox.addLayout(mainmiddlebox)
        horizontalmainbox.addLayout(rbtnrow)

        topbox = QHBoxLayout()
        toprightside = QHBoxLayout()
        toprightside.addStretch(1)
        topleftside = QVBoxLayout()
        topbox.addLayout(toprightside)
        topbox.addLayout(topleftside)

        finalbox = QVBoxLayout()

        finalbox.addLayout(topbox)
        finalbox.addLayout(horizontalmainbox)


        self.setLayout(finalbox)

        self.setGeometry(self.top, self.left, self.width, self.height)
        self.setWindowTitle("ACDI Simulator")
        self.show()

        self.setStyleSheet("background : black;")


app = QApplication(sys.argv)
app.setStyle("fuison")
w = fenster()
sys.exit(app.exec_())

To make the programm code work u need circle.py

from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys


class circle(QMainWindow):

    def __init__(self):
        super().__init__()

        timer = QTimer(self)

        timer.timeout.connect(self.update)

        timer.start(500)

        self.setWindowTitle('Circle')

        self.setGeometry(200, 200, 300, 300)

        self.setStyleSheet("background : black;")

        self.rPointer = QtGui.QPolygon([QPoint(0, 0),
                                        QPoint(-10, -90),
                                        QPoint(10, -90)])

        self.sPointer = QtGui.QPolygon([QPoint(0, 0),
                                        QPoint(-10, -90),
                                        QPoint(10, -90)])

        self.bColor = Qt.white

        self.GreenCol = Qt.green

        self.sColor = Qt.red

        self.tik = 0

    def paintEvent(self, event):

        rec = min(self.width(), self.height())

        self.tik = self.tik + 1
        self.tik = self.tik % 360

        painter = QPainter(self)

        def drawPointer(color, rotation, pointer):

            painter.setBrush(QBrush(color))

            painter.save()

            painter.rotate(rotation)

            painter.drawConvexPolygon(pointer)

            painter.restore()

        painter.setRenderHint(QPainter.Antialiasing)

        painter.translate(self.width() / 2, self.height() / 2)

        painter.scale(rec / 200, rec / 200)

        painter.setPen(QtCore.Qt.NoPen)

        drawPointer(self.GreenCol, (self.tik), self.rPointer)

        drawPointer(self.sColor, 90, self.sPointer)

        painter.setPen(QPen(self.bColor, 1, Qt.SolidLine))

        painter.setBrush(QBrush(QtCore.Qt.NoBrush))

        painter.drawEllipse(-92, -92, 184, 184)

        for i in range(0, 90):

            if (i % 5) == 0:
                painter.drawLine(87, 0, 97, 0)

            painter.rotate(9)

        painter.end()


if __name__ == '__main__':

    app = QApplication(sys.argv)

    win = circle()
    win.show()

    sys.exit(app.exec_())

Since i am clearly not able to tell what i want here a picture:
Since i am clearly not able to tell what i want here a picture

I want the a frame around the Displayvbox. The Displayvbox contains some labels and the two circles. How is it possible to make this frame. I really don't get this....


Solution

  • A QFrame is a container widget, which is a widget intended only as a way to "group" other widgets.

    If you want to show widgets inside a frame, you cannot just add the frame to the layout and add those widgets to the same layout: you need to set a layout for the frame, add the widgets to that layout, and then add the frame to the "main" layout.

    In your case, you can create the frame in DisplayMainWindowBox and directly return that instead of the layout:

        def DisplayMainWindowBox(self):
    
            frame = QFrame()
            frame.setFrameShape(QFrame.StyledPanel)
            frame.setStyleSheet("background-color: blue")
            frame.setLineWidth(3)
    
            # directly install the layout on the frame
            maingrahpic = QVBoxLayout(frame)
            # which is the shorthand version of: 
            # maingrahpic = QVBoxLayout(frame)
            # frame.setLayout(maingrahpic)
    
            topgraphicbox = QFormLayout()
            circle1 = circle()
            topgraphicbox.addWidget(circle1)
    
            BottomGraphicBox = QFormLayout()
            circle2 = circle()
            BottomGraphicBox.addWidget(circle2)
    
            maingrahpic.addLayout(topgraphicbox)
            maingrahpic.addLayout(BottomGraphicBox)
    
            # return the frame, not the layout
            return frame
    
        def initMe(self):
            # ...
            maingraphicbox = self.DisplayMainWindowBox()
    
            middlebox = QHBoxLayout()
            middlebox.addLayout(llabelrow)
            middlebox.addWidget(maingraphicbox)
            middlebox.addLayout(rlabelrow)
            # ...
    

    I suggest you to read more about layout management and also do some experimenting by using them in Qt designer so that you can better understand how layout management works under Qt.
    Also consider that width() and height() are existing attributes of all QWidget classes, so you should not overwrite them with custom variables, as doing it would make access to those properties more difficult.

    Finally, your circle subclass should probably inherit from QWidget and not QMainWindow (which is normally intended to be used as a top level window, not as a custom widget that is going to be added to a parent).