Синтаксис signal.connect
Я пытаюсь создать окно с двумя FileChooserButtons
, Первый должен помочь пользователю выбрать каталог, поэтому я использую действие Select_folder; второе - позволить пользователю выбрать файл.
Проблема в том, что я хотел, чтобы второй изменил текущую папку в зависимости от выбора, сделанного пользователем в первом.
Моей первоначальной идеей было использовать Signal.connect, как в строке:
Signal.connect(chooser1, "selection_changed", folder_changed, null)
Тем не менее, это приводит меня к следующей ошибке компиляции:
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)
Я также попытался добавить (callback)folder_changed согласно этому почтовому сообщению в списке рассылки vala, но безрезультатно.
Это весь код:
[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 ответ
Обратный вызов для Gtk должен включать параметр для объекта, который сгенерировал сигнал. Также Genie и Vala имеют синтаксическую поддержку сигналов GLib, чтобы с ними было легче работать. Вот пример, основанный на вашем коде:
[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()
Несколько замечаний:
- Название сигнала,
"selection_changed"
стал атрибутомfolder_chooser
который ты тогдаconnect
к. Компилятор Vala выполняет преобразование вGLib.Signal
во время компиляции FileChooserButton
,folder_chooser
, был удален из области видимости класса. Теперь к нему обращаются как к аргументу обратного вызова. Таким образом, он определяется как параметр функции обратного вызова- Вы заметите, что параметр для обратного вызова ожидает
FileChooser
типа а неFileChooserButton
тип. Это потому чтоselection_changed
сигнал является частьюFileChooser
интерфейс, которыйFileChooserButton
затем реализует. Это эффективно даетFileChooserButton
более одного типа - Хотя
_file_chooser
объявлен таким образом, что он доступен во всей области видимости класса, он был сделан доступным только внутри класса с помощью подчеркивания
С помощью Signal.connect()
гораздо ближе к C API для Gtk. Если вам нужно сделать это, то следующие действия работают на основе вашего исходного кода:
[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()
Несколько замечаний:
- Да, вам нужно привести к обратному вызову
GLib.Callback
как вы нашли в почтовом сообщении, на которое вы ссылались - Данные экземпляра вам нужны
Window
объект, который вы создалиFileChooserButton
ибо так меняетсяnull
вself
работает здесь - Vala поместит данные экземпляра в качестве первого параметра, поэтому, чтобы переопределить значение по умолчанию, вы должны использовать
CCode
атрибут, то есть[CCode( instance_pos = 2 )]
в этом случае - Ожидается, что объект, генерирующий сигнал, будет первым параметром функции обратного вызова, поэтому он присутствует в определении, даже если он не используется в этом примере. Это определяется как
Widget
типа, но вы можете изменить это наFileChooser
использоватьget_uri()
вызов
Что касается вашего вопроса о форматировании кода, я предпочитаю разбивать длинные строки, как вы можете видеть. Я не уверен, что пока есть согласованная "лучшая практика" для Genie.