I am trying to make a QLabel appear over a QGridLayout, but I cannot figure how to do it.
This is a sample code:
from PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QFrame, QLabel
import sys
class Foo(QWidget):
def __init__(self):
super().__init__()
grid_layout = QGridLayout()
rect1 = QLabel('RECT1')
rect1.setStyleSheet("color: green;")
grid_layout.addWidget(rect1, 0, 1)
rect2 = QLabel('RECT2')
rect2.setStyleSheet("color: blue;")
grid_layout.addWidget(rect2, 0, 2)
self.setLayout(grid_layout)
self.show()
app = QApplication(sys.argv)
foo = Foo()
sys.exit(app.exec_())
which produces the following output:
For instance, I want to create another QLabel in red, and display it over them, in the center of the image:
red_label = QLabel('red')
red_labe.setStyleSheet("font-size:20pt; color: red;");
Something like this:
How can I achieve that?
A possible solution is to make red_label son of the QWidget for it you must pass the self parameter when the object is created. In addition to this the QLabel must change size when the window does, emulating the layout task for it will create a signal that will be emited in the resizeEvent event:
import sys
from PyQt5 import QtCore, QtWidgets
class Foo(QtWidgets.QWidget):
sizeChanged = QtCore.pyqtSignal(QtCore.QSize)
def __init__(self):
super().__init__()
grid_layout = QtWidgets.QGridLayout(self)
rect1 = QtWidgets.QLabel("RECT1")
rect1.setStyleSheet("color: green;")
grid_layout.addWidget(rect1, 0, 1)
rect2 = QtWidgets.QLabel("RECT2")
rect2.setStyleSheet("color: blue;")
grid_layout.addWidget(rect2, 0, 2)
red_label = QtWidgets.QLabel("red", self)
red_label.setAlignment(QtCore.Qt.AlignCenter)
red_label.setStyleSheet("font-size: 20pt; color: red;")
self.sizeChanged.connect(red_label.resize)
def resizeEvent(self, event):
self.sizeChanged.emit(event.size())
super().resizeEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
foo = Foo()
foo.show()
sys.exit(app.exec_())
This may be a little less elegant of a solution, but it does keep the red labeled centered as the window is resized.
class Foo(QWidget):
def __init__(self):
super().__init__()
grid_layout = QGridLayout()
rect1 = QLabel('RECT1')
rect1.setStyleSheet("color: green;")
grid_layout.addWidget(rect1, 0, 0)
rect2 = QLabel('RECT2')
rect2.setStyleSheet("color: blue;")
grid_layout.addWidget(rect2, 0, 2)
grid_layout_two = QGridLayout()
blank_label = QLabel()
red_label = QLabel('red')
red_label.setStyleSheet("font-size:20pt; color: red;")
grid_layout_two.addWidget(blank_label, 0, 0)
grid_layout_two.addWidget(red_label, 0, 1)
grid_layout_two.addWidget(blank_label, 0, 2)
grid_layout_three = QGridLayout()
grid_layout_three.addItem(grid_layout, 0, 0)
grid_layout_three.addItem(grid_layout_two, 0, 0)
self.setLayout(grid_layout_three)
self.show()
app = QApplication(sys.argv)
foo = Foo()
sys.exit(app.exec_())
Basically making three grid layouts, positioning the elements so that the red label is in the center of the other two labels but in a grid layout that is in front of the other labels layout.
Related
I'm trying to create a custom window (namely a custom bar with close buttons, etc.) and I'm using the following code for this:
from PySide6.QtWidgets import QWidget, QLabel, QPushButton, QHBoxLayout
from PySide6.QtCore import Qt, QSize, QPoint, QRect
from PySide6.QtGui import QIcon
class CustomBar(QWidget):
def init(self, main_window):
super().init()
self.main_window = main_window
self.layout = QHBoxLayout()
self.buttons_layout = QHBoxLayout()
self.buttons_layout.setContentsMargins(0, 0, 0, 0)
self.buttons_layout.setSpacing(0)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(0)
self.setStyleSheet("background-color: rgb(60, 63, 65);")
# ------- title -------
self.title = QLabel("MyApp")
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.title.setFixedWidth(200)
# ------- minimize button -------
self.minimize_button = QPushButton()
self.minimize_button.setIcon(QIcon("media\\ui\\icons\\enabled_button.png"))
self.minimize_button.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
self.minimize_button.setIconSize(QSize(16, 16))
self.minimize_button.setFixedSize(QSize(16, 16))
self.minimize_button.clicked.connect(self.minimize_window)
self.buttons_layout.addWidget(self.minimize_button)
# ------- close button -------
self.close_button = QPushButton()
self.close_button.setIcon(QIcon("media\\ui\\icons\\disabled_button.png"))
self.close_button.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
self.close_button.setIconSize(QSize(16, 16))
self.close_button.setFixedSize(QSize(16, 16))
self.close_button.clicked.connect(self.close_window)
self.buttons_layout.addWidget(self.close_button)
self.layout.addWidget(self.title)
self.layout.addLayout(self.buttons_layout)
self.setLayout(self.layout)
self.current_mouse_position = QPoint(0, 0)
def minimize_window(self):
self.main_window.showMinimized()
def close_window(self):
self.main_window.close()
def mousePressEvent(self, event):
self.current_mouse_position = self.mapToGlobal(event.pos())
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
new_mouse_position = self.mapToGlobal(event.pos())
mouse_movement = new_mouse_position - self.current_mouse_position
self.current_mouse_position = new_mouse_position
window_pos = QPoint(self.main_window.geometry().x(), self.main_window.geometry().y())
new_window_pos = window_pos + mouse_movement
self.main_window.setGeometry(QRect(new_window_pos, self.main_window.size()))
And this is the result of this:
For clarity, I will add a stroke to each bar element.
I also added the Qt.WA_TranslucentBackground attribute to the main window to make it transparent and then rounded the corners.
The problem is this: as you can see in the screenshots, the close buttons and the title have different sizes and if I set them to gray too, it will be a jagged line, moreover, the buttons have a transparent background, while the title has a gray one.
I need to leave it like this.
Is it possible to create a placeholder widget, set styles (color, rounded corners) for it, and place the title and buttons on it? Approximately like this:
I am trying to make a programmable sequencer where I can configure objects that I've programmed and create a list of them to run. That requires me to instantiate that object by defining it's properties and I'd like to make a tab control on the blue widget shown below that has an inputs and outputs tab.
Anytime I try to implement this, it replaces all of the other widgets:
Surely that has to be a way to use a standard tab control in a widget right?
Code below:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QGridLayout, QLabel, QMainWindow, QWidget, QTabWidget, QVBoxLayout
from PyQt5.QtGui import QColor, QPalette
# Placeholder widget for setting up layout
class Color(QWidget):
def __init__(self, color):
super().__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
# Creating tab widgets
class MyTabWidget(QTabWidget):
def __init__(self):
super().__init__()
self.setTabPosition(QTabWidget.North)
for n, color in enumerate(['blue', 'purple']):
self.addTab(Color(color), color)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
layout = QGridLayout()
# 1
layout.addWidget(Color("red"), 0, 0, 2, 1)
# 2
layout.addWidget(Color("yellow"), 2, 0, 3, 1)
# 3
layout.addWidget(Color("green"), 0, 1, 5, 4)
# 4
# layout.addWidget(Color("blue"), 0, 5, 5, 1)
tabs = MyTabWidget()
layout.addWidget(tabs, 0, 5, 5, 1)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The size policy of the QTabWidget is set to stretch and since the stretch factors of the QGridLayout items is 0 then it will cause the items to be compressed. The solution is to set the stretch factors to 1:
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
for column in range(layout.columnCount()):
layout.setColumnStretch(column, 1)
for row in range(layout.rowCount()):
layout.setRowStretch(row, 1)
I'm trying to put a QProgressBar below a QPushButton and align them on the center of a QVBoxLayout, but for some reason the button stays left aligned when the progress bar is present and center aligned if it is not.
I tried setting the alignment of all parent widgets and layouts to Qt.AlignCenter, but the progress bar keeps making the button go to the left.
connect_box = QVBoxLayout()
connect_box.setAlignment(Qt.AlignCenter)
connect_button = QPushButton('Connect')
connect_button.setFixedSize(120, 30)
connect_progress = QProgressBar()
connect_progress.setRange(0, 10000)
connect_progress.setValue(0)
connect_box.addWidget(connect_button)
connect_box.addWidget(connect_progress)
connect_box.setContentsMargins(0, 20, 0, 0)
I expect the button to stay center aligned when the progress bar is added.
Try it:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MyWidget(QWidget):
def __init__(self):
super().__init__()
connect_button = QPushButton('Connect')
connect_button.setFixedSize(120, 30)
connect_progress = QProgressBar()
connect_progress.setRange(0, 10000)
connect_progress.setValue(0)
connect_box = QVBoxLayout(self)
connect_box.setAlignment(Qt.AlignCenter)
connect_box.addWidget(connect_button, alignment=Qt.AlignCenter) # < ----
connect_box.addWidget(connect_progress)
connect_box.setContentsMargins(0, 20, 0, 0)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
I'm trying to incorporate a QSplitter. The code works perfectly from a functionality standpoint, but the QSplitter itself doesn't appear correctly under the default PyQt style... possibly because it is itself embedded within a vertical splitter. This is confusing for the user.
If you uncomment out the line (and thus change the default PyQt style), the QSplitter visualizes correctly only when hovered over... however, I also don't want this other style.
Can anyone provide any guidance on this matter?
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
L_layout = QGridLayout()
R_layout = QGridLayout()
L_widgets = QWidget()
L_widgets.setLayout(L_layout)
R_widgets = QWidget()
R_widgets.setLayout(R_layout)
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
btn1 = QPushButton('btn1')
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
textedit = QTextEdit()
L_layout.addWidget(topleft, 0, 0, 1, 1)
L_layout.addWidget(btn1, 1, 0, 1, 1)
R_layout.addWidget(textedit)
splitter1 = QSplitter(Qt.Horizontal,frameShape=QFrame.StyledPanel,frameShadow=QFrame.Plain)
splitter1.addWidget(L_widgets)
splitter1.addWidget(R_widgets)
splitter1.setStretchFactor(1,1)
splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
hbox.addWidget(splitter2)
self.setLayout(hbox)
#QApplication.setStyle(QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QSplitter demo')
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
EDIT: This is apparently a known macOS bug. When viewed on Linux, the bar of splitter1 has the same look as splitter2. I'll leave this topic open in case anyone else knows of a suitable workaround for mac.
Because the QPushButton has default minimum size, when you want to move splitter to left,
the button has reached its minimum size. So you can not move left anymore, otherwise the left will will collapse.
So if you want the left showing as you want, you can set the minimum size off button widget.
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
L_layout = QGridLayout()
R_layout = QGridLayout()
L_widgets = QWidget()
L_widgets.setLayout(L_layout)
R_widgets = QWidget()
R_widgets.setLayout(R_layout)
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
btn1 = QPushButton('btn1')
btn1.setMinimumWidth(1) # For example : set the minimum width to 1, then you can move left until the btn1 width is 1
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
textedit = QTextEdit()
L_layout.addWidget(topleft, 0, 0, 1, 1)
L_layout.addWidget(btn1, 1, 0, 1, 1)
R_layout.addWidget(textedit)
splitter1 = QSplitter(Qt.Horizontal,frameShape=QFrame.StyledPanel,frameShadow=QFrame.Plain)
splitter1.addWidget(L_widgets)
splitter1.addWidget(R_widgets)
splitter1.setStretchFactor(1,1)
splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)
splitter2.addWidget(bottom)
hbox.addWidget(splitter2)
self.setLayout(hbox)
#QApplication.setStyle(QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QSplitter demo')
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm trying to add a simple square to a grid layout, but it doesn't seem to work.
Here is the code:
self.resultFrame = QFrame()
self.resultFrame.setGeometry(100, 200, 0, 0)
self.resultFrame.setStyleSheet("QWidget { background-color: #000 }")
gridLayout.addWidget(self.resultFrame, 0, 0, 1, 4)
If I switch self.resultFrame to, for example, a QLabel or a QPushButton, it seems to work fine, but not with QFrame.
What could I be doing wrong?
It's hard to make out what you could be doing wrong since we don't see the rest of the code, but at least I can confirm that this simple example draws a black frame and button inside a grid layout.
from PySide import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent = None):
super(MyWindow, self).__init__(parent)
self.resultFrame = QtGui.QFrame()
self.resultFrame.setGeometry(100, 200, 0, 0)
self.resultFrame.setStyleSheet("QFrame { background-color: #000 }")
self.myButton = QtGui.QPushButton(self, 'test')
gridLayout = QtGui.QGridLayout()
gridLayout.addWidget(self.resultFrame, 0, 0)
gridLayout.addWidget(self.myButton, 0, 1)
self.setLayout(gridLayout)
self.resize(400, 400)
self.show()
win = MyWindow()
It could also be the way you use spans when using the grid layout's addWidget method with the rest of your items. For example, if I used gridLayout.addWidget(self.resultFrame, 0, 0, 1 ,4) in the code above the button will no longer be in view!