PyQt Fading a QLabel - python

I'm currently trying to fade a specific QLabel in and out. My first try was to use the setAlphaChannel, however this just didn't work.
My current approach is to use a for-loop and set the stylesheet of the QLabel. Sadly this makes a unverifiable bug, sometimes the fading works properly, sometimes the QLabel doesn't fade out but is fading in and more random stuff. For me the problem is untraceable.
Here is my current code:
def fade_greeting(self, foo, bar):
for i in range(255, -1, -5):
print(i)
string = "font : 45px; font : bold; color : rgba(220, 220, 220, " + str (i) + "); font-family : HelveticaNeue-UltraLight"
time.sleep(0.2)
self.greeting_text.setStyleSheet(string)
time.sleep(2)
self.greeting_text.setText(greeting())
time.sleep(2)
for i in range(0, 256, 5):
print(i)
string = "font : 45px; font : bold; color : rgba(220, 220, 220, " + str (i) + "); font-family : HelveticaNeue-UltraLight"
time.sleep(0.2)
self.greeting_text.setStyleSheet(string)
Is there something I missed? Or is there maybe a different approach to this problem?
Already thanks for your help!

After some trial and error, I found a working recipe:
def fade(self, widget):
self.effect = QGraphicsOpacityEffect()
widget.setGraphicsEffect(self.effect)
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.setStartValue(1)
self.animation.setEndValue(0)
self.animation.start()
def unfade(self, widget):
self.effect = QGraphicsOpacityEffect()
widget.setGraphicsEffect(self.effect)
self.animation = QtCore.QPropertyAnimation(self.effect, b"opacity")
self.animation.setDuration(1000)
self.animation.setStartValue(0)
self.animation.setEndValue(1)
self.animation.start()
I guess you can call it on any widget. I call it on QLabel. For example:
self.fade(self._your_widget_here_)
# or
self.unfade(self._your_widget_here_)
It will fadein or fadeout your widget.

sleep() is a blocking function that is not suitable to use in the main GUI thread, Qt provides tools to handle this type of tasks as QVariantAnimation, it provides the colors in an appropriate way for the required animation.
To change the colors you can use QPalette as I show below:
class AnimationLabel(QLabel):
def __init__(self, *args, **kwargs):
QLabel.__init__(self, *args, **kwargs)
self.animation = QVariantAnimation()
self.animation.valueChanged.connect(self.changeColor)
#pyqtSlot(QVariant)
def changeColor(self, color):
palette = self.palette()
palette.setColor(QPalette.WindowText, color)
self.setPalette(palette)
def startFadeIn(self):
self.animation.stop()
self.animation.setStartValue(QColor(0, 0, 0, 0))
self.animation.setEndValue(QColor(0, 0, 0, 255))
self.animation.setDuration(2000)
self.animation.setEasingCurve(QEasingCurve.InBack)
self.animation.start()
def startFadeOut(self):
self.animation.stop()
self.animation.setStartValue(QColor(0, 0, 0, 255))
self.animation.setEndValue(QColor(0, 0, 0, 0))
self.animation.setDuration(2000)
self.animation.setEasingCurve(QEasingCurve.OutBack)
self.animation.start()
def startAnimation(self):
self.startFadeIn()
loop = QEventLoop()
self.animation.finished.connect(loop.quit)
loop.exec_()
QTimer.singleShot(2000, self.startFadeOut)
class Widget(QWidget):
def __init__(self):
super().__init__()
lay = QVBoxLayout(self)
self.greeting_text = AnimationLabel("greeting_text")
self.greeting_text.setStyleSheet("font : 45px; font : bold; font-family : HelveticaNeue-UltraLight")
lay.addWidget(self.greeting_text)
btnFadeIn = QPushButton("fade in")
btnFadeOut = QPushButton("fade out")
btnAnimation = QPushButton("animation")
lay.addWidget(btnFadeIn)
lay.addWidget(btnFadeOut)
lay.addWidget(btnAnimation)
btnFadeIn.clicked.connect(self.greeting_text.startFadeIn)
btnFadeOut.clicked.connect(self.greeting_text.startFadeOut)
btnAnimation.clicked.connect(self.greeting_text.startAnimation)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Widget()
ex.show()
sys.exit(app.exec_())

Related

How to display icon and text together in PYQT5 menubar

So, i want to display both the text and the ICON as a menubar item.
I have used the below statement as:
self.helpMenu = menubar1.addMenu(QtGui.QIcon("home.png"),"&TEXT")
But this displays only the icon and not the text.
So need help to fix it
Premise
It seems that, despite Qt provides an addMenu() function to create a menu that has both an icon and text, it is not fully supported.
There is a related and very old bug report on the matter, which has been flagged as closed and "Out of scope". I cannot test it right now, but I'm going to suppose that it's due to the native menubar support, which is mostly intended for macOS and Linux distros that support that feature.
That said, a workaround is possible, and that's done through a QProxyStyle.
It's a bit complex, but it works seamlessly given that:
it's enabled only when the native menubar feature is not used (whether it's available or just disabled);
it uses the 'fusion' style or the default style on Windows;
The trick is to ensure that the proxy returns a correct size for sizeFromContents() that includes both the text and the icon if both exist, and to use the default implementations as much as possible in drawControl() and drawItemText() (which is called from more standard styles).
class MenuProxy(QtWidgets.QProxyStyle):
menuHack = False
alertShown = False
def useMenuHack(self, element, opt, widget):
if (element in (self.CT_MenuBarItem, self.CE_MenuBarItem) and
isinstance(widget, QtWidgets.QMenuBar) and
opt.icon and not opt.icon.isNull() and opt.text):
if not self.alertShown:
if widget.isNativeMenuBar():
# this will probably not be shown...
print('WARNING: menubar items with icons and text not supported for native menu bars')
styleName = self.baseStyle().objectName()
if not 'windows' in styleName and styleName != 'fusion':
print('WARNING: menubar items with icons and text not supported for "{}" style'.format(
styleName))
self.alertShown = True
return True
return False
def sizeFromContents(self, content, opt, size, widget=None):
if self.useMenuHack(content, opt, widget):
# return a valid size that includes both the icon and the text
alignment = (QtCore.Qt.AlignCenter | QtCore.Qt.TextShowMnemonic |
QtCore.Qt.TextDontClip | QtCore.Qt.TextSingleLine)
if not self.proxy().styleHint(self.SH_UnderlineShortcut, opt, widget):
alignment |= QtCore.Qt.TextHideMnemonic
width = (opt.fontMetrics.size(alignment, opt.text).width() +
self.pixelMetric(self.PM_SmallIconSize) +
self.pixelMetric(self.PM_LayoutLeftMargin) * 2)
textOpt = QtWidgets.QStyleOptionMenuItem(opt)
textOpt.icon = QtGui.QIcon()
height = super().sizeFromContents(content, textOpt, size, widget).height()
return QtCore.QSize(width, height)
return super().sizeFromContents(content, opt, size, widget)
def drawControl(self, ctl, opt, qp, widget=None):
if self.useMenuHack(ctl, opt, widget):
# create a new option with no icon to draw a menubar item; setting
# the menuHack allows us to ensure that the icon size is taken into
# account from the drawItemText function
textOpt = QtWidgets.QStyleOptionMenuItem(opt)
textOpt.icon = QtGui.QIcon()
self.menuHack = True
self.drawControl(ctl, textOpt, qp, widget)
self.menuHack = False
# compute the rectangle for the icon and call the default
# implementation to draw it
iconExtent = self.pixelMetric(self.PM_SmallIconSize)
margin = self.pixelMetric(self.PM_LayoutLeftMargin) / 2
top = opt.rect.y() + (opt.rect.height() - iconExtent) / 2
iconRect = QtCore.QRect(opt.rect.x() + margin, top, iconExtent, iconExtent)
pm = opt.icon.pixmap(widget.window().windowHandle(),
QtCore.QSize(iconExtent, iconExtent),
QtGui.QIcon.Normal if opt.state & self.State_Enabled else QtGui.QIcon.Disabled)
self.drawItemPixmap(qp, iconRect, QtCore.Qt.AlignCenter, pm)
return
super().drawControl(ctl, opt, qp, widget)
def drawItemText(self, qp, rect, alignment, palette, enabled, text, role=QtGui.QPalette.NoRole):
if self.menuHack:
margin = (self.pixelMetric(self.PM_SmallIconSize) +
self.pixelMetric(self.PM_LayoutLeftMargin))
rect = rect.adjusted(margin, 0, 0, 0)
super().drawItemText(qp, rect, alignment, palette, enabled, text, role)
class Test(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
menu = self.menuBar().addMenu(QtGui.QIcon.fromTheme('document-new'), 'File')
menu.addAction(QtGui.QIcon.fromTheme('application-exit'), 'Quit')
self.menuBar().addMenu(QtGui.QIcon.fromTheme('edit-cut'), 'Edit')
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle(MenuProxy(QtWidgets.QStyleFactory.create('fusion')))
# or, for windows systems:
# app.setStyle(MenuProxy())
test = Test()
test.show()
sys.exit(app.exec_())
I have the same story with Windows 7 and PyQt 5.12.2 and tried to solve it like this:
import sys
from PyQt5.Qt import *
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.centralWidget = QLabel("Hello, World")
self.centralWidget.setAlignment(Qt.AlignCenter)
self.setCentralWidget(self.centralWidget)
menuBar = QMenuBar(self)
self.setMenuBar(menuBar)
self.helpContentAction = QAction(QIcon("img/readMe.png"), "&Help Content", self)
self.aboutAction = QAction("&About", self)
# helpMenu = menuBar.addMenu(QIcon("img/qtlogo.png"), "&Help")
helpMenu = menuBar.addMenu(" &Help") # +++
# ^^^^^^^^^^^^
helpMenu.addAction(self.helpContentAction)
helpMenu.addAction(self.aboutAction)
qss = """
QMenuBar {
background-color: qlineargradient(
x1:0, y1:0, x2:0, y2:1,
stop:0 lightgray, stop:1 darkgray
);
}
QMenuBar::item {
background-color: darkgray;
padding: 1px 5px 1px -25px; /* +++ */
background: transparent;
image: url(img/qtlogo.png); /* +++ * /
}
QMenuBar::item:selected {
background-color: lightgray;
}
QMenuBar::item:pressed {
background: lightgray;
}
"""
if __name__ == "__main__":
app = QApplication(sys.argv)
# app.setStyle('Fusion')
app.setStyleSheet(qss) # +++
app.setFont(QFont("Times", 10, QFont.Bold))
win = Window()
win.setWindowTitle("Python Menus")
win.resize(600, 350)
win.show()
sys.exit(app.exec_())

Does pyqt support a stacked progress bar with two values?

Similar to this question, but for pyqt. I have an application that has two threads, one of which processes some data (time consuming), and the second thread that presents the results and asks for verification on the results. I want to show the number of objects processed in a progress bar. However, I also want to show the number of objects verified by user. Number processed will always be equal or greater than the number of objects verified (since you can't verify what hasn't been verified). In essence, it's kind of like the loading bar of a youtube video or something, showing a grey part that is "loaded" and red part that is "watched." Is this something that can be supported in pyqt? The documentation for QProgressBar does not seem to hint that there's any support. Using PyQt5 and Python 3.6.
It should look similar to this:
Here's a minimal viable code that has TWO separate progress bars, one for the number of objects processed and the other for the number verified, but I want them overlapped...
import sys
from PyQt5.QtWidgets import (QApplication, QDialog,
QProgressBar, QPushButton)
class Actions(QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.objectsToProcess = 100
self.objectsProcessed = 0
self.objectsVerified = 0
self.processProgress = QProgressBar(self)
self.processProgress.setGeometry(5, 5, 300, 25)
self.processProgress.setMaximum(self.objectsToProcess)
self.verifyProgress = QProgressBar(self)
self.verifyProgress.setGeometry(5, 35, 300, 25)
self.verifyProgress.setMaximum(self.objectsToProcess)
self.processButton = QPushButton('Process', self)
self.processButton.move(5, 75)
self.verifyButton = QPushButton('Verify', self)
self.verifyButton.move(90, 75)
self.show()
self.processButton.clicked.connect(self.process)
self.verifyButton.clicked.connect(self.verify)
def process(self):
if self.objectsProcessed + 1 < self.objectsToProcess:
self.objectsProcessed += 1
self.processProgress.setValue(self.objectsProcessed)
def verify(self):
if self.objectsVerified < self.objectsProcessed:
self.objectsVerified += 1
self.verifyProgress.setValue(self.objectsVerified)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Actions()
sys.exit(app.exec_())
Result from above code:
A possible solution is to create a new attribute in QProgressBar that shows the alternative advance, and to do the painting we can use a QProxyStyle:
from PyQt5 import QtCore, QtGui, QtWidgets
class ProxyStyle(QtWidgets.QProxyStyle):
def drawControl(self, element, option, painter, widget):
if element == QtWidgets.QStyle.CE_ProgressBar:
super(ProxyStyle, self).drawControl(element, option, painter, widget)
if hasattr(option, 'alternative'):
alternative = option.alternative
last_value = option.progress
last_pal = option.palette
last_rect = option.rect
option.progress = alternative
pal = QtGui.QPalette()
# alternative color
pal.setColor(QtGui.QPalette.Highlight, QtCore.Qt.red)
option.palette = pal
option.rect = self.subElementRect(QtWidgets.QStyle.SE_ProgressBarContents, option, widget)
self.proxy().drawControl(QtWidgets.QStyle.CE_ProgressBarContents, option, painter, widget)
option.progress = last_value
option.palette = last_pal
option.rect = last_rect
return
super(ProxyStyle, self).drawControl(element, option, painter, widget)
class ProgressBar(QtWidgets.QProgressBar):
def paintEvent(self, event):
painter = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOptionProgressBar()
if hasattr(self, 'alternative'):
opt.alternative = self.alternative()
self.initStyleOption(opt)
painter.drawControl(QtWidgets.QStyle.CE_ProgressBar, opt)
#QtCore.pyqtSlot(int)
def setAlternative(self, value):
self._alternative = value
self.update()
def alternative(self):
if not hasattr(self, '_alternative'):
self._alternative = 0
return self._alternative
class Actions(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('Progress Bar')
self.objectsToProcess = 100
self.objectsProcessed = 0
self.objectsVerified = 0
self.progress_bar = ProgressBar(maximum=self.objectsToProcess)
self.process_btn = QtWidgets.QPushButton('Process')
self.verify_btn = QtWidgets.QPushButton('Verify')
self.process_btn.clicked.connect(self.process)
self.verify_btn.clicked.connect(self.verify)
lay = QtWidgets.QGridLayout(self)
lay.addWidget(self.progress_bar, 0, 0, 1, 2)
lay.addWidget(self.process_btn, 1, 0)
lay.addWidget(self.verify_btn, 1, 1)
def process(self):
if self.objectsProcessed + 1 < self.objectsToProcess:
self.objectsProcessed += 1
self.progress_bar.setValue(self.objectsProcessed)
def verify(self):
if self.objectsVerified < self.objectsProcessed:
self.objectsVerified += 1
self.progress_bar.setAlternative(self.objectsVerified)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle(app.style()))
w = Actions()
w.show()
sys.exit(app.exec_())
Thanks for #eyllanesc for providing a robust solution. I chose to go with a lighter (admittedly hackish) solution of overlapping two progress bars and making the top bar slightly transparent using QGraphicsOpacityEffect.
# Opaque prog bar
self.verifyProgress = QProgressBar(self)
self.verifyProgress.setGeometry(5, 5, 300, 25)
self.verifyProgress.setMaximum(self.objectsToProcess)
self.verifyProgress.setFormat('%p% / ')
self.verifyProgress.setAlignment(Qt.AlignCenter)
# Must set the transparent prog bar second to overlay on top of opaque prog bar
self.processProgress = QProgressBar(self)
self.processProgress.setGeometry(5, 5, 300, 25)
self.processProgress.setMaximum(self.objectsToProcess)
self.processProgress.setFormat(' %p%')
self.processProgress.setAlignment(Qt.AlignCenter)
op = QGraphicsOpacityEffect(self.processProgress)
op.setOpacity(0.5)
self.processProgress.setGraphicsEffect(op)
Result:
I needed to do something similar recently and choose to use a gradient color for the progressbar chunk since I needed to use stylesheets too.
def set_pb_value(self, pb, value_1, value_2):
if value_2 > value_1:
pb.setValue(value_2)
pb.setFormat("{} / {}".format(value_1, value_2))
pb.setStyleSheet('QProgressBar::chunk {' +
'background-color: qlineargradient(spread:pad, x1:' + str(value_1/pb.maximum()) + ', y1:0, x2:' +
str(value_1/value_2) + ', y2:0, stop:' + str(value_1/value_2) + ' rgba(0, 255, 0, 255), stop:1 '
'rgba(255, 0, 0, 255)); width: -1px; margin: -1px;}')
else:
pb.setValue(value_1)
pb.setFormat("%v")
My values were whole numbers so value_1/pb.maximum() was necessary for me, but change it per your needs.
I also had some issues with the other stylesheets and the progressbar margins which is why they are set to -1 right now, you may not need to include that.

How can i have a transparent background in a pyside QWidget, but keep its children opaque

I have an widget that contain a lot of children , i want to set its background transparent , but keep its children opaque.
I'am using PySide 1.2.1 win7
I have try something like this:
self.setAttribute(Qt.WA_TranslucentBackground,True);
self.setStyleSheet("background-color:rgba(40,40,150,150);border:0px;")
but it dosen't work for me . It make the whole widget transparent . I want to keep the children opaque. Can someone help me ? Thank you so much. Here is my code , thanks for help.
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class M_SCROLL_GRID_WIDGET(QWidget):
# This is a common ui class .
def __init__(self,column_count):
super(M_SCROLL_GRID_WIDGET, self).__init__()
self.column_count = column_count
self.visible_widget_list = []
self.scroll_widget = QWidget()
self.scroll_area = QScrollArea()
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setWidget(self.scroll_widget)
self.main_layout = QGridLayout()
self.main_layout.setSpacing(0)
self.scroll_widget.setLayout(self.main_layout)
self.main_layout.setAlignment(Qt.AlignTop)
master_layout = QVBoxLayout(self)
master_layout.addWidget(self.scroll_area)
self.setLayout(master_layout)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setStyleSheet("background-color:rgba(40,40,150,150);border:0px;")
def Get_Widget_Count(self):
return len(self.visible_widget_list)
def Add_Widget_To_Vis_List(self, widget):
self.visible_widget_list.append(widget)
def Remove_Widget_To_Vis_List(self, widget):
self.visible_widget_list.remove(widget)
def Remove_All_Widgets(self):
for i in reversed(range(self.main_layout.count())):
widget = self.main_layout.itemAt(i).widget()
widget.setParent(None)
def Clean_Visible_List(self):
self.visible_widget_list = []
def Refresh(self):
for widget_index in xrange(len(self.visible_widget_list)):
r_position = widget_index / self.column_count
c_position = (widget_index + 1) % self.column_count
if c_position == 0:
c_position = self.column_count
self.main_layout.addWidget(self.visible_widget_list[widget_index], r_position, c_position)
if __name__ == '__main__':
app = QApplication(sys.argv)
caofan = M_SCROLL_GRID_WIDGET(3)
btn_list = []
caofan.Remove_All_Widgets()
for a in xrange(50):
btn = QPushButton(str(a+1))
btn_list.append(btn)
caofan.Add_Widget_To_Vis_List(btn)
caofan.Refresh()
caofan.show()
app.exec_()
I suspect the real problem is that the style sheet you specify is propagating to the child widgets.
So, remove...
self.setStyleSheet("background-color:rgba(40,40,150,150);border:0px;")
and override QWidget::paintEvent with something like...
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(self.rect(), QColor(40, 40, 150, 150))

How to make a widget's height a fixed proportion to its width

I'm working on a PyQt5 application that needs to have a banner along the top. The banner is just a wide image, whose width should always be the width of the window, and whose height should be a fixed proportion. In other words, the banner image's height should depend on the width of the window. The widget beneath the banner (the main content) should stretch to fill all available vertical space.
I've basically ported this SO answer to PyQt5:
class Banner(QWidget):
def __init__(self, parent):
super(Banner, self).__init__(parent)
self.setContentsMargins(0, 0, 0, 0)
pixmap = QPixmap('banner-1071797_960_720.jpg') # see note below
self._label = QLabel(self)
self._label.setPixmap(pixmap)
self._label.setScaledContents(True)
self._label.setFixedSize(0, 0)
self._label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self._resizeImage()
def resizeEvent(self, event):
super(Banner, self).resizeEvent(event)
self._resizeImage()
def _resizeImage(self):
pixSize = self._label.pixmap().size()
pixSize.scale(self.size(), Qt.KeepAspectRatio)
self._label.setFixedSize(pixSize)
(For this example, I'm using this free banner image, but there's nothing special about it.)
I've put the banner in the application code below, where a label serves as a placeholder for the main content:
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
widget.setContentsMargins(0, 0, 0, 0)
layout = QVBoxLayout(widget)
banner = Banner(widget)
bannerSizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
bannerSizePolicy.setHeightForWidth(True)
banner.setSizePolicy(bannerSizePolicy)
layout.addWidget(banner)
label = QLabel('There should be a banner above')
label.setStyleSheet('QLabel { background-color: grey; color: white; }');
layout.addWidget(label)
layout.setStretch(0, 1)
widget.resize(320, 200)
widget.move(320, 200)
widget.setWindowTitle('Banner Tester')
widget.show()
sys.exit(app.exec_())
The problem is, the label fills 100% of the window—the banner isn't visible at all.
I've tried many different size policies and stretch factors, and removing size policies altogether, but haven't found how to do what I need. The image in the banner should be proportionately scaled to fit the window's width, and the label should fill the remaining vertical space in the window.
Ideas?
#kuba-ober's comment was right: I had to implement hasHeightForWidth() and heightForWidth() in the Banner class.
Here's the modified code, which works the way I want. All the modifications have comments within the code.
class Banner(QWidget):
def __init__(self, parent):
super(Banner, self).__init__(parent)
self.setContentsMargins(0, 0, 0, 0)
pixmap = QPixmap('banner-1071797_960_720.jpg')
# First, we note the correct proportion for the pixmap
pixmapSize = pixmap.size()
self._heightForWidthFactor = 1.0 * pixmapSize.height() / pixmapSize.width()
self._label = QLabel('pixmap', self)
self._label.setPixmap(pixmap)
self._label.setScaledContents(True)
self._label.setFixedSize(0, 0)
self._label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
self._resizeImage(self.size())
def hasHeightForWidth(self):
# This tells the layout manager that the banner's height does depend on its width
return True
def heightForWidth(self, width):
# This tells the layout manager what the preferred and minimum height are, for a given width
return math.ceil(width * self._heightForWidthFactor)
def resizeEvent(self, event):
super(Banner, self).resizeEvent(event)
# For efficiency, we pass the size from the event to _resizeImage()
self._resizeImage(event.size())
def _resizeImage(self, size):
# Since we're keeping _heightForWidthFactor, we can code a more efficient implementation of this, too
width = size.width()
height = self.heightForWidth(width)
self._label.setFixedSize(width, height)
if __name__ == '__main__':
app = QApplication(sys.argv)
widget = QWidget()
widget.setContentsMargins(0, 0, 0, 0)
layout = QVBoxLayout(widget)
banner = Banner(widget)
# Turns out we don't need the bannerSizePolicy now
# bannerSizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
# bannerSizePolicy.setHeightForWidth(True)
# banner.setSizePolicy(bannerSizePolicy)
layout.addWidget(banner)
label = QLabel('There should be a banner above')
label.setStyleSheet("QLabel { background-color: grey; color: white; }");
layout.addWidget(label)
layout.setStretch(1, 1)
widget.resize(320, 200)
widget.move(320, 200)
widget.setWindowTitle('Banner Tester')
widget.show()
sys.exit(app.exec_())

How to get background of textview in pygobject “gtk3”?

I'd like to get the current background color of my textview to change it and restore it later.
here what I tried:
context = textview.get_style_context()
state = Gtk.StateFlags.NORMAL
color = context.get_background_color(state)
I tried all possible states, but none returns the correct background color (white in my case)
Any idea how to get it?
I'm not exactly sure what you specific problem is without seeing more code, but here is a quick example that overrides the background and then restores it on a button click:
from gi.repository import Gtk, Gdk
import sys
class MyWindow(Gtk.ApplicationWindow):
def __init__(self, app):
Gtk.Window.__init__(self, title="Textview example", application=app)
self.set_default_size(250, 100)
self.set_border_width(10)
self.view = Gtk.TextView()
self.style_context = self.view.get_style_context()
self.default_bg_color = self.style_context.get_background_color(Gtk.StateFlags.NORMAL)
self.view.override_background_color(Gtk.StateFlags.NORMAL,
Gdk.RGBA(0, 0, 0, 1))
self.btn = Gtk.Button(label="Click Here")
self.btn.connect("clicked", self.on_btn_clicked)
box = Gtk.VBox()
box.pack_start(self.view, True, True, 0)
box.pack_start(self.btn, False, False, 0)
self.add(box)
def on_btn_clicked(self, widget):
current_bg = self.style_context.get_background_color(Gtk.StateFlags.NORMAL)
if current_bg == self.default_bg_color:
self.view.override_background_color(Gtk.StateFlags.NORMAL,
Gdk.RGBA(0, 0, 0, 1))
else:
self.view.override_background_color(Gtk.StateFlags.NORMAL,
self.default_bg_color)
class MyApplication(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
win = MyWindow(self)
win.show_all()
def do_startup(self):
Gtk.Application.do_startup(self)
app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)

Categories

Resources