update QStyle in EnterEvent - python

i wanna update the QStyle of the LineEdit while the mouse is in\out the widget (enterEvent\leaveEvent ) i tried to add a bool variable to the drawPrimitive function but i get this error
TypeError: drawPrimitive(self, QStyle.PrimitiveElement, QStyleOption, QPainter, widget: QWidget = None): 'a' is not a valid keyword argument
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PushButton_2 import Push_Button_
import sys
class LineEditStyle(QProxyStyle):
def drawPrimitive(self, element, option, painter, widget,a=None):
if a :
self.pen = QPen(QColor('green'))
else :
self.pen = QPen(QColor('red'))
self.pen.setWidth(4)
if element == QStyle.PE_FrameLineEdit:
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(self.pen)
painter.drawRoundedRect(QRect(0,0,400,40), 10, 10)
else:
super().drawPrimitive(element, option, painter, widget)
class LineEdit(QLineEdit):
def __init__(self,*args,**kwargs):
QLineEdit.__init__(self,*args,**kwargs)
self.a = 0
def enterEvent(self, a0):
self.a = 1
def leaveEvent(self, a0):
self.a = 0
def paintEvent(self,event):
option = QStyleOption()
option.initFrom(self)
self.style().drawPrimitive(QStyle.PE_FrameLineEdit,option,a=self.a)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QMainWindow()
window.setGeometry(500,500,400,400)
window.setStyleSheet('background-color:#373737')
line = LineEdit(parent=window)
line.setGeometry(20,200,400,40)
style = LineEditStyle()
line.setStyle(style)
window.show()
sys.exit(app.exec())

You mustn't use the QStyleSheet with the QStyle because it makes a confusion and you have to set the default parameter Widget as None
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PushButton_2 import Push_Button_
import sys
class LineEditStyle(QProxyStyle):
def drawPrimitive(self, element, option, painter, widget=None,a=None):
if a :
self.pen = QPen(QColor('green'))
else :
self.pen = QPen(QColor('red'))
self.pen.setWidth(4)
if element == QStyle.PE_FrameLineEdit:
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(self.pen)
painter.drawRoundedRect(QRect(0,0,400,40), 10, 10)
else:
super().drawPrimitive(element, option, painter, widget)
def subElementRect(self, element, option, widget):
if element == QStyle.SE_LineEditContents :
return QRect(0,0,50,30)
else :
return super().subElementRect(element, option, widget)
def drawItemText(self, painter, rect, flags, pal, enabled, text, textRole):
rect_ = QRect(20,20,50,50)
text = text.upper()
painter.drawText(text,rect_,Qt.AlignCenter)
class LineEdit(QLineEdit):
def __init__(self,*args,**kwargs):
QLineEdit.__init__(self,*args,**kwargs)
self.a = 0
def enterEvent(self, a0):
self.a = 1
def leaveEvent(self, a0):
self.a = 0
def paintEvent(self,event):
option = QStyleOption()
option.initFrom(self)
painter = QPainter(self)
self.style().drawPrimitive(QStyle.PE_FrameLineEdit,option,painter,a=self.a)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QMainWindow()
window.setGeometry(500,500,400,400)
#window.setStyleSheet('background-color:#373737')
line = LineEdit(parent=window)
line.setGeometry(20,200,400,40)
style = LineEditStyle()
line.setStyle(style)
window.show()
sys.exit(app.exec())

You might find QStyleSheets useful for something like this.
I mocked this up in Qt Designer by entering the following in styleSheet property (in code you would do mywidget.setStyleSheet('<parameters>') ):
QLineEdit {
border: 3px solid red;
}
QLineEdit:focus {
border: 3px solid green;
}
Edit: styleSheet string above works on focus, but the original question was about enterEvent/leaveEvent, which trigger on mouse hover. As #musicamente rightfully points out, to work on mouse hover the :hover pseudo state can be used instead of :focus:
QLineEdit {
border: 3px solid red;
}
QLineEdit:hover {
border: 3px solid green;
}
I made a QMainWindow with 2 QLineEdits: 1 has styleSheet set and the other is default. When the focus moves to the regular QLineEdit, the modified QLineEdit turns red.
You can make ALL of the QLineEdits behave the same by editing the styleSheet of their parent. In your case, you could use window.setStyleSheet('..... Here's another mockup in Qt Designer:

Related

How to fix hover effect for multi QFrame in PyQt5?

My intention is to make a Hover effect for multiple frames at a time. For Example, Below is my code, I have three frames. Two inner frames and one outer frame. If the mouse enters where ever, that is, either in an outer frame or in the inner frames, I need a hover effect for three frames, at a time.
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class Dynamic_Widgets(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Dynamic Widget")
self.lbl = QLabel("this is text")
self.btn = QPushButton("Button")
self.lbl_1 = QLabel("-----------")
self.lbl_r = QLabel("My text ")
self.btn_r = QPushButton("Button888888")
self.lbl_1r = QLabel(('\u2261' * 60))
my_font_1 = QFont("Arial", 10, QFont.Bold)
my_font_1.setLetterSpacing(QFont.AbsoluteSpacing, -6)
self.lbl_1r.setFont(my_font_1)
self.vbox = QHBoxLayout()
self.frame = QFrame()
self.frame_right = QFrame()
self.frame_all = QFrame()
self.frame.setObjectName("ob_frame")
self.frame_right.setObjectName("ob_frame_right")
self.frame_all.setObjectName("ob_frame_all")
self.frame.setProperty("type", "2")
self.frame_right.setProperty("type", "2")
self.frame_all.setProperty("type", "2")
self.framebox = QVBoxLayout(self.frame)
self.framebox_right = QVBoxLayout(self.frame_right)
self.framebox_all = QHBoxLayout(self.frame_all)
self.framebox_all.setContentsMargins(0, 0, 0, 0)
self.framebox_all.setSpacing(0)
self.framebox_all.addWidget(self.frame)
self.framebox_all.addWidget(self.frame_right)
self.vbox.addWidget(self.frame_all)
self.setLayout(self.vbox)
self.frame.setFixedSize(100, 100)
self.frame_right.setFixedSize(100, 100)
self.frame_all.setFixedSize(220, 120)
self.frame.setStyleSheet(f"QFrame#ob_frame{{background-color: lightgreen;}}")
self.frame_right.setStyleSheet(f"QFrame#ob_frame_right{{background-color: lightgreen;}}")
self.frame_all.setStyleSheet(f"QFrame#ob_frame_all{{background-color: green;}}")
#self.frame_all.setStyleSheet('QFrame:hover { background: yellow; }')
self.framebox.addWidget(self.lbl)
self.framebox.addWidget(self.btn)
self.framebox.addWidget(self.lbl_1)
self.framebox_right.addWidget(self.lbl_r)
self.framebox_right.addWidget(self.btn_r)
self.framebox_right.addWidget(self.lbl_1r)
def main():
app = QApplication(sys.argv)
ex = Dynamic_Widgets()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Setting individual stylesheets can be useful for very specific and relatively static styling, but, in general, it's usually better to have a centralized QSS or, at least, different QSS set for common parents.
In normal situations, a single Class:hover selector would suffice, but if the children have properties that need to be overridden by a change in the parent, it is necessary to install an event filter on the parent.
Considering that the event filter will match Enter and Leave events, the hover selector doesn't make a lot of sense anymore: we can create a "default" style sheet stored as instance attribute and set/override it depending on those events:
class Dynamic_Widgets(QWidget):
def __init__(self):
# ...
self.frame_all_qss = '''
QFrame#ob_frame_all {
background-color: green;
}
QFrame#ob_frame {
background-color: lightgreen;
}
QFrame#ob_frame_right {
background-color: lightgreen;
}
'''
self.frame_all.setStyleSheet(self.frame_all_qss)
self.frame_all.installEventFilter(self)
def eventFilter(self, obj, event):
if obj == self.frame_all:
if event.type() == event.Enter:
res = obj.event(event)
self.frame_all.setStyleSheet(
'QFrame#ob_frame_all { background: yellow; }')
return res
elif event.type() == event.Leave:
res = obj.event(event)
self.frame_all.setStyleSheet(self.frame_all_qss)
return res
return super().eventFilter(obj, event)

Align Icon in QPushButton

Starting the program, the QIcon is aligned on the left (it's standard i guess) with the text right to it.
Instead I want the icon to be centered on top with the text below it.
I tried using setStyleSheet with show_all.setStyleSheet("QIcon { vertical-align: top }") and show_all.setStyleSheet("QPushButton { text-align: bottom }").
How can I achieve this?
QPushButton doesn't allow to choose the layout of its icon and label. Also, remember that while Qt features style sheets to style widgets, not all CSS known properties and selectors are available. Furthermore, style sheets only work on widgets, so using the QIcon selector isn't supported, since QIcon is not a QWidget subclass.
The most simple solution is to use a QToolButton and set the toolButtonStyle correctly:
self.someButton = QtWidgets.QToolButton()
# ...
self.someButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)
The alternative is to subclass the button, provide a customized paint method and reimplement both sizeHint() and paintEvent(); the first is to ensure that the button is able to resize itself whenever required, while the second is to paint the button control (without text!) and then paint both the icon and the text.
Here's a possible implementation:
from PyQt5 import QtCore, QtGui, QtWidgets
class CustomButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._icon = self.icon()
if not self._icon.isNull():
super().setIcon(QtGui.QIcon())
def sizeHint(self):
hint = super().sizeHint()
if not self.text() or self._icon.isNull():
return hint
style = self.style()
opt = QtWidgets.QStyleOptionButton()
self.initStyleOption(opt)
margin = style.pixelMetric(style.PM_ButtonMargin, opt, self)
spacing = style.pixelMetric(style.PM_LayoutVerticalSpacing, opt, self)
# get the possible rect required for the current label
labelRect = self.fontMetrics().boundingRect(
0, 0, 5000, 5000, QtCore.Qt.TextShowMnemonic, self.text())
iconHeight = self.iconSize().height()
height = iconHeight + spacing + labelRect.height() + margin * 2
if height > hint.height():
hint.setHeight(height)
return hint
def setIcon(self, icon):
# setting an icon might change the horizontal hint, so we need to use a
# "local" reference for the actual icon and go on by letting Qt to *think*
# that it doesn't have an icon;
if icon == self._icon:
return
self._icon = icon
self.updateGeometry()
def paintEvent(self, event):
if self._icon.isNull() or not self.text():
super().paintEvent(event)
return
opt = QtWidgets.QStyleOptionButton()
self.initStyleOption(opt)
opt.text = ''
qp = QtWidgets.QStylePainter(self)
# draw the button without any text or icon
qp.drawControl(QtWidgets.QStyle.CE_PushButton, opt)
rect = self.rect()
style = self.style()
margin = style.pixelMetric(style.PM_ButtonMargin, opt, self)
iconSize = self.iconSize()
iconRect = QtCore.QRect((rect.width() - iconSize.width()) / 2, margin,
iconSize.width(), iconSize.height())
if self.underMouse():
state = QtGui.QIcon.Active
elif self.isEnabled():
state = QtGui.QIcon.Normal
else:
state = QtGui.QIcon.Disabled
qp.drawPixmap(iconRect, self._icon.pixmap(iconSize, state))
spacing = style.pixelMetric(style.PM_LayoutVerticalSpacing, opt, self)
labelRect = QtCore.QRect(rect)
labelRect.setTop(iconRect.bottom() + spacing)
qp.drawText(labelRect,
QtCore.Qt.TextShowMnemonic|QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop,
self.text())
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = CustomButton('Alles anzeigen', icon=QtGui.QIcon.fromTheme('document-new'))
w.setIconSize(QtCore.QSize(32, 32))
w.show()
sys.exit(app.exec_())
Alternatively, try it:
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtWidgets import (QApplication, QWidget, QGridLayout,
QToolBar, QAction)
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
add_action = QAction(QIcon("img/add.png"), "Add", self)
add_action.triggered.connect(self.addValue)
sub_action = QAction(QIcon("img/min.png"), "Sub", self)
sub_action.triggered.connect(self.subValue)
toolbar = QToolBar()
toolbar.setContentsMargins(0, 0, 0, 0)
toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon | Qt.AlignLeading)
toolbar.setIconSize(QSize(50, 50))
toolbar.addAction(add_action)
toolbar.addAction(sub_action)
rootGrid = QGridLayout(self)
rootGrid.addWidget(toolbar)
def addValue(self):
print("def addValue:")
def subValue(self):
print("def subValue:")
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Widget()
main.show()
sys.exit(app.exec_())

PyQt5 Laying Properly

I've already looked heavily to see how to properly layer my ui and haven't found out how to layer my windows so it comes off looking somewhat like this:
I want to have my background layer which I have set as a label with an image and then have a qt widget with login centered in the middle of it almost popping out at the user however when I do this it comes out with the widget behind my main window, it doesn't align properly and it also doesnt "follow" the window when I move it around image provided:
import PyQt5.QtWidgets
import sys
class LoginPanel(PyQt5.QtWidgets.QWidget):
def __init__(self):
PyQt5.QtWidgets.QWidget.__init__(self)
self.setFixedSize(600,400)
self.setWindowFlags(PyQt5.QtCore.Qt.FramelessWindowHint | PyQt5.QtCore.Qt.WindowStaysOnTopHint)
self.setStyleSheet("""
QWidget {
background-color: #CBCAB7;
border-radius: 50px;
}
""")
self.show()
class Auth(PyQt5.QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Login")
self.setFixedSize(1200,800)
self.setWindowFlags(PyQt5.QtCore.Qt.WindowCloseButtonHint | PyQt5.QtCore.Qt.WindowMinimizeButtonHint)
self.setWindowIcon(PyQt5.QtGui.QIcon("assets\\login.ico"))
self.background = PyQt5.QtWidgets.QLabel("", self)
self.layout = PyQt5.QtWidgets.QGridLayout()
self.layout.addWidget(LoginPanel(), 0, 1)
self.set_background()
self.show()
#self.layout.setAlignment(PyQt5.QtCore.Qt.AlignCenter)
def set_background(self):
img = PyQt5.QtGui.QPixmap("assets\\background.png")
pixmap = img.scaled(self.width(), self.height())
self.background.setPixmap(img)
self.background.resize(self.width(), self.height())
if __name__ == "__main__":
app = PyQt5.QtWidgets.QApplication(sys.argv)
a = Auth()
sys.exit(app.exec())
Here is my current code, I just wanted some help sense while looking online I was unable to find any great examples or references.
My recommendation is not to create a new window but to set it as a child of the window, and to raise it above any other child, you must use raise_() method, also add a QGraphicsDropShadowEffect to establish the floating window effect:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class LoginPanel(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setFixedSize(600, 400)
self.container = QtWidgets.QWidget(self)
self.container.setStyleSheet(
"""
background-color: #CBCAB7;
border-radius: 50px;
"""
)
offset = 30
self.container.setGeometry(
self.rect().adjusted(offset, offset, -offset, -offset)
)
effect = QtWidgets.QGraphicsDropShadowEffect(
blurRadius=50, offset=QtCore.QPointF(0, 0)
)
self.container.setGraphicsEffect(effect)
lay = QtWidgets.QFormLayout(self)
lay.setContentsMargins(2 * offset, 2 * offset, 2 * offset, 2 * offset)
lay.addRow("Username:", QtWidgets.QLineEdit())
lay.addRow("Email:", QtWidgets.QLineEdit())
class Auth(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Login")
self.setFixedSize(1200, 800)
self.setWindowFlags(
QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint
)
self.setWindowIcon(QtGui.QIcon("assets\\login.ico"))
self.background = QtWidgets.QLabel(self)
self.set_background()
self.panel = LoginPanel(self)
self.center_panel()
def set_background(self):
img = QtGui.QPixmap("assets\\background.png")
pixmap = img.scaled(self.size())
self.background.setPixmap(pixmap)
self.background.resize(self.size())
def resizeEvent(self, event):
super().resizeEvent(event)
self.center_panel()
def center_panel(self):
g = self.panel.geometry()
g.moveCenter(self.rect().center())
self.panel.setGeometry(g)
self.panel.raise_()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
a = Auth()
a.show()
sys.exit(app.exec())

Custom QPushButton inside QStyledItemDelegate

Problem:
I'm able to add a QPushButton to a QStyledItemDelegate just fine. I'm faking the button press inside the delegate's editorEvent method so when you press it an action happens. I'm having trouble getting my QPushButton's style sheet working though- It only reads the first background parameter which is "red" and doesn't change on mouse hover or press.
It's unclear how I should go about setting up button click and hover detection to make the button act like a real button on the delegate. Do I need to set up an eventFilter? Should I do this at the view level? Do I do this inside the delegate's paint method? A combination of everything?
Goals:
Mouse hover over the list time will show the button button's icon.
Mouse hover over the button will change its background color.
Mouse clicks on the button will darken the background color to show a a click happened.
I'd like to set these parameters in a style sheet if possible, but I also don't mind doing it all within a paint function. Whatever works!
Current implementation
The button widget is red with a folder icon. The items correctly change color on select and hover (I want to keep that), but the item's buttons don't change at all.
Thanks!
Here's what I've put together so far:
import sys
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets
class DelegateButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super(DelegateButton, self).__init__(parent)
# self.setLayout(QHBoxLayout())
size = 50
self.setFixedSize(size, size)
self.setIcon(self.style().standardIcon(QtWidgets.QStyle.SP_DialogOpenButton))
self.setStyleSheet("""
QPushButton{
background:red;
height: 30px;
font: 12px "Roboto Thin";
border-radius: 25
}
QPushButton:hover{
background: green;
}
QPushButton:hover:pressed{
background: blue;
}
QPushButton:pressed{
background: yellow;
}
""")
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(300, 300)
# Model/View
entries = ['one', 'two', 'three']
model = QtGui.QStandardItemModel()
delegate = ListItemDelegate()
self.listView = QtWidgets.QListView(self)
self.listView.setModel(model)
self.listView.setItemDelegate(delegate)
for i in entries:
item = QtGui.QStandardItem(i)
model.appendRow(item)
# Layout
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(self.listView)
self.setLayout(main_layout)
# Connections
delegate.delegateButtonPressed.connect(self.on_delegate_button_pressed)
def on_delegate_button_pressed(self, index):
print('"{}" delegate button pressed'.format(index.data(QtCore.Qt.DisplayRole)))
class ListItemDelegate(QtWidgets.QStyledItemDelegate):
delegateButtonPressed = QtCore.Signal(QtCore.QModelIndex)
def __init__(self):
super(ListItemDelegate, self).__init__()
self.button = DelegateButton()
def sizeHint(self, option, index):
size = super(ListItemDelegate, self).sizeHint(option, index)
size.setHeight(50)
return size
def editorEvent(self, event, model, option, index):
# Launch app when launch button clicked
if event.type() == QtCore.QEvent.MouseButtonRelease:
click_pos = event.pos()
rect_button = self.rect_button
if rect_button.contains(click_pos):
self.delegateButtonPressed.emit(index)
return True
else:
return False
else:
return False
def paint(self, painter, option, index):
spacing = 10
icon_size = 40
# Item BG #########################################
painter.save()
if option.state & QtWidgets.QStyle.State_Selected:
painter.setBrush(QtGui.QColor('orange'))
elif option.state & QtWidgets.QStyle.State_MouseOver:
painter.setBrush(QtGui.QColor('black'))
else:
painter.setBrush(QtGui.QColor('purple'))
painter.drawRect(option.rect)
painter.restore()
# Item Text ########################################
rect_text = option.rect
QtWidgets.QApplication.style().drawItemText(painter, rect_text, QtCore.Qt.AlignVCenter | QtCore.Qt.AlignLeft, QtWidgets.QApplication.palette(), True, index.data(QtCore.Qt.DisplayRole))
# Custom Button ######################################
self.rect_button = QtCore.QRect(
option.rect.right() - icon_size - spacing,
option.rect.bottom() - int(option.rect.height() / 2) - int(icon_size / 2),
icon_size,
icon_size
)
option = QtWidgets.QStyleOptionButton()
option.initFrom(self.button)
option.rect = self.rect_button
# Button interactive logic
if self.button.isDown():
option.state = QtWidgets.QStyle.State_Sunken
else:
pass
if self.button.isDefault():
option.features = option.features or QtWidgets.QStyleOptionButton.DefaultButton
option.icon = self.button.icon()
option.iconSize = QtCore.QSize(30, 30)
painter.save()
self.button.style().drawControl(QtWidgets.QStyle.CE_PushButton, option, painter, self.button)
painter.restore()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Try:
https://doc.qt.io/qt-4.8/qstyle.html#StateFlag-enum
import sys
import PySide.QtCore as core
import PySide.QtGui as gui
QPushButton#pushButton {
background-color: yellow;
}
QPushButton#pushButton:hover {
background-color: rgb(224, 255, 0);
}
QPushButton#pushButton:pressed {
background-color: rgb(224, 0, 0);
}
Your custom QStyledItemDelegate catches the mouse event, so that it is not passed to the QListView. So in the QStyledItemDelegate.editor(Event) one simply needs to add.
if event.type() == core.QEvent.MouseButtonPress:
return False
Now the selection is recognizable in the paint()-method using option.state & gui.QStyle.State_Selected.
if __name__ == '__main__':
app = gui.QApplication(sys.argv)
app.setStyleSheet('QListView::item:hover {background: none;}')
mw = gui.QMainWindow()
model = MyListModel()
view = gui.QListView()
view.setItemDelegate(MyListDelegate(parent=view))
view.setSpacing(5)
view.setModel(model)
mw.setCentralWidget(view)
mw.show()
sys.exit(app.exec_())
class MyListDelegate(gui.QStyledItemDelegate):
w = 300
imSize = 90
pad = 5
h = imSize + 2*pad
sepX = 10
def __init__(self, parent=None):
super(MyListDelegate, self).__init__(parent)
def paint(self, painter, option, index):
mouseOver = option.state in [73985, 73729]
if option.state & QStyle.State_MouseOver::
painter.fillRect(option.rect, painter.brush())
pen = painter.pen()
painter.save()
x,y = (option.rect.x(), option.rect.y())
dataRef = index.data()
pixmap = dataRef.pixmap()
upperLabel = dataRef.upperLabel()
lowerLabel = dataRef.lowerLabel()
if mouseOver:
newPen = gui.QPen(core.Qt.green, 1, core.Qt.SolidLine)
painter.setPen(newPen)
else:
painter.setPen(pen)
painter.drawRect(x, y, self.w, self.h)
painter.setPen(pen)
x += self.pad
y += self.pad
painter.drawPixmap(x, y, pixmap)
font = painter.font()
textHeight = gui.QFontMetrics(font).height()
sX = self.imSize + self.sepX
sY = textHeight/2
font.setBold(True)
painter.setFont(font)
painter.drawText(x+sX, y-sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
upperLabel)
font.setBold(False)
font.setItalic(True)
painter.setFont(font)
painter.drawText(x+sX, y+sY,
self.w-self.imSize-self.sepX, self.imSize,
core.Qt.AlignVCenter,
lowerLabel)
painter.restore()
def sizeHint(self, option, index):
return core.QSize(self.w, self.imSize+2*self.pad)
def editorEvent(self, event, model, option, index):
if event.type() == core.QEvent.MouseButtonRelease:
print 'Clicked on Item', index.row()
if event.type() == core.QEvent.MouseButtonDblClick:
print 'Double-Clicked on Item', index.row()
return True
window.button->setAutoFillBackground(false);
window.button->setAutoFillBackground(true);
window.button->setPalette(*palette_red);
Another Solution To Set CSS:
import sys
from PyQt5 import Qt as qt
class TopLabelNewProject(qt.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
layout = qt.QHBoxLayout(self)
layout.setContentsMargins(40, 0, 32, 0)
self.setLayout(layout)
self.setFixedHeight(80)
self.label = qt.QLabel("Dashboard")
layout.addWidget(self.label, alignment=qt.Qt.AlignLeft)
# self.newProjectButton = Buttons.DefaultButton("New project", self)
self.newProjectButton = qt.QPushButton("New project", self)
layout.addWidget(self.newProjectButton, alignment=qt.Qt.AlignRight)
style = '''
QWidget {
background-color: white;
}
QLabel {
font: medium Ubuntu;
font-size: 20px;
color: #006325;
}
QPushButton {
background-color: #006325;
color: white;
min-width: 70px;
max-width: 70px;
min-height: 70px;
max-height: 70px;
border-radius: 35px;
border-width: 1px;
border-color: #ae32a0;
border-style: solid;
}
QPushButton:hover {
background-color: #328930;
}
QPushButton:pressed {
background-color: #80c342;
}
'''
if __name__ == '__main__':
app = qt.QApplication(sys.argv)
app.setStyleSheet(style)
ex = TopLabelNewProject()
ex.show()
sys.exit(app.exec_())

How to change QPushButton text and background color

I am using following code to connect QMenu to QPushButton. When button is clicked a pull-down menu with multiple sub-menu's items is shown.
button=QPushButton()
button.setText("Press Me")
font=QtGui.QFont()
button.setFont(font)
button.setSizePolicy(ToolButtonSizePolicy)
button.setPopupMode(QtGui.QToolButton.InstantPopup)
menu=QtGui.QMenu()
button.setMenu(menu)
menuItem1=menu.addAction('Menu Item1')
menuItem2=menu.addAction('Menu Item2')
Now depending on a condition I would like to customize QPushButton display by giving it a text and background color. The following line of code (which is supposed to change background color) has no effect on QPushButton connected to QMenu.
button.setStyleSheet('QPushButton {background-color: #A3C1DA}')
I would like to know how to change the background color of QPushButton as well as button's text's color.
Apart from some inconsistencies with your code example setting the background color and text color of a QPushButton works just fine with:
setStyleSheet('QPushButton {background-color: #A3C1DA; color: red;}')
Example (using PySide):
from PySide import QtGui
app = QtGui.QApplication([])
button = QtGui.QPushButton()
button.setStyleSheet('QPushButton {background-color: #A3C1DA; color: red;}')
button.setText('Press Me')
menu = QtGui.QMenu()
menuItem1 = menu.addAction('Menu Item1')
menuItem2 = menu.addAction('Menu Item2')
button.setMenu(menu)
button.show()
app.exec_()
results in:
For those who still want to change color of button with the instruction
button.setStyleSheet('QPushButton {background-color: #A3C1DA}')
and not able to do so, just modify the above instruction to
button.setStyleSheet('QPushButton {background-color: #A3C1DA; border: none}')
And it will change the button color, so the trick is to remove the border
I would add a comment to Trilarions answer, but not enough rep..
I was able to use his suggestion, without removing borders by
self.show()
self.button.setStyleSheet('background-color: red;')
AFTER doing a .show()
on my application. not sure why after works but not before. If anyone can explain that would be great
Change the background color when mouse is over the button
self.button.setStyleSheet(
"QPushButton::hover{"
"background-color: #ffd2cf;"
"border: none;"
"}"
)
You can improve your button further:
self.button.setToolTip("Hell o World")
self.button.mousePressEvent = lambda v: self.button.setIconSize(QSize(25, 25))#incresing iconsize
self.button.mouseReleaseEvent = lambda v: self.button.setIconSize(QSize(20, 20))#resetting to original iconsize
self.button.setStyleSheet(
"QPushButton::hover{"
"background-color: #ffd2cf;"
"border: none;"
"}"
)
self.button.myIcon = QIcon("c:/users/user-name/Pictures/icons/delete-row.png")
self.button.setIcon(self.button.myIcon)
self.button.setIconSize(QSize(20, 20))#setting original icon size
Here's a generic DecorableButton:
from PySide6.QtWidgets import (QPushButton)
from PySide6.QtGui import (QIcon, QMouseEvent)
from PySide6.QtCore import (Qt, QSize)
class DecButton(QPushButton):
def __init__(self, text: str = None, size: QSize = None, iconPath: str = None,
iconSize: QSize = None, onPressIconSizeIncrease: QSize = None,
onFocusBackgroundColor: str = None, toolTip: str = None, parent=None, color=None):
super().__init__(parent=parent)
##initializing UI
self.initUI(text=text, size=size, iconPath=iconPath,
iconSize=iconSize, onPressIconSizeIncrease=onPressIconSizeIncrease,
onFocusBackgroundColor=onFocusBackgroundColor, toolTip=toolTip, color=color)
pass
def initUI(self, text: str = None, size: QSize = None, iconPath: str = None,
iconSize: QSize = None, onPressIconSizeIncrease: int = None,
onFocusBackgroundColor: str = None, toolTip: str = None, color: str = None):
if text is not None:
self.setText(text)
if size is not None:
self.setFixedSize(size)
if iconPath is not None:
self.buttonIcon = QIcon(iconPath)
self.setIcon(self.buttonIcon)
self.buttonIconSize = iconSize
if iconSize:
self.setIconSize(self.buttonIconSize)
self.onPressIconSizeIncrease = onPressIconSizeIncrease
if onFocusBackgroundColor is not None:
self.setStyleSheet(
"QPushButton::hover{"
f"background-color: {onFocusBackgroundColor};"
"border: none;"
"}"
)
if color is not None:
if onFocusBackgroundColor is None:
self.setStyleSheet(
"QPushButton{"
f"background-color: {color};"
"border: none;"
"}"
)
else:
self.setStyleSheet(
"QPushButton{"
f"background-color: {color};"
"border: none;"
"}"
"QPushButton::hover{"
f"background-color: {onFocusBackgroundColor};"
"border: none;"
"}"
)
self.setToolTip(toolTip)
def mousePressEvent(self, event: QMouseEvent) -> None:
super().mousePressEvent(event)
if self.onPressIconSizeIncrease:
self.setIconSize(self.onPressIconSizeIncrease)
def mouseReleaseEvent(self, event: QMouseEvent) -> None:
super().mouseReleaseEvent(event)
if self.onPressIconSizeIncrease:
self.setIconSize(self.buttonIconSize)
if __name__ == "__main__":
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout)
app = QApplication([])
widget = QWidget()
widget.layout = QHBoxLayout()
widget.button = DecButton(iconPath="c:/users/devpa/Pictures/icons/delete-row.png",
iconSize=QSize(25, 25), onPressIconSizeIncrease=QSize(30, 30),
size=QSize(35, 35), onFocusBackgroundColor='#facdcd', color='#fcf8f7')
widget.layout.addWidget(widget.button)
widget.setLayout(widget.layout)
widget.show()
app.exec()
Output Window:
Changing button's text:
from PyQt5.QtWidgets import QPushButton
button = QPushButton("Some text")
button.setText('New text')
Changing button's background color:
from PyQt5.QtWidgets import QPushButton
button = QPushButton("Some text")
button1.setStyleSheet("background-color: red");
# or
# button2.setStyleSheet("background-color:#ff0000;");
# or
# button3.setStyleSheet("background-color:rgb(255,0,0)");

Categories