I have a simple Python application with a PyQt QTableWidget with multiple columns and rows. If the user resizes a column to a size that is just smaller than the cell can hold.. the font of the cell will shrink by about 1 point in size (see animated GIF below). I have fiddled with almost every QTableWidget setting in QtDesigner. I would like the font size to remain consistent regardless.
What is causing this and how can I prevent it?
Update:
In my __main__ section, I create a stylesheet for buttons.
I apply this style sheet using setStyleSheet.
If I comment-out setStyleSheet, the problem goes away.
Adding QTableWidget{font: 9pt "Segoe UI";} also fixes, but I'd rather not do that.
Why is this stylesheet causing this?
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
stylesheet = """
QPushButton:hover, QComboBox:hover
{
background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #cbc9c5, stop: 1 #b9b7b5);
border: 2px solid #78879b;
border-radius: 3px;
}
"""
app.setStyleSheet(stylesheet)
myapp = MyProgram() # instantiate the main window
myapp.show() # show the main window
rc = app.exec_()
myapp.close()
sys.exit(rc) # exit with the same return code of Qt application
Related
Calling SetWindowCompositionAttribute can indeed add the acrylic effect of Win10 to the window, but I have a problem that I still can't solve, that is, how to realize the rounded window while adding the acrylic effect. As shown in the picture below, even if I use win32guiSetWindowRgn(int(self.winId()),win32gui.CreateRoundRectRgn(0, 0, 500, 500, 500, 500), True) in pyqt, the acrylic panel cannot be cropped. May I ask Do you have any good ideas?
The SetWindowCompositionAttribute API is not public. To apply one or more high quality effects to an image or a set of images, you can use Direct2D.
Here are some helpful links for you get started:
How to load an image into Direct2D effects using the FilePicker
Directional blur effect
Custom effects
And if you still you still want to use SetWindowCompositionAttribute API, I would suggest that you raise your voice on Feedback Hub.
You can use border-radius to make a workaround
(UpdateLayeredWindow is equivalent to WA_TranslucentBackground, SetWindowRgn don' have affect over SetWindowCompositionAttribute blur)
Full code:
Stylesheet = """
#Custom_Widget {
border-radius: 20px;
opacity: 100;
border: 8px solid #cdced4;
}
#closeButton {
min-width: 36px;
min-height: 36px;
border-radius: 10px;
}
#closeButton:hover {
color: #FFFFFF;
background: red;
}
"""
import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from BlurWindow.blurWindow import GlobalBlur
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setStyleSheet(Stylesheet)
self.setWindowFlag(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.resize(488, 388)
GlobalBlur(self.winId(),Acrylic=True,hexColor='#FFFFFF20')
self.Borders() #the real MainWindow
def Borders(self):
window = QMainWindow(self)
window.setAttribute(Qt.WA_TranslucentBackground)
window.setWindowFlag(Qt.FramelessWindowHint)
window.resize(500, 400)
self.widget = QWidget(window)
window.setCentralWidget(self.widget)
self.widget.setObjectName('Custom_Widget')
self.layout = QHBoxLayout(self.widget)
self.layout.addWidget(QPushButton(
'X', self,clicked=exit, objectName='closeButton'))
self.layout.addWidget(QLabel("<h2 style='color:blue;'>Blurry</h2>"))
window.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
UpdateLayeredWindow alpha example: https://github.com/wxWidgets/Phoenix/issues/1544
How do I get the font size and color of the text in the tooltip to change from that of the button? It keeps displaying as the size/font of the pushbutton instead of it's own. Also how do I get the text "leave the program" to actually fit in the tooltip?
I've tried this method and couldn't get it to work:
Setting the text colour of a tooltip in PyQt
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.resize(100, 100)
self.setWindowTitle("Example")
self.leave = QPushButton("X", self)
self.leave.setStyleSheet("background-color : grey ; color : red ; font: 20pt")
self.leave.setToolTip("Leave the Program")
self.setStyleSheet("QToolTip{background-color : blue ; color: k ; font: 12pt}")
self.leave.move(38, 25)
self.leave.resize(24, 50)
self.leave.clicked.connect(self.exit)
def exit(self):
app.quit()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The tool tip in question is a child of the button not of the main window so it will inherit the style sheet of the button (as well as those of the button's ancestors). Since you didn't specify a selector in the style sheet of the button, the style rules in this style sheet will be applied to all the button's children including the tool tip (unless they have a style sheet themselves). One way around this is to limit the button's style sheet to QPushButton objects only by doing something like
self.leave.setStyleSheet("QPushButton{background-color : grey ; color : red ; font: 20pt}")
Furthermore, to get the background color of the tool tip to change from default I needed to specify a style rule for its border, e.g.
self.setStyleSheet(" QToolTip{ border: 1px solid white; background-color: blue ; color: k ; font: 12pt}")
I am not sure if this is a bug or by design.
Screenshot:
I have to create a custom widget that looks like the following:
custom_widget_sketch
Each custom widget is a representation of one LIPO battery, and displays the battery volatge (V), status text (charging, discharging, etc), serial number of the battery (S/N) and three status LEDs (yellow, green and red)
After I have created the custom widget I need to add 30 of these in a grid of 6*5. My assumption here is that once I have created that custom widget it should be as simple as adding say a QPushButton in a QGridLayout like so:
custom_layput = QGridLayout()
custom_layout.addWidget(custom_widget, 0, 0)
custom_layout.addWidget(custom_widget, 0, 1)
.
.
.
custom_layout.addWidget(custom_widget, 6, 5)
The final screen would look like this:
main_window_sketch
Considering all of these requirements I have the following questions:
Will I able able to create such a complex/rich custom widget using PyQt5? Is it doable?
Is this the correct approach to create the custom widget: first draw a square using QPainter (this is the blue square in the custom_widget_sketch), then add QLineEdits to dispaly the voltage (V) text, serial number (S/N) text and the Status text, add a QLabel for displaying the "V", "S/N" and "STATUS" labels in the custom widget, then draw the three circles: one each for the yellow, green and red LEDs, then use a combination of QVBoxLayout and QHBoxLayout to arrange the QLineEdits, QLabels, the square and the circles (LED indicators)
How do I package this custom widget such that I can simply add it to a layout like I would add a QPushButton or a QLineEdit?
PS: The custom_widget_sketch also contains a line and a square with three lines inside it in the top left corner. This is to depict the connector for the LIPO battery. It may be too complex to implement that right now. So I would be happy even if I am able to implement everything other than these two elements
I have been through a few SO questions but they all refer to one tutorial, which is not my end goal.
I would appreciate any code snippets, general outline of code/steps to follow or links to any articles/tutorials that create custom widgets similar to the one I wish to create.
Python code for the custom widget I ended up creating. The widget looks as follows:
from PyQt5.QtGui import QPainter, QPen,QBrush,QColor
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout,QPushButton, QLineEdit, QLabel, QVBoxLayout, QHBoxLayout, QSizePolicy, QGroupBox
import sys
class BatteryStatusWidget(QWidget):
def __init__(self):
super(BatteryStatusWidget, self).__init__()
#Voltage widgets
self.voltage_text = QLineEdit()
self.voltage_text.setReadOnly(True)
self.voltage_label = QLabel("V")
self.voltage_label.setStyleSheet("QLabel {color : white}")
#Status widgets
self.status_text = QLineEdit()
self.status_text.setReadOnly(True)
self.status_label = QLabel("STATUS")
self.status_label_font = QtGui.QFont()
self.status_label_font.setPointSize(12)
self.status_label.setFont(self.status_label_font)
self.status_label.setAlignment(QtCore.Qt.AlignCenter)
self.status_label.setStyleSheet("QLabel {color : white}")
#Serial number
self.serial_number_text = QLineEdit()
self.serial_number_label = QLabel("S/N")
#LED widgets
self.yellow_led_label = QLabel()
self.yellow_led_label.setStyleSheet("QLabel {background-color : yellow; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")
self.green_led_label = QLabel()
self.green_led_label.setStyleSheet("QLabel {background-color : green; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")
self.red_led_label = QLabel()
self.red_led_label.setStyleSheet("QLabel {background-color : red; border-color : black; border-width : 1px; border-style : solid; border-radius : 10px; min-height: 20px; min-width: 20px}")
#Number Identifier Label
#This label is for tagging the widget with the same label as on the PCB
self.number_label = QLabel("Test")
self.number_label.setAlignment(QtCore.Qt.AlignCenter)
self.number_label_font = QtGui.QFont()
self.number_label_font.setPointSize(12)
self.number_label_font.setBold(True)
self.number_label.setFont(self.number_label_font)
#Layouts
#voltage layout
self.voltage_layout = QHBoxLayout()
self.voltage_layout.addWidget(self.voltage_text)
self.voltage_layout.addWidget(self.voltage_label)
#Serial number layout
self.serial_num_layout = QHBoxLayout()
self.serial_num_layout.addWidget(self.serial_number_label)
self.serial_num_layout.addWidget(self.serial_number_text)
#Voltage and status box layouts
self.blue_container = QWidget()
self.blue_container.setStyleSheet("background-color:rgb(77, 122, 194);")
self.blue_box_layout = QVBoxLayout()
self.blue_box_layout.addLayout(self.voltage_layout)
self.blue_box_layout.addWidget(self.status_text)
self.blue_box_layout.addWidget(self.status_label)
self.blue_container.setLayout(self.blue_box_layout)
#Blue box+ serial num layout
self.non_led_layout = QVBoxLayout()
#self.non_led_layout.addWidget(self.number_label)
self.non_led_layout.addWidget(self.blue_container)
self.non_led_layout.addLayout(self.serial_num_layout)
#LED layout
self.led_layout = QVBoxLayout()
self.led_layout.addWidget(self.yellow_led_label)
self.led_layout.addWidget(self.green_led_label)
self.led_layout.addWidget(self.red_led_label)
self.led_layout.addStretch(1)
#Main Layout
self.main_layout = QHBoxLayout()
self.main_layout.addLayout(self.non_led_layout)
self.main_layout.addLayout(self.led_layout)
#Main group box
self.main_group_box = QGroupBox()
self.main_group_box.setStyleSheet("QGroupBox{font-size: 10px}")
self.main_group_box.setTitle("Chan #")
self.main_group_box.setLayout(self.main_layout)
#Outer main layout to accomodate the group box
self.outer_main_layout = QVBoxLayout()
self.outer_main_layout.addWidget(self.main_group_box)
#Set the main layout
self.setLayout(self.outer_main_layout)
self.setWindowTitle("Battery Widget")
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = BatteryStatusWidget()
main_window.show()
app.exec_()
I was able to easily create 30 instances of the custom widget and add it to a QGridLayout as I posted in my question. The final GUI screen looks as follows:
There's no need to use QPainter for the blue square, as you can use stylesheets for your whole widget, the trick is to use selectors.
I tried to create your widget and used this stylesheet:
Battery {
background-color: white;
}
QFrame#statusFrame {
background-color: rgb(64, 112, 190);
}
QFrame#statusFrame QLabel {
color: white;
font-weight: bold;
font-size: 24pt;
}
QLineEdit {
border: 1px solid black;
font-size: 24pt;
}
#serialLabel {
font-weight: bold;
font-size: 16pt;
}
I created a "container" QWidget, the status rectangle is actually a QFrame with its own layout, which I named statusFrame (you can set it in designer, or by means of setObjectName(str)).
By using object names and child selectors, I was able to set specific fonts for its labels by using the QFrame#statusFrame QLabel selector (which means "apply to each QLabel that is a child of a QFrame"); I also set the serialLabel object name to the s/n label, allowing me to set a different font size.
You can do this from code or using designer, just remember to set the right object names and parent/children hierarchy.
I was able to draw the "connector" part too, which requires to set fixed margins to the main widget:
class Battery(QtWidgets.QWidget):
connPath = QtGui.QPainterPath()
connPath.addRect(30, 10, 40, 28)
connPath.moveTo(30, 16)
connPath.lineTo(45, 16)
connPath.moveTo(30, 24)
connPath.lineTo(45, 24)
connPath.moveTo(30, 32)
connPath.lineTo(45, 32)
cablePen = QtGui.QColor(77, 122, 194)
def __init__(self):
QtWidgets.QWidget.__init__(self)
# the following is only if you create the whole widget from code,
# otherwise ensure to set both widget and layout contentsMargins
# accordingly in designer
self.setContentsMargins(25, 50, 10, 10)
layout = QtWidgets.QGridLayout()
self.setLayout(layout)
layout.setContentsMargins(0, 0, 0, 0)
# ...
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setRenderHints(qp.Antialiasing)
qp.translate(.5, .5)
qp.drawPath(self.connPath)
qp.setPen(self.cablePen)
cablePath = QtGui.QPainterPath()
cablePath.moveTo(30, 24)
top = self.statusFrame.geometry().top()
cablePath.quadTo(0, top + 20, 25, top + 40)
qp.drawPath(cablePath)
As you can see, it's almost the same as yours.
I'm trying to make a side panel with pyqt. I'm able to make nice looking buttons but not able to fill the rest of the space with the same color.
My goal is to add the same blue color to space under the buttons, all the way to the bottom. Now my buttons are inside of a box layout which is inside of a widget (just to be able to set the style) which is inside of a grid cell which is inside of a widget.
I tried to add one more widget to the box layout, but it is not stretching to fill the space. I can set minimum height, but then if the window is resized, the blue area won't resize.
import sys
import PySide2.QtWidgets as qt
from PySide2 import QtCore, QtGui
import os
class main_page:
def create(self):
# Create main window
main_window = qt.QMainWindow()
# Set some parameters for main window
main_window.setGeometry(50,50,700,400)
main_window.setWindowTitle("Here will be name of the program")
# Create central widget that will contain layout to contain widgets. Eh...
central_widget = qt.QWidget()
central_widget.setStyleSheet("background: white;")
# Add central widget to main window
main_window.setCentralWidget(central_widget)
# Create main grid layout that will organize everything
main_grid = qt.QGridLayout(central_widget)
main_grid.setSpacing(0)
main_grid.setMargin(0)
# Create widget that will contain layout and now we can set style for the widget.
widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid = qt.QWidget()
widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid.setStyleSheet(
'''
QPushButton {
background: #FF005AA1;
color: white;
text-align: center;
border: none;
font-weight: 500;
font-size: 15px;
height: 48px;
width: 120px;
}
QPushButton:hover {
background-color: #FF014a82;
}
QPushButton:checked {
background: #FF01508c;
}
QPushButton:pressed {
color: #FF005AA1;
background: white;
}
''')
# On left side we will have some (or at least one) button
left_side_buttons = qt.QVBoxLayout(widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid)
left_side_buttons.setSpacing(0)
left_side_buttons.setMargin(0)
# And add it to main box the left most cell
main_grid.addWidget(widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid, 0, 0, alignment = QtCore.Qt.AlignTop)
main_grid.setRowStretch(0,1)
# Column 0 must not stretch
main_grid.setColumnStretch(0,0)
# Column 1 must stretch
main_grid.setColumnStretch(1,1)
# Add widgets to container
left_side_buttons.addWidget(qt.QPushButton("First button"))
left_side_buttons.addWidget(qt.QPushButton("Second button"))
# Add separator line
line = qt.QFrame()
line.setFrameShape(qt.QFrame.HLine)
line.setFrameShadow(qt.QFrame.Sunken)
left_side_buttons.addWidget(line)
# Add color for rest of the space
color_filler = qt.QWidget()
# I can use this to hack to make colored area bigger but it won't stretch
color_filler.setMinimumHeight(100)
left_side_buttons.addWidget(color_filler)
main_grid.addWidget(qt.QListView(), 0, 1)
main_window.show()
# Add list view to right side
main_grid.addWidget(qt.QListView(), 0, 1)
main_window.show()
return main_window
def main():
app = qt.QApplication(sys.argv)
my_main_page = main_page().create()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Here's what I get and what I want:
Probably the easiest way to get what you want, is to do the following
Add QObject { background: #FF005AA1; } to the style sheet of widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid.
Remove the alignment argument when you add widget_that_would_not_be_needed_if_qt_would_not_be_so_stupid to main_grid (or use alignment = QtCore.Qt.AlignJustify),
Replace color_filler with a stretchable space at the bottom of left_side_buttons (a stretchable space can be added via left_side_buttons.addStretch()).
Screenshot:
I'm looking to change the colour of the Value text from default black to white.
I've got a stylesheet, but the color: white only seems to apply to the text, not the value text.
'''
Load UI
'''
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setStyleSheet("""
QMainWindow {background-color: rgb(80,80,80); color: white;}
QProgressDialog {background-color: rgb(80,80,80); color: white;}
""")
sys.exit(app.exec_())
I've also tried adding the QProgressBar to the stylesheet, but this didn't do anything either.
This is my code for the progress dialog:
def pathCasingFixFUNC(self):
'''
Fixes the path files that were named badly in notepad ++
'''
self.XprobBadCasing = ["List of bad file paths i'm checking"]
Xprogress = QtGui.QProgressDialog("Converting Path Names...", "Cancel", 0, len(self.XprobBadCasing), self)
Xprogress.setWindowModality(QtCore.Qt.WindowModal)
Xprogress.setWindowTitle('Processing')
Can i set the value font colour using Xprogress.value.setFont() or something?