从 Ada 事件处理程序参数获取事件源指针
Getting Event Source Pointer from Ada Event Handler Parameters
使用 GtkAda,我想确定切换了哪个单选按钮。
我想出的最好的是这段不太漂亮的代码,它遍历所有按钮以查找哪些按钮被切换:
procedure On_Pgm_Btn_Click
(Button : access Gtk.Widget.Gtk_Widget_Record'Class) is
Button_Array : array (Positive range <>) of Gtk_Radio_Button := (Pgm_Bit, Pgm_1, Pgm_2, Pgm_3, Pgm_4);
begin
for Index In Button_Array'range loop
if Button_Array(Index).Get_Active then
Selected_Program_Button := Button_Array(Index);
exit;
end if;
end loop;
end On_Pgm_Btn_Click;
这是使用此处理程序连接代码调用的:
Gtkada.Handlers.Widget_Callback.Connect (Pgm_Bit, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_1, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_2, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_3, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_4, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
我可以在调试器中看到参数Button的值与产生事件的按钮具有相同的地址,但我不知道常规方式使用此参数。它的类型是 Gtk.Widget.Gtk_Widget_Record'Class,这表明如果我对单选按钮进行未经检查的转换,我可能会破解代码;
如何从参数 Button 获取单选按钮?
(另外,如果有更好的方法获取单选按钮组的状态,我很想知道。我没有找到任何好的例子。)
更新解决方案
从下面接受的答案中,我了解到视图转换的实现就像函数调用一样简单,如 ARM 4.6 的示例所示。处理程序变成了这样:
procedure On_Pgm_Btn_Click
(Button : access Gtk.Widget.Gtk_Widget_Record'Class) is
This_Button : Gtk_Radio_Button;
begin
This_Button := Gtk_Radio_Button(Button);
if This_Button.Get_Active then
Selected_Program_Button := This_Button;
end if;
end On_Pgm_Btn_Click;
涉及的类型已经在gtk-radio-button.ads中定义为:
type Gtk_Radio_Button_Record is new Gtk_Check_Button_Record with null record;
type Gtk_Radio_Button is access all Gtk_Radio_Button_Record'Class;
并在 gtk_widget.ads 中为:
type Gtk_Widget_Record is new GObject_Record with null record;
type Gtk_Widget is access all Gtk_Widget_Record'Class;
因此没有理由重新定义它们或使用接受的答案中提供的包和示例代码。
修改后的代码中重要的一行是:
This_Button := Gtk_Radio_Button(Button);
执行视图转换。
这应该由查看转换 (ARM 4.6(5)) 而不是未经检查的转换来处理。
我没有安装 Gtk,所以我写了这篇文章(在 AdaCore’s documentation 进行了一些研究之后),我认为这是 self-contained 的等价物,并且可以使用 GCC 5.1.0 成功编译.
package View_Conversions is
type Widget_Record is tagged null record;
-- Represents Gtk.Widget.Gtk_Widget_Record
type Button_Record is new Widget_Record with null record;
type Button is access all Button_Record'Class;
-- Represents Gtk.Radio_Button.Gtk_Radio_Button
procedure On_Click (Widget : access Widget_Record'Class);
end View_Conversions;
和body
package body View_Conversions is
Selected : Button;
-- Records the selected button
procedure On_Click (Widget : access Widget_Record'Class) is
begin
Selected := Button (Widget);
-- If the Widget is a Button, save it; if not, raise CE
end On_Click;
end View_Conversions;
与未经检查的转换相比的优势在于,这是一个经过检查的转换,如果传递的 Widget
实际上不是 Button
,您将在 Constraint_Error
转换点。
使用 GtkAda,我想确定切换了哪个单选按钮。
我想出的最好的是这段不太漂亮的代码,它遍历所有按钮以查找哪些按钮被切换:
procedure On_Pgm_Btn_Click
(Button : access Gtk.Widget.Gtk_Widget_Record'Class) is
Button_Array : array (Positive range <>) of Gtk_Radio_Button := (Pgm_Bit, Pgm_1, Pgm_2, Pgm_3, Pgm_4);
begin
for Index In Button_Array'range loop
if Button_Array(Index).Get_Active then
Selected_Program_Button := Button_Array(Index);
exit;
end if;
end loop;
end On_Pgm_Btn_Click;
这是使用此处理程序连接代码调用的:
Gtkada.Handlers.Widget_Callback.Connect (Pgm_Bit, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_1, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_2, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_3, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
Gtkada.Handlers.Widget_Callback.Connect (Pgm_4, "toggled", On_Pgm_Btn_Click'Unrestricted_Access);
我可以在调试器中看到参数Button的值与产生事件的按钮具有相同的地址,但我不知道常规方式使用此参数。它的类型是 Gtk.Widget.Gtk_Widget_Record'Class,这表明如果我对单选按钮进行未经检查的转换,我可能会破解代码;
如何从参数 Button 获取单选按钮?
(另外,如果有更好的方法获取单选按钮组的状态,我很想知道。我没有找到任何好的例子。)
更新解决方案
从下面接受的答案中,我了解到视图转换的实现就像函数调用一样简单,如 ARM 4.6 的示例所示。处理程序变成了这样:
procedure On_Pgm_Btn_Click
(Button : access Gtk.Widget.Gtk_Widget_Record'Class) is
This_Button : Gtk_Radio_Button;
begin
This_Button := Gtk_Radio_Button(Button);
if This_Button.Get_Active then
Selected_Program_Button := This_Button;
end if;
end On_Pgm_Btn_Click;
涉及的类型已经在gtk-radio-button.ads中定义为:
type Gtk_Radio_Button_Record is new Gtk_Check_Button_Record with null record;
type Gtk_Radio_Button is access all Gtk_Radio_Button_Record'Class;
并在 gtk_widget.ads 中为:
type Gtk_Widget_Record is new GObject_Record with null record;
type Gtk_Widget is access all Gtk_Widget_Record'Class;
因此没有理由重新定义它们或使用接受的答案中提供的包和示例代码。
修改后的代码中重要的一行是:
This_Button := Gtk_Radio_Button(Button);
执行视图转换。
这应该由查看转换 (ARM 4.6(5)) 而不是未经检查的转换来处理。
我没有安装 Gtk,所以我写了这篇文章(在 AdaCore’s documentation 进行了一些研究之后),我认为这是 self-contained 的等价物,并且可以使用 GCC 5.1.0 成功编译.
package View_Conversions is
type Widget_Record is tagged null record;
-- Represents Gtk.Widget.Gtk_Widget_Record
type Button_Record is new Widget_Record with null record;
type Button is access all Button_Record'Class;
-- Represents Gtk.Radio_Button.Gtk_Radio_Button
procedure On_Click (Widget : access Widget_Record'Class);
end View_Conversions;
和body
package body View_Conversions is
Selected : Button;
-- Records the selected button
procedure On_Click (Widget : access Widget_Record'Class) is
begin
Selected := Button (Widget);
-- If the Widget is a Button, save it; if not, raise CE
end On_Click;
end View_Conversions;
与未经检查的转换相比的优势在于,这是一个经过检查的转换,如果传递的 Widget
实际上不是 Button
,您将在 Constraint_Error
转换点。