如何使用 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>