I want the effect in the picture. The qlabel is in the layout, and the font is centered. Below is the code I wrote, which is different from what I want. First, qlabel is outside the layout, and second, the font is not centered.
import sys
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QLabel, QApplication, QWidget, QVBoxLayout, QStyleOption, QPainter, QStyle
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setGeometry(100, 100, 500, 500)
vbox = QVBoxLayout()
self.setLayout(vbox)
a = QLabel('aaa')
b = QLabel('bbb')
vbox.addWidget(a)
vbox.addWidget(a, alignment=Qt.AlignHCenter | Qt.AlignTop)
vbox.addWidget(b, alignment=Qt.AlignHCenter | Qt.AlignBottom)
self.setStyleSheet("""
Example{
border-width: 1px;
border-style: solid;
border-color: red;
min-width:500px;
max-width:500px;
min-height:500px;
max-height:500px;
padding:1px 1px 1px 1px;
margin-bottom:30px;
}
QLabel{
min-width:500px;
max-width:500px;
min-height:50px;
max-height:50px;
margin:0px;
padding:0px;
background-color:#cdcdcd;
text-align: center center;
}
""")
self.show()
def paintEvent(self, event):
super(Example, self).paintEvent(event)
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The logic of the layouts is to handle the geometry of the elements but you are also handling the geometry with the stylesheet, causing the problem you observe. On the other hand, the QLabel does not have the text-align property but you have to use qproperty-alignment: AlignCenter;.
To avoid this it is better to avoid managing the geometry with stylesheet but with the methods of the class, considering the solution is:
import sys
from PyQt4.QtCore import Qt
from PyQt4.QtGui import (
QLabel,
QApplication,
QWidget,
QVBoxLayout,
QStyleOption,
QPainter,
QStyle,
)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.setGeometry(100, 100, 500, 500)
self.label_a = QLabel("aaa")
self.label_b = QLabel("bbb")
self.label_a.setFixedHeight(50)
self.label_b.setFixedHeight(50)
vbox = QVBoxLayout(self)
vbox.setContentsMargins(1, 1, 1, 1)
vbox.addWidget(self.label_a)
vbox.addWidget(QWidget(), stretch=1)
vbox.addWidget(self.label_b)
self.setFixedSize(500, 500)
self.setStyleSheet(
"""
Example{
border-width: 1px;
border-style: solid;
border-color: red;
padding:1px 1px 1px 1px;
}
QLabel{
margin:0px;
padding:0px;
background-color:#cdcdcd;
qproperty-alignment: AlignCenter;
}
"""
)
def paintEvent(self, event):
super(Example, self).paintEvent(event)
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
def main():
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Related
I made three group boxes in a vertical layout. What I want is that they are right next to each other, no space in between. I set window layout margins (.setContentsMargins) and it removes all margins except the one in between them. I tried setting gbox style sheet, padding and margins to 0 but nothing happens. Any ideas?
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QGroupBox
class mainWindow(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 800, 600)
self.setFixedSize(800, 600)
self.winLayout = QVBoxLayout()
# ==================================================================
self.gboxFirst, self.gboxFirstLayout = self.create_v_layout()
self.gboxSecond, self.gboxSecondLayout = self.create_v_layout()
self.gboxThird, self.gboxThirdLayout = self.create_v_layout()
self.winLayout.addWidget(self.gboxFirst)
self.winLayout.addWidget(self.gboxSecond)
self.winLayout.addWidget(self.gboxThird)
self.winLayout.setContentsMargins(0,0,0,0)
# ==================================================================
# Coloring gbox-es
self.gboxFirst.setStyleSheet(""" QGroupBox {
background-color: red;
}""")
self.gboxSecond.setStyleSheet(""" QGroupBox {
background-color: green;
}""")
self.gboxThird.setStyleSheet(""" QGroupBox {
background-color: blue;
}""")
self.setLayout(self.winLayout)
self.show()
def create_v_layout(self):
gbox = QGroupBox()
gboxLayout = QVBoxLayout()
gbox.setLayout(gboxLayout)
return gbox, gboxLayout
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = mainWindow()
app.exec_()
How to make a Hover effect for Two or More QLabels at a time? For Example, In my code, I need to hover effect for Lbl1 and Lbl2 at a time. ( Either Mouse enter into a QLabel 1 or QLabel 2, both QLabels will take a Hover Effect)
from PyQt5 import QtWidgets
class Hover_Multiple(QtWidgets.QWidget):
def __init__(self):
super(). __init__()
self.setWindowTitle("Hover Effects")
self.lbl1 = QtWidgets.QLabel("Python")
self.lbl1.setFixedSize(100,50)
self.lbl1.setStyleSheet(mystyle())
self.lbl2 = QtWidgets.QLabel("PyQt5")
self.lbl2.setStyleSheet(mystyle())
self.lbl2.setFixedSize(100,50)
self.hbox = QtWidgets.QHBoxLayout()
self.hbox.addStretch()
self.hbox.addWidget(self.lbl1)
self.hbox.addWidget(self.lbl2)
self.hbox.addStretch()
self.hbox.setSpacing(0)
self.hbox.setContentsMargins(0,0,0,0)
self.setLayout(self.hbox)
def mystyle():
return"""
QLabel
{
background-color:lightgreen;
min-height : 25%; min-width : 40%;
border:0px solid;border-color:red;
text-align:centre ;font-size :10pt; font-family:Trebuchet MS; color:Black; padding : 2px;
}
QLabel::hover
{
background-color: red;
color :white;
}
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = Hover_Multiple()
mainwindow.show()
sys.exit(app.exec_())
A possible solution is to use a qproperty that serves as a flag to change the painting, and that qproperty must be changed in the widgets when some widget is triggered by the QEvent::HoverEnter and QEvent::HoverLeave events and that can be done using an eventfilter.
from PyQt5 import QtCore, QtWidgets
class HoverHelper(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._widgets = []
#property
def widgets(self):
return self._widgets
def add_widget(self, widget):
if not isinstance(widget, QtWidgets.QWidget):
raise TypeError(f"{widget} must be QWidget object")
widget.installEventFilter(self)
widget.setAttribute(QtCore.Qt.WA_Hover)
self.widgets.append(widget)
def eventFilter(self, obj, event):
if obj in self.widgets:
if event.type() == QtCore.QEvent.HoverEnter:
self.change_property(True)
elif event.type() == QtCore.QEvent.HoverLeave:
self.change_property(False)
return super().eventFilter(obj, event)
def change_property(self, hovered):
for widget in self.widgets:
widget.setProperty("hovered", hovered)
widget.style().polish(widget)
class Hover_Multiple(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Hover Effects")
self.setStyleSheet(style_sheet())
self.lbl1 = QtWidgets.QLabel("Python")
self.lbl1.setFixedSize(100, 50)
self.lbl2 = QtWidgets.QLabel("PyQt5")
self.lbl2.setFixedSize(100, 50)
lay = QtWidgets.QHBoxLayout(self)
lay.addStretch()
lay.addWidget(self.lbl1)
lay.addWidget(self.lbl2)
lay.addStretch()
lay.setSpacing(0)
lay.setContentsMargins(0, 0, 0, 0)
helper = HoverHelper(self)
helper.add_widget(self.lbl1)
helper.add_widget(self.lbl2)
def style_sheet():
return """
QLabel{
background-color: lightgreen;
min-height: 25%;
min-width: 40%;
border: 0px solid;
border-color: red;
text-align: center;
font-size: 10pt;
font-family: Trebuchet MS;
color: black;
padding: 2px;
}
QLabel[hovered="true"]{
background-color: red;
color: white;
}
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainwindow = Hover_Multiple()
mainwindow.show()
sys.exit(app.exec_())
I am creating a LoginWindow and am using QLineEdit in order to make a place for my users to enter their details. Right now, I'm focused on creating the GUI. As shown in the picture, I am not sure why the layout looks like that, considering how I have setAlignment to AlignCenter. This also goes for QPushButton. Is there a class I am not aware to fix this formatting issue?
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout
import time #For time sleep
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("MidiScribe - Login Window")
self.setFixedSize(800,800)
self.setStyleSheet("""background-color: crimson;
border-color: maroon;
border: 2.5px outset rgb(128, 128, 128);
border-radius: 3px;""")
container = QWidget()
self.setCentralWidget(container)
mainLayout = QVBoxLayout(container)
self.username = QLineEdit()
self.username.setFixedWidth(300)
self.username.setStyleSheet("""background-color: white;""")
mainLayout.addWidget(self.username)
self.username.setAlignment(QtCore.Qt.AlignCenter)
self.setLayout(mainLayout)
self.password = QLineEdit()
self.password.setFixedWidth(300)
self.password.setStyleSheet("""background-color: white""")
mainLayout.addWidget(self.password)
self.password.setAlignment(QtCore.Qt.AlignCenter)
self.setLayout(mainLayout)
self.loginbutton = QPushButton("Login")
self.loginbutton.setFixedSize(50,50)
self.loginbutton.setStyleSheet("QPushButton { background-color: lightcoral }"
"QPushButton:Hover { background-color: lightpink }"
"QPushButton:pressed { background-color: indianred }" )
mainLayout.addWidget(self.loginbutton)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
There are many solutions for this case, but among them is to use a container that has the minimum size to show all the widgets and that is established through a QGridLayout:
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("MidiScribe - Login Window")
self.setFixedSize(800, 800)
self.setStyleSheet(
"""background-color: crimson;
border-color: maroon;
border: 2.5px outset rgb(128, 128, 128);
border-radius: 3px;"""
)
self.username = QLineEdit(alignment=QtCore.Qt.AlignCenter)
self.username.setFixedWidth(300)
self.username.setStyleSheet("""background-color: white;""")
self.password = QLineEdit(alignment=QtCore.Qt.AlignCenter)
self.password.setFixedWidth(300)
self.password.setStyleSheet("""background-color: white""")
self.loginbutton = QPushButton("Login")
self.loginbutton.setFixedSize(50, 50)
self.loginbutton.setStyleSheet(
"QPushButton { background-color: lightcoral }"
"QPushButton:Hover { background-color: lightpink }"
"QPushButton:pressed { background-color: indianred }"
)
container = QWidget(objectName="container")
container.setStyleSheet("QWidget#container{border: none}")
container.setContentsMargins(0, 0, 0, 0)
lay = QVBoxLayout(container)
lay.addWidget(self.username, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.password, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.loginbutton, alignment=QtCore.Qt.AlignCenter)
container.setFixedSize(container.sizeHint())
central_widget = QWidget()
self.setCentralWidget(central_widget)
grid_layout = QGridLayout(central_widget)
grid_layout.addWidget(container, 1, 1)
Just do alignment for mainLayout:
mainLayout.addWidget(self.loginbutton, alignment=QtCore.Qt.AlignCenter)
mainLayout.setAlignment(QtCore.Qt.AlignCenter)
I have a code to generate a GUI with PyQt5 that enables a user to create multiple buttons (QPushButton) based on an entry (QLineEdit), and to delete these buttons when pressing an "X" button (deleteLater()).
My problem is that when deleting some of these buttons by pressing the associated X-button, this leaves a small empty space where the buttons were initially, and I therefore wonder how to remove these spaces?
Image of the empty spaces
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLineEdit, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QGroupBox, QScrollArea, QLabel
from PyQt5.QtCore import Qt
import sys
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.setWindowTitle("My Program")
self.setGeometry(100, 100, 1500, 1500)
self.initUI()
def initUI(self):
widgets = MainWidgets()
self.setCentralWidget(widgets)
class MainWidgets(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.grid = QGridLayout()
self.grid.setColumnStretch(0, 1)
self.grid.setColumnStretch(1, 1)
self.grid.setColumnStretch(2, 1)
self.grid.setColumnStretch(3, 1)
self.grid.setColumnStretch(4, 1)
self.groupBox = QGroupBox("Labels")
self.groupBox.setStyleSheet('''
QGroupBox::title {
subcontrol-position: top center;
}
''')
right_column_layout = QVBoxLayout(self.groupBox)
scrollArea = QScrollArea()
scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scrollArea.setWidgetResizable(True)
right_column_layout.addWidget(scrollArea)
scrollArea.setWidget(RightColWidgets())
self.grid.addWidget(self.groupBox, 0, 5, 1, 5)
self.setLayout(self.grid)
class RightColWidgets(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.layout = QVBoxLayout(self)
self.labelEntry = QLineEdit(self)
self.addLabelButton = QPushButton(self)
self.addLabelButton.setText("Add Label")
self.addLabelButton.clicked.connect(self.addNewLabel)
self.emptyspace = QLabel(self)
self.layout.addWidget(self.labelEntry, stretch=0)
self.layout.addWidget(self.addLabelButton, stretch=0)
self.layout.addWidget(self.emptyspace, stretch=1)
def addNewLabel(self):
labelname = self.labelEntry.text()
newLabelItems = Labels(self, labelname)
self.layout.insertWidget(2, newLabelItems)
class Labels(QWidget):
def __init__(self, parent, labelname, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.mylabelname = labelname
self.initUI()
def initUI(self):
self.labelButton = QPushButton(self)
self.labelButton.setText(str(self.mylabelname))
self.labelButton.setStyleSheet("""
QPushButton {border: 1px solid back; background: rgba(103, 186, 181, 0.5); padding-top: 10px; padding-bottom: 10px}
""")
self.labelButton.clicked.connect(self.printbutton)
self.buttonErase = QPushButton(self)
self.buttonErase.setText("X")
self.buttonErase.setStyleSheet("""
QPushButton {border: 1px solid back; padding-right: 5 px; padding-left: 5 px; padding-top: 10px; padding-bottom: 10px}
""")
self.buttonErase.clicked.connect(self.erasebutton)
layout = QHBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.labelButton, stretch=1)
layout.addWidget(self.buttonErase, stretch=0)
def printbutton(self):
print('clicked:', self.labelButton.text())
def erasebutton(self):
self.labelButton.deleteLater()
self.buttonErase.deleteLater()
if __name__ == '__main__':
app = QApplication(sys.argv)
# app.setStyle('Fusion')
window = MyWindow()
window.showMaximized()
sys.exit(app.exec_())
Deleting the children does not delete the container, so what you see is the empty Labels widget with the spacing of its layout contentsMargins().
A simple solution could be to directly connect the button with its own deleteLeter(), which automatically deletes its children:
self.buttonErase.clicked.connect(self.deleteLater)
A better solution would be to connect the signal to the parent and let it do everything necessary in a cleaner way, as you might need to keep track of the existing widgets (for instance, to remove them from the list of currently existing labels):
class RightColWidgets(QWidget):
# ...
def addNewLabel(self):
labelname = self.labelEntry.text()
newLabelItems = Labels(self, labelname)
self.layout.insertWidget(2, newLabelItems)
newLabelItems.buttonErase.clicked.connect(
lambda: self.deleteLabel(newLabelItems))
def deleteLabel(self, widget):
self.layout.removeWidget(widget)
widget.deleteLater()
Obviously, in this case you don't need to connect the clicked signal in the initUi of the Label class anymore.
Note that layout() is an existing (and dynamic) property of any QWidget, so you should not overwrite it.
I have QWidget, which contains QVBoxLayout and QLabel. Indeed when I put Qlabel inside QVBoxLayout it fill the QVBoxLayout. How to make QLabel ignore QVBoxLayout.
How to make the red border only around 'Text Label' ?
I've tried using setStyleSheet, setGeometry, but it didn't work. And I think using maximumsize is not the good option.
Thank you
A simple solution is to use QSizePolicy so that instead of expanding, it contracts to the minimum:
from PyQt5 import QtCore, QtWidgets
class Label(QtWidgets.QLabel):
def __init__(self, *args, **kwargs):
super(Label, self).__init__(*args, **kwargs)
self.setAlignment(QtCore.Qt.AlignCenter)
self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
lbl = Label("TextLabel")
lbl.setStyleSheet('''background: red;''')
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(lbl, alignment=QtCore.Qt.AlignCenter)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Try it:
import sys
from PyQt5.QtWidgets import *
class Widget(QWidget):
def __init__(self):
super().__init__()
label = QLabel("TextLabel")
layout = QGridLayout(self)
layout.addWidget(label)
CSS = """
QLabel {
font-family: Ubuntu-Regular;
font-size: 12px;
qproperty-alignment: AlignCenter;
color: blue;
border: 3px solid red;
border-radius: 4px;
min-height: 40px;
max-height: 40px;
min-width: 48px;
max-width: 100px;
background: yellow;
}
"""
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyleSheet(CSS)
ex = Widget()
ex.show()
app.exec_()