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;
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...
The parameter passing mode in the Initialize functions.
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
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)
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.
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;
}
Related
i created two buttons a that display a Gtk_Radio_Button and a button that display a GtK_label but when i click on buttons nothing happens. I don't understand why it doesn't work yet the code compiles and runs without finding any error.
main_Program.adb
With Gtk.Window; Use Gtk.Window;
With Gtk.Button; Use Gtk.Button;
With Gtk.Grid; Use Gtk.Grid;
With file; Use file;
Procedure main_program is
Bouton : Gtk_Button;
Bouton2 : Gtk_Button;
Win : Gtk_Window;
Test : Test_Record;
begin
Gtk.Main.Init;
Init_Grid (Container => Test);
Gtk_New (Win);
Win.Add (Test.Grid);
Win.Set_Default_Size (Width => 600,
Height => 400);
Gtk_New (Bouton,Label => "Bouton");
Test.Grid.Attach (Bouton,0,0);
P.Connect (Widget => Bouton,
Name => Signal_Clicked,
Marsh => Test2.P.To_Marshaller (Init_Button'Access),
After => False);
Gtk_New (Bouton2,Label => "Bouton2");
Test.Grid.Attach (Bouton2,50,4);
P.Connect (Widget => Bouton2,
Name => Signal_Clicked,
Marsh => Test2.P.To_Marshaller (Init_Text'Access),
After => False);
Win.Show_All;
Main;
end Main_Program;
file.ads
With Gtk.Label; Use Gtk.Label;
With Gtk.Radio_Button; Use Gtk.Radio_Button;
With Gtk.Grid; Use Gtk.Grid;
With Gtk.Handlers;
Package file is
type Test_Record is record
Text : Gtk_Label;
Grid : Gtk_Grid;
Button_Radio : Gtk_Radio_Button;
end record;
Procedure Init_Text ( Self : access Gtk_Widget_Record'Class );
-- Callback for create the text
Procedure Init_Button (Self : access Gtk_Widget_Record'Class );
-- Callback for Initialize the Radio Button;
Procedure Init_Grid (Container : out Test_Record);
-- Initialize the Gtk.Grid.Gtk_Grid
Package P is new Gtk.Handlers.Callback (Gtk_Widget_Record);
Use P;
end file;
file.adb
With file; Use file;
Package body file is
Procedure Init_Grid ( Container : out Test_Record ) is
begin
Gtk_New (Container.Grid);
end Init_Grid;
Procedure Init_Button ( Self : access Gtk_Widget_Record'Class ) is
V : Test_Record;
begin
Init_Grid (Container => V);
Gtk_New (V.Button_Radio,
Group => null,
Label => "Button Radio");
V.Grid.Attach (V.Button_Radio,0,50);
V.Grid.Show;
end Init_Button;
Procedure Init_Text (Self : access Gtk_Widget_Record'Class) is
V : Test_Record;
begin
Init_Grid (Container => V);
Gtk_New (V.Text);
V.Text.Set_Label ("Hello,World");
V.Grid.Attach (V.Text,150,0);
V.Grid.Show;
end Init_Text;
end file;
I want that when I click on the first button it shows me a radio button and when I click on the second button it shows me a label.
I would consider to not create/destroy the label and radio button, but just toggle their visibility instead. Furthermore, I would also recommend to derive the main window from the GTK window type and always properly terminate the application when requested (see Destroy_Event_Callback in the example below).
app.ads
package App is
end App;
app-main_window.ads
with Gtk.Window; use Gtk.Window;
with Gtk.Grid; use Gtk.Grid;
with Gtk.Button; use Gtk.Button;
with Gtk.Check_Button; use Gtk.Check_Button;
with Gtk.Label; use Gtk.Label;
package App.Main_Window is
type App_Main_Window_Record is new Gtk_Window_Record with private;
type App_Main_Window is access all App_Main_Window_Record'Class;
------------------
-- Constructors --
------------------
procedure Gtk_New
(Main_Window : out App_Main_Window);
procedure Initialize
(Main_Window : not null access App_Main_Window_Record'Class);
private
Window_Width : constant := 300;
Window_Height : constant := 100;
type App_Main_Window_Record is
new Gtk.Window.Gtk_Window_Record with
record
Grid : Gtk_Grid;
Button_1 : Gtk_Button;
Button_2 : Gtk_Button;
Check_Button : Gtk_Check_Button;
Label : Gtk_Label;
end record;
end App.Main_Window;
app-main_window.adb
with Gtk.Main;
with Gtk.Widget;
with Gtk.Window;
with Gdk.Event;
package body App.Main_Window is
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
function On_Button_1_Pressed_Callback
(Self : access Gtk.Widget.Gtk_Widget_Record'Class;
Event : Gdk.Event.Gdk_Event_Button) return Boolean;
function On_Button_2_Pressed_Callback
(Self : access Gtk.Widget.Gtk_Widget_Record'Class;
Event : Gdk.Event.Gdk_Event_Button) return Boolean;
-------------
-- Gtk_New --
-------------
procedure Gtk_New (Main_Window : out App_Main_Window) is
begin
Main_Window := new App_Main_Window_Record;
App.Main_Window.Initialize (Main_Window);
end Gtk_New;
----------------
-- Initialize --
----------------
procedure Initialize
(Main_Window : not null access App_Main_Window_Record'Class)
is
begin
-- Initialize and setup the window.
Gtk.Window.Initialize (Main_Window);
Main_Window.Set_Title ("Demo Window");
Main_Window.Set_Size_Request (Window_Width, Window_Height);
Main_Window.Set_Resizable (False);
-- Attach callback: properly end the GTK application when requested.
Main_Window.On_Destroy
(Call => Destroy_Event_Callback'Access);
-- Add a grid.
Gtk_New (Main_Window.Grid);
Main_Window.Grid.Set_Hexpand (True);
Main_Window.Grid.Set_Vexpand (True);
Main_Window.Grid.Set_Column_Homogeneous (True);
Main_Window.Grid.Set_Row_Homogeneous (True);
Main_Window.Add (Main_Window.Grid);
-- Create the two buttons.
Gtk_New (Main_Window.Button_1, Label => "Button 1");
Gtk_New (Main_Window.Button_2, Label => "Button 2");
-- Insert both buttons into the grid.
--
-- +------+------+
-- | | |
-- +------+------+
-- (0,1) --> | XXXX | XXXX | <-- (1,1)
-- +------+------+
Main_Window.Grid.Attach
(Child => Main_Window.Button_1,
Left => 0,
Top => 1);
Main_Window.Grid.Attach
(Child => Main_Window.Button_2,
Left => 1,
Top => 1);
-- Attach "button pressed" callbacks.
Main_Window.Button_1.On_Button_Press_Event
(Call => On_Button_1_Pressed_Callback'Access);
Main_Window.Button_2.On_Button_Press_Event
(Call => On_Button_2_Pressed_Callback'Access);
-- Create new label and check button.
Gtk_New (Main_Window.Label, Str => "Hello World!");
Gtk_New (Main_Window.Check_Button, Label => "A Check Button");
-- Insert both into the grid.
--
-- +------+------+
-- (0,0) --> | XXXXXXXXXXX | Width: 2 columns
-- +------+------+
-- | | |
-- +------+------+
Main_Window.Grid.Attach
(Child => Main_Window.Label,
Left => 0,
Top => 0,
Width => 2);
Main_Window.Grid.Attach
(Child => Main_Window.Check_Button,
Left => 0,
Top => 0,
Width => 2);
-- Show everything except the check button.
Main_Window.Show;
Main_Window.Grid.Show;
Main_Window.Button_1.Show;
Main_Window.Button_2.Show;
Main_Window.Label.Show;
end Initialize;
----------------------------
-- 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;
----------------------------------
-- On_Button_1_Pressed_Callback --
----------------------------------
function On_Button_1_Pressed_Callback
(Self : access Gtk.Widget.Gtk_Widget_Record'Class;
Event : Gdk.Event.Gdk_Event_Button) return Boolean
is
-- (parent) (parent)
-- Button (Self) -------> Grid -------> Window
Grid : Gtk_Grid := Gtk_Grid (Self.Get_Parent);
Window : App_Main_Window := App_Main_Window (Grid.Get_Parent);
begin
-- Just toggle visibility.
Window.Label.Set_Visible (False);
Window.Check_Button.Set_Visible (True);
return True; -- GDK_EVENT_STOP, do not propagate event to parent.
end On_Button_1_Pressed_Callback;
----------------------------------
-- On_Button_2_Pressed_Callback --
----------------------------------
function On_Button_2_Pressed_Callback
(Self : access Gtk.Widget.Gtk_Widget_Record'Class;
Event : Gdk.Event.Gdk_Event_Button) return Boolean
is
Grid : Gtk_Grid := Gtk_Grid (Self.Get_Parent);
Window : App_Main_Window := App_Main_Window (Grid.Get_Parent);
begin
Window.Label.Set_Visible (True);
Window.Check_Button.Set_Visible (False);
return True; -- GDK_EVENT_STOP, do not propagate event to parent.
end On_Button_2_Pressed_Callback;
end App.Main_Window;
main.adb
with Gtk.Main;
with App.Main_Window;
procedure Main is
use App.Main_Window;
Main_Window : App_Main_Window;
begin
Gtk.Main.Init;
Gtk_New (Main_Window);
Gtk.Main.Main;
end Main;
I have an unusual situation in which elaboration code is simply not being executed at all. This is not an elaboration order issue, but rather an elaboration at all issue.
The problem is that I don't "with" the unit in question whatsoever, yet in theory it should still be accessible, as long as its elaboration occurs.
Of course I could just add a useless "with" for the unit in question, but in my real use case there are a large number of units that I would have to do that with.
My question is if there is any way either in the code, through pragmas, in the gpr project file, or through command-line switches that I could force the compiler to include a file even though it thinks the file isn't referenced?
Here is a minimal working example:
as.ads:
package As is
type A is tagged null record;
type Nothing is null record;
function Create (Ignored : not null access Nothing) return A;
function Image (From : A) return String;
end As;
as.adb:
package body As is
function Create (Ignored : not null access Nothing) return A is
(null record);
function Image (From : A) return String is ("A");
end As;
finder.ads:
with Ada.Tags;
package Finder is
procedure Register (Name : String; Tag : Ada.Tags.Tag);
function Find (Name : String; Default : Ada.Tags.Tag) return Ada.Tags.Tag;
end Finder;
finder.adb:
with Ada.Containers.Indefinite_Vectors;
package body Finder is
type Name_Tag (Size : Natural) is
record
Name : String (1 .. Size);
To : Ada.Tags.Tag;
end record;
package Name_Tag_Vectors is new Ada.Containers.Indefinite_Vectors (Positive, Name_Tag);
Name_Tags : Name_Tag_Vectors.Vector := Name_Tag_Vectors.Empty_Vector;
procedure Register (Name : String; Tag : Ada.Tags.Tag) is begin
Name_Tags.Append ((Name'Length, Name, Tag));
end Register;
function Find (Name : String; Default : Ada.Tags.Tag) return Ada.Tags.Tag is begin
for Tag of Name_Tags loop
if Tag.Name = Name then
return Tag.To;
end if;
end loop;
return Default;
end Find;
end Finder;
bs.ads:
with As;
package Bs is
type B is new As.A with null record;
function Create (Ignored : not null access As.Nothing) return B;
function Image (From : B) return String;
end Bs;
bs.adb:
with Finder;
package body Bs is
function Create (Ignored : not null access As.Nothing) return B is
(As.Create (Ignored) with null record);
function Image (From : B) return String is ("B");
begin
Finder.Register ("B", B'Tag);
end Bs;
test.adb:
with As; use As;
-- with Bs; -- (uncommenting this line solves my problem, but what if I had the rest of the alphabet?)
with Finder;
with Ada.Tags.Generic_Dispatching_Constructor;
with Ada.Text_IO;
procedure Test is
function Constructor is new Ada.Tags.Generic_Dispatching_Constructor (
T => A,
Parameters => Nothing,
Constructor => Create);
Nada : aliased Nothing := (null record);
What : A'Class := Constructor (Finder.Find ("B", A'Tag), Nada'Access);
begin
Ada.Text_IO.Put_Line (What.Image);
end Test;
The compiler thinks your package Bs isn't referenced because it isn't. You don't have a with clause for it, so it's not part of your program.
A simple example:
a.ads
package A is
procedure Blah;
end A;
a.adb
with Ada.Text_IO;
package body A is
procedure Blah is begin null; end Blah;
begin
Ada.Text_IO.Put_Line("Elaborate A");
end A;
b.ads
package B is
procedure Blah;
end B;
b.adb
with Ada.Text_IO;
package body B is
procedure Blah is begin null; end Blah;
begin
Ada.Text_IO.Put_Line("Elaborate B");
end B;
main.adb
with Ada.Text_IO;
with A;
procedure Main is
begin
Ada.Text_IO.Put_Line("Main");
end Main;
When I run main, it prints
Elaborate A
Main
It doesn't print Elaborate B because that package isn't part of the program; it's just a couple of source files in the same directory.
The obvious solution is to add the with clauses.
I don't know whether there's a less obvious solution. If there is, it's probably compiler-specific. But I'm not sure why a compiler would have a feature that lets you incorporate an otherwise unused package into a program.
What I’ve done (e.g. here ff) is to actually reference the units in the main program (with pragma Unreferenced to prevent warnings).
Alternatively, you could have a package e.g. Required_Units with all the necessary withs included, and then with that from the main program.
Even if there was some alternative process, you’d have to tell it what units you need to have included; might as well go with the flow and do it in Ada!
Since the package Bs is invisible to your program, so is the type B.
So the next question is: why do you need to register type B if it is not used anywhere?
If an Ada compiler did elaborate all units (packages or standalone subprograms) that are irrelevant to a main program, but are visible through source path, it would become really messy!...
I'm using the excellent Inno Setup installer and I notice that some Applications (often from Microsoft) get installed with their launch icon already highly visible ('pinned?') in the start menu (in Windows 7). Am I totally reliant on the most-recently-used algorithm for my icon to be 'large' in the start menu, or is there a way of promoting my application from the installer please?
It is possible to pin programs, but not officially. Based on a code posted in this thread (which uses the same way as described in the article linked by #Mark Redman) I wrote the following:
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
// these constants are not defined in Windows
SHELL32_STRING_ID_PIN_TO_TASKBAR = 5386;
SHELL32_STRING_ID_PIN_TO_STARTMENU = 5381;
SHELL32_STRING_ID_UNPIN_FROM_TASKBAR = 5387;
SHELL32_STRING_ID_UNPIN_FROM_STARTMENU = 5382;
type
HINSTANCE = THandle;
HMODULE = HINSTANCE;
TPinDest = (
pdTaskbar,
pdStartMenu
);
function LoadLibrary(lpFileName: string): HMODULE;
external 'LoadLibrary{#AW}#kernel32.dll stdcall';
function FreeLibrary(hModule: HMODULE): BOOL;
external 'FreeLibrary#kernel32.dll stdcall';
function LoadString(hInstance: HINSTANCE; uID: UINT;
lpBuffer: string; nBufferMax: Integer): Integer;
external 'LoadString{#AW}#user32.dll stdcall';
function TryGetVerbName(ID: UINT; out VerbName: string): Boolean;
var
Buffer: string;
BufLen: Integer;
Handle: HMODULE;
begin
Result := False;
Handle := LoadLibrary(ExpandConstant('{sys}\Shell32.dll'));
if Handle <> 0 then
try
SetLength(Buffer, 255);
BufLen := LoadString(Handle, ID, Buffer, Length(Buffer));
if BufLen <> 0 then
begin
Result := True;
VerbName := Copy(Buffer, 1, BufLen);
end;
finally
FreeLibrary(Handle);
end;
end;
function ExecVerb(const FileName, VerbName: string): Boolean;
var
I: Integer;
Shell: Variant;
Folder: Variant;
FolderItem: Variant;
begin
Result := False;
Shell := CreateOleObject('Shell.Application');
Folder := Shell.NameSpace(ExtractFilePath(FileName));
FolderItem := Folder.ParseName(ExtractFileName(FileName));
for I := 1 to FolderItem.Verbs.Count do
begin
if FolderItem.Verbs.Item(I).Name = VerbName then
begin
FolderItem.Verbs.Item(I).DoIt;
Result := True;
Exit;
end;
end;
end;
function PinAppTo(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_PIN_TO_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_PIN_TO_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
function UnpinAppFrom(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
The above code first reads the caption of the menu item for pinning or unpinning applications from the string table of the Shell32.dll library. Then connects to the Windows Shell, and for the target app. path creates the Folder object, then obtains the FolderItem object and on this object iterates all the available verbs and checks if their name matches to the one read from the Shell32.dll library string table. If so, it invokes the verb item action by calling the DoIt method and exits the iteration.
Here is a possible usage of the above code, for pinning:
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc has been pinned to the taskbar.', mbInformation, MB_OK);
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc has been pinned to the start menu.', mbInformation, MB_OK);
And for unpinning:
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc is not pinned to the taskbar anymore.', mbInformation, MB_OK);
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc is not pinned to the start menu anymore.', mbInformation, MB_OK);
Please note that even though this code works on Windows 7 (and taskbar pinning also on Windows 8.1 where I've tested it), it is really hacky way, since there is no official way to programatically pin programs to taskbar, nor start menu. That's what the users should do by their own choice.
There's a reason there's no programmatic way to pin things to the taskbar/start menu. In my experience, I have seen the start menu highlight newly-created shortcuts, and that's designed to handle exactly this situation. When you see a newly-installed program show up on the start menu, it's probably because of that algorithm and not because the installer placed it there.
That said, if a new shortcut does not appear highlighted, it may be because the installer extracts a pre-existing shortcut and preserves an old timestamp on it, rather than using the API function to create a shortcut in the start menu.
Have a look at: http://blogs.technet.com/deploymentguys/archive/2009/04/08/pin-items-to-the-start-menu-or-windows-7-taskbar-via-script.aspx
How do I fix this Seg Fault in my DLL?
I'm generating a Windows DLL (in Ada) and using the DLL from an Ada
program. I’m using AdaCore’s GNAT GPS v6.0.1 IDE for both the DLL
and an Ada program to test the DLL, running on a Windows 7 machine.
Two separate project files are used, one for the DLL, the other for
the test driver. The DLL does not have any DLLMain nor initialization
or finalization routines.
As a first step (because I've never created a DLL or used GPS prior to this, do know some Ada though), I coded two very simple functions for the DLL. One function returns a pointer to a string, the other function returns a fixed length string.
The test program successfully calls the DLL function that returns a fixed-length
string, however when calling the function that returns a string pointer, a
segmentation fault occurs. Here is the gcc debug output:
Program received signal SIGSEGV, Segmentation fault.
0x6b81dd2c in system.secondary_stack.ss_mark () from C:\GNAT\2014\bin\libgnat-2014.dll
(gdb) quit
Here is the code:
DLL Spec
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
package String_Utils is
type String_Ptr_T is access String;
type Spec_Str is new String (1..7);
function Int_Trim_Left( IntToTrim : Integer) return String_Ptr_T;
pragma Export(DLL, Int_Trim_Left, "String_Utils__Int_Trim_Left");
function Spec( Input_Int : Integer) return Spec_Str;
pragma Export(DLL, Spec, "String_Utils__Spec");
end String_Utils;
DLL Body
package body String_Utils is
function Int_Trim_Left( IntToTrim : Integer) return String_Ptr_T is
String_Ptr : String_Ptr_T;
begin
Text_IO.Put_Line("About to call new String in DLL.");
String_Ptr := new String'(
Ada.Strings.Fixed.Trim(Integer'Image(IntToTrim),
Ada.Strings.Left));
return String_Ptr;
end;
--
function Spec( Input_Int : Integer) return Spec_Str
is
Result_Spec : String := "ABC-UNK";
begin
case Input_Int is
when 1 => return "ABC-STD"; -- Standard
when 2 => return "ABC-PRF"; -- Performance
when 3 => return "DEF-DTL"; -- Detailed
when Others => return "ABC-UNK";
end case;
end;
DLL Project File
project HAGUtils is
for Library_Name use "HAGUtils";
for Library_Dir use "libdir";
for Library_Version use "0.01";
for Library_Kind use "dynamic";
for Object_Dir use "obj";
for Source_Dirs use ("src");
for Source_Files use ("string_utils.adb", "string_utils.ads");
end HAGUtils;
Test Driver
-- Driver for DLL
with Text_IO; use Text_IO;
procedure test_ada_dll is
type String_Ptr_T is access String;
subtype String7 is String(1..7);
input_val : Integer := 0;
Spec_Str : String7 := (Others => ' ');
Int_String_Ptr : String_Ptr_T:= null;
-- Import
function Int_Trim_Left ( IntToTrim : Integer) return String_Ptr_T
is
function Inner_Int_Trim_Left ( IntToTrim : Integer) return String_Ptr_T;
pragma Import (DLL, Inner_Int_Trim_Left, "String_Utils__Int_Trim_Left");
begin
return Inner_Int_Trim_Left (IntToTrim);
end Int_Trim_Left;
-- Import
function Spec ( Input_Int : Integer) return String7
is
function Inner_Spec ( Input_Int : Integer) return String7;
pragma Import (DLL, Inner_Spec, "String_Utils__Spec");
begin
return Inner_Spec (Input_Int);
end Spec;
begin
input_val := 3;
Spec_Str := Spec(input_val);
Text_IO.Put_Line("The Spec is -- " & Spec_Str);
Text_IO.Put_Line("Calling Int_Trim_Left with --" & Integer'Image(input_val));
Int_String_Ptr := Int_Trim_Left(input_val);
Text_IO.Put_Line("After call --" & Int_String_Ptr.all);
end;
I think that the SEGV happened because your DLL wasn’t initialized. The Ada runtime system needs initialization, which in the absence of DLLs would be called up in the GNAT bind process (you may have seen calls to gnatbind or gprbind flashing up the screen).
However, you have a DLL that requires the RTS to be initialized (the part that deals with the secondary stack, which is where GNAT constructs temporary unconstrained objects such as strings); but the binder isn’t aware of this because of the way you’ve linked your program (you don’t say, but I suspect you’ve specified the DLL via -lHAGutils?).
The way to get GNAT to handle this for you is to write a project file for the test program and have it with your DLL’s project:
with "HAGutils";
project Test_Ada_Dll is
for Main use ("test_ada_dll.adb");
for Exec_Dir use ".";
for Source_Files use ("test_ada_dll.adb");
for Object_Dir use ".build";
end Test_Ada_Dll;
This then makes the interfaces of HAGlib visible to test_ada_dll, so you can change it to say
with Text_IO; use Text_IO;
with String_Utils;
procedure test_ada_dll is
input_val : Integer := 0;
Spec_Str : String_Utils.Spec_Str := (Others => ' ');
Int_String_Ptr : String_Utils.String_Ptr_T:= null;
begin
input_val := 3;
Spec_Str := String_Utils.Spec(input_val);
Text_IO.Put_Line("The Spec is -- " & String (Spec_Str));
Text_IO.Put_Line("Calling Int_Trim_Left with --" & Integer'Image(input_val));
Int_String_Ptr := String_Utils.Int_Trim_Left(input_val);
Text_IO.Put_Line("After call --" & Int_String_Ptr.all);
end;
(note, the conversion in Text_IO.Put_Line("The Spec is -- " & String (Spec_Str)); is because Spec_Str is a derived type; I think it’s be more normal in this case to make it a subtype).
Further, you no longer need to use the pragma Exports in String_Utils’s spec.
The result of this is that the binder is aware of the properties of your HAGutils DLL, and can arrange for the necessary initializations to happen.
There is a way in which you can make your original code work, which is to use the GPR attribute Library_Auto_Init in HAGutils.gpr:
for Library_Auto_Init use “true”;
but I think you’d have to make HAGlib a proper standalone library. This is quite complex to get right, and not necessary to get the library working to start with.
I'm new to programming and just started with Qtada 3.2, so please be indulgent :D
My goal is to drag a picture (png) from one table view model to another.
While the image is already shown during drag in the minimal example below, I guess overriding mouse press and mouse release events should be the solution?
Is there anything else I need to do, like create drop action, mime data or item delegate?
Although I had a look at the QtAda tutorials, I still don't know how to correctly setup overriding events for my table views.
Really tried a lot, but nothing worked. Right now I'm stuck and confused.
It would be nice if somebody could point me to the right direction, or even better, show me a working example!
Bonus question #1: Is there a better / more correct way to load an image into a item model?
Bonus question #2: How to get rid of the line edits in the table? I just need the image to be shown in a cell, nothing else.
Thanks in advance!
Michael
My example:
main.adb
with Qt4.Core_Applications;
with Qt4.Objects;
with Qt4.Push_Buttons.Constructors;
with Qt4.Splitters.Constructors;
with Qt4.Splitters;
with Qt4.Strings;
with Qt_Ada.Application;
with Table_View_Big;
with Table_View_Small;
procedure Main is
begin
Qt_Ada.Application.Initialize;
declare
Quit : constant not null access Qt4.Push_Buttons.Q_Push_Button'Class
:= Qt4.Push_Buttons.Constructors.Create
(Qt4.Strings.From_Utf_16 ("Quit"));
Splitter : constant not null Qt4.Splitters.Q_Splitter_Access
:= Qt4.Splitters.Constructors.Create(The_Orientation => Qt4.Vertical);
Big_Table : constant not null Table_View_Big.Big_Table_Access
:= Table_View_Big.Constructors.Create;
Small_Table : constant not null Table_View_Small.Small_Table_Access
:= Table_View_Small.Constructors.Create;
begin
Splitter.Add_Widget(Big_Table);
Splitter.Add_Widget(Small_Table);
Splitter.Add_Widget(Quit);
Qt4.Objects.Connect (Quit,
Qt4.Signal ("clicked()"),
Qt4.Core_Applications.Instance,
Qt4.Slot ("quit()"));
Splitter.Set_Fixed_Size(640,480);
Splitter.Show;
Qt_Ada.Application.Execute;
end;
end Main;
table_view_small.ads :
with Qt4.Table_Views.Constructors;
with Qt4.Table_Views.Directors;
with Qt4.Abstract_Item_Models;
--with Qt4.Mouse_Events;
package Table_View_Small is
type Small_Table is limited new Qt4.Table_Views.Q_Table_View with private;
type Small_Table_Access is access all Small_Table'Class;
package Constructors is
function Create return not null Small_Table_Access;
end Constructors;
private
type Small_Table is new Qt4.Table_Views.Directors.Q_Table_View_Director with record
Small_Table_Item_Model : Qt4.Abstract_Item_Models.Q_Abstract_Item_Model_Access;
end record;
-- overriding procedure Mouse_Press_Event
-- (Self : not null access Table_Small;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
-- overriding procedure Mouse_Move_Event
-- (Self : not null access Table_Small;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
-- overriding procedure Mouse_Release_Event
-- (Self : not null access Table_Small;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
end Table_View_Small;
table_view_small.adb
with Qt4.Icons;
with Qt4.Model_Indices;
with Qt4.Standard_Item_Models.Constructors;
with Qt4.Strings;
with Qt4.Variants;
with Table_View_Small.MOC;
pragma Warnings (Off, Table_View_Small.MOC);
package body Table_View_Small is
use Qt4;
package body Constructors is
function Create return not null Small_Table_Access is
Self : constant Table_View_Small.Small_Table_Access := new Table_View_Small.Small_Table;
begin
Qt4.Table_Views.Directors.Constructors.Initialize (Self);
declare
Icon : Qt4.Icons.Q_Icon;
Data_Role : Qt4.Item_Data_Role := qt4.Decoration_Role;
Index : Qt4.Model_Indices.Q_Model_Index;
begin
Self.Small_Table_Item_Model := Qt4.Abstract_Item_Models.Q_Abstract_Item_Model_Access
(Qt4.Standard_Item_Models.Constructors.Create (1, 6, Self));
Icon := Qt4.Icons.Create(Qt4.Strings.From_Ucs_4("anypng.png"));
Index := Self.Small_Table_Item_Model.Index(0,0);
Qt4.Abstract_Item_Models.Set_Data(Self.Small_Table_Item_Model,index,icon.To_Q_Variant,Data_Role);
Self.Set_Model(Self.Small_Table_Item_Model);
-- Drag & Drop
Self.Set_Accept_Drops(true);
Self.Set_Drag_Enabled(true);
Self.Set_Drop_Indicator_Shown(true);
-- Self.Set_Drag_Drop_Mode(Qt4.Abstract_Item_Views.Internal_Move);
return Self;
end;
end Create;
end Constructors;
-- overriding procedure Mouse_Press_Event
-- (Self : not null access Small_Table;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class)
-- is
-- null;
-- end Mouse_Press_Event;
end Table_View_Small;
table_view_big.ads
with Qt4.Table_Views.Constructors;
with Qt4.Table_Views.Directors;
with Qt4.Abstract_Item_Models;
package Table_View_Big is
type Big_Table is limited new Qt4.Table_Views.Q_Table_View with private;
type Big_Table_Access is access all Big_Table'Class;
package Constructors is
function Create return not null Big_Table_Access;
end Constructors;
private
type Big_Table is new Qt4.Table_Views.Directors.Q_Table_View_Director with record
Big_Table_Item_Model : Qt4.Abstract_Item_Models.Q_Abstract_Item_Model_Access;
end record;
-- overriding procedure Mouse_Press_Event
-- (Self : not null access Big_Table;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
--
-- overriding procedure Mouse_Move_Event
-- (Self : not null access Big_Table;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
-- overriding procedure Mouse_Release_Event
-- (Self : not null access Big_Table;
-- Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class);
end Table_View_Big;
table_view_big.adb
with Qt4.Abstract_Item_Views;
with Qt4.Sizes;
with Qt4.Standard_Item_Models.Constructors;
with Table_View_Big.MOC;
pragma Warnings (Off, Table_View_Big.MOC);
package body Table_View_Big is
package body Constructors is
function Create return not null Big_Table_Access is
Self : constant Table_View_Big.Big_Table_Access := new Table_View_Big.Big_Table;
begin
Qt4.Table_Views.Directors.Constructors.Initialize (Self);
declare
begin
Self.Big_Table_Item_Model := Qt4.Abstract_Item_Models.Q_Abstract_Item_Model_Access
(Qt4.Standard_Item_Models.Constructors.Create (25, 25, Self));
Self.Set_Model(Self.Big_Table_Item_Model);
Self.Set_Selection_Mode(Qt4.Abstract_Item_Views.No_Selection);
-- Drag & Drop
Self.Set_Accept_Drops(true);
Self.Set_Drag_Enabled(false);
Self.Set_Drop_Indicator_Shown(true);
-- Self.Set_Drag_Drop_Mode (Qt4.Abstract_Item_Views.Drop_Only);
return Self;
end;
end Create;
end Constructors;
end Table_View_Big;
table_view_view_test_dd.gpr
with "qt_gui";
project Table_View_Test_DD is
type Build_Modes is ("Application", "Metadata");
Build_Mode : Build_Modes := external ("BUILD_MODE");
for Source_Dirs use (".", ".amoc");
case Build_Mode is
when "Application" =>
for Main use ("main.adb");
for Object_Dir use ".objs";
for Exec_Dir use ".";
when "Metadata" =>
for Languages use ("Amoc");
for Object_Dir use ".amoc";
for Source_Files use ("table_view_small.ads",
"table_view_big.ads");
end case;
package Compiler is
for Default_Switches ("Ada") use ("-g", "-gnat05");
end Compiler;
package IDE is
for QtAda_Amoc_Invocation_Switch use "-XBUILD_MODE=Metadata";
end IDE;
-- for Languages use ("Ada");
package Naming is
for Casing use "lowercase";
end Naming;
end Table_View_Test_DD;