如何正确更改pygtk gtk.Button颜色

时间:2015-12-02 22:36:17

标签: python user-interface button colors pygtk

在我的应用程序中,我有大约500个按钮,这些按钮在采取特定操作时都会更新其标签和颜色。当我注意到(通过使用cProfile和pdb)问题是由更改按钮颜色引起的时候,我遇到了崩溃和性能问题:

self.button.modify_bg(gtk.STATE_PRELIGHT, color)
self.button.modify_bg(gtk.STATE_NORMAL, color)
像这样的500次调用需要5秒的永久性(这也会冻结GUI),并且应用程序运行的时间越长,速度就越慢。如果有人想知道,我有一个强大的处理器和大量的可用内存。

之前我试图按照docs中的建议使用EventBox。但是,这只会改变按钮后面的颜色,而不是表面上的颜色:

import gtk

win = gtk.Window()
win.connect("destroy", gtk.main_quit)

btn = gtk.Button("test")
eb = gtk.EventBox()
eb.add(btn)
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("red"))

win.add(eb)
win.show_all()

gtk.main()

结果:

button is not red

我还尝试了另一种涉及检索和修改样式的方法。这导致与modify_bg相同的缓慢。此外,我还在随机位置随机崩溃,通常会出现低级内存分配错误,例如从gtk中双重释放。

import gtk

win = gtk.Window()
win.connect("destroy", gtk.main_quit)

btn = gtk.Button("test")
#copy the current style and replace the background
style = btn.get_style().copy()
style.bg[gtk.STATE_NORMAL] = gtk.gdk.color_parse("red")

#set the button's style to the one you created
btn.set_style(style)

win.add(btn)
win.show_all()

gtk.main()

按钮的颜色似乎是由操作系统管理的,我无法在没有缓慢,崩溃或不良结果的情况下找到解决方法。我非常需要通过颜色传达有关按钮的重要信息。

那么如何正确更改按钮颜色?

1 个答案:

答案 0 :(得分:0)

我最终使用gtk.EventBox实现了我自己的Button,gtk.Label在其小部件树中保存了set_label()。与按钮不同,设置标签颜色似乎与操作系统不冲突。

我还实现了一些便利功能,例如modify_bg

import gtk class ColoredButton(gtk.EventBox): ''' This class implements a simple unanimated button whose color can be changed ''' def __init__(self, widget = gtk.Label()): ''' widget must be a gtk.Label this is not checked in this simple version ''' #initialize superclass EventBox super(ColoredButton, self).__init__() #embed widget inside vbox and hbox self.widget = widget self.vbox = gtk.VBox(homogeneous=False, spacing=0) self.hbox = gtk.HBox(homogeneous=False, spacing=0) self.hbox.pack_start(self.vbox, expand = True, fill=False) self.vbox.pack_start(self.widget, expand = True, fill = False) #draws a frame around the entire construct to make everything look more like a button self.frame = gtk.Frame() self.frame.add(self.hbox) #add the final "button" to this EventBox in order to handle events self.add(self.frame) #define which events should be reacted to, those constants can be found in pygtk docs self.add_events(gtk.gdk.BUTTON_RELEASE_MASK) self.add_events(gtk.gdk.BUTTON_PRESS_MASK) self.add_events(gtk.gdk.ENTER_NOTIFY_MASK) self.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) #activate focus self.set_can_focus(True) #align the "button" text in the middle of the box self.widget.set_alignment(xalign=0.5, yalign=0.5) def show(self): super(ColoredButton, self).show() self.hbox.show() self.vbox.show() self.frame.show() self.widget.show() def set_label(self, label): self.set_text(label) def set_text(self, text): self.widget.set_text(text) def changeColor(self, color, state = gtk.STATE_NORMAL): if color is not None: currentcolor = self.style.bg[state] #too lazy to look up in docs if color != currentcolor also works if color.red != currentcolor.red or color.green != currentcolor.green or color.blue != currentcolor.blue: self.modify_bg(state, color) def changeTextColor(self, color, state = gtk.STATE_NORMAL): if color is not None: currentcolor = self.style.bg[state] if color.red != currentcolor.red or color.green != currentcolor.green or color.blue != currentcolor.blue: self.widget.modify_fg(gtk.STATE_NORMAL, color) def onButtonClick(widget, event = None): if event.button == 1: widget.set_label("left click") elif event.button == 2: widget.set_label("middle click") elif event.button == 3: widget.set_label("right click") import gtk w = gtk.Window() w.connect('destroy', gtk.main_quit) coloredbutton=ColoredButton(widget = gtk.Label("Hello there")) coloredbutton.changeColor(gtk.gdk.color_parse("black")) coloredbutton.changeTextColor(gtk.gdk.color_parse("yellow")) coloredbutton.set_size_request(width = 100, height = 50) coloredbutton.connect("button-release-event", onButtonClick) w.add(coloredbutton) w.show_all() gtk.main() 仍然太慢,但不会导致崩溃。通过检查当前颜色是否与我想要设置的颜色相同,我还为不改变的按钮节省了大量的计算时间。

我的代码非常粗略,但它适用于我的目的。随意使其更加强大和/或灵活:

my colored button

Meteor.methods({
  add_new_email: function(address)
  {
    Accounts.addEmail(Meteor.userId(), address);
  }
});