问题
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 ()
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.
As an extra, less important point, what is the best practice: to split and indent long lines or to allow them in the code?
回答1:
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 offolder_chooser
which you thenconnect
to. The Vala compiler does the conversion toGLib.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 aFileChooserButton
type. This is because theselection_changed
signal is part of theFileChooser
interface that theFileChooserButton
then implements. This effectively gives aFileChooserButton
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 theFileChooserButton
for, so changingnull
toself
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 toFileChooser
to use theget_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.
来源:https://stackoverflow.com/questions/34689763/the-signal-connect-syntax