signals with GtkAda

225 Views Asked by At

My concern is that I created a callback function, which should display a Gtk_Entry when we click on the Gtk_Button but is that when I click on the button nothing happens. I don't understand.

File.ads

Package Test is

    Type T_Test is record
        Conteneur : Gtk_Fixe;
        L_Entree : Gtk_Entry;
    end Record;

    Procedure Le_Callback (Emetteur : access Gtk_Button_Record'Class);

    Package P is new Gtk.Handlers.Callback (Gtk_Button_Record);

    Use P;

end Test;

File.adb

Package body Test is

    Procedure Initialise_Conteneur (Object : T_Test) is
    begin
        Gtk_New (Object.Conteneur);

    end Initialise_Conteneur;

    Procedure Le_Callback (Emetteur : access Gtk_Button_Record'Classs) is
        V : T_Test;

    begin
        Initialise_Conteneur (Object => V);
        Gtk_New (V.L_Entree);
        V.Conteneur.Add (V.L_Entree);

        V.L_Entree.Show;

    end Le_Callback;
end Test;

Main.adb

Procedure Main is
    Win : Gtk_Window;
    Button : Gtk_Button;
    Posix : T_Test;

begin
    Init;
    Initialize (object => Posix);

    1
    Gtk_New (Win);
    Win.Set_Default_Size (600,400);

    Gtk_New (Button,"Bouton");

    Test.P.Connect (Widget => Button,
                    Name => Signal_Clicked,
                    Marsh => P.To_Marshaller (Le_Test'Access),
                    After => true);

    Posix.Conteneur.Add (Button);
    Win.Add (Posix.Conteneur);

    Win.Show_All;
    Main;

end Main;
2

There are 2 best solutions below

1
On

This is more some sort of comment, but this is how would I do it in vala (Compile with valac --pkg=gtk+-3.0 $FILENAME.

int main (string[] args) {
    Gtk.init (ref args);
    var window = new Gtk.Window ();
    window.title = "MyWindow";
    window.destroy.connect (Gtk.main_quit);
    // Create a box, where we later add the button and then the entry
    var box = new Gtk.Box (Gtk.Orientation.VERTICAL, /*spacing*/ 2);
    var button = new Gtk.Button.with_label ("Bouton!");
    // Connect to the signal "clicked", that is executed, as soon
    // as the button is clicked by the user
    button.clicked.connect (() => { // () => {...} is your callback.
        // Add the entry to the box
        box.pack_start (new Gtk.Entry());
        // Redraw the window
        window.show_all ();
    });
    // Add the button to the box
    box.pack_start (button);
    // Add the box to the window
    window.add (box);
    // Show the main window
    window.show_all ();  
    // GTK-Mainloop
    Gtk.main ();
    return 0; 
}
3
On

Revised answer.

Slightly hacked package ... to export the Initialize method called in Main. (I'm also adding a Button instead of an Entry to make my life simpler)

with Gtk; use Gtk;
with Gtk.Button; use Gtk.Button;
with Gtk.Handlers; use Gtk.Handlers;
with Gtk.Fixed; use Gtk.Fixed;


Package Test is

    Type T_Test is record
        Conteneur : Gtk_Fixed;
        Bouton : Gtk_Button;
    end Record;
    
    procedure Initialize (Object : out T_Test);

    Procedure Le_Callback (Emetteur : access Gtk_Button_Record'Class);

    Package P is new Gtk.Handlers.Callback (Gtk_Button_Record);

    Use P;

end Test;

Several issues in the package body...

  1. The parameter passing mode in the Initialize functions.
  2. Make sure the new visible object is in a different place than the old one ... (noting that GTK_Fixed is a harder container to use than the others, in terms of manual layout
  3. The callback creates a new container (now with a button in it) ... but until the container belongs to something, it cannot be displayed. The main window isn't directly visible in this package, so I added it to the parent container of the button that emitted the signal. (There are ways of passing user data to the handler; you could use that to pass in teh top level window or some other container)
  4. And of course we must display the modifications, so let's just redraw the top level window.

(junk text to fix markup issue)

Package body Test is

    Procedure Initialise_Conteneur (Object : out T_Test) is
    begin
        Gtk_New (Object.Conteneur);
    end Initialise_Conteneur;
    
    procedure Initialize (Object : out T_Test) renames Initialise_Conteneur;
  
    Procedure Le_Callback (Emetteur : access Gtk_Button_Record'Class) is
        V : T_Test;
    begin
        Initialise_Conteneur (Object => V);
        Gtk_New (V.Bouton,"Autre_Bouton");
        V.Conteneur.Add (V.Bouton);
        -- make sure it doesn't sit on the other button... 
        -- Using gtk.fixed is hard work compared to newer containers
        V.Conteneur.Move(V.Bouton,0,35);

        -- Add our new GTK_Fixed container to the outer one
        -- note Get_Parent returns a GTK_Widget'Class so we must 
        -- view convert to a GTK_Container or GTK_Fixed to see the Add method
        Gtk_Fixed(Emetteur.Get_Parent).Add(V.Conteneur);

        -- And re-display the top level window
        Emetteur.Get_Toplevel.Show_All;
    end Le_Callback;
end Test;

And the main program (connecting Le_Callback, not the nonexistent Le_Test)...

with Gtk.Button; use Gtk.Button;
with Gtk.Window; use Gtk.Window;
with Gtk.Main;
with test; use test;

Procedure Main is
    Win : Gtk_Window;
    Button : Gtk_Button;
    Posix : T_Test;

begin
    Gtk.Main.Init;
    Initialize (object => Posix);

    Gtk_New (Win);
    Win.Set_Default_Size (600,400);

    Gtk_New (Button,"Bouton");

    Test.P.Connect (Widget => Button,
                    Name => Signal_Clicked,
                    Marsh => P.To_Marshaller (Le_Callback'Access),
                    After => true);
            

    Posix.Conteneur.Add (Button);
    Win.Add (Posix.Conteneur);
    Win.Show_All;
    GTK.Main.Main;

end Main;

and my GPR file for it.

with "gtkada";
-- with "gtkada_gl";
project Test is
   for Main use ("main.adb");
   for Source_Dirs use (".");
   for Object_Dir use "obj";
   for Exec_Dir use ".";

   package Compiler is
      for Default_Switches ("Ada") use ("-g", "-O1", "-gnatafo");
   end Compiler;
   package Binder is
      for Default_Switches ("Ada") use ("-E");
   end Binder;
   package Linker is
--      for Default_Switches ("Ada") use ("-lgtkglada");
   end Linker;
end Test;

Now it builds (in future, PLEASE make the example code buildable! would have saved a good chunk of time) and I get to see a button...

Press the button and the second button appears below it, so we know the handler is connected to the button, and receiving button press messages.