如何使用 GtkAda 创建文件选择器?
How to create a file chooser with GtkAda?
我正在尝试使用 GtkAda 创建一个应用程序并需要用户从他的 PC select 一个文件。但是,我发现没有办法在不导致此错误的情况下创建文件选择器: raised PROGRAM_ERROR : unhandled signal.
使用 Glade 3.22.1
我尝试创建一个文件选择器按钮并将其 link 添加到文件选择器对话框中。它会导致同样的错误。
没有空地
我尝试在 GPS 中创建文件选择器对话框和文件选择器按钮,但出现同样的错误。
然后我找到了Gtkada.File_Selection包。它的描述说它自己处理信号并且只需要一个函数。可悲的是,它会导致同样致命的错误。
我正在使用 Fedora 29。GtkAda 2018 版、GPS 2018 和 GNAT 8.3.1。
Log_Filter_Handlers.ads
with Gtkada.File_Selection; use Gtkada.File_Selection;
package Log_Filter_Handlers is
Retour : Unbounded_String;
procedure Button_Select_File_Clicked
(Self : access Gtk_Button_Record'Class);
end Log_Filter_Handlers;
Log_Filter_Handlers.adb
procedure Button_Select_File_Clicked
(Self : access Gtk_Button_Record'Class) is
begin
Retour := To_Unbounded_String
(File_Selection_Dialog (Title => "Select your file",
Default_Dir => "",
Dir_Only => False,
Must_Exist => True) );
end Button_Select_File_Clicked;
Gtkada-File_Selection.ads
package Gtkada.File_Selection is
function File_Selection_Dialog
(Title : Glib.UTF8_String := "Select File";
Default_Dir : String := "";
Dir_Only : Boolean := False;
Must_Exist : Boolean := False) return String;
end Gtkada.File_Selection;
一旦应用程序创建文件选择器小部件(无论是对话框还是按钮),在本例中是通过调用 Button_Select_File_Clicked。它立即导致此错误:
raised PROGRAM_ERROR : unhandled signal
我也有一些警告
Gtk-Message: 10:43:33.615: Failed to load module "pk-gtk-module"
Gtk-Message: 10:43:33.615: Failed to load module "canberra-gtk-module"
Gtk-Message: 10:43:33.616: Failed to load module "pk-gtk-module"
Gtk-Message: 10:43:33.616: Failed to load module "canberra-gtk-module"
Fontconfig warning: "/home/bob/Applications/Gnat_IDE/Gnat-community/etc/fonts/fonts.conf", line 86: unknown element "blank"
(log_filter_main:24417): Gtk-WARNING **: 10:43:33.841: Could not load a pixbuf from icon theme.
This may indicate that pixbuf loaders or the mime database could not be found.
谢谢。
很难说是什么原因导致未处理的信号错误。您可以考虑进行堆栈跟踪以查看引发异常的位置(另请参阅 Rosetta code 上的示例)。
下面的示例适用于 GNAT CE 2019。您可以在自己的环境中对其进行测试以查看问题是否仍然存在,或者使用 GitHub.[=26 上找到的最新版本的 GtkAda 测试您自己的代码=]
更新
快速搜索显示带有消息 "unhandled signal" 的 Program_Error
从未从 GtkAda 中引发。事实上,这种异常似乎只能发生在GNAT/Adarun-time(见init.c
and seh_init.c
)。虽然 seh_init.c
仅由针对 Win32 和 Cygwin 的 run-time 使用(请参阅该文件开头附近的评论),但 init.c
用于其他各种 run-time包括 Linux 的那个。因此,我认为您观察到的 Program_Error
是在 init.c
中引发的,因为某些 kernel 信号无法由 GNAT/Ada run-time 处理.
您可能会通过跟踪发送到您的应用程序的信号获得一些额外的信息(另请参阅 this post 上的 SO):
strace -e 'trace=!all' <program_name>
main.adb
with File_Selection_Demo;
procedure Main is
begin
File_Selection_Demo.Run;
end Main;
file_selection_demo.ads
package File_Selection_Demo is
procedure Run;
end File_Selection_Demo;
file_selection_demo.adb
with Ada.Text_IO;
with Gtk.Main;
with Gtk.Widget;
with Gtk.Builder;
with Gtk.Window;
with Gtk.Button;
with Gtk.GEntry;
with Gtkada.File_Selection;
with Glib; use Glib;
with Glib.Error; use Glib.Error;
package body File_Selection_Demo is
-- Widgets
Builder : Gtk.Builder.Gtk_Builder;
Window : Gtk.Window.Gtk_Window;
Button : Gtk.Button.Gtk_Button;
GEntry : Gtk.GEntry.Gtk_Entry;
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
procedure Clicked_Event_Callback
(Button : access Gtk.Button.Gtk_Button_Record'Class);
---------
-- Run --
---------
procedure Run is
use Gtk.Builder;
use Gtk.Window;
use Gtk.Button;
use Gtk.GEntry;
Success : GUint;
Error : aliased GError;
begin
-- Initialize GtkAda.
Gtk.Main.Init;
-- Construct a Gtk_Builder instance and load our UI description.
Gtk_New (Builder);
Success := Builder.Add_From_File ("./example.glade", Error'Access);
if Success = 0 then
Ada.Text_IO.Put_Line ("failed to read Glade file");
Error_Free (Error);
return;
end if;
-- Entry
GEntry := Gtk_Entry (Builder.Get_Object ("Entry"));
-- Button
Button := Gtk_Button (Builder.Get_Object ("Button"));
Button.On_Clicked (Clicked_Event_Callback'Access);
-- Window
Window := Gtk_Window (Builder.Get_Object ("Window"));
Window.On_Destroy (Destroy_Event_Callback'Access);
Window.Show_All;
-- Start the main event loop
Gtk.Main.Main;
end Run;
----------------------------
-- Destroy_Event_Callback --
----------------------------
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class)
is
begin
Gtk.Main.Main_Quit;
end Destroy_Event_Callback;
----------------------------
-- Clicked_Event_Callback --
----------------------------
procedure Clicked_Event_Callback
(Button : access Gtk.Button.Gtk_Button_Record'Class) is
begin
declare
Response : String :=
Gtkada.File_Selection.File_Selection_Dialog
(Title => "Select your file",
Default_Dir => "",
Dir_Only => False,
Must_Exist => True);
begin
GEntry.Set_Text (Response);
end;
end Clicked_Event_Callback;
end File_Selection_Demo;
example.glade
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="Window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">GTK File Selector Demo</property>
<property name="resizable">False</property>
<property name="window_position">center</property>
<child>
<object class="GtkBox" id="HBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="Entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="hexpand">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="Button">
<property name="label" translatable="yes">Choose File...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">10</property>
<property name="margin_right">12</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
我正在尝试使用 GtkAda 创建一个应用程序并需要用户从他的 PC select 一个文件。但是,我发现没有办法在不导致此错误的情况下创建文件选择器: raised PROGRAM_ERROR : unhandled signal.
使用 Glade 3.22.1
我尝试创建一个文件选择器按钮并将其 link 添加到文件选择器对话框中。它会导致同样的错误。
没有空地
我尝试在 GPS 中创建文件选择器对话框和文件选择器按钮,但出现同样的错误。
然后我找到了Gtkada.File_Selection包。它的描述说它自己处理信号并且只需要一个函数。可悲的是,它会导致同样致命的错误。
我正在使用 Fedora 29。GtkAda 2018 版、GPS 2018 和 GNAT 8.3.1。
Log_Filter_Handlers.ads
with Gtkada.File_Selection; use Gtkada.File_Selection;
package Log_Filter_Handlers is
Retour : Unbounded_String;
procedure Button_Select_File_Clicked
(Self : access Gtk_Button_Record'Class);
end Log_Filter_Handlers;
Log_Filter_Handlers.adb
procedure Button_Select_File_Clicked
(Self : access Gtk_Button_Record'Class) is
begin
Retour := To_Unbounded_String
(File_Selection_Dialog (Title => "Select your file",
Default_Dir => "",
Dir_Only => False,
Must_Exist => True) );
end Button_Select_File_Clicked;
Gtkada-File_Selection.ads
package Gtkada.File_Selection is
function File_Selection_Dialog
(Title : Glib.UTF8_String := "Select File";
Default_Dir : String := "";
Dir_Only : Boolean := False;
Must_Exist : Boolean := False) return String;
end Gtkada.File_Selection;
一旦应用程序创建文件选择器小部件(无论是对话框还是按钮),在本例中是通过调用 Button_Select_File_Clicked。它立即导致此错误:
raised PROGRAM_ERROR : unhandled signal
我也有一些警告
Gtk-Message: 10:43:33.615: Failed to load module "pk-gtk-module"
Gtk-Message: 10:43:33.615: Failed to load module "canberra-gtk-module"
Gtk-Message: 10:43:33.616: Failed to load module "pk-gtk-module"
Gtk-Message: 10:43:33.616: Failed to load module "canberra-gtk-module"
Fontconfig warning: "/home/bob/Applications/Gnat_IDE/Gnat-community/etc/fonts/fonts.conf", line 86: unknown element "blank"
(log_filter_main:24417): Gtk-WARNING **: 10:43:33.841: Could not load a pixbuf from icon theme.
This may indicate that pixbuf loaders or the mime database could not be found.
谢谢。
很难说是什么原因导致未处理的信号错误。您可以考虑进行堆栈跟踪以查看引发异常的位置(另请参阅 Rosetta code 上的示例)。
下面的示例适用于 GNAT CE 2019。您可以在自己的环境中对其进行测试以查看问题是否仍然存在,或者使用 GitHub.[=26 上找到的最新版本的 GtkAda 测试您自己的代码=]
更新
快速搜索显示带有消息 "unhandled signal" 的 Program_Error
从未从 GtkAda 中引发。事实上,这种异常似乎只能发生在GNAT/Adarun-time(见init.c
and seh_init.c
)。虽然 seh_init.c
仅由针对 Win32 和 Cygwin 的 run-time 使用(请参阅该文件开头附近的评论),但 init.c
用于其他各种 run-time包括 Linux 的那个。因此,我认为您观察到的 Program_Error
是在 init.c
中引发的,因为某些 kernel 信号无法由 GNAT/Ada run-time 处理.
您可能会通过跟踪发送到您的应用程序的信号获得一些额外的信息(另请参阅 this post 上的 SO):
strace -e 'trace=!all' <program_name>
main.adb
with File_Selection_Demo;
procedure Main is
begin
File_Selection_Demo.Run;
end Main;
file_selection_demo.ads
package File_Selection_Demo is
procedure Run;
end File_Selection_Demo;
file_selection_demo.adb
with Ada.Text_IO;
with Gtk.Main;
with Gtk.Widget;
with Gtk.Builder;
with Gtk.Window;
with Gtk.Button;
with Gtk.GEntry;
with Gtkada.File_Selection;
with Glib; use Glib;
with Glib.Error; use Glib.Error;
package body File_Selection_Demo is
-- Widgets
Builder : Gtk.Builder.Gtk_Builder;
Window : Gtk.Window.Gtk_Window;
Button : Gtk.Button.Gtk_Button;
GEntry : Gtk.GEntry.Gtk_Entry;
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
procedure Clicked_Event_Callback
(Button : access Gtk.Button.Gtk_Button_Record'Class);
---------
-- Run --
---------
procedure Run is
use Gtk.Builder;
use Gtk.Window;
use Gtk.Button;
use Gtk.GEntry;
Success : GUint;
Error : aliased GError;
begin
-- Initialize GtkAda.
Gtk.Main.Init;
-- Construct a Gtk_Builder instance and load our UI description.
Gtk_New (Builder);
Success := Builder.Add_From_File ("./example.glade", Error'Access);
if Success = 0 then
Ada.Text_IO.Put_Line ("failed to read Glade file");
Error_Free (Error);
return;
end if;
-- Entry
GEntry := Gtk_Entry (Builder.Get_Object ("Entry"));
-- Button
Button := Gtk_Button (Builder.Get_Object ("Button"));
Button.On_Clicked (Clicked_Event_Callback'Access);
-- Window
Window := Gtk_Window (Builder.Get_Object ("Window"));
Window.On_Destroy (Destroy_Event_Callback'Access);
Window.Show_All;
-- Start the main event loop
Gtk.Main.Main;
end Run;
----------------------------
-- Destroy_Event_Callback --
----------------------------
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class)
is
begin
Gtk.Main.Main_Quit;
end Destroy_Event_Callback;
----------------------------
-- Clicked_Event_Callback --
----------------------------
procedure Clicked_Event_Callback
(Button : access Gtk.Button.Gtk_Button_Record'Class) is
begin
declare
Response : String :=
Gtkada.File_Selection.File_Selection_Dialog
(Title => "Select your file",
Default_Dir => "",
Dir_Only => False,
Must_Exist => True);
begin
GEntry.Set_Text (Response);
end;
end Clicked_Event_Callback;
end File_Selection_Demo;
example.glade
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="Window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">GTK File Selector Demo</property>
<property name="resizable">False</property>
<property name="window_position">center</property>
<child>
<object class="GtkBox" id="HBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="Entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="hexpand">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="Button">
<property name="label" translatable="yes">Choose File...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">10</property>
<property name="margin_right">12</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>