I found some tutorial code online about QFormLayout:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
def window():
app = QApplication(sys.argv)
win = QWidget()
l1 = QLabel("Name")
nm = QLineEdit()
l2 = QLabel("Address")
add1 = QLineEdit()
add2 = QLineEdit()
fbox = QFormLayout()
fbox.addRow(l1, nm)
vbox = QVBoxLayout()
vbox.addWidget(add1)
vbox.addWidget(add2)
fbox.addRow(l2, vbox)
hbox = QHBoxLayout()
r1 = QRadioButton("Male")
r2 = QRadioButton("Female")
hbox.addWidget(r1)
hbox.addWidget(r2)
hbox.addStretch()
fbox.addRow(QLabel("sex"), hbox)
fbox.addRow(QPushButton("Submit"), QPushButton("Cancel"))
win.setLayout(fbox)
win.setWindowTitle("PyQt")
win.show()
sys.exit(app.exec_())
The right bottom one is what the original GUI looks like.
When I dragged the widget horizontally, the right top one is what GUI looks like.
When I dragged the widget vertically, the left one is what GUI looks like.
It seems those labels and buttons will follow the horizontal change but failed to change as the main widget changes vertically. Is there anyway to do this to make all buttons and labels change dynamically?
Related
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.
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)
# ...
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.
I found some tutorial code online about QFormLayout:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
def window():
app = QApplication(sys.argv)
win = QWidget()
l1 = QLabel("Name")
nm = QLineEdit()
l2 = QLabel("Address")
add1 = QLineEdit()
add2 = QLineEdit()
fbox = QFormLayout()
fbox.addRow(l1, nm)
vbox = QVBoxLayout()
vbox.addWidget(add1)
vbox.addWidget(add2)
fbox.addRow(l2, vbox)
hbox = QHBoxLayout()
r1 = QRadioButton("Male")
r2 = QRadioButton("Female")
hbox.addWidget(r1)
hbox.addWidget(r2)
hbox.addStretch()
fbox.addRow(QLabel("sex"), hbox)
fbox.addRow(QPushButton("Submit"), QPushButton("Cancel"))
win.setLayout(fbox)
win.setWindowTitle("PyQt")
win.show()
sys.exit(app.exec_())
The right bottom one is what the original GUI looks like.
When I resize the widget horizontally, the right top one is what GUI looks like.
When I resize the widget vertically, the left one is what GUI looks like.
It seems those labels and buttons will follow the horizontal change, but fail to change as the main widget changes vertically. Is there any way to expand the widgets vertically with QFormLayout as well?
I'm trying to use QFromLayout for a PySide panel, but I can't get alignment to work. I would like to have all fields line up vertically. Currently they are not lining up, I guess becuse of the length of the label? I tried with bot setHorizontalAlignment() and to fill the label with white spaces, but no luck.
Edit:
Here's a better example of what's not aligned.
Basically I want all "column 2" to be aligned vertically.
Any ideas? Image of panel
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class MyPanel(QWidget):
def __init__(self, parent = None):
super(MyPanel, self).__init__(parent)
self.grp1 = QGroupBox()
self.form_layout1 = QFormLayout()
self.drop1 = QComboBox()
self.drop1.addItems(["item1", "item2"])
self.form_layout1.addRow('drop', self.drop1)
self.line1 = QLineEdit()
self.form_layout1.addRow("long long line", self.line1)
self.btn1 = QPushButton("button")
self.form_layout1.addRow("", self.btn1)
self.grp2 = QGroupBox()
self.form_layout2 = QFormLayout()
self.check2 = QCheckBox()
self.form_layout2.addRow("checkbox", self.check2)
self.line2 = QLineEdit()
self.form_layout2.addRow("line", self.line2)
# Set layouts.
self.grp1.setLayout(self.form_layout1)
self.grp2.setLayout(self.form_layout2)
# Main layout.
self.layout = QVBoxLayout()
self.layout.addWidget(self.grp1)
self.layout.addWidget(self.grp2)
self.setLayout(self.layout)
# Show
app = QApplication(sys.argv)
panel = MyPanel()
panel.show()
app.exec_()