在没有实际点击按钮的情况下与按钮交互的正确方法是什么?
我有一个按钮“按钮”,可以点击:
我有一个树视图,其行必须双击:
只有第一部分有效。调用“foo”函数(通过按钮的回调,直接用于树视图项),并且检索参数(“filename”),但是如何执行作业的第2部分(更改“按钮”的属性) ,这是它的图标)?
import gtk
class Lister(object):
def __init__(self):
self.hbox = gtk.HBox()
liststore = gtk.ListStore(str)
liststore.append(["foo"])
liststore.append(["bar"])
treeview = gtk.TreeView(liststore)
self.hbox.pack_start(treeview, False)
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn("Column 1")
col.pack_start(cell, True)
col.set_attributes(cell,text=0)
treeview.connect('row-activated', self.open_file)
treeview.append_column(col)
def open_file(self, button, *args):
Buttons().the_method(self, "foo")
class Buttons(object):
OPEN_IMAGE = gtk.image_new_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
CLOSED_IMAGE = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_BUTTON)
def __init__(self):
self.button = gtk.Button() # THIS is the button to modify
self.hbox = gtk.HBox()
self.hbox.pack_start(self.button, False)
self.button.set_image(self.OPEN_IMAGE)
self.button.connect('clicked', self.the_method, "plop")
self.toggled = True
def the_method(self, button, filename):
print filename
print vars(self)
if self.toggled:
self.button.set_image(self.CLOSED_IMAGE)
self.toggled = False
else:
self.button.set_image(self.OPEN_IMAGE)
self.toggled = True
class GUI(object):
def delete_event(self, widget, event, data=None):
gtk.main_quit()
return False
def __init__(self):
self.window = gtk.Window()
self.window.set_size_request(100, 150)
self.window.connect("delete_event", self.delete_event)
vbox = gtk.VBox()
vbox.pack_start(Buttons().hbox, False, False, 1)
vbox.pack_start(Lister().hbox)
self.window.add(vbox)
self.window.show_all()
return
def main():
gtk.main()
if __name__ == "__main__":
GUI()
main()
答案 0 :(得分:4)
我非常不同意user1146332的回答。这不是一个GTK +问题,也不是一个强大的设计问题,只是一个面向对象的编程问题。您的错误的原因是您像这样致电the_method
:
Buttons().the_method(self, "foo")
这不起作用,因为你混合了两个不同的基本内容:一个类和一个类的实例。当您致电Buttons()
时,您正在创建Buttons
课程的新实例。因此,由于此类不是单例,您实际上是使用新的GtkButton创建一个新实例,并且最终不会与您之前创建的按钮进行交互。
这里的解决方案是让Lister
对象知道它需要修改的内容,这意味着存储您之前创建的Buttons
实例,例如在self.button
中,并调用the_method
就可以了。
self.button.the_method("foo")
以下是您的代码的略微修改版本。重要的是Lister
实例现在知道它需要修改的Buttons
实例。
import gtk
class Lister(object):
def __init__(self, button):
self.hbox = gtk.HBox()
self.button = button
liststore = gtk.ListStore(str)
liststore.append(["foo"])
liststore.append(["bar"])
treeview = gtk.TreeView(liststore)
self.hbox.pack_start(treeview, False)
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn("Column 1")
col.pack_start(cell, True)
col.set_attributes(cell,text=0)
treeview.connect('row-activated', self.open_file)
treeview.append_column(col)
def open_file(self, button, *args):
self.button.the_method("foo")
class Buttons(object):
OPEN_IMAGE = gtk.image_new_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
CLOSED_IMAGE = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_BUTTON)
def __init__(self):
self.button = gtk.Button() # THIS is the button to modify
self.hbox = gtk.HBox()
self.hbox.pack_start(self.button, False)
self.button.set_image(self.OPEN_IMAGE)
self.button.connect('clicked', self.the_method, "plop")
self.toggled = True
def the_method(self, filename):
print filename
print vars(self)
if self.toggled:
self.button.set_image(self.CLOSED_IMAGE)
self.toggled = False
else:
self.button.set_image(self.OPEN_IMAGE)
self.toggled = True
class GUI(object):
def delete_event(self, widget, event, data=None):
gtk.main_quit()
return False
def __init__(self):
self.window = gtk.Window()
self.window.set_size_request(100, 150)
self.window.connect("delete_event", self.delete_event)
vbox = gtk.VBox()
buttons = Buttons()
vbox.pack_start(buttons.hbox, False, False, 1)
vbox.pack_start(Lister(buttons).hbox)
self.window.add(vbox)
self.window.show_all()
return
def main():
gtk.main()
if __name__ == "__main__":
GUI()
main()
然而,仍有很大的改进空间。我建议您不要使用__init__
函数来创建窗口小部件,而是使用create
方法返回窗口小部件树的顶层窗口小部件。这是因为您无法在__init__
中返回任何内容,因此使用其他方法更容易,而不是在那里引发异常。
b = Buttons()
vbox.pack_start(b.create(), False, False, 1)
l = Lister(b)
vbox.pack_start(l.create(), False, False, 1)
其他改进可能是(对不起,我在这里使用C命名为GTK类/函数,我比python更好):
GtkToggleButton
而不是自己跟踪按钮状态在linuxfr上见到你: - )
答案 1 :(得分:0)
首先,我对python一无所知,但我对gtk+
有一些经验,而且我或多或少熟悉它的概念。
我注意到的第一件事是你定义了一个名为GUI
的类和两个名为Buttons
和Lister
的独立类。对我来说,这样的方法只有在你设计最后提到的两个类时才有意义,因为它们是一种(复合)小部件。这样您就可以在更高级别实例化它们,例如在GUI类中。这将是一种通用方法,如果您想重用这些新小部件,则非常有意义。
你这样做的方式对我来说没有意义。根据我迄今为止收集的内容Buttons
和Lister
的实际目的是使用小部件填充主应用程序窗口,将回调连接到这些小部件的信号,并将这些回调定义为方法。
我认为如果你这样做的话,你会限制gtk的灵活性。例如,您将信号连接到回调,原则上您无法访问界面的所有小部件。相比之下,我更喜欢代码中的一个常见位置,在该位置我将信号连接到回调,并且我可以主要将所有感兴趣的小部件传递给特定的回调。
事实上,人们经常需要在回调中对几个小部件进行操作。因此,您必须考虑将回调实现为GUI类的方法,它们可以主要访问用户界面的所有元素。
另外,您应该考虑使用glade
设计界面。这样你的代码就会更清晰。
补充(在推送一些代码之后):
import gtk
class GUI(object):
OPEN_IMAGE = gtk.image_new_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
CLOSED_IMAGE = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_BUTTON)
toggled = True
def __init__(self):
self.window = gtk.Window()
self.window.set_size_request(100, 150)
self.window.connect("delete_event", gtk.main_quit)
vbox = gtk.VBox()
self.button = gtk.Button() # THIS is the button to modify
self.button.set_image(self.OPEN_IMAGE)
liststore = gtk.ListStore(str)
liststore.append(["foo"])
liststore.append(["bar"])
self.treeview = gtk.TreeView(liststore)
cell = gtk.CellRendererText()
col = gtk.TreeViewColumn("Column 1")
col.pack_start(cell, True)
col.set_attributes(cell,text=0)
self.treeview.append_column(col)
vbox.pack_start(self.button, False, False, 1)
vbox.pack_start(self.treeview, False, False, 1)
self.treeview.connect('row-activated', self.the_method_wrapper, "plop")
self.button.connect('clicked', self.the_method, "plop")
self.window.add(vbox)
self.window.show_all()
return
def the_method_wrapper(self, button, *args):
self.the_method(self, "foo")
def the_method(self, button, filename):
print filename
print vars(self)
if self.toggled:
self.button.set_image(self.CLOSED_IMAGE)
self.toggled = False
else:
self.button.set_image(self.OPEN_IMAGE)
self.toggled = True
def main():
gtk.main()
if __name__ == "__main__":
GUI()
main()