How to customise QGroupBox title in PyQt5? - python

Here's a piece of code that creates a simple QGroupBox:
from PyQt5.QtWidgets import (QApplication, QWidget,
QGroupBox, QGridLayout)
class QGroupBoxTest(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
gb = QGroupBox()
gb.setTitle('QGroupBox title')
appLayout = QGridLayout()
appLayout.addWidget(gb, 0, 0)
self.setLayout(appLayout)
self.setWindowTitle('QGroupBox test window')
self.setGeometry(300, 300, 300, 200)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
test = QGroupBoxTest()
test.show()
sys.exit(app.exec_())
and here's what the output looks like to me:
Now let's say I want to add some style to it and I do this by adding this line to the initUI method:
gb.setStyleSheet("border: 1px solid gray; border-radius: 5px")
here's the output:
As can be clearly seen from the pic, the title has ended up inside the frame and now is overlapping the frame border.
So I have three questions actually:
Why did the title move?
How do I move it about and place it wherever I want (if possible)?
What if I simply want to round off border corners without specifying the border-style property. Let's say I want the border-style to stay the same as in the first pic but with rounded corners. How do I do that?

1) Probably that's the default QT placement, in the first image the platform style is used, and its take care of borders and title placement, when you change the stylesheet you override something and you get the ugly placement.
2) You can control the "title" position using the QGroupBox:title controls, for example:
gb.setStyleSheet('QGroupBox:title {'
'subcontrol-origin: margin;'
'subcontrol-position: top center;'
'padding-left: 10px;'
'padding-right: 10px; }')
will result in something like this:
3) My suggestion is to create different strings for the stylesheet attributes you want to change, then compose them to create the style you want.

Even though this question has already been answered, I will post what I've figured out regarding technics of applying style sheets to widgets in PyQt which partly answers my original question. I hope someone will find it useful.
I think it's nice to keep the styles in separate css(qss) files:
/*css stylesheet file that contains all the style information*/
QGroupBox {
border: 1px solid black;
border-radius: 5px;
}
QGroupBox:title{
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 0 3px 0 3px;
}
and the python code looks like this:
from PyQt5.QtWidgets import (QApplication, QWidget,
QGroupBox, QGridLayout)
from PyQt5.QtCore import QFile, QTextStream
class QGroupBoxTest(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
gb = QGroupBox()
gb.setTitle('QGroupBox title:')
gb.setStyleSheet(self.getStyleSheet("./styles.qss"))
appLayout = QGridLayout()
appLayout.addWidget(gb, 0, 0)
self.setLayout(appLayout)
self.setWindowTitle('QGroupBox test window')
self.setGeometry(300, 300, 300, 300)
def getStyleSheet(self, path):
f = QFile(path)
f.open(QFile.ReadOnly | QFile.Text)
stylesheet = QTextStream(f).readAll()
f.close()
return stylesheet
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
test = QGroupBoxTest()
test.show()
sys.exit(app.exec_())
which yields the following output:

Related

Qcompleter autocomplete in pyqt5 not showing options as i type

I've added a dropdown using Qcombobox.
It has three options: B4, B4.5, B5
If user selects B4.5 and starts typing in the QlineEdit, the autopopulate options should come up based on the list "names" but it doesn't happen. What am I doing wrong ?
Here's the code :
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QCompleter
import sys
from PyQt5.Qt import QApplication, QLabel, QLineEdit
class KnowledgeBaseGui(QMainWindow):
def __init__(self):
super().__init__()
self.mwidget = QMainWindow(self)
self.layout = QGridLayout()
self.setLayout(self.layout)
self.setGeometry(500, 400, 650, 650)
self.setWindowTitle("pyqt5")
self.nand_cmd_menu_current_text = None
def cmd_button(self):
self.combo_cmd = QComboBox(self)
self.combo_cmd.setGeometry(80, 175, 115, 35)
self.combo_cmd.setFont(QFont('Times', 11))
self.combo_cmd.setStyleSheet("background-color: rgb(166,180,242);border: 2px solid rgb(20,20,20)")
self.combo_cmd.addItems(["CMDs", "B4.5", "B5", "B6"])
self.combo_cmd.currentTextChanged.connect(self.design_manual_select)
pass_val = self.design_manual_select(self.nand_cmd_menu_current_text)
def design_manual_select(self, val):
names = ["apple", "alpha", "beta", "blackberry", "charlie", "delta", "chilton", "dawn"]
cmd_lineEdit = QLineEdit(self)
cmd_lineEdit.setGeometry(200, 175, 150, 35)
if val == "B4.5":
print(val)
completer = QCompleter(names)
cmd_lineEdit.setCompleter(completer)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv) # To create the App
app.setStyleSheet("QMainWindow{"
"background-image:url(abc.jpg); background-color: rgb(130,130,125);"
"border: 1px solid rgb(1,1,1)}")
CallKnowledgeBaseGui = KnowledgeBaseGui()
CallKnowledgeBaseGui.cmd_button()
CallKnowledgeBaseGui.show()
sys.exit(app.exec()) # To start the App
Well, to be honest, there are a few things that are wrong.
you're creating a child QMainWindow that you're not using (and a child main window is rarely used anyway);
you're creating a layout, but you're not using it since you're not adding widgets to it;
QMainWindow does not support setting layouts anyway, and a central widget (with its own layout) should be used instead;
design_manual_select is called on startup, but such function should be theoretically called upon user interaction;
that function continuously creates a new QLineEdit on which the completer is set, and that new line edit is never shown anyway (widgets created with a parent in the constructor and not added to a layout are not automatically shown if the parent is already visible);
there's no function that resets the completer if the current combo item is not B4.5;
So, let's fix all that:
a QWidget must be set as a central widget, and a layout must be set for it;
widgets must be added to that layout, and just once;
since the completer must change upon current text change, it must be properly updated if the text doesn't match;
class KnowledgeBaseGui(QMainWindow):
def __init__(self):
super().__init__()
self.mwidget = QWidget()
self.setCentralWidget(self.mwidget)
self.layout = QGridLayout(self.mwidget)
self.setGeometry(500, 400, 650, 650)
self.setWindowTitle("pyqt5")
self.combo_cmd = QComboBox()
self.combo_cmd.setFont(QFont('Times', 11))
self.combo_cmd.setStyleSheet("background-color: rgb(166,180,242);border: 2px solid rgb(20,20,20)")
self.combo_cmd.addItems(["CMDs", "B4.5", "B5", "B6"])
self.layout.addWidget(self.combo_cmd)
self.combo_cmd.currentTextChanged.connect(self.design_manual_select)
self.cmd_lineEdit = QLineEdit()
self.layout.addWidget(self.cmd_lineEdit)
def design_manual_select(self, val):
if val == "B4.5":
names = ["apple", "alpha", "beta", "blackberry", "charlie", "delta", "chilton", "dawn"]
self.cmd_lineEdit.setCompleter(QCompleter(names))
else:
self.cmd_lineEdit.setCompleter(None)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyleSheet("QMainWindow{"
"background-image:url(abc.jpg); background-color: rgb(130,130,125);"
"border: 1px solid rgb(1,1,1)}")
callKnowledgeBaseGui = KnowledgeBaseGui()
callKnowledgeBaseGui.show()
sys.exit(app.exec())

Button doesn't show up

i'm trying to do a simple GUI for a python script that convert some text into a specific format but buttons doesn't show up in the window.
I first create the button class
class Button(QPushButton):
def __init__(self, btn_name=None):
super().__init__()
self.button = QPushButton(btn_name)
self.button.setCursor(
QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
self.button.setStyleSheet(
"""*{border: 4px solid 'green';
border-radius: 45px;
font-size: 35px;
color: 'white';
padding: 25px 0;
margin: 100px, 200px}
*:hover{background: 'green'}
*:pressed{background: 'lightgreen'}"""
)
Then create the window class like this
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.window = QWidget()
self.window.resize(500, 500)
self.window.setWindowTitle("Pantuflis Software")
self.window.setFixedWidth(1000)
self.window.setStyleSheet("background: 'black';")
self.grid = QGridLayout()
self.window.setLayout(self.grid)
self.button = Button("Play")
self.grid.addWidget(self.button)
self.window.show()
Finally add the rest
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
But the button doesn't show up, only the main window does. I also tried the same but without creataing the button from my own class and works. Must be something wrong in the button class but i can't see what is.
If you are going to implement inherence then you have to apply the changes to the class. In your case it has a class that inherits from QPushButton but where you create the custom button which is not necessary, the same with the main window. My recommendation is that the OP should review his notes about inheritance.
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QCursor
from PyQt6.QtWidgets import QApplication, QGridLayout, QPushButton, QWidget
class Button(QPushButton):
def __init__(self, btn_name=""):
super().__init__(btn_name)
self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
self.setStyleSheet(
"""*{border: 4px solid 'green';
border-radius: 45px;
font-size: 35px;
color: 'white';
padding: 25px 0;
margin: 100px, 200px}
*:hover{background: 'green'}
*:pressed{background: 'lightgreen'}"""
)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.resize(500, 500)
self.setWindowTitle("Pantuflis Software")
self.setFixedWidth(1000)
self.setStyleSheet("background: 'black';")
self.grid = QGridLayout(self)
self.button = Button("Play")
self.grid.addWidget(self.button)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

PyQt5 QPushButton setSyleSheet does not change button color when pressed

After studying various examples in this forum, I tried to change the color of a button when pressed. The button is normally blue, and when it is pressed I want it to turn red. The following code does display a blue button with white text, but it does not change to red when pressed. Please advise. I'm fairly new to learning python/pyqt5.
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton
class Push_button(QPushButton):
def __init__(self, parent=None):
super(Push_button, self).__init__(parent)
self.setStyleSheet("background-color: rgb(0,0,255); color: rgb(255,255,255); \
pressed {background-color : rgb(255,0,0); color: rgb(255,255,255);} ")
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.myButton = Push_button(self)
self.myButton.setText("myButton")
self.myButton.clicked.connect(self.myButtonClicked)
def myButtonClicked(self):
print("myButtonClicked")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
You are not using selectors correctly.
Right now your stylesheet sets the blue background color universally, and the red color for classes named "pressed".
self.setStyleSheet('''
QPushButton {
background-color: rgb(0,0,255); color: rgb(255,255,255);
}
QPushButton:pressed {
background-color : rgb(255,0,0); color: rgb(255,255,255);
}
''')
Read more about selector types in the official documentation.

Why does a class inhering another class not produce the same results as 'another class'?

I am developing an application in Python using PyQt5. Here is the code in question:
class Dialog(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout()
self.main = QtWidgets.QWidget()
self.main.setLayout(self.layout)
self.setStyleSheet(QMainWindowStyle)
self.setCentralWidget(self.main)
self.show()
class AppearanceTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
class SettingsDialog(Dialog):
def __init__(self):
super().__init__()
self.tabs = QtWidgets.QTabWidget(self)
self.tabs.setStyleSheet(QTabWidgetStyle)
self.layout.addWidget(self.tabs)
self.tab_appearance = AppearanceTab()
self.tab_appearance.setStyleSheet(QWidgetStyle)
self.tab_appearance_layout = QtWidgets.QGridLayout()
self.tab_appearance.setLayout(self.tab_appearance_layout)
self.tabs.addTab(self.tab_appearance, "Appearance")
self.tab_server = QtWidgets.QWidget()
self.tab_server.setStyleSheet(QWidgetStyle)
self.tab_server_layout = QtWidgets.QGridLayout()
self.tab_server.setLayout(self.tab_server_layout)
self.tabs.addTab(self.tab_server, "Server")
Why is it that when self.tab_appearance is an AppearanceTab instance (which should be a copy of QWidget) it has a different style to self.tab_server (i.e. background colour changes) when self.tab_server is an instance of QWidget?
The stylesheet just defines background-color: #333333 and color: #dddddd.
Thanks in advance.
EDIT:
I believe that the stylesheet is not being properly applied to AppearanceTab, however I don;t know why that would be seeing as it just inherits from QWidget.
EDIT 2:
A MCVE (along with the rest of my project) can be found on github.
In the documentation, there is a paragraph the paragraph about inheritance and style:
Inheritance
In classic CSS, when font and color of an item is not explicitly set, it gets automatically inherited from the parent. When using Qt Style Sheets, a widget does not automatically inherit its font and color setting from its parent widget.
If we want to set the color on a QGroupBox and its children, we can write:
qApp->setStyleSheet("QGroupBox, QGroupBox * { color: red; }");
So you probably want to to change
QMainWindowStyle = QMainWindow {color: #dddddd; background-color: #333333;}
to
QMainWindowStyle = QMainWindow, QMainWindow * {color: #dddddd; background-color: #333333;}
so that all the child widgets of the main window have the same style.
Try it:
from PyQt5 import QtWidgets
class Dialog(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout()
self.main = QtWidgets.QWidget()
self.main.setLayout(self.layout)
# self.setStyleSheet(QMainWindowStyle)
self.setCentralWidget(self.main)
self.show()
class AppearanceTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
class SettingsDialog(Dialog):
def __init__(self):
super().__init__()
self.tabs = QtWidgets.QTabWidget(self)
# self.tabs.setStyleSheet(QTabWidgetStyle)
self.layout.addWidget(self.tabs)
self.tab_appearance = AppearanceTab()
# self.tab_appearance.setStyleSheet(QWidgetStyle)
## self.tab_appearance.setStyleSheet("QWidget, QWidget * {color: #dddddd; background-color: #333333;}") #note: Tried this however it didn't work.
self.tab_appearance_layout = QtWidgets.QGridLayout()
self.tab_appearance.setLayout(self.tab_appearance_layout)
self.tabs.addTab(self.tab_appearance, "Appearance")
self.tab_server = QtWidgets.QWidget()
# self.tab_server.setStyleSheet(QWidgetStyle)
self.tab_server_layout = QtWidgets.QGridLayout()
self.tab_server.setLayout(self.tab_server_layout)
self.tabs.addTab(self.tab_server, "Server")
style = """
QWidget {
color: #dddddd;
background-color: #333333;
}
QMainWindow {
color: #dddddd;
background-color: #333333;
}
QTabWidget {
background-color: #333333;
color: #dddddd;
}
QTabBar {
color: #dddddd;
background-color: #333333;
}
"""
if __name__ == "__main__":
QtWidgets.QApplication.setStyle(QtWidgets.QStyleFactory.create("Fusion"))
app = QtWidgets.QApplication([])
app.setStyleSheet(style) # < ---
d = SettingsDialog()
print(app.exec_())

PyQt: Getting the amount of lines from QTextEdit

I am trying to make a chat application, so i added the QTextEdit widget where user types the content, maximum height of widget is 30 pixels, so basically one line.
self.msgtext = QtGui.QTextEdit(self)
self.msgtext.setObjectName('msgtext')
self.msgtext.setStyleSheet("#msgtext {background-color: black; color: yellow; font-size: 18pt; }")
self.msgtext.setMaximumSize(500, 30)
self.msgtextplain = self.msgtext.toPlainText()
I want to increase the maximum height of the widget whenever user get's one new line, But i don't know if there is any signal that can tell that i have reached new line.
Is there any signal, that can count the amount of lines from QTextEdit?
You can use blockCount() but don't forget to also resize whatever parent you are using for your QTextEdit. Here is an example:
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
class Window(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.msgtext = QtWidgets.QTextEdit(self)
self.msgtext.setObjectName('msgtext')
self.msgtext.setStyleSheet("#msgtext {background-color: black; color: yellow; font-size: 18pt; }")
self.msgtext.resize(500, 30)
self.msgtextplain = self.msgtext.toPlainText()
self.msgtext.textChanged.connect(self.changed)
def changed(self):
lines = self.msgtext.document().blockCount()
self.msgtext.resize(500, 30*lines)
self.resize(500, 30*lines)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
It's PyQt5. To do this in PyQt4 change everything that is QtWidgets to QtGui (and check the import lines evidently; this should be enough but do tell if you have any difficulties). Here is the result:

Categories

Resources