Using QFrames in QT for Python? - python

how to place objects within the confines of a QFrame as i can't get my head around it. I've read the documentation on https://doc.qt.io/qtforpython/PySide2/QtWidgets/QFrame.html but its just not sinking in for me. I've also looked at various code snippets but nothing seems to do what i want.
When i try to call methods of either a QPushButton or QFrame there seems to be no options for either to interact with each other.
from PySide2.QtWidgets import *
import sys
class ButtonTest(QWidget):
def __init__(self):
QWidget.__init__(self)
self.button1 = QPushButton("Button 1")
self.button2 = QPushButton("Button 2")
self.myframe = QFrame()
self.myframe.setFrameShape(QFrame.StyledPanel)
self.myframe.setFrameShadow(QFrame.Plain)
self.myframe.setLineWidth(3)
self.buttonlayout = QVBoxLayout(self.myframe)
self.buttonlayout.addWidget(self.button1)
self.buttonlayout.addWidget(self.button2)
self.setLayout(self.buttonlayout)
app = QApplication(sys.argv)
mainwindow = ButtonTest()
mainwindow.show()
sys.exit(app.exec_())
They pass in the QFrame as an argument when constructing the layout. This compiles fine, but the frame is nowhere to be seen.

The problem is simple: A layout can only be established in a widget, to better understand you have to know that:
lay = QXLayout(foowidet)
equals:
lay = QXLayout()
foowidget.setLayout(lay)
In your code you first pointed out that buttonlayout handles myframe's child widgets(self.buttonlayout = QVBoxLayout(self.myframe)) but then you have set it to handle window's children(self.addWidget(self.myframe).
The solution is to establish the QFrame through a layout:
class ButtonTest(QWidget):
def __init__(self):
super(ButtonTest, self).__init__()
self.button1 = QPushButton("Button 1")
self.button2 = QPushButton("Button 2")
self.myframe = QFrame()
self.myframe.setFrameShape(QFrame.StyledPanel)
self.myframe.setFrameShadow(QFrame.Plain)
self.myframe.setLineWidth(3)
buttonlayout = QVBoxLayout(self.myframe)
buttonlayout.addWidget(self.button1)
buttonlayout.addWidget(self.button2)
lay = QVBoxLayout(self)
lay.addWidget(self.myframe)

Related

PyQt5 Example of Using `QSizePolicy` to Shrink a Widget

I am trying to stop a widget from expanding by setting its size policy but things are not working.
The following code runs:
from PyQt5.QtWidgets import*
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QHBoxLayout()
self.left_widget = pg.GraphicsLayoutWidget()
self.layout.addWidget(self.left_widget)
self.right_widget = RightWidget()
#self.right_widget.groupbox.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
self.layout.addWidget(self.right_widget)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
class RightWidget(QWidget):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.groupbox = QGroupBox()
self.groupbox.setTitle("some title")
#self.groupbox.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
self.groupboxlayout = QVBoxLayout()
self.button1 = QPushButton ("1")
self.groupboxlayout.addWidget(self.button1)
self.button2 = QPushButton ("2")
self.groupboxlayout.addWidget(self.button2)
self.button3 = QPushButton ("3")
self.groupboxlayout.addWidget(self.button3)
self.groupbox.setLayout(self.groupboxlayout)
self.layout.addWidget(self.groupbox)
self.button4 = QPushButton ("4")
self.layout.addWidget(self.button4)
self.button5 = QPushButton ("5")
self.layout.addWidget(self.button5)
self.setLayout(self.layout)
if __name__ == '__main__':
import sys
system_app = QApplication(sys.argv)
main = MainWindow()
main.show()
system_app.exec()
It gives:
The specific choice of widgets should not matter. The point is that, there is a large widget on the left and there are smaller widgets on the right that is not large enough to fill the column. I want to modify the above code to shrink the widgets on the right hand side. That is:
In words, I want the widgets to shrink to top and bottom of the page in a way taking minimum space (and hence leaving the middle empty).
I attempted to use QSizePolicy to achieve the desired result. The commented lines seem to have no impact on the page at all. I don't know what went wrong.

PyQt5 Problem involving QMainWindow class, QAction and probably the setCentralWidget() function, what to do? [duplicate]

This question already has answers here:
PyQT Navigation between layouts
(2 answers)
Closed 1 year ago.
How to get back my MainWindow ?
From my MainWindow. If I Press either the "Open Left Box" button or "Open Right Box" button, it's worked and at the same time, If I press the "Back" Button from Left Box, nothing will happen. How to obtain the main window? (Simply, I want to know how to set Layouts and remove layouts in setcentral Widgets)
import sys,os
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Class_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Main Window")
self.initUI()
def initUI(self):
self.widgets()
self.layouts()
def widgets(self):
self.Masterbtn = QPushButton("Master")
self.transbtn = QPushButton("tanscation")
self.reportbtn = QPushButton("Reports")
self.masterlbl = QLabel("Master Label")
self.translbl = QLabel("transcation label")
self.reportlbl = QLabel("Report Label")
self.leftboxbtn = QPushButton("Open Left Box")
self.leftboxbtn.clicked.connect(self.leftboxopn)
self.rightboxbtn = QPushButton("Open Right Box")
self.rightboxbtn.clicked.connect(self.rightboxopn)
self.backbtn =QPushButton("Back")
self.backbtn.clicked.connect(self.mainwindow)
def layouts(self):
self.mainbox = QVBoxLayout()
self.mainbox.addWidget(self.leftboxbtn)
self.mainbox.addWidget(self.rightboxbtn)
self.leftbox = QVBoxLayout()
self.leftbox.addWidget(self.Masterbtn)
self.leftbox.addWidget(self.transbtn)
self.leftbox.addWidget(self.reportbtn)
self.leftbox.addWidget(self.backbtn)
self.rightbox = QVBoxLayout()
self.rightbox.addWidget(self.masterlbl)
self.rightbox.addWidget(self.translbl)
self.rightbox.addWidget(self.reportlbl)
# self.rightbox.addWidget(self.backbtn)
widget = QWidget()
widget.setLayout(self.mainbox)
self.setCentralWidget(widget)
def leftboxopn(self):
self.setWindowTitle("Left Box ")
widget = QWidget()
widget.setLayout(self.leftbox)
self.setCentralWidget(widget)
def rightboxopn(self):
self.setWindowTitle("Right Box")
widget = QWidget()
widget.setLayout(self.rightbox)
self.setCentralWidget(widget)
def mainwindow(self):
self.setWindowTitle("Main Window")
widget = QWidget()
widget.setLayout(self.mainbox)
self.setCentralWidget(widget)
def main():
app = QApplication(sys.argv)
mainwindow = Class_MainWindow()
mainwindow.show()
sys.exit(app.exec_())
if __name__ =="__main__":
main()
You cannot "get back" anything, because everytime you use setCentralWidget() the existing widget gets deleted, as the documentation explains:
Note: QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time.
When you call setCentralWidget() on another widget, the previous is completely deleted, including all its children. When a Qt object is deleted, all its child objects gets deleted along with it, and the result is that the self.mainbox you created in the beginning doesn't exist any more (the python object exists, but remember that PyQt objects are only a reference to the actual Qt objects: a Qt object can be deleted if Qt requires it, even if the python reference still exists).
In substance (and, in any case), you should not replace the central widget everytime, but use a paged widget like QStackedWidget as the central widget instead, and then switch to the other interfaces using its functions: setCurrentIndex() or setCurrentWidget().
In order to properly use it, all child widgets must be added to a QWidget container, which will then be added as individual "pages" to QStackedWidget:
class Class_MainWindow(QMainWindow):
# ...
def layouts(self):
self.mainContainer = QWidget()
self.mainbox = QVBoxLayout(self.mainContainer)
self.mainbox.addWidget(self.leftboxbtn)
self.mainbox.addWidget(self.rightboxbtn)
self.leftContainer = QWidget()
self.leftbox = QVBoxLayout(self.leftContainer)
self.leftbox.addWidget(self.Masterbtn)
self.leftbox.addWidget(self.transbtn)
self.leftbox.addWidget(self.reportbtn)
self.leftbox.addWidget(self.backbtn)
self.rightContainer = QWidget()
self.rightbox = QVBoxLayout(self.rightContainer)
self.rightbox.addWidget(self.masterlbl)
self.rightbox.addWidget(self.translbl)
self.rightbox.addWidget(self.reportlbl)
# self.rightbox.addWidget(self.backbtn)
self.stackedWidget = QStackedWidget()
self.setCentralWidget(self.stackedWidget)
self.stackedWidget.addWidget(self.mainContainer)
self.stackedWidget.addWidget(self.leftContainer)
self.stackedWidget.addWidget(self.rightContainer)
def leftboxopn(self):
self.setWindowTitle("Left Box ")
self.stackedWidget.setCurrentWidget(self.leftContainer)
def rightboxopn(self):
self.setWindowTitle("Right Box")
self.stackedWidget.setCurrentWidget(self.rightContainer)
def mainwindow(self):
self.setWindowTitle("Main Window")
self.stackedWidget.setCurrentWidget(self.mainContainer)

pyqt5: some widgets are disappear in my label

I am implement my-self label, but some widget is disappear.
My code is:
from PyQt5.QtWidgets import *
import sys
class TypeManagerLabel(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
btnLayout = QHBoxLayout()
self.__nameLineEdit = QLineEdit()
self.__opBtn = QPushButton('Add/Remove')
self.__colorBtn = QPushButton('Color')
btnLayout.addWidget(self.__nameLineEdit)
btnLayout.addWidget(self.__opBtn)
layout.addLayout(btnLayout)
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
# layout.addStretch()
lab2 = QPushButton('test')
layout.addWidget(lab2)
app = QApplication(sys.argv)
dialog = MyWin()
dialog.show()
app.exec_()
Currently, the label is OK, and the result should be:
Now, I want the QLineEdit should be located on the top of the label, thus I add a stretch. And the code is:
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
layout.addStretch() ###################### add the stretch
lab2 = QPushButton('test')
layout.addWidget(lab2)
And the result is:
In the above figure, the QLineEdit is disappeared.
#
My environment is:
win 10
python 3.7.8
pyqt5 5.14.0
--------------------------------update ----------------------------------
Thank for the suggestion from musicamante and Heike, subclass QWidget instead of QLabel. But the new bug is reported after I add some new widget. The code is:
from PyQt5.QtWidgets import *
import sys
class TypeManagerLabel(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
btnLayout = QHBoxLayout()
self.__nameLineEdit = QLineEdit()
self.__opBtn = QPushButton('Add')
btnLayout.addWidget(self.__nameLineEdit)
btnLayout.addWidget(self.__opBtn)
layout.addLayout(btnLayout)
infoLabel = QLabel()
layout.addWidget(infoLabel)
self.__infoLayout = QVBoxLayout()
infoLabel.setLayout(self.__infoLayout)
self.__opBtn.clicked.connect(self.addRemoveSlot)
def addRemoveSlot(self, checked=False):
name = self.__nameLineEdit.text()
layout = QHBoxLayout()
checkBox = QCheckBox()
lineEdit = QLineEdit(name)
layout.addWidget(checkBox)
layout.addWidget(lineEdit)
self.__infoLayout.addLayout(layout)
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
# layout.addStretch()
lab2 = QPushButton('test')
layout.addWidget(lab2)
app = QApplication(sys.argv)
dialog = MyWin()
dialog.show()
app.exec_()
When I input a string in the QLineEdit, and click the "Add" button, the result is:
The above figure is what I expected.
But if I add stretch with the code:
class MyWin(QLabel):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
self.setLayout(layout)
lab1 = TypeManagerLabel()
layout.addWidget(lab1)
layout.addStretch() ###################### add the stretch
lab2 = QPushButton('test')
layout.addWidget(lab2)
Then, if I input a string in the QLineEdit and click the 'Add' button, the expected widget would not appear.
QLabel is a very special type of widget. While it seems very simple, it is not: it has its own behavior when dealing with sizes, and that's in order to accomodate all requirements a widget that is primarily based on (possibly) variable text size, not only horizontally, but vertically also.
That said, one should never try to add layouts and child widgets to classes that are not intended to be used as container, most importantly it should not be done on widgets with peculiar behavior like QLabel.
Using such a widget to contain other widgets is not only a very bad idea, but also completely useless, as you're not actually using the real features a QLabel provides (showing text or images).
To add children and layouts, just use a nested layout, a plain QWidget class, or any other container widgets like QGroupBox or QFrame.
Even after the comments, you're still trying to add widgets to a QLabel. Remove that label, and just add the layout to the main one.
class TypeManagerLabel(QWidget):
def __init__(self):
super().__init__()
# ...
layout.addLayout(btnLayout)
self.__infoLayout = QVBoxLayout()
layout.addLayout(self.__infoLayout)
self.__opBtn.clicked.connect(self.addRemoveSlot)
# ...

Cannot create QScrollArea with QWidget and QVBoxLayout to QWidget with QVBoxLayout

I have this code:
class Window(QWidget):
def __init__(self):
super().__init__()
def init_gui(self):
self.layout = QVBoxLayout()
self.setLayout(self.layout)
self.new1()
self.new2()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
scroll_area.setWidget(widget)
layout = QVBoxLayout()
widget.setLayout(layout)
button = QPushButton("Ahoj")
layout.addWidget(button)
self.layout.addLayout(layout)
def new1(self):
self.create_scroll_area()
def new2(self):
self.create_scroll_area()
I get this error message:
QLayout::addChildLayout: layout "" already has a parent
What's wrong?
Who is layout's parent? Widget? I also tried self.widget instead of widget and it still does not work.
Please try this code.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=None)
self.init_gui()
def init_gui(self):
self.create_scroll_area()
self.showMaximized()
def create_scroll_area(self):
scroll_area = QScrollArea()
widget = QWidget()
layout = QVBoxLayout()
button = QPushButton("Ahoj")
layout.addWidget(button)
widget.setLayout(layout)
scroll_area.setWidget(widget)
self.setLayout(layout)
def main():
app = QApplication([])
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Let's revise from A to Z.
1 to write self.init_gui() in __init__ constructor.
If you don't do it, you can't execute init_gui method at the first time.
2.setLayout() or setWidget() should be written at the last place at least.
In python, we prepare the things we want to show, and set them on the mainwidget, and show them at the last time.
3.please pay attention to self.layout name.
Widget has originally setLayout() method. and layout() method.
If you make self.layout = ***, you crush the original method of QWidget.
4. it may as well delete new1 and new2 method.
please call them directly.
5. please look create_scroll_area method.
You make three widget.QScrollArea,QWidget,QPushButton.
and make a layout object.and you set the layout into QWidget.
But you set the QWidget before the widget set the layout.
It is not good order for coding.
You make QPushButton but the button doesn't belong to any widget.
Because you set the button on the self.layout certainly, but if you want to show it, you must setLayout(self.layout) at the last position.

Getting the tops of side-by-side widgets to align using PySide

In the code below, the top of the QTextEdit and QGraphicsView widgets are not aligned when using QHBoxLayout. However, if you comment out QTextEdit and uncomment the other QGraphicsView setup, the top of the widgets align perfectly. Here are my questions:
What causes this alignment issue to occur and how can it be fixed?
Are issues like this best avoided by using Qt Creator?
Is the whole QGraphicsView() --> QGraphicsScene() --> QWidget() necessary to place graphics next to other widgets?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__()
# Create Widget1
widget1 = QTextEdit()
#widget1 = QWidget()
#view1 = QGraphicsView()
#scene1 = QGraphicsScene(0,0,200,500)
#view1.setScene(scene1)
#layout = QHBoxLayout()
#layout.addWidget(view1)
#widget1.setLayout(layout)
# Create Widget2
widget2 = QWidget()
view2 = QGraphicsView()
scene2 = QGraphicsScene(0,0,200,500)
view2.setScene(scene2)
layout = QHBoxLayout()
layout.addWidget(view2)
widget2.setLayout(layout)
# Layout of Side by Side windows
container = QWidget()
layout = QHBoxLayout()
layout.addWidget(widget1)
layout.addWidget(widget2)
container.setLayout(layout)
# Scroll Area Properties
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(False)
scroll.setWidget(container)
# Scroll Area Layer add
vLayout = QVBoxLayout(self)
vLayout.addWidget(scroll)
self.setLayout(vLayout)
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = Widget()
dialog.show()
app.exec_()
The layouts have a default margin. So if one widget is in a layout, and its neighbour is not, they will not be aligned. To remove the default margin, you can do this:
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
However, in your example, the container widget and layout for the QGraphicsView aren't doing anything useful. So you could remove those, and along with some other simplifications, arrive at this:
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__()
widget1 = QTextEdit()
widget2 = QGraphicsView()
widget2.setScene(QGraphicsScene(0, 0, 200, 500, widget2))
container = QWidget()
layout = QHBoxLayout(container)
layout.addWidget(widget1)
layout.addWidget(widget2)
scroll = QScrollArea()
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(False)
scroll.setWidget(container)
vLayout = QVBoxLayout(self)
vLayout.addWidget(scroll)
Using Qt Designer is certainly very useful when experimenting with the layouts of a complex application. However, the code it generates is usually quite verbose compared with what you can achieve when coding by hand. For long-term maintainability, though, using Qt Designer seems the best option.

Categories

Resources