Reputation: 13
I want the colour of a button to change when I click on it.
Or more general I want to update/refresh the Gtk.Button or Gtk.Box. The entire Gtk.Window would be fine as well.
The only way I found to update a widget in Gtk3 is the Gtk.widget.queue_draw() method, but it looks like it
only works with a Gtk.DrawingArea (Drawin with cairo on Zetcode, it's for Gtk2 but I've read there
haven't been made many changes in this section). I would assume it works on any widget since it is named
gtk.widget.queue_draw and not gtk.drawingArea.queue_draw and also it's not producing an
error but it appears to be omitted.
I might have a wrong understanding of how it is supposed to work though. The only guis I've made before are
some time ago and were simple things in Java.
So here is my code example:
# -*- coding: utf-8 -*-
from gi.repository import Gtk, Gdk
import cairo
a = 0
class ProgWindow(Gtk.Window):
def __init__(self):
super(ProgWindow, self).__init__() # don't know what this is doing, works also without
self.window = Gtk.Window.__init__(self, title="example")
self.connect("delete-event", Gtk.main_quit)
box = Gtk.Box()
self.add(box)
button = Gtk.Button("Hello")
if (a==0):
button.set_name('green_button')
button.set_tooltip_text("should be green")
else:
button.set_name('red_button')
button.set_tooltip_text("should be red")
button.connect("clicked", callback_clicked)
box.add(button)
def callback_clicked(self):
global a
print(a)
a = 1
self.queue_draw()
gui() # creates a new window with the correct colour and tool tip
def gui():
win = ProgWindow()
win.show_all()
Gtk.main()
style_provider = Gtk.CssProvider()
css_data = """
#green_button{
background: #009900;
font-size: 120%;
font-weight: 600;
}
#red_button{
background: #FF0000;
font-size: 120%;
font-weight: 600;
}
"""
style_provider.load_from_data(css_data.encode())
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
if __name__ == "__main__":
gui()
I've also read somewhere, that it is possible to invalidate an area. Would that maybe be the way to do it?
Also I've read that things get updated once the Gtk.main() loop is reached again.
If so, how do I evoke this? As I said I'm quit new to gui programming but my understanding is,
that this is where it's "stuck" most of the time while waiting for i.e. user input.
Or would removing the widget and place a new one in the same space do the job?
Any help and explanation would be greatly appreciated
Thanks
Upvotes: 1
Views: 2938
Reputation: 1182
You have made it really really too complicated, here below a simplified version that will make the button green when clicked.
p.s. changing the colors of the widgets like this should realy be an exception and not the rule, breaking user themes is generally not a good idea.
from gi.repository import Gtk
class CSSButtonApp(object):
def __init__(self):
self.mycolor = '''
GtkButton {
border-image: none;
background-image: none;
background-color: green;
color: white;
}
'''
self.window = Gtk.Window()
self.window.set_title('CSS Button')
self.window.set_default_size(200, 100)
self.window.set_border_width(10)
self.window.connect('destroy', lambda w: Gtk.main_quit())
button = Gtk.Button(label="My Button")
self.window.add(button)
provider = Gtk.CssProvider()
provider.load_from_data(self.mycolor)
button.connect("clicked", self.apply_css, provider)
self.window.show_all()
def apply_css(self, widget, provider):
Gtk.StyleContext.add_provider(widget.get_style_context(),
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
def main(self):
Gtk.main()
if __name__ == '__main__':
app = CSSButtonApp()
app.main()
Upvotes: 1
Reputation: 57920
You don't need to run queue_draw()
for this. You also shouldn't recreate your GUI every time you want the button to change color. This is likely messing things up, because in gui()
you create a new window and start a new main loop with Gtk.main()
, leading to many main loops running recursively. This is something you don't want.
Instead, use button.set_name('green-button')
or red-button
to change the color. No further action should be necessary other than returning from the signal handler.
Even better would be to use style classes instead of IDs — you might want to have more than one green or red button. In that case, put .green-button
and .red-button
in your CSS (instead of #green-button
and #red-button
) and use this to change the color:
button.get_style_context().remove_class('green-button')
button.get_style_context().add_class('red-button')
Or vice versa.
Upvotes: 3