1

在不实际单击按钮的情况下与按钮交互的正确方法是什么?

我有一个按钮“按钮”,点击后可以:

  • 调用方法“the_method”,该方法将打印已传递给它的参数(此处为“文件名”)
  • 切换它自己的属性,这里是它的图标。

而且我有一个树视图,其行必须在双击时:

  • 调用方法“the_method”,该方法将打印已传递给它的参数(此处为“文件名”)
  • 切换“按钮”的属性,这里是它的图标。

只有第一部分有效。调用“foo”函数(通过按钮的回调,直接用于树视图项)并检索参数(“文件名”)确定,但如何执行作业的第 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()
4

2 回答 2

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)

其他改进可能是(对不起,我在这里为 GTK 类/函数使用 C 命名,我比 python 更了解):

  • 使用 aGtkToggleButton而不是自己跟踪按钮状态
  • 使用 gtk_button_set_use_stock 告诉按钮将您在按钮中设置的标签解释为按钮的股票 id(这也可能打印相关文本,对此不确定)
  • 切换到 GTK 3(使用 pyGObject),因为这是 GTK 2 代码(使用 pyGTK),除非您想要 Windows 兼容性

在 linuxfr 上见 :-)

于 2013-08-10T03:44:06.373 回答
0

首先,我对python一无所知,但我有一些经验,gtk+而且我或多或少地熟悉它的概念。

我注意到的第一件事是您定义了一个名为的类和两个名为and的GUI单独类。对我来说,这种方法只有在你设计最后提到的两个类时才有意义,它们本身就是一种(复合)小部件。这样您就可以在更高级别上实例化它们,例如在 GUI 类中。如果您想重用这些新的小部件,这将是一种通用方法并且非常有意义。ButtonsLister

你这样做的方式对我来说没有意义。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()
于 2013-08-09T18:38:12.657 回答