Update/refresh Gtk3 中的小部件 (pygobject) 和 python3

Update/refresh Widget in Gtk3 (pygobject) and python3

我希望按钮的颜色在我点击时改变。
或者更笼统地说,我想 update/refresh Gtk.Button 或 Gtk.Box。整个 Gtk.Window 也可以。 我发现在 Gtk3 中更新小部件的唯一方法是 Gtk.widget.queue_draw() 方法,但它看起来像 仅适用于 Gtk.DrawingArea(Drawin with cairo on Zetcode,它适用于 Gtk2,但我在那里读过 本节未做太多改动)。我假设它适用于任何小部件,因为它被命名为 gtk.widget.queue_draw 而不是 gtk.drawingArea.queue_draw 而且它也没有产生 错误,但它似乎被省略了。
我可能对它应该如何工作有错误的理解。我之前制作的唯一 guis 是 前段时间在 Java 中是简单的事情。
所以这是我的代码示例:

# -*- 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()

我也在某处读到,有可能使一个区域无效。那可能是这样做的方法吗? 我还读到,一旦再次到达 Gtk.main() 循环,事情就会更新。 如果是这样,我该如何唤起这一点?正如我所说,我是 gui 编程的新手,但我的理解是, 这就是它 "stuck" 大部分时间等待用户输入的地方。
或者删除小部件并在同一个 space 中放置一个新的小部件可以完成这项工作吗?
任何帮助和解释将不胜感激
谢谢

您不需要为此 运行 queue_draw()。您也不应该在每次希望按钮更改颜色时都重新创建 GUI。这可能会把事情搞砸,因为在 gui() 中你创建了一个新的 window 并用 Gtk.main() 开始了一个新的主循环,导致许多主循环 运行 递归。这是你不想要的。

而是使用 button.set_name('green-button')red-button 来更改颜色。除了从信号处理程序返回之外,不需要采取进一步的行动。

更好的方法是使用样式 类 而不是 ID — 您可能希望有多个绿色或红色按钮。在这种情况下,将 .green-button.red-button 放入 CSS(而不是 #green-button#red-button)并使用它来更改颜色:

button.get_style_context().remove_class('green-button')
button.get_style_context().add_class('red-button')

反之亦然。

你把它弄得太复杂了,下面是一个简化版本,点击时按钮会变成绿色。

p.s。 像这样更改小部件的颜色应该是一个例外而不是规则,破坏用户主题通常不是一个好主意。

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()