Why the sizePolicy doesn't affect on widgets that aren't in layout?
here is an example:
from PyQt5 import QtWidgets
app = QtWidgets.QApplication([])
window = QtWidgets.QWidget()
window.setGeometry(50, 50, 500, 300)
test_widget = QtWidgets.QWidget(window)
test_widget.setMinimumSize(100, 100)
test_widget.setStyleSheet("background-color:red")
size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
test_widget.setSizePolicy(size_policy)
window.show()
app.exec()
But that doesn't work, if you changed the main window size the red box still has the same size.
So how can I make that red box resizeable when the parent (main window) is changing.
NOTE: I don't want to use Layouts for some reason.
I'm not sure I completely understand your GUI design but you should note that a single cell (as defined by a row/column pair) in a QGridLayout can be occupied by more than a single widget. A (very) simple example demonstrates this...
#!/usr/local/bin/python3
import os
import sys
from PySide2.QtWidgets import QApplication, QGridLayout, QLabel, QPushButton, QWidget
from PySide2.QtCore import Qt
class widget(QWidget):
def __init__ (self, parent = None):
super(widget, self).__init__(parent)
gl = QGridLayout(self)
pb = QPushButton("Show/Hide Menu")
self.menu = QLabel("Menu goes here...")
self.menu.setAlignment(Qt.AlignCenter)
self.menu.setStyleSheet("background-color: #40800000;")
canvas = QLabel("Canvas")
canvas.setAlignment(Qt.AlignCenter)
canvas.setStyleSheet("background-color: #40000080;")
gl.addWidget(pb, 0, 0)
gl.addWidget(canvas, 0, 0, 2, 2)
pb.raise_()
pb.clicked.connect(self.toggle_menu)
gl.addWidget(self.menu, 1, 0)
self.menu.hide()
def toggle_menu (self, checked):
self.menu.setVisible(not self.menu.isVisible())
if __name__ == '__main__':
app = QApplication([])
w = widget()
w.show()
app.exec_()
[I've used PySide2 as I don't have PyQt5 installed.]
So if I have understood correctly then I don't see why you can't make use of a QGridLayout. Could save you a lot of work.
Related
I'm making an application in PyQt4 and this is my code so far:
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUi()
def initUi(self):
self.setWindowTitle('Main Menu')
self.setFixedSize(1200, 625)
self.firstWidgets()
self.show()
def firstWidgets(self):
self.vbox1 = QtGui.QVBoxLayout()
self.task1 = QtGui.QLabel('Check 1', self)
self.task1CB = QtGui.QCheckBox(self)
self.hbox1 = QtGui.QHBoxLayout()
self.hbox1.addWidget(self.task1)
self.hbox1.addWidget(self.task1CB)
self.vbox1.addLayout(self.hbox1)
self.setLayout(self.vbox1)
def main():
application = QtGui.QApplication(sys.argv)
gui = MainWindow()
sys.exit(application.exec_())
if __name__=='__main__':
main()
My problem is in MainWindow.firstWidgets(). I try to set a layout but I get an error even though that's my first time using .setLayout for that form, which confuses me.
QWidget::setLayout: Attempting to set QLayout "" on MainWindow "",
which already has a layout
You can't set a QLayout directly on the QMainWindow. You need to create a QWidget and set it as the central widget on the QMainWindow and assign the QLayout to that.
wid = QtGui.QWidget(self)
self.setCentralWidget(wid)
layout = QtGui.QVBoxLayout()
wid.setLayout(layout)
NOTE: This is for Qt4 -- see the other answer on this question for the Qt5 updated code.
Just an update to Brenden Abel's answer:
QWidget and QVBoxLayout (for Python3, PyQt5) are now contained in the PyQt5.QtWidgets module and not the PyQt5.QtGui module.
So updated code:
wid = QtWidgets.QWidget(self)
self.setCentralWidget(wid)
layout = QtWidgets.QVBoxLayout()
wid.setLayout(layout)
This is an example using PyQt5
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('My App')
# Cannot set QxxLayout directly on the QMainWindow
# Need to create a QWidget and set it as the central widget
widget = QWidget()
layout = QVBoxLayout()
b1 = QPushButton('Red' ); b1.setStyleSheet("background-color: red;")
b2 = QPushButton('Blue' ); b2.setStyleSheet("background-color: blue;")
b3 = QPushButton('Yellow'); b3.setStyleSheet("background-color: yellow;")
layout.addWidget(b1)
layout.addWidget(b2)
layout.addWidget(b3)
widget.setLayout(layout)
self.setCentralWidget(widget)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I am following a bunch of guides I managed to come close to what I expect for my program to look. However with the solution I came to the button is added at the top-left corner of the main layout (layout_main), while I'd like it to be centered. This is my code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QSizePolicy,
QTabWidget,
QVBoxLayout,
QWidget,
qApp,
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Test")
self.setGeometry(0, 0, 1000, 700)
btn_start = QPushButton("Test button", self)
btn_start.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
btn_start.setMaximumSize(900, 500)
btn_start.setMinimumSize(200, 200)
lbl_test = QLabel("Test label", self)
layout_main = QVBoxLayout()
layout_main.addWidget(btn_start)
#layout_main.setAlignment(btn_start, Qt.AlignCenter)
layout_main.addWidget(lbl_test)
tabs = QTabWidget(self)
tabs.setTabPosition(QTabWidget.North)
tabs.setMovable(True)
main = QWidget(self)
main.setLayout(layout_main)
tabs.addTab(main, "Main tab")
self.setCentralWidget(tabs)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
And this is how it looks
When I tried to center it with layout_main.setAlignment(btn_start, Qt.AlignCenter), the commented line, then the button is centered, but sized down to the minimum size
How can I center the button while having it expand the way I want? I have tried lots of things like adding the button to it's own layout or inside a container widget, but no solution worked yet.
I run your code and find out that the btn_start.setMaximumSize limit the button to expand.
Edit your code as I told you now, if there are other problems comment and I will edit the solution.
I'm having trouble with spacing widgets in a QVboxlayout. I have this code:
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
win_w, win_h = 250, 1
self.setGeometry((1920 - win_w) // 2, (1080 - win_h) // 2, win_w, win_h)
self.setWindowTitle('Test')
self.setFont(QtGui.QFont('Times', 12))
self.central_widget()
def central_widget(self):
widget = QtWidgets.QWidget()
grid = QtWidgets.QGridLayout()
group_box1 = QtWidgets.QGroupBox('Group Box')
v1 = QtWidgets.QVBoxLayout()
text_edit1 = QtWidgets.QTextEdit()
v1.addWidget(QtWidgets.QPushButton('Button'))
v1.addWidget(text_edit1)
group_box1.setLayout(v1)
grid.addWidget(group_box1, 0, 0)
widget.setLayout(grid)
self.setCentralWidget(widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
Running this brings up this window:
Adding this line v1.setSpacing(100) changes it to this:
Is there any way to make it add the spacing horizontally? Like this:
Use the alignment keyword argument for addWidget():
v1.addWidget(QtWidgets.QPushButton('Button'), alignment=QtCore.Qt.AlignRight)
As already suggested, you should carefully read the documentation about layout managers, including all the listed QLayout subclasses and all their methods. You can do some experiments on your own with them also in Designer, so that you can better understand how they work by directly seeing the results.
I'm making an application in PyQt4 and this is my code so far:
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.initUi()
def initUi(self):
self.setWindowTitle('Main Menu')
self.setFixedSize(1200, 625)
self.firstWidgets()
self.show()
def firstWidgets(self):
self.vbox1 = QtGui.QVBoxLayout()
self.task1 = QtGui.QLabel('Check 1', self)
self.task1CB = QtGui.QCheckBox(self)
self.hbox1 = QtGui.QHBoxLayout()
self.hbox1.addWidget(self.task1)
self.hbox1.addWidget(self.task1CB)
self.vbox1.addLayout(self.hbox1)
self.setLayout(self.vbox1)
def main():
application = QtGui.QApplication(sys.argv)
gui = MainWindow()
sys.exit(application.exec_())
if __name__=='__main__':
main()
My problem is in MainWindow.firstWidgets(). I try to set a layout but I get an error even though that's my first time using .setLayout for that form, which confuses me.
QWidget::setLayout: Attempting to set QLayout "" on MainWindow "",
which already has a layout
You can't set a QLayout directly on the QMainWindow. You need to create a QWidget and set it as the central widget on the QMainWindow and assign the QLayout to that.
wid = QtGui.QWidget(self)
self.setCentralWidget(wid)
layout = QtGui.QVBoxLayout()
wid.setLayout(layout)
NOTE: This is for Qt4 -- see the other answer on this question for the Qt5 updated code.
Just an update to Brenden Abel's answer:
QWidget and QVBoxLayout (for Python3, PyQt5) are now contained in the PyQt5.QtWidgets module and not the PyQt5.QtGui module.
So updated code:
wid = QtWidgets.QWidget(self)
self.setCentralWidget(wid)
layout = QtWidgets.QVBoxLayout()
wid.setLayout(layout)
This is an example using PyQt5
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QPushButton, QWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('My App')
# Cannot set QxxLayout directly on the QMainWindow
# Need to create a QWidget and set it as the central widget
widget = QWidget()
layout = QVBoxLayout()
b1 = QPushButton('Red' ); b1.setStyleSheet("background-color: red;")
b2 = QPushButton('Blue' ); b2.setStyleSheet("background-color: blue;")
b3 = QPushButton('Yellow'); b3.setStyleSheet("background-color: yellow;")
layout.addWidget(b1)
layout.addWidget(b2)
layout.addWidget(b3)
widget.setLayout(layout)
self.setCentralWidget(widget)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm using pyqt for the first time and I am trying to figure out how to get the text "example.py" in my Qlabel to align vertically. In this code I have set the Qlabel to a fixed height of 35, but the text is not sitting center between the top of the window and the top of the splitter below it.
If I set the fixed height of the Qlabel to 20, that gets a little closer to things looking vertically aligned (but not totally) but also introduces the problem of some of the bottom of the test "example.py" getting cut off.
Maybe it has something to do with some margin or something above the splitter section... Makes me think that it could be the case and that's why the text is getting cut off at the bottom. In either case I am not sure how to address the issue.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os, sys
from PyQt5.QtWidgets import (QApplication, QWidget, QFrame, QSplitter, QStyleFactory,
QHBoxLayout, QVBoxLayout, QLabel)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
#self.showFullScreen()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
topbar = QLabel("example.py", self)
topbar.setAlignment(Qt.AlignVCenter)
topbar.setIndent(20)
topbar.setFixedHeight(35)
layout.addWidget(topbar)
v_left = QFrame(self)
v_left.setFrameShape(QFrame.StyledPanel)
v_middle = QFrame(self)
v_middle.setFrameShape(QFrame.StyledPanel)
v_right = QFrame(self)
v_right.setFrameShape(QFrame.StyledPanel)
splitter = QSplitter(Qt.Horizontal)
splitter.setHandleWidth(0)
splitter.addWidget(v_left)
splitter.addWidget(v_middle)
splitter.addWidget(v_right)
layout.addWidget(splitter)
self.setLayout(layout)
self.setGeometry(100, 100, 1000, 800)
self.setWindowTitle('PiePy')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I found the solution to my issue while I was working on setting up transparency. I added the line self.setAttribute(Qt.WA_NoSystemBackground, True) to my code and that made it clear in the application that there is indeed a space between the Qlabel and the splitter below it.
The solution was a simple one I just added layout.setSpacing(0) to the code and that took care of it.
You are using a QVBoxLayout where it will obey its default behavior, try putting your topbar inside a QHBoxLayout and adding this layout to your main layout(QVBoxLayout). Once you have this configuration add a stretch in each side of your topbar inside the QHBoxLayout to make it goes to the middle.
You would have something like that, from your code:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os, sys
from PyQt5.QtWidgets import (QApplication, QWidget, QFrame, QSplitter, QStyleFactory,
QHBoxLayout, QVBoxLayout, QLabel)
from PyQt5.QtCore import Qt
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
#self.showFullScreen()
layout = QVBoxLayout()
layout_title = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
topbar = QLabel("example.py", self)
topbar.setAlignment(Qt.AlignVCenter)
topbar.setIndent(20)
topbar.setFixedHeight(35)
layout_title.addStretch(-1)
layout_title.addWidget(topbar)
layout_title.addStretch(-1)
layout.addLayout(layout_title)
v_left = QFrame(self)
v_left.setFrameShape(QFrame.StyledPanel)
v_middle = QFrame(self)
v_middle.setFrameShape(QFrame.StyledPanel)
v_right = QFrame(self)
v_right.setFrameShape(QFrame.StyledPanel)
splitter = QSplitter(Qt.Horizontal)
splitter.setHandleWidth(0)
splitter.addWidget(v_left)
splitter.addWidget(v_middle)
splitter.addWidget(v_right)
layout.addWidget(splitter)
self.setLayout(layout)
self.setGeometry(100, 100, 1000, 800)
self.setWindowTitle('PiePy')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
The logic is that you have something like that:
# [---------------------------------] <-main_layout (QVBoxLayout)
# item1 [---stretch----topbar----stretch] <-layout_title (QHBoxLayout)
# item2 [------------QSplitter----------]
# [---------------------------------] <-main_layout (QVBoxLayout)