Reputation: 103
I'm trying to make some "complex" button styling with Qt, using QSS, but I'm facing an issue that I can't resolve.
I want to do a gradient rounded border, for example going from blue on the left side to red on the right side:
result wanted
So, here is the stylesheet applied to a QPushButton:
background:
white;
border-radius:
30px;
border-style:
solid;
border-width:
10px;
border-color:
qlineargradient(x1:0, y1:0, x2:1, y2:0, stop: 0 blue, stop: 1 red)
red
qlineargradient(x1:0, y1:0, x2:1, y2:0, stop: 0 blue, stop: 1 red)
blue;
And here is the result.
Pretty ugly, right?
Upvotes: 3
Views: 8194
Reputation: 11
This might helpful for you, late but might help somebody
import sys
from PyQt5.QtCore import pyqtSignal
import sys
from PyQt5.QtWidgets import QApplication, QPushButton, QVBoxLayout,
QWidget, QFrame
class StyledButton(QFrame):
clicked = pyqtSignal()
def __init__(self, parent=None, size_=(150, 50), border_=3,
radius_=10):
super().__init__(parent)
self.size_ = size_
self.border_ = border_
self.radius_ = radius_
self.init_ui()
def init_ui(self):
if self.size_ is not None:
self.setFixedSize(self.size_[0] + (self.border_ * 2), self.size_[1] + (self.border_ * 2))
self.setFrameStyle(QFrame.Box | QFrame.Plain)
self.setStyleSheet(f"border-radius: {self.radius_}px;") # Set rounded corners
gradient_style = f"border: none; border-radius: {self.radius_ * 0.5}px; background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #f00, stop: 0.25 #f0f, stop: 0.5 #f00, stop: 0.75 #00f, stop: 1 #0f0);"
self.setStyleSheet(gradient_style)
self.button = QPushButton('Button')
self.button.setFixedSize(self.size_[0], self.size_[1])
self.button.setStyleSheet('background-color: black; color: white;')
self.layout = QVBoxLayout(self)
self.layout.setContentsMargins(self.border_, self.border_, self.border_, self.border_)
self.layout.addWidget(self.button)
# Connect QPushButton's clicked signal to emit the custom signal from StyledButton
self.button.clicked.connect(self.emit_custom_signal)
def emit_custom_signal(self):
self.clicked.emit()
def fun():
print("Button is clicked")
def main():
app = QApplication(sys.argv)
layout = QVBoxLayout()
combined_widget = StyledButton()
combined_widget1 = StyledButton()
combined_widget1.button.setStyleSheet('background-color: green; color: red;')
combined_widget2 = StyledButton()
combined_widget3 = StyledButton()
combined_widget.clicked.connect(fun) # Connect the custom signal to the function
layout.addWidget(combined_widget)
layout.addWidget(combined_widget1)
layout.addWidget(combined_widget2)
layout.addWidget(combined_widget3)
window = QWidget()
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Upvotes: 0
Reputation: 808
This issue has been reported to Qt as a bug and there is no indication that they will ever fix it: https://bugreports.qt.io/browse/QTBUG-2221
I was able to work around it by creating a .png image on paint.net (you can use any image creation program) of this exact border. I set the background to transparent, and made sure the border of the image was the border I wanted on the QPushButton. I then set the .png file up as a resource and entered this in the QPushButton stylesheet:
border: none;
border-image: url(:/icons/images/blue-red-gradient.png);
background-color: rgb(255, 255, 255);
border-radius: 15px;
Here is what the final result looked like on my QMainWindow:
Another thing that you can do is to subclass a QPushButton and override it's paint event. Paint your border there and promote all of your QPushButtons to this new class. This would be more of a pain though, so I prefer my first solution personally.
Upvotes: 3