signal.connect语法 [英] The signal.connect syntax

查看:128
本文介绍了signal.connect语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用两个 FileChooserButtons 创建一个窗口。第一个应该可以帮助用户选择一个目录,因此我使用的是Select_folder操作;第二个是允许用户选择一个文件。



问题在于我想让第二个文件夹根据用户在第一个文件夹中所做的选择更改当前文件夹。



我最初的想法是使用Signal.connect,如下所示:

  Signal.connect(chooser1 ,selection_changed,folder_changed,null)

但是,这给我带来了以下编译错误: / p>

  exercise4_1.gs:62.55-62.68:错误:无法创建委托对象没有实例方法或闭包
Signal.connect (chooser1,selection_changed,folder_changed,null)
^^^^^^^^^^^^^^
编译失败:1个错误,0个警告

我也试着根据这个邮件沟通在vala邮件列表中,无济于事。

这是整个代码:
$ b使用
Gtk
GLib

class TestWindow:Window
chooser1:Gtk.FileChooserButton
chooser2:Gtk.FileChooserButton
构造()

//窗口的一般特性
title =文件选择器
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
chooser1 = new FileChooserButton(
选择一个文件夹,
FileChooserAction.SELECT_FOLDER

chooser2 =新建FileChooserButton(
选择一个文件夹,
FileChooserAction.OPEN

chooser1.set_current_folder(Environment.get_h ome_dir())
chooser2.set_current_folder(Environment.get_home_dir())

Signal.connect(chooser1,selection_changed,folder_changed,null)

var box = new Gtk.Box(Gtk.Orientation.VERTICAL,0)
box.pack_start(chooser1,true,true,0)
box.pack_start(chooser2,true,true,0)
添加(box)


def folder_changed()
var folder = chooser1.get_filename()
chooser2.set_current_folder(文件夹)


init
Gtk.init(ref args)
var test = new TestWindow()
test.show_all()
Gtk.main()




  1. 当然,我对这个特定语法缺乏理解,但是因为我卡住了,我会欣赏一个指针,让我摆脱它。

  2. 作为一个额外的,不太重要的点,最佳实践是什么:分割和缩进长行或在代码中允许它们?



解决方案

Gtk的回调需要包含生成信号的对象的参数。另外,Genie和Vala对GLib信号的语法支持使信号更容易处理。这是一个基于你的代码的例子:

pre $ code $ [$ indent = 4]
使用
Gtk
$ b $ class TestWindow:Window
_file_chooser:FileChooserButton
$ b $ construct()
title =文件选择器
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)

var folder_chooser = new FileChooserButton(
选择一个文件夹,
FileChooserAction.SELECT_FOLDER

folder_chooser .set_current_folder(Environment.get_home_dir())
folder_chooser.selection_changed.connect(folder_changed)
$ b _file_chooser = new FileChooserButton(
选择文件,
FileChooserAction。 OPEN

_file_choos er.set_current_folder(Environment.get_home_dir())

var box = new Box(Orientation.VERTICAL,0)
box.pack_start(folder_chooser,true,true,0)
box.pack_start(_file_chooser,true,true,0)
add(box)
$ b $ def folder_changed(folder_chooser_widget:FileChooser)
folder:string = folder_chooser_widget.get_uri()
_file_chooser.set_current_folder_uri(文件夹)

初始化
Gtk.init(ref args)
var test = new TestWindow()
test.show_all()
Gtk.main()

需要注意的几点:


  • 信号名称selection_changed已成为 folder_chooser 然后你连接到。 Vala编译器在编译时转换为 GLib.Signal
  • FileChooserButton , folder_chooser ,已从类的范围中删除。它现在通过作为参数传递给回调来访问。所以它被定义为回调函数的参数。

  • 您会注意到回调参数需要 FileChooser 类型,而不是 FileChooserButton 类型。这是因为 selection_changed 信号是 FileChooser 接口的一部分, FileChooserButton 然后执行。这实际上给出了 FileChooserButton 多于一个类型
  • 虽然声明了 _file_chooser 所以它可以在整个类的范围内使用,它只能在类内通过使用下划线来访问



使用 Signal.connect()更接近Gtk的C API。如果您需要这样做,那么下面的工作基于您的原始代码:

  [indent = 4] 
使用
Gtk
$ b $ class TestWindow:Window
chooser1:FileChooserButton
chooser2:FileChooserButton $ b $ construct()

//一般特性窗口
title =文件选择器
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
chooser1 = new FileChooserButton(
Choose a文件夹,
FileChooserAction.SELECT_FOLDER

chooser2 =新FileChooserButton(
选择一个文件夹,
FileChooserAction.OPEN

chooser1.set_current_folder(Environment.get_home_dir())
chooser2.set_current_folder(Environment.get_home_dir())

Signal.connect(
chooser1,
selection_changed,
(GLib.Callback)folder_changed,
self


var box = new Box(Orientation.VERTICAL,0)
box.pack_start(chooser1,true,true,0)
box.pack_start (chooser2,true,true,0)
add(box)

[CCode(instance_pos = 2)]
//或[CCode(instance_pos = -1)] to总是最后
def folder_changed(folder_chooser:Widget)
folder:string = chooser1.get_uri()
chooser2.set_current_folder_uri(文件夹)

初始化
Gtk.init(ref args)
var test = new TestWindow()
test.show_all()
Gtk.main()


需要注意的几点:将回调转换为 GLib.Callback ,就像您在链接到的邮件中找到的那样

  • 您需要的实例数据是 Window 对象创建了 FileChooserButton ,因此将 null 更改为 self 在此工作

  • Vala会将实例数据作为第一个参数,因此要覆盖默认值,您必须使用 CCode 属性,即 [CCode(instance_pos = 2)] 在这种情况下

  • 生成信号的对象仍然是回调函数的第一个参数,所以它在定义中存在,即使它在本例中未使用。这被定义为 Widget 类型,但您可以将其更改为 FileChooser 以使用 get_uri () call



  • 正如你所看到的,对于你的代码格式问题,我更喜欢分割长线。我不确定Genie是否已经达成了一致的最佳做法。

    I am trying to create a window with two FileChooserButtons. The first one should help the user pick a directory, thus I am using the action Select_folder; the second is to allow the user pick a file.

    The problem is that I wanted the second one to change the current folder depending on the choice the user made in the first one.

    My initial idea was to use Signal.connect, as in the line:

    Signal.connect(chooser1, "selection_changed", folder_changed, null)
    

    However, this is getting me the following compilation error:

    exercise4_1.gs:62.55-62.68: error: Cannot create delegate without target for instance method or closure
            Signal.connect(chooser1, "selection_changed", folder_changed, null)
                                                          ^^^^^^^^^^^^^^
    Compilation failed: 1 error(s), 0 warning(s)
    

    I've also tried adding (callback)folder_changed as per this mail communication at vala mailing list, to no avail.

    This is the whole code:

    [indent=4]
    
    uses
        Gtk
        GLib
    
    class TestWindow : Window
        chooser1:Gtk.FileChooserButton
        chooser2:Gtk.FileChooserButton
        construct()
    
            // General characteristics of the window
            title = "File chooser"
            window_position = WindowPosition.CENTER
            destroy.connect(Gtk.main_quit)
            chooser1 = new FileChooserButton(
                                                "Choose a Folder",
                                                FileChooserAction.SELECT_FOLDER
                                                )
            chooser2 = new FileChooserButton(
                                                 "Chooser a Folder",
                                                 FileChooserAction.OPEN
                                                 )
            chooser1.set_current_folder(Environment.get_home_dir())
            chooser2.set_current_folder(Environment.get_home_dir())
    
            Signal.connect(chooser1, "selection_changed", folder_changed, null)
    
            var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0)
            box.pack_start(chooser1, true, true,0)
            box.pack_start(chooser2, true, true,0)
            add(box)
    
    
        def folder_changed()
            var folder = chooser1.get_filename()
            chooser2.set_current_folder(folder)
    
    
    init
        Gtk.init (ref args)
        var test = new TestWindow ()
        test.show_all ()
        Gtk.main ()
    

    1. It is certainly my lack of understanding about this particular syntax, but since I am stuck, I would appreciate a pointer to get me out of it.

    2. As an extra, less important point, what is the best practice: to split and indent long lines or to allow them in the code?

    解决方案

    A callback for Gtk needs to include a parameter for the object that generated the signal. Also Genie and Vala have syntax support for GLib signals to make signals easier to work with. Here is an example based on your code:

    [indent=4]
    uses
        Gtk
    
    class TestWindow:Window
        _file_chooser:FileChooserButton
    
        construct()
            title = "File chooser"
            window_position = WindowPosition.CENTER
            destroy.connect( Gtk.main_quit )
    
            var folder_chooser = new FileChooserButton(
                                             "Choose a Folder",
                                             FileChooserAction.SELECT_FOLDER
                                            )
            folder_chooser.set_current_folder( Environment.get_home_dir() )
            folder_chooser.selection_changed.connect( folder_changed )
    
            _file_chooser = new FileChooserButton(
                                            "Chooser a File",
                                            FileChooserAction.OPEN
                                            )
            _file_chooser.set_current_folder( Environment.get_home_dir() )
    
            var box = new Box( Orientation.VERTICAL, 0 )
            box.pack_start( folder_chooser, true, true, 0 )
            box.pack_start( _file_chooser, true, true, 0 )
            add( box )
    
        def folder_changed( folder_chooser_widget:FileChooser )
            folder:string = folder_chooser_widget.get_uri()
            _file_chooser.set_current_folder_uri( folder )
    
    init
        Gtk.init( ref args )
        var test = new TestWindow()
        test.show_all()
        Gtk.main()
    

    A few points to note:

    • The signal name, "selection_changed" has become an attribute of folder_chooser which you then connect to. The Vala compiler does the conversion to GLib.Signal at compile time
    • The FileChooserButton, folder_chooser, has been removed from the scope of the class. It is now accessed by being passed as an argument to the callback. So it is defined as a parameter of the callback function
    • You will notice the parameter for the callback expects a FileChooser type and not a FileChooserButton type. This is because the selection_changed signal is part of the FileChooser interface that the FileChooserButton then implements. This effectively gives a FileChooserButton more than one type
    • Although _file_chooser is declared so it is available within the whole scope of the class, it has been made only accessible within the class by using the underscore

    Using Signal.connect() is much closer to the C API for Gtk. If you need to do this then the following works based on your original code:

    [indent=4]
    uses
        Gtk
    
    class TestWindow:Window
        chooser1:FileChooserButton
        chooser2:FileChooserButton
        construct()
    
            // General characteristics of the window
            title = "File chooser"
            window_position = WindowPosition.CENTER
            destroy.connect( Gtk.main_quit )
            chooser1 = new FileChooserButton(
                                             "Choose a Folder",
                                             FileChooserAction.SELECT_FOLDER
                                            )
            chooser2 = new FileChooserButton(
                                            "Chooser a Folder",
                                            FileChooserAction.OPEN
                                            )
            chooser1.set_current_folder( Environment.get_home_dir() )
            chooser2.set_current_folder( Environment.get_home_dir() )
    
            Signal.connect( 
                          chooser1, 
                          "selection_changed", 
                          (GLib.Callback)folder_changed,
                          self
                          )
    
            var box = new Box( Orientation.VERTICAL, 0 )
            box.pack_start( chooser1, true, true, 0 )
            box.pack_start( chooser2, true, true, 0 )
            add( box )
    
        [CCode( instance_pos = 2 )]
        // or [CCode( instance_pos = -1 )] to always be last
        def folder_changed( folder_chooser:Widget )
            folder:string = chooser1.get_uri()
            chooser2.set_current_folder_uri( folder )
    
    init
        Gtk.init( ref args )
        var test = new TestWindow()
        test.show_all()
        Gtk.main()
    

    A few points to note:

    • Yes you do need to cast the callback to GLib.Callback as you found in the mail message you linked to
    • The instance data you need is the Window object you have created the FileChooserButton for, so changing null to self works here
    • Vala will put instance data as the first parameter, so to override the default you have to use a CCode attribute, that is [CCode( instance_pos = 2 )] in this case
    • The object generating the signal is still expected to be the first parameter of the callback function, so it is there in the definition even though it is unused in this example. This is defined as Widget type, but you can change this to FileChooser to use the get_uri() call

    For your code formatting question I prefer to split long lines, as you can see. I'm not sure there is an agreed "best practise" for Genie as yet.

    这篇关于signal.connect语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆