Logged in as Guest
Open Source Visual RAD



Home >
Getting Started >
GNAVI FAQ >
The GNAVI Project >
GNAVI Extras >
Join >
Latest Additions >
Press Releases >
Links >
Contact >
About >
Login >

Back
GWindows - UserGuide
RAD GUI Development Framework for Windows

GWindows User Guide

GWindows User Guide

 

 

Table of Contents

 

Table of Contents. 1

Getting Started. 1

Introduction. 1

Installing GWindows. 2

Using GWindows. 2

GWindows Overview.. 2

Directory Structure Overview.. 3

GWindows Package Overview.. 3

Using ActiveX Controls. 6

Tutorials. 7

Tutorial Overview.. 7

Tutorial 1 - Hello World. 7

Tutorial 2 – My First Window.. 8

Tutorial 3 – The Dynamic Window.. 9

Tutorial 4 – Event Handling. 10

Tutorial 5 – Controls. 13

Tutorial 6 – Fitting it all in. 14

Tutorial 7 – Drawing. 16

Tutorial 8 – Paint Events. 19

Tutorial 9 – Drawing Objects. 19

Tutorial 10 – Printing. 21

Tutorial 11 – Menus. 22

Tutorial 12 – Window Fonts. 23

Tutorial 13 – Z-Order 23

Tutorial 14 – Parent Windows. 24

Tutorial 15 – Capturing the Mouse. 25

Tutorial 16 – Changing the Cursor 26

Tutorial 17 – Dialogs. 27

Tutorial 18 – Databases. 28

Tutorial 19 – Database Bound Controls. 29

Tutorial 20 – Packing and Docking. 31

Tutorial 21 – Playing Sounds. 32

Tutorial 22 – ActiveX.. 32

Tutorial 23 – ActiveX Events. 34

 

 

Getting Started

 

Introduction

 

GWindows is incredibly powerful yet it is simple and intuitive. The guide will get you started in no time programming with GWindows.

 

 

Installing GWindows

 

 

Step 1

            Download and install GNATCOM from http://www.adapower.com/gnatcom

 

Step 2

            Download the latest version from http://www.adapower.com/gwindows

 

Step 3

            Unzip the files some where on your hard drive

 

Step 4

There are two different modes that GWindows can be compiled, ANSI and UNICODE.

 

If you are using GWindows on Windows 9X or ME or intend that applications created with GWindows will run on Windows 9X or ME then you must use the ANSI compile:

 

make ANSI=1 install

 

If the applications you will be developing will run only on NT/2000/XP then you can take advantage of the UNICODE version and its support for wide characters and faster performance on these OS versions my using:

 

make UNICODE=1 install

Step 5

You can then do a make with in the tutorials directory or in individual samples.

 

 

Using GWindows

 

 

GWindows Overview

 

 

GWindows is the Professional Open Source Ada 95 Win32 RAD Framework. It introduces for the first time to Ada programming a comprehensive rapid application development framework spanning GUI, Database and Active X integration. It brings the power of Ada to programming domains that up until now are dominated by VB and Delphi.

 

GWindows includes extensive bindings to the Windows GUI including support for common controls and dialogs, printing, and owner drawn extensions to controls. In addition, GWindows adds a number of new controls, keyboard support, multiple models of event handling, Active

X controls, support for creating dialogs and windows from resource files, dynamic garbage collected windows, Window docking, non-GUI bindings, database support, database bound controls, and much more!

 

GWindows builds as either ANSI or UNICODE (a first for Ada!) for internationalization and performance boosts on Windows NT, 2000, and XP. GWindows is tightly integrated with GNATCOM, the Ada 95 COM/DCOM/COM+ Development Framework and Tools opening every facet of the Windows platforms to Ada 95 development. Never again will the cries be heard, "but there are no bindings" on the Windows platform!

 

GWindows is designed to take advantage of Ada's unique combination of features rich typing mechanisms. It is not a think binding to an underlying C interface, but a complete framework that takes advantage of Ada at every level.

 

Directory Structure Overview

 

Under the GWindows directory are the following directories

 

Bindings

            Location of GWindows source code

Contrib

            Additional source code contributed by GWindows users

Doc

            Documentation

Redist

            Redistributable binary components

Samples

            Samples of different uses of GWindows

Test

            Code used to test different areas of GWindows

Tools

            Tools for programming with GWindows

Tools\gnatreg

            An application for registering directories as locations of standard GNAT libraries.

Tools\gbmanager

            An application for creating a repository of bound ActiveX/COM/DCOM components

Tutorials

            Location of tutorial code

 

GWindows Package Overview

 

GWindows

Base package of GWindows. gwindows.ads is a copy of either gwindows_ansi.ads or gwindows_Unicode.ads depending on the build type.

 

Applications at run time can determine if they are Unicode or ANSI builds by checking the constant Character_Mode.

 

GWindows allows for the transparent use and compilation of ANSI and Unicode builds through a set of character and string types that take the place of their standard Ada equivalents.

 

GCharacter, GString, GString_Unbounded instead of Ada standard types Character, String and Unbounded_String (or their wide type equivalents).

 

GChar_C, GString_C in place of Interfaces.C.char and Interfaces.C.char_array

 
GWindows.GStrings

GWindows string conversion and handling subprograms. gwindows-gstrings.adb is a copy of either gwindows-gstrings_ansi.adb or gwindows-gstrings_unicode.adb depending on the build type.

 

Conversion routines are available to convert between, GStrings, GString_C, GString_Unbounded, Strings, Wide_Strings, BSTR and VARIANTS.

 

GWindows.GStrings.Unbounded

Renames Ada.Strings.Unbounded or Ada.Strings.Wide_Unbounded depending on the build type.

 
GWindows.Message_Boxes

Message_Boxes and Input_Boxes

 

GWindows.Application

Subprograms needed to start Windows message loops in order for the application to start responding to events. These include the main application event loop and modal window loops and modal dialog box loops. Also contains subprograms for general application wide tasks.

 

GWindows.Base

Base type for all windows, dialogs and controls including general events for all GWindows objects.

 
GWindows.Windows

Base type for windows, mdi windows, dialogs and custom controls

 

GWindows.Windows.Main

A GWindows window that shuts down the main application loop when the window is closed.

 

GWindows.Windows.MDI

Types to aid in the creation of MDI based Windows applications

 
GWindows.ActiveX

ActiveX Controls Type

 

GWindows.Databases

Bindings to ADO databases and for binding controls to databases

 

GWindows.Databases.Controls

Controls to make database programming easier

 
GWindows.Buttons

Buttons, Radio Buttons, Check Boxes, etc.

 

GWindows.Combo_Boxes

Combo Boxes and Drop Downs

 

GWindows.Common_Controls

Bindings to Win32 “Common Controls” an extend set of operating system provided controls

 
GWindows.Edit_Boxes

Controls for accepting text

 

GWindows.Edit.Rich

Rich text controls

 
GWindows.List_Boxes

List box controls

 
GWindows.Scroll_Bars

Scroll bar controls (not scroll bars on windows)

 

GWindows.Static_Controls

Labels, Bitmap, Meta File and Icon controls

 

GWindows.Scroll_Panels

Scroll panel objects can be placed in a window to create a virtual space with in the window with automatic handling of scroll bars

 
GWindows.Packing_Boxes

Objects to control layout of controls

 

GWindows.Panels

Panel controls

 
GWindows.Drawing

Subprograms for drawing on windows and controls

 

GWindows.Drawing.Capabilities

Subprograms for determining the capabilities of a device to be drawn on

 

GWindows.Drawing_Objects

Pens, Bitmaps, Icons, etc. objects for use with GWindows.Drawing

 

GWindows.Drawing_Panels

Control used to make drawing easier on windows by providing a persistent canvas

 

GWindows.Common_Dialogs

Bindings to Win32 “Common Dialogs” a set of dialogs boxes provided by the operating system to give applications a consistent look and feel.

 
GWindows.Menus

Subprograms to handle window menus and popups

 
GWindows.Multi_Media

Subprograms for making use of different medias such as sound

 

GWindows.Image_Lists

Image list objects used with many common controls

 
GWindows.Carets

Windows caret (blinking text cursor) support

 
GWindows.Cursors

Support for handling the Windows mouse cursor.

 

GWindows.Colors

Color types, constants and subprograms

 

GWindows.Constants

Constants such as the dialog control IDs commonly used

 

GWindows.Metrics

Subprograms to determine nature of system where application is running

 
GWindows.Key_States

Subprograms to determine keyboard state at any moment

 

GWindows.Events

Pre canned event handlers

 

GWindows.Types

Types used through out GWindows

 

GWindows.Errors

Subprograms for handling Win32 errors

 

GWindows.Registry

Subprograms for accessing the Win32 registry

 

GWindows.Utilities

Routines to assist in binding to Win32 methods

 

GWindows.Internal

Internal private package for GWindows

           

 

Using ActiveX Controls

 

ActiveX controls are “the” success story of component based software development. There are tens of thousands of controls written and available for free or purchase on the web and in programming catalogs, not to mention a huge array of controls that are part of the operating system itself. GWindows makes it possible to incorporate these controls in to Ada applications.

 

GWindows.ActiveX contains only two creation methods and a single property. The creation methods bind to a helper dll called gwocx1.dll that must be available on the application’s path. This DLL takes care of the nasty details of hosting the ActiveX control in a standard Windows window, which is then embedded in to your applications window. The single property grants access to the control ‘s COM interface by which all communications are done using the package GNATCOM.Dispinterface for dynamic access to the control or through Ada bindings generated by BindCOM or GBManager.

 

The steps to using an ActiveX control are:

 

1. Create the parent window

2. Create the control using GWindows.ActiveX.Create and its CLSID or Program ID

3. Either use:

            GNATCOM.Dispinterface.Query

(MyDispatch, GWindows.ActiveX.Interface (MyControl));

 

            For dynamic control of the Control

Or

Use the Query method on the type for the Control generated by BindCOM or GBManager.

 

Using dynamic control for the Control either requires knowledge of the controls API at design time or it can be queried at run time using the GNATCOM.ITypeInfo interface.

 

The easiest way to control the Control is to create a binding for it before hand.

 

 

 

 

 

Tutorials

 

 

Tutorial Overview

 

You can find source code for all the tutorials in the directory GWindows\tutorials. For all directory paths, substitute GWindows with the root director of you GWindows installation.

 

 

Tutorial 1 - Hello World

 

GWindows offers a number of Message Box routines in the package GWindows.Message_Boxes. Message boxes give your application the opportunity of getting the attention of the user, relating a message to him or getting a simple response.

 

with GWindows.GStrings;

with GWindows.Message_Boxes;

 

procedure Tutorial1 is

   use GWindows.Message_Boxes;

 

   Result : Message_Box_Result;

begin

   Message_Box (Title => "Tutorial1",

                Text  => "My first GWindows Application",

                Icon  => Exclamation_Icon);

 

   Result := Message_Box (Title => "Tutorial1",

                          Text  => "Nice GUI huh?",

                          Style => Yes_No_Box,

                          Icon  => Question_Icon);

 

   if Result = Yes then

      Message_Box ("Cool....", "I like your answer");

   else

      Message_Box ("What....", "You have no taste");

   end if;

 

   for I in 1 .. 3 loop

      Message_Box ("A Number",

                   GWindows.GStrings.To_GString_From_String (I'Img));

   end loop;

end Tutorial1;

 

If you looked at the specs for GWindows.Message_Boxes (perhaps even if you haven't) the above code should be easy to understand. The only "twist" is the use of GWindows.GStrings.

 

GWindows.GStrings is the magic behind GWindows ability to implement both ANSI and UNICODE bindings to the Win32 API.

 

The difference between the two is that ANSI is an 8 bit encoding of strings equivalent to the string type in Ada and UNICODE is a 16 bit encoding of strings equivalent to wide_string in Ada. The root GWindows package, depending on build type, either sets:

 

   subtype GCharacter is Wide_Character;

   subtype GString is Wide_String;

   subtype GString_Unbounded is

     Ada.Strings.Wide_Unbounded.Unbounded_Wide_String;

 

or sets:

 

   subtype GCharacter is Character;

   subtype GString is String;

   subtype GString_Unbounded is Ada.Strings.Unbounded.Unbounded_String;

 

In order to make development of software that can be compiled against either build type, GWindows provides a package GWindows.GStrings that will convert between GStrings, Ada, C and COM types. Thankfully, GNAT will take string literals and convert them to the proper type, so the conversion routines are often not needed.

 

If you are going to be using only one type of binding it may be possible to circumvent the use of GStrings, but don't! You never know where you code may end up. Perhaps some one wants to port your cool killer game to a Japanese version where ANSI just won't do the trick or perhaps your neat-o server might be running on a server farm of Win 2K machines pushing the limit and UNICODE is the way to do it.

 

Tutorial 2 – My First Window

 

Message Boxes may be enough for the rare quick and dirty application, but they are hardly what makes GUI programs more user friendly than text based applications. The following code is perhaps the simplest full Windows application you can write in GWindows:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Application;

 

procedure Tutorial2 is

   pragma Linker_Options ("-mwindows");

 

   Main_Window : Main_Window_Type;

begin

   Create (Main_Window, "My First Window");

   Visible (Main_Window, True);

 

   GWindows.Application.Message_Loop;

end Tutorial2;

As you can already see GUI programming with GWindows is not exactly brain surgery.

 

First we declare our Window object, in this case a specialized type of Window, a Main_Window_Type that will automatically shut down the application when its window is closed.

 

Then we begin our application by creating the GUI object associated with our Main_Window_Type and set its visible property to true. All top level windows are created by default as invisible and all controls by default are created visible. As can be seen from the specs in GWindows.Windows, it is possible to also set the location and size of the window when creating the window (we will discuss the Is_Dynamic parameter in the next tutorial.)

 

The least intuitive part of this tutorial code is the GWindows.Application.Message_Loop line. All Windows applications make use of message loops to dispatch serially control messages to the GUI objects. Every task in your Ada program where GUI objects are created must include a message loop and windows containing ActiveX controls must be created in the main task of the application. Once created a window may be manipulated from any Ada task. For some examples of multi threaded programming of GWindows, see the directory GWindows\samples\tasks

 

GNAT can produce both console and GUI applications for windows, the linker option, -mwindows, tells GNAT to compile a GUI application instead of a console application. Frequently when creating GWindows applications, I compile without the –mwindows option so that I can send output to the console while my GUI application is running. Once I know that my application is running the way I like, I strip our the console writes and compile with the –mwindows option.

 

Tutorial 3 – The Dynamic Window

 

As I promised, we will talk in this tutorial about the Is_Dynamic parameter to create. GWindows allows for the dynamic creation of GWindows window and control types that when their GUI elements are destroyed they are deallocated. For example:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Windows; use GWindows.Windows;

with GWindows.GStrings;

with GWindows.Application;

 

procedure Tutorial3 is

   pragma Linker_Options ("-mwindows");

 

   function "+"(S : String) return GWindows.GString

     renames GWindows.GStrings.To_GString_From_String;

 

   Main_Window : Main_Window_Type;

begin

   Create (Main_Window, "The Main Window");

   Visible (Main_Window, True);

 

   declare

      A_Window : Window_Access;

   begin

      for N in 1 .. 3 loop

         A_Window := new Window_Type;

 

         Create (A_Window.all, +("Dynamic Window" & N'Img),

                 Width      => 75,

                 Height     => 75,

                 Is_Dynamic => True);

         Visible (A_Window.all);

      end loop;

   end;

 

   GWindows.Application.Message_Loop;

end Tutorial3;

 

Once any of the dynamic windows are closed (or the main window since all the the other windows will close when it closes) the memory allocated for each window by

 

         A_Window := new Window_Type;

 

will be deallocated automaticly by GWindows.

 

Dynamic windows are not a frequent occurrence outside of MDI (Multi Document Interface) applications, but they are there when you need them.

 

By the way, if you are doing a lot of coding with GStrings, you may want to rename the To_GString_From_String function in to something simpler like the + operator.

 

Tutorial 4 – Event Handling

 

So you can display windows, but how do you find out what the user does with your window? Through events.

 

There are two event models used in GWindows, inheritance and event handlers. The inheritance model is mainly used for extending GWindows with new or custom functionality, while the event handlers are most often used with a particular instance of a window or a control.

 

There are a huge number of events that can be made use of, for a quick look at the list of events, the Quick_Ref.txt document in the GWindows\doc directory comes in handy. Eventually you will want to implement handlers for these events. Events are described in the spec files in a section that always starts with a comment that looks like this:

 

   -------------------------------------------------------------------------

   --  Window_Type - Events

   -------------------------------------------------------------------------

 

In those sections each event is given with a short description.

 

To handle these events using the inheritance model, just extend the type and override the procedure.

 

For example:

 

with GWindows.Windows.Main;

 

package Tutorial4_Window is

 

   type My_Window_Type is

     new GWindows.Windows.Main.Main_Window_Type with private;

   type My_Window_Access is access all My_Window_Type;

   type Pointer_To_My_Window_Class is access all My_Window_Type'Class;

 

   procedure On_Close (Window    : in out My_Window_Type;

                       Can_Close :    out Boolean);

 

private

   type My_Window_Type is

     new GWindows.Windows.Main.Main_Window_Type with null record;

end Tutorial4_Window;

 

I could have written this package with out adding all the extra access types and extending My_Window_Type in private, but it helps to be consistent with the framework when creating new type of GWindows objects.

 

The implementation of this package would simply be:

 

package body Tutorial4_Window is

 

   --------------

   -- On_Close --

   --------------

 

   procedure On_Close

     (Window    : in out My_Window_Type;

      Can_Close :    out Boolean)

   is

      use GWindows.Message_Boxes;

   begin

      Can_Close := Message_Box (Window, "Tutorial4", "Ok to close?",

                                Yes_No_Box, Question_Icon) =  Yes;

   end On_Close;

 

end Tutorial4_Window;

 

This may seem like a lot of work for implementing event handling, and it is. The pay off is when you reuse My_Window_Type for a few hundred windows. If you are in need of just creating one My_Window, then event handlers are certainly simpler to write and use.

 

For every event there are two additional procedures defined in a spec, handler property procedure for setting the handler and a fire procedure to execute the handler. Unless you are extending a GWindows object, you will not be using the fire procedure. The handler property procedure is declared as the name of the event followed by “_Handler” and takes two parameters, the object and the event handler. For example the On_Close event would be:

 

   procedure On_Close_Handler (Window  : in out Window_Type;

                               Handler : in Close_Event);

 

To implement an On_Close handler, we need to create a procedure that has the same signature as the close event, which is nothing more then an access to procedure:

 

   type Close_Event is access

     procedure (Window    : in out GWindows.Base.Base_Window_Type'Class;

                Can_Close :    out Boolean);

 

The signature always has as the first parameter Window    : in out GWindows.Base.Base_Window_Type'Class; and the remaining parameters if any are exactly the same as the inheritable event procedure.

 

So for our example we would implement the following:

 

   declare

      Main_Window : GWindows.Windows.Main.Main_Window_Type;

     

      procedure Do_On_Close

       (Window    : in out GWindows.Base.Base_Window_Type'Class;

        Can_Close :    out Boolean)

      is

        use GWindows.Message_Boxes;

      begin

        Can_Close := Message_Box (Window, "Tutorial4", "Ok to close?",

                               Yes_No_Box, Question_Icon) =  Yes;

      end Do_On_Close;

     

   begin

      Create (Main_Window, "Event Handling Winodw");

      Visible (Main_Window, True);

      On_Close_Handler (Main_Window, Do_On_Close'Unrestricted_Access);

     

      GWindows.Application.Message_Loop;

   end;

 

 

You will notice that since Do_On_Close is not declared at library level, we must make use of Unrestricted_Access. You must of course make sure that Do_On_Close does not go out of scope for the length of time that it may be possible called, i.e. as along as Main_Window is around.

 

Here is the complete code for using both types of inheritance:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Windows; use GWindows.Windows;

with GWindows.Base;

with GWindows.Application;

with GWindows.Message_Boxes;

 

with Tutorial4_Window; use Tutorial4_Window;

 

procedure Tutorial4 is

   pragma Linker_Options ("-mwindows");

begin

  

   declare

      My_Window   : Tutorial4_Window.My_Window_Type;

   begin

      Create (My_Window, "Event Handling Winodw");

      Visible (My_Window, True);

 

      GWindows.Application.Message_Loop;

   end;

  

   declare

      Main_Window : GWindows.Windows.Main.Main_Window_Type;

     

      procedure Do_On_Close

       (Window    : in out GWindows.Base.Base_Window_Type'Class;

        Can_Close :    out Boolean)

      is

        use GWindows.Message_Boxes;

      begin

        Can_Close := Message_Box (Window, "Tutorial4", "Ok to close?",

                               Yes_No_Box, Question_Icon) =  Yes;

      end Do_On_Close;

     

   begin

      Create (Main_Window, "Event Handling Window");

      Visible (Main_Window, True);

      On_Close_Handler (Main_Window, Do_On_Close'Unrestricted_Access);

     

      GWindows.Application.Message_Loop;

   end;

  

end Tutorial4;

 

 

Tutorial 5 – Controls

 

Now that we understand the basics of GWindows and its event model, we can go on to make are Windows a little more usable by adding some controls. Controls in GWindows are just another type of GWindows object and follows that we have already discussed.

 

Here is an simple example adding controls to a window:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.Edit_Boxes; use GWindows.Edit_Boxes;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.Message_Boxes;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial5 is

   pragma Linker_Options ("-mwindows");

  

   Main_Window : GWindows.Windows.Main.Main_Window_Type;

   User_Name   : GWindows.Edit_Boxes.Edit_Box_Type;

   Disp_Button : GWindows.Buttons.Button_Type;

  

   procedure Do_Display

     (Window    : in out GWindows.Base.Base_Window_Type'Class)

   is

   begin

      GWindows.Message_Boxes.Message_Box ("Controls Window", Text (User_Name));

   end Do_Display;

  

begin

   Create (Main_Window, "Controls Window", Width => 200, Height => 125);

   Visible (Main_Window, True);

   Keyboard_Support (Main_Window, True);

  

   Create_Label (Main_Window, "Name :", 10, 10, 50, 25);

  

   Create (User_Name, Main_Window, "", 70, 10, 100, 25);

  

   Create (Disp_Button, Main_Window, "&Display", 10, 50, 75, 30);

   On_Click_Handler (Disp_Button, Do_Display'Unrestricted_Access);

  

   GWindows.Application.Message_Loop;

end Tutorial5;

 

 

 

As you can see adding controls is just a matter of calling the create procedure for the control, including the parent window and its location. For Static controls (like labels, icons, bitmaps, etc.) on a page, it is possible to create them with out have a variable for them. If you plan on making changes at run time or responding to events on them, you can still create them with a variable.

 

There is a new property that we set to true on the Main_Window, Keyboard_Support. This allows us to respond to move around the various controls using the standard Windows keyboard controls like the tab key, or to go direct to a control such as the display button using its “hot key”. The buttons hot key is set by using the ampersand (&) before the letter in the text to be used with the Alt-Key combination for instant access.

 

A more complex example of using controls can be found in form_example.adb located at GWindows\samples\simple

 

Tutorial 6 – Fitting it all in

 

Using GWindows.Scroll_Panels, there is no need to worry if you are running out of space for all your controls! You can create a virtual window with in a Scroll Panel that the user can move around in using scroll bars. The following code demonstrates using Scroll_Panels as top level windows and as controls.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Scroll_Panels; use GWindows.Scroll_Panels;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.Edit_Boxes; use GWindows.Edit_Boxes;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.Message_Boxes;

with GWindows.Events;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial6 is

   pragma Linker_Options ("-mwindows");

begin

   --  Using a Scroll Panel as a Window

 

   declare

      Main_Window : GWindows.Scroll_Panels.Scroll_Panel_Type;

      User_Name   : GWindows.Edit_Boxes.Edit_Box_Type;

      Disp_Button : GWindows.Buttons.Button_Type;

 

      procedure Do_Display

        (Window    : in out GWindows.Base.Base_Window_Type'Class)

      is

      begin

         GWindows.Message_Boxes.Message_Box

           ("Scroll Window", Text (User_Name));

      end Do_Display;

   begin

      Create (Main_Window, "Scroll Window", Width => 200, Height => 150);

      Visible (Main_Window, True);

      On_Destroy_Handler (Main_Window,

                           GWindows.Events.Do_End_Application'Access);

      --  Since Scroll_Panel_Type is not derived from Main_Window_Type

      --  it will not automaticly close the application when the window

      --  is destroyed. This handler will do that for us.

 

      Panel_Size (Main_Window, 500, 500);

 

      Keyboard_Support (Main_Window.Panel, True);

 

      Create_Label (Main_Window.Panel, "Name :", 150, 10, 50, 25);

 

      Create (User_Name, Main_Window.Panel, "", 230, 10, 100, 25);

 

      Create (Disp_Button, Main_Window.Panel, "&Display", 150, 50, 75, 30);

      On_Click_Handler (Disp_Button, Do_Display'Unrestricted_Access);

 

      Focus (User_Name);

 

      GWindows.Application.Message_Loop;

   end;

 

   --  Using a Scroll Panel as a control

 

   declare

      Main_Window  : GWindows.Windows.Main.Main_Window_Type;

      Scroll_Panel : GWindows.Scroll_Panels.Scroll_Panel_Type;

      User_Name   : GWindows.Edit_Boxes.Edit_Box_Type;

      Disp_Button : GWindows.Buttons.Button_Type;

 

      procedure Do_Display

        (Window    : in out GWindows.Base.Base_Window_Type'Class)

      is

      begin

         GWindows.Message_Boxes.Message_Box

           ("Scroll Window", Text (User_Name));

      end Do_Display;

   begin

      Create (Main_Window, "Scrolling Window 2", Width => 400, Height => 400);

      Visible (Main_Window, True);

 

      Create_As_Control (Scroll_Panel, Main_Window,

                         Top    => 20,

                         Left   => 20,

                         Width  => 300,

                         Height => 300);

 

      Panel_Size (Scroll_Panel, 500, 500);

 

      Keyboard_Support (Scroll_Panel.Panel, True);

 

      Create_Label (Scroll_Panel.Panel, "Name :", 150, 10, 50, 25);

 

      Create (User_Name, Scroll_Panel.Panel, "", 230, 10, 100, 25);

 

      Create (Disp_Button, Scroll_Panel.Panel, "&Display", 150, 50, 75, 30);

      On_Click_Handler (Disp_Button, Do_Display'Unrestricted_Access);

 

      Focus (User_Name);

 

      GWindows.Application.Message_Loop;

   end;

 

end Tutorial6;

 

Just keep in mind when adding controls that the internal panel (Scroll_Panel.Panel) needs to be the parent window and everything else is very straight forward.

 

As you can see, in GWindows any object derived from GWindows.Windows.Window_Type can be created as either a top level window (using Create) or as a control (Create_As_Control).

 

 

Tutorial 7 – Drawing

 

In addition to placing controls on a window, we can also draw on a window. In GWindows there are two primary ways of drawing, using a drawing panel, or directly on a window. When drawing directly on to a window, you will need to handle the On_Paint event in order to redraw any of your drawing whenever the operating system requests it. With a drawing panel, this is taken care of for you.

 

In this tutorial, we present use of the drawing panel, in the next, we will show how to use the On_Paint event. Following that, we will introduce more about drawing and drawing objects in GWindows

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Drawing_Panels; use GWindows.Drawing_Panels;

with GWindows.Scroll_Panels; use GWindows.Scroll_Panels;

with GWindows.Drawing;

with GWindows.Colors; use GWindows.Colors;

with GWindows.Events;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial7 is

   pragma Linker_Options ("-mwindows");

 

   use GWindows.Drawing;

 

   procedure Draw_Something

     (Canvas : in out GWindows.Drawing.Canvas_Type'Class)

   is

   begin

      for N in 1 .. 100 loop

         Fill_Rectangle (Canvas,

                         (N * 2, N * 2, N + 20, N + 20),

                         COLOR_3DHILIGHT);

         Fill_Rectangle (Canvas,

                         (N * 2 + 200, N * 2 + 200, N + 180, N + 180),

                         COLOR_DESKTOP);

      end loop;

   end Draw_Something;

 

begin

   --  Using a Drawing Panel as a Window

 

   declare

      Main_Window : GWindows.Drawing_Panels.Drawing_Panel_Type;

      Canvas      : GWindows.Drawing.Memory_Canvas_Type;

   begin

      Create (Main_Window, "Drawing Window", Width => 200, Height => 125);

      Visible (Main_Window, True);

      On_Destroy_Handler (Main_Window,

                          GWindows.Events.Do_End_Application'Access);

      --  Since Drawing_Panel_Type is not derived from Main_Window_Type

      --  it will not automaticly close the application when the window

      --  is destroyed. This handler will do that for us.

 

      Auto_Resize (Main_Window, False);

      Resize_Canvas (Main_Window,

                     GWindows.Application.Desktop_Width,

                     GWindows.Application.Desktop_Height);

      --  By turning off auto resize and setting canvas to the size of

      --  of the desktop contents will be saved no matter how we

      --  resize the window

 

      Get_Canvas (Main_Window, Canvas);

 

      Redraw (Main_Window, False);

 

      Draw_Something (Canvas);

 

      GWindows.Application.Message_Loop;

   end;

 

   --  Using a Drawing Panel as a Control

 

   declare

      Main_Window  : GWindows.Windows.Main.Main_Window_Type;

      Draw_Control : GWindows.Drawing_Panels.Drawing_Panel_Type;

      Canvas       : GWindows.Drawing.Memory_Canvas_Type;

   begin

      Create (Main_Window, "Drawing Window", Width => 400, Height => 400);

      Visible (Main_Window, True);

 

      Create_As_Control (Draw_Control, Main_Window,

                         Top    => 20,

                         Left   => 20,

                         Width  => 300,

                         Height => 300);

 

      Get_Canvas (Draw_Control, Canvas);

 

      Redraw (Draw_Control, False);

 

      Draw_Something (Canvas);

 

      GWindows.Application.Message_Loop;

   end;

 

   --  Using a Drawing Panel in a Scroll Panel

 

   declare

      Main_Window  : GWindows.Windows.Main.Main_Window_Type;

      Scroll_Panel : GWindows.Scroll_Panels.Scroll_Panel_Type;

      Draw_Control : GWindows.Drawing_Panels.Drawing_Panel_Type;

      Canvas       : GWindows.Drawing.Memory_Canvas_Type;

   begin

      Create (Main_Window, "Drawing Window", Width => 400, Height => 400);

      Visible (Main_Window, True);

 

      Create_As_Control (Scroll_Panel, Main_Window,

                         Top    => 20,

                         Left   => 20,

                         Width  => 300,

                         Height => 300);

 

      Panel_Size (Scroll_Panel, 500, 500);

 

      Create_As_Control (Draw_Control, Scroll_Panel.Panel,

                         Top    => 0,

                         Left   => 0,

                         Width  => 0,

                         Height => 0);

      Dock (Draw_Control, GWindows.Base.Fill);

      Dock_Children (Scroll_Panel.Panel);

 

      Get_Canvas (Draw_Control, Canvas);

 

      Redraw (Draw_Control, False);

 

      Draw_Something (Canvas);

 

      GWindows.Application.Message_Loop;

   end;

 

end Tutorial7;

 

As you can see after doing drawing on the internal canvas of the draw panel, we call Redraw on the panel to have the internal canvas painted on to the window. One advantage is that this provides double buffering for smooth animation and other graphic tasks.

 

When using the Scroll Panel version you may notice a little bit of flicker when scrolling around. This can be removed by setting an On_Erase_Background handler on Scroll_Panel.Panel that does nothing and thus prevents a draw of the background color before a redraw of the contents of the panel.

 

One interesting set of procedures called in this example not directly connected to drawing worth noting is:

      Dock (Draw_Control, GWindows.Base.Fill);

      Dock_Children (Scroll_Panel.Panel);

 

GWindows has a simple docking mechanism for laying out panels and controls for more examples on docking see GWindows\samples\simple\dock_test.adb

 

Tutorial 8 – Paint Events

 

In traditional Windows painting, you would handle paint requests from the OS. This model is still available in GWindows as an alternative to Drawing Panels. Here is simple code that demonstrates how:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Drawing;

with GWindows.Colors;

with GWindows.Types;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial8 is

   pragma Linker_Options ("-mwindows");

 

   procedure Do_Paint

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      Canvas : in out GWindows.Drawing.Canvas_Type;

      Area   : in     GWindows.Types.Rectangle_Type)

   is

     use GWindows.Drawing;

     use GWindows.Colors;

   begin

      for N in 1 .. 100 loop

         Fill_Rectangle (Canvas,

                         (N * 2, N * 2, N + 20, N + 20),

                         COLOR_3DHILIGHT);

         Fill_Rectangle (Canvas,

                         (N * 2 + 200, N * 2 + 200, N + 180, N + 180),

                         COLOR_DESKTOP);

      end loop;

   end Do_Paint;

 

   Main_Window : GWindows.Windows.Main.Main_Window_Type;

begin

   Create (Main_Window, "On_Paint Drawing Window",

          Width => 200, Height => 200);

   Visible (Main_Window, True);

   On_Paint_Handler (Main_Window, Do_Paint'Unrestricted_Access);

  

   GWindows.Application.Message_Loop;

end Tutorial8;

 

 

No suprises here, just a matter of setting an On_Paint handler. You could of course do the same thing using inheritance and overriding On_Pain, but we will leave that as an exercise for the reader.

 

Tutorial 9 – Drawing Objects

 

The two basic concepts to be understood for drawing in GWindows is the Canvas and the Drawing Object. You draw on a Canvas with Drawing Objects, surprise!

 

You can request a Canvas_Type directly from a Window at any type by using the Get_Canvas method or receive a canvas as part of an On_Paint or On_Erase_Background message. The Printer_Canvas_Type  is received from calls to Choose_Printer or Choose_Default_Printer from GWindows.Common_Dialogs. You request a Memory_Canvas_Type from Drawing Panels.

 

In all cases, the same drawing methods are used from GWindows.Drawing.

 

In GWindows.Drawing_Objects there are a number of Drawing_Objects that you can select in to a canvas using Select_Object. Once selected in, they will be used for drawing operations. Example so Drawing_Objects include Brushes, pens, bitmaps and icons.

 

Here is a simple example of using various drawing objects.

 

with GWindows.Drawing_Panels; use GWindows.Drawing_Panels;

with GWindows.Drawing; use GWindows.Drawing;

with GWindows.Drawing_Objects; use GWindows.Drawing_Objects;

with GWindows.Colors; use GWindows.Colors;

with GWindows.Events;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial9 is

   pragma Linker_Options ("-mwindows");

 

   Main_Window : GWindows.Drawing_Panels.Drawing_Panel_Type;

   Canvas      : GWindows.Drawing.Memory_Canvas_Type;

   Brush       : GWindows.Drawing_Objects.Brush_Type;

   Pen         : GWindows.Drawing_Objects.Pen_Type;

begin

   Create (Main_Window, "On_Paint Drawing Window",

           Width => 200, Height => 200);

   Visible (Main_Window, True);

   On_Destroy_Handler (Main_Window,

                       GWindows.Events.Do_End_Application'Access);

   Auto_Resize (Main_Window, False);

   Resize_Canvas (Main_Window,

                  GWindows.Application.Desktop_Width,

                  GWindows.Application.Desktop_Height,

                  False);

 

   Get_Canvas (Main_Window, Canvas);

 

   Create_Pen (Pen,

               Style => Solid,

               Width => 3,

               Color => Blue);

   Select_Object (Canvas, Pen);

 

   Create_Solid_Brush (Brush,

                       Color => Orange);

   Select_Object (Canvas, Brush);

 

   Ellipse (Canvas,

            10, 10,

            Client_Area_Width (Main_Window) - 10,

            Client_Area_Height (Main_Window) - 10);

 

   Create_Hatch_Brush (Brush,

                       Style => Cross,

                       Color => Red);

   Select_Object (Canvas, Brush);

 

   Create_Stock_Pen (Pen, Null_Pen);

   Select_Object (Canvas, Pen);

 

   Rectangle (Canvas,

              25, 25,

              Client_Area_Width (Main_Window) - 25,

              Client_Area_Height (Main_Window) - 25);

 

   Redraw (Main_Window, False);

 

   GWindows.Application.Message_Loop;

end Tutorial9;

 

 

Tutorial 10 – Printing

 

Printing with GWindows is just an extension of drawing on any canvas. You can use one of two procedures in GWindows.Common_Dialogs to choose the printer to output to. Once you have the printers canvas, you need to start the document and give it a name for the print spooler using Start_Document. Then use Start_Page and End_Page to mark off each page.

 

with Interfaces.C;

 

with GWindows.Drawing; use GWindows.Drawing;

with GWindows.Common_Dialogs; use GWindows.Common_Dialogs;

with GWindows.Message_Boxes;

with GWindows.Windows;

 

procedure Tutorial10 is

   Canvas    : GWindows.Drawing.Printer_Canvas_Type;

   Settings  : GWindows.Common_Dialogs.DEVMODE;

   Flags     : Interfaces.C.unsigned := 0;

   From_Page : Natural := 1;

   To_Page   : Natural := 1;

   Copies    : Natural := 1;

   Success   : Boolean;

   Null_Win  : GWindows.Windows.Window_Type;

begin

   Choose_Printer (Null_Win, Canvas, Settings, Flags,

                   From_Page, To_Page, 1, 1, Copies, Success);

 

   if Success then

      Start_Document (Canvas, "Tutorial10 Document");

      Start_Page (Canvas);

 

      Put (Canvas, 100, 100, "Hello World!");

 

      Ellipse (Canvas, 200, 200, 500, 500);

 

      End_Page (Canvas);

      End_Document (Canvas);

      GWindows.Message_Boxes.Message_Box ("Tutorial 10", "Done");

   else

      GWindows.Message_Boxes.Message_Box ("Tutorial 10",

                                          "Printing Canceled");

   end if;

end Tutorial10;

 

 

Tutorial 11 – Menus

 

GWindows can create menus in code or load menus from resources embedded in the application. Menus once loaded can then be placed on windows or used as “context” menus that pop up on a right mouse button click.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Menus; use GWindows.Menus;

with GWindows.Application;

with GWindows.Base;

 

procedure Tutorial11 is

   pragma Linker_Options ("-mwindows");

 

   Main_Window : Main_Window_Type;

   Main_Menu   : Menu_Type := Create_Menu;

   File_Menu   : Menu_Type := Create_Popup;

   Sub_Menu    : Menu_Type := Create_Popup;

 

   ID_Exit     : constant := 100;

   ID_Open     : constant := 101;

   ID_Save     : constant := 102;

   ID_About    : constant := 103;

 

   procedure Do_Menu_Select

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      Item   : in     Integer)

   is

   begin

      case Item is

         when ID_Exit =>

            GWindows.Application.End_Application;

         when others =>

            null;

      end case;

   end Do_Menu_Select;

 

   procedure Do_Context_Menu

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      X      : in     Integer;

      Y      : in     Integer)

   is

   begin

      Display_Context_Menu (Main_Window_Type (Window), File_Menu, 0, X, Y);

   end Do_Context_Menu;

 

begin

   Create (Main_Window, "My First Window");

   Visible (Main_Window, True);

 

   Append_Item (File_Menu, "&Open", ID_Open);

   Append_Item (File_Menu, "&Save", ID_Save);

   Append_Separator (File_Menu);

 

   Append_Item (File_Menu, "E&xit", ID_Exit);

   Append_Menu (Main_Menu, "&Files", File_Menu);

 

   Append_Item (Sub_Menu, "A&bout", ID_About);

   Append_Menu (File_Menu, "Other", Sub_Menu);

 

   Menu (Main_Window, Main_Menu);

 

   On_Menu_Select_Handler (Main_Window, Do_Menu_Select'Unrestricted_Access);

   On_Context_Menu_Handler (Main_Window, Do_Context_Menu'Unrestricted_Access);

 

   GWindows.Application.Message_Loop;

end Tutorial11;

 

 

Tutorial 12 – Window Fonts

 

You may have noticed in Tutorial 5 that the fonts used in the controls looks a little different than most Windows applications. By default Windows sets a window to use the System font. GWindows allows you to change the font used by any window. When created, controls take their font from their parent window, but this can be changed at any time.

 

Add a with for GWindows.Drawing_Objects to Tutorial 5 and then after the Create of the Window add:

 

   declare

      Window_Font : GWindows.Drawing_Objects.Font_Type;

   begin

      --  Use Standard Windows GUI font instead of system font

      GWindows.Drawing_Objects.Create_Stock_Font

       (Window_Font, GWindows.Drawing_Objects.Default_GUI);

      Set_Font (Main_Window, Window_Font);

   end;

 

If you wanted you could just change the font of the button by doing:

Set_Font (Disp_Button, Window_Font)

 

Tutorial 13 – Z-Order

 

The order that windows appear on the screen is easily controlled using the Order method. As you can also see from this example GWindows types are like any other Ada type and can be used in Arrays, Records, etc. Order also controls tab order in controls. The initial order is the order each item is created. After that use Order to change the order.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Windows; use GWindows.Windows;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.GStrings; use GWindows.GStrings;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial13 is

   pragma Linker_Options ("-mwindows");

  

   subtype Window_Number_Type is Positive range 1 .. 5;

  

   type Window_Array_Type is array (Window_Number_Type'Range) of

     GWindows.Windows.Window_Type;

  

   Main_Window    : GWindows.Windows.Main.Main_Window_Type;

   Windows        : Window_Array_Type;

   Next_Button    : GWindows.Buttons.Button_Type;

   Current_Window : Window_Number_Type := Window_Number_Type'Last;

  

   procedure Do_Click

     (Window : in out GWindows.Base.Base_Window_Type'Class)

   is

   begin

      Order (Windows (Current_Window), GWindows.Base.Bottom);

      if Current_Window = Window_Number_Type'Last then

        Current_Window := Window_Number_Type'First;

      else

        Current_Window := Window_Number_Type'Succ (Current_Window);

      end if;

   end Do_Click;

  

begin

   Create (Main_Window, "Z-Order Window", Width => 100, Height => 100);

   Visible (Main_Window, True);

   Center (Main_Window);

  

   for N in Window_Array_Type'Range loop

      Create (Windows (N), To_GString_From_String ("TEST" & N'Img),

             Width => 75, Height => 75);

      Visible (Windows (N));

   end loop;

  

   Create (Next_Button, Main_Window, "&Next", 10, 10,

          Client_Area_Width (Main_Window) - 20,

          Client_Area_Height (Main_Window) - 20);

   On_Click_Handler (Next_Button, Do_Click'Unrestricted_Access);

  

   GWindows.Application.Message_Loop;

end Tutorial13;

 

 

 

Tutorial 14 – Parent Windows

 

In GWindows it is possible to access the parent window of a child window or control and even to re-parent the window or control using the Parent property.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial14 is

   pragma Linker_Options ("-mwindows");

 

   Window1     : Main_Window_Type;

   Window2     : Main_Window_Type;

   Jump_Button : Button_Type;

 

   procedure Do_Click (Window : in out GWindows.Base.Base_Window_Type'Class) is

      use GWindows.Base;

   begin

      if Text (Parent (Window).all) = "Window 1" then

         Parent (Window, Window2);

      else

         Parent (Window, Window1);

      end if;

   end Do_Click;

 

begin

   Create (Window1, "Window 1", Width => 100, Height => 100);

   Visible (Window1, True);

 

   Create (Window2, "Window 2",

           Top   => Top (Window1),

           Left  => Left (Window1) + 200,

           Width => 100, Height => 100);

   Visible (Window2, True);

 

   Create (Jump_Button, Window1, "Jump!", 10, 10,

           Client_Area_Width (Window1) - 20,

           Client_Area_Height (Window1) - 20);

   On_Click_Handler (Jump_Button, Do_Click'Unrestricted_Access);

 

   GWindows.Application.Message_Loop;

end Tutorial14;

 

 

Tutorial 15 – Capturing the Mouse

 

In Windows, you are generally only able to capture mouse movements with in your window, but by using the Capture and Release methods in the up and down button handlers (Window only lets you capture while the mouse button is down), you can capture the mouse movements even off your window.

 

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.GStrings; use GWindows.GStrings;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial15 is

   pragma Linker_Options ("-mwindows");

 

   Main_Window : Main_Window_Type;

   X_Label     : Label_Type;

   Y_Label     : Label_Type;

 

   procedure Do_Mouse_Move

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      X      : in     Integer;

      Y      : in     Integer;

      Keys   : in     GWindows.Windows.Mouse_Key_States)

   is

   begin

      Text (X_Label, GWindows.GStrings.Image (X));

      Text (Y_Label, GWindows.GStrings.Image (Y));

   end Do_Mouse_Move;

 

   procedure Do_Left_Mouse_Button_Down

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      X      : in     Integer;

      Y      : in     Integer;

      Keys   : in     GWindows.Windows.Mouse_Key_States)

   is

   begin

      Capture_Mouse (Main_Window);

   end Do_Left_Mouse_Button_Down;

 

   procedure Do_Left_Mouse_Button_Up

     (Window : in out GWindows.Base.Base_Window_Type'Class;

      X      : in     Integer;

      Y      : in     Integer;

      Keys   : in     GWindows.Windows.Mouse_Key_States)

   is

   begin

      GWindows.Base.Release_Mouse;

   end Do_Left_Mouse_Button_Up;

 

begin

   Create (Main_Window, "Mouse Demo Window", Width => 200, Height => 200);

   Visible (Main_Window, True);

 

   Create (X_Label, Main_Window, "0", 10, 10, 40, 25, Center);

   Create (Y_Label, Main_Window, "0", 60, 10, 40, 25, Center);

 

   On_Mouse_Move_Handler (Main_Window, Do_Mouse_Move'Unrestricted_Access);

   On_Left_Mouse_Button_Down_Handler (Main_Window,

                               Do_Left_Mouse_Button_Down'Unrestricted_Access);

   On_Left_Mouse_Button_Up_Handler (Main_Window,

                             Do_Left_Mouse_Button_Up'Unrestricted_Access);

 

   GWindows.Application.Message_Loop;

end Tutorial15;

 

Tutorial 16 – Changing the Cursor

 

In order to change the Cursor in GWindows, you need to handle the On_Cursor_Change event and use the Set_Cursor procedure from GWindows.Cursors.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Cursors;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial16 is

   pragma Linker_Options ("-mwindows");

 

   Main_Window : Main_Window_Type;

 

   procedure Do_Change_Cursor

     (Window : in out GWindows.Base.Base_Window_Type'Class)

   is

      use GWindows.Cursors;

   begin

      Set_Cursor (Load_System_Cursor (IDC_CROSS));

   end Do_Change_Cursor;

 

begin

   Create (Main_Window, "Cursor Window", Width => 200, Height => 200);

   Visible (Main_Window, True);

   On_Change_Cursor_Handler (Main_Window,

                             Do_Change_Cursor'Unrestricted_Access);

 

   GWindows.Application.Message_Loop;

end Tutorial16;

 

Tutorial 17 – Dialogs

 

Creating custom dialogs in GWindows is easy. Just open the window using Show_Dialog instead of setting its visible property to true. If you use the Dialog_Button_Type, you can set a custom ID for the return value.

 

with GWindows.GStrings.IO; use GWindows.GStrings.IO;

 

with GWindows.Windows; use GWindows.Windows;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.Application;

with GWindows.Constants; use GWindows.Constants;

 

procedure Tutorial17 is

   Dialog        : Window_Type;

   OK_Button     : Default_Button_Type;

   Cancel_Button : Cancel_Button_Type;

   More_Button   : Dialog_Button_Type;

 

   ID_MORE       : constant := 101;

 

   Result        : Integer := ID_MORE;

 

begin

   while Result = ID_MORE loop

     Create_As_Dialog (Dialog, "My Dialog Window",

                       Width => 200, Height => 100);

 

     Create_Label (Dialog, "Have you had enough yet?",

                   10, 10,

                   Client_Area_Width (Dialog) - 20,

                   25, Center);

 

     Create (OK_Button, Dialog, "O&k",

             10, Client_Area_Height (Dialog) - 40,

             50, 25, ID => IDOK);

 

     Create (Cancel_Button, Dialog, "&Cancel",

             70, Client_Area_Height (Dialog) - 40,

             50, 25, ID => IDCANCEL);

 

     Create (More_Button, Dialog, "&More",

             130, Client_Area_Height (Dialog) - 40,

             50, 25, ID => ID_MORE);

 

     Result := GWindows.Application.Show_Dialog (Dialog);

   end loop;

 

   if Result = IDOK then

      Put_Line ("Have a nice day!");

   else

      Put_Line ("Sorry for the trouble...");

   end if;

end Tutorial17;

 

Tutorial 18 – Databases

 

What good would a RAD GUI tool be with out Database support?

 

GWindows uses ADO to give access to ODBC and OLEDB databases. Here is a simple text based (GWindows is of value even with out a GUI !) database example.

 

with GNATCOM.Initialize;

with GWindows.GStrings.IO; use GWindows.GStrings.IO;

with GWindows.Databases; use GWindows.Databases;

 

procedure Tutorial18 is

   Connection : Database_Type;

   Recordset  : Recordset_Type;

begin

   GNATCOM.Initialize.Initialize_COM;

 

   Open (Connection,

         "Provider=Microsoft.Jet.OLEDB.4.0; " &

         "Data Source=adotest.mdb");

 

   Open (Recordset,

         Connection,

         "SELECT * FROM People",

         Dynamic,

         Optimistic);

 

   while not EOF (Recordset) loop

      for N in 1 .. Field_Count (Recordset) loop

         Put_Line

           (Field_Name (Recordset, N) & " = " & Field_Value (Recordset, N));

      end loop;

 

      if Field_Value (Recordset, "LastName") = "TestLName" then

         Put_Line ("This record is being deleted");

         Delete (Recordset);

      end if;

      Move_Next (Recordset);

      New_Line;

   end loop;

 

   Add_New (Recordset);

   Field_Value (Recordset, "LastName", "TestLName");

   Field_Value (Recordset, "FirstName", "TestLName");

   Update (Recordset);

 

   Close (Recordset);

   Close (Connection);

end Tutorial18;

 

Since ADO is COM based, we need to first call GNATCOM’s Intitialize_COM procedure. Once that is done we can open the connection with either an OLEDB connection string as in this example or and ODBC DSN. The we open our Recordset on the connection  with an SQL query and a way we go!

 

Tutorial 19 – Database Bound Controls

 

GWindows goes a step further then just offering database bindings, you also have the ability to bind controls to a recordset (through GWindows.Databases.Controls.Binding_Recordset_Type) and even get a pre made database GUI control.

 

Here is an example of binding controls and using the Database_Control_Type:

 

with GNATCOM.Initialize;

with GNATCOM.IErrorInfo;

 

with GWindows.GStrings; use GWindows.GStrings;

with GWindows.Databases.Controls;

use GWindows.Databases.Controls; use GWindows.Databases;

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Edit_Boxes; use GWindows.Edit_Boxes;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.Message_Boxes; use GWindows.Message_Boxes;

with GWindows.Base; use GWindows.Base;

with GWindows.Application;

 

procedure Tutorial19 is

   Main_Window : Main_Window_Type;

   ID          : aliased Edit_Box_Type;

   LastName    : aliased Edit_Box_Type;

   FirstName   : aliased Edit_Box_Type;

   Address     : aliased Edit_Box_Type;

   City        : aliased Edit_Box_Type;

   State       : aliased Edit_Box_Type;

   Zip         : aliased Edit_Box_Type;

   Country     : aliased Edit_Box_Type;

   DB_Control  : Database_Control_Type;

begin

   GNATCOM.Initialize.Initialize_COM;

 

   --  Setup Controls

   Create (Main_Window, "Database Window", Width => 400, Height => 500);

   Keyboard_Support (Main_Window);

   Center (Main_Window);

 

   Create_As_Control (DB_Control, Main_Window, "", 0, 0, 0, 30);

   Dock (DB_Control, At_Top);

 

   Create_Label (Main_Window, "ID", 10, 40, 100, 25);

   Create_Label (Main_Window, "Last Name", 10, 80, 100, 25);

   Create_Label (Main_Window, "First Name", 10, 120, 100, 25);

   Create_Label (Main_Window, "Address", 10, 160, 100, 25);

   Create_Label (Main_Window, "City", 10, 200, 100, 25);

   Create_Label (Main_Window, "State", 10, 240, 100, 25);

   Create_Label (Main_Window, "Zip", 10, 280, 100, 25);

   Create_Label (Main_Window, "Country", 10, 320, 100, 25);

 

   Create (ID, Main_Window, "",

           120, 40, 200, 30);

   Read_Only (ID);

   Create (LastName, Main_Window, "",

           120, 80, 200, 30);

   Create (FirstName, Main_Window, "",

           120, 120, 200, 30);

   Create (Address, Main_Window, "",

           120, 160, 200, 30);

   Create (City, Main_Window, "",

           120, 200, 200, 30);

   Create (State, Main_Window, "",

           120, 240, 200, 30);

   Create (Zip, Main_Window, "",

           120, 280, 200, 30);

   Create (Country, Main_Window, "",

           120, 320, 200, 30);

 

   --  Setup Database and Bindings

 

   Open (DB_Control.Database,

         "Provider=Microsoft.Jet.OLEDB.4.0; " &

         "Data Source=adotest.mdb");

 

   Open (DB_Control.Recordset,

         DB_Control.Database,

         "SELECT * FROM People",

         Dynamic,

         Optimistic);

 

   Bind_Text_Control (DB_Control.Recordset,

                      "ID",

                      ID'Unchecked_Access,

                      Read_Only);

   Bind_Text_Control (DB_Control.Recordset,

                      "LastName",

                      LastName'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "FirstName",

                      FirstName'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "Address",

                      Address'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "City",

                      City'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "State",

                      State'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "Zip",

                      Zip'Unchecked_Access);

   Bind_Text_Control (DB_Control.Recordset,

                      "Country",

                      Country'Unchecked_Access);

 

   --  Get Started

   Fill_Bindings (DB_Control.Recordset);

   Dock_Children (Main_Window);

   Visible (Main_Window, True);

 

   GWindows.Application.Message_Loop;

exception

   when others =>

      Message_Box ("Error",

                   To_GString_From_String (GNATCOM.IErrorInfo.Get_IErrorInfo),

                   Icon => Error_Icon);

end Tutorial19;

 

For an example of using Dynamic windows to automatically create a front end to a database see GWindows\samples\databases\db_view.adb

 

Tutorial 20 – Packing and Docking

 

GWindows offers additional flexability beyond the standard Windows method of placing controls in a window with the use of Docking and Packing. This example demonstrates how they can be used together.

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.Buttons; use GWindows.Buttons;

with GWindows.Static_Controls; use GWindows.Static_Controls;

with GWindows.Edit_Boxes; use GWindows.Edit_Boxes;

with GWindows.Packing_Boxes; use GWindows.Packing_Boxes;

with GWindows.Base;

with GWindows.Application;

 

procedure Tutorial20 is

   Main_Window : Main_Window_Type;

   Box         : Packing_Box_Type;

   Box2        : Packing_Box_Type;

   Box3        : Packing_Box_Type;

   Box4        : Packing_Box_Type;

   Button1     : Button_Type;

   Button2     : Button_Type;

   Button3     : Button_Type;

   Button4     : Button_Type;

   Button5     : Button_Type;

   Button6     : Button_Type;

   Edit1       : Edit_Box_Type;

   Edit2       : Edit_Box_Type;

   Edit3       : Edit_Box_Type;

 

begin

   Create (Main_Window, "Packing Boxes in a Window",

           Width => 500, Height => 250);

 

   Create (Box, Main_Window, 0, 0, 100, 0, Vertical);

   Dock (Box, GWindows.Base.At_Left);

 

   Fill_Width (Box);

   Fill_Height (Box);

   Padding (Box, 5);

   Insets (Box, (10, 10, 10, 10));

 

   Create (Box2, Main_Window, 0, 0, 0, 50, Horizontal);

   Dock (Box2, GWindows.Base.At_Top);

 

   Fill_Width (Box2);

   Fill_Height (Box2);

   Padding (Box2, 5);

   Insets (Box2, (10, 10, 10, 10));

 

   Create (Box3, Main_Window, 0, 0, 100, 0, Vertical);

   Dock (Box3, GWindows.Base.At_Left);

 

   Fill_Width (Box3);

   Padding (Box3, 5);

   Insets (Box3, (10, 15, 10, 10));

 

   Create (Box4, Main_Window, 0, 0, 0, 0, Vertical);

   Dock (Box4, GWindows.Base.Fill);

 

   Fill_Width (Box4);

   Padding (Box4, 5);

   Insets (Box4, (10, 10, 10, 10));

 

   Dock_Children (Main_Window);

 

   Create (Button1, Box, "Button1", 0, 0, 0, 0);

   Create (Button2, Box, "Button2", 0, 0, 0, 0);

   Create (Button3, Box, "Button3", 0, 0, 0, 0);

 

   Pack (Box);

 

   Create (Button4, Box2, "Button3", 0, 0, 0, 0);

   Create (Button5, Box2, "Button4", 0, 0, 0, 0);

   Create (Button6, Box2, "Button5", 0, 0, 0, 0);

 

   Pack (Box2);

 

   Create_Label (Box3, "Field 1", 0, 0, 0, 30);

   Create_Label (Box3, "Field 2", 0, 0, 0, 30);

   Create_Label (Box3, "Field 3", 0, 0, 0, 30);

 

   Pack (Box3);

 

   Create (Edit1, Box4, "", 0, 0, 0, 30);

   Create (Edit2, Box4, "", 0, 0, 0, 30);

   Create (Edit3, Box4, "", 0, 0, 0, 30);

 

   Pack (Box4);

 

   Visible (Main_Window);

   GWindows.Application.Message_Loop;

end Tutorial20;

 

Tutorial 21 – Playing Sounds

 

GWindows offers some basic procedures to play wav files from files, resources or system events.

 

with GWindows.Multi_Media; use GWindows.Multi_Media;

 

procedure Tutorial21 is

begin

   Play_Sound_From_Alias ("SystemStart");

   Play_Sound_From_File ("hello.wav");

end Tutorial21;

 

The available Aliases can be found by looking at the registry at HKEY_CURRENT_USER\AppEvents\EvetLables.  Any of the key names listed there can be used. The sound associated with the event in the control panel applet for sounds will then be played.

 

 

Tutorial 22 – ActiveX

 

There are so many overloaded terms used in programming for ActiveX, that the best way to quickly learn how to make use of ActiveX and GWindows is just to do it.

 

First, let’s pick an ActiveX control to bind using GBManager.

 

Run the program gnatcom\tools\gbmanager\gbmanager.exe

 

From the File menu of gbmanager we can pick the location that GBManager will use for storing COM bindings by using the menu option – Set Binding Repository Location. I have a directory called C:\Bindings where I place all my COM bindings. You only have to set the location once and it will be stored in the registry and GNAT will automatically look for the bindings in that location.

 

Look down the tree for the type library called: Microsoft Internet Controls

 

Expand the tree and you should see the various versions of the library that are available for binding. On my machine, it is version 1.1.

 

Click on the latest version and choose Bind from the file menu.

 

When asked for the base package name to use type: ie

 

After a few seconds, you will have a full binding to the explorer shell of the operating system. Using it we can embed a web/file browser in to our application.

 

You can now close GBManager.

 

If you go to the binding repository directory and open ie.ads, you can do a search in the text file for CLSID. The CLSID is a GUID (Global Unique Identifier) that uniquely names an ActiveX object. For our example, we are going to use the WebBrowser Control, CLSID_WebBrowser.

 

Now we are set to write our application:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.ActiveX; use GWindows.ActiveX;

with GWindows.GStrings;

with GWindows.Base;

with GWindows.Application;

 

with GNATCOM.Initialize;

with IE;

with IE.IWebBrowser_Interface;

 

procedure Tutorial22 is

   Main_Window : Main_Window_Type;

   IE_Control  : Activex_Type;

   IE_COM      : IE.IWebBrowser_Interface.IWebBrowser_Type;

begin

   GNATCOM.Initialize.Initialize_COM;

 

   Create (Main_Window, "My Web Browser");

 

   Create (IE_Control, Main_Window,

           IE.CLSID_WebBrowser,

           1, 1, 1, 1);

   Dock (IE_Control, GWindows.Base.Fill);

 

   Visible (Main_Window);

 

   IE.IWebBrowser_Interface.Query (IE_COM, Interface (IE_Control));

   IE.IWebBrowser_Interface.Navigate (IE_COM,

                                      GWindows.GStrings.To_BSTR_From_GString

                                        ("http://www.adapower.com"));

 

   GWindows.Application.Message_Loop;

end Tutorial22;

 

 

Once we create the control, we use GWindows.ActiveX.Interface to access its internal COM interface. The COM interface returned though is the generic IQueryInterface. Since we generated thick bindings to the IWebBrowser interface, we use the Query procedure of the generated IWebBrowser_Type  to access the object in a more natural Ada way. Now that we have access, the application navigates to everyone’s favorite web site!

 

Tutorial 23 – ActiveX Events

 

Now that we know how to create and talk to ActiveX controls it is also important to learn how to listen to them.

 

First we need to derive an object from the event object in our generated bindings and override any events we wish to handle . The event object for the IWebBrowser interface is located in IE.DWebBrowserEvents2_Events and is called DWebBrowserEvents2_Event.

 

with IE.DWebBrowserEvents2_Events;

with GNATCOM.Types;

 

package Tutorial23_Handle_Events is

 

   type Handle_Event_Type is

     new IE.DWebBrowserEvents2_Events.DWebBrowserEvents2_Event

     with null record;

 

   procedure DocumentComplete

     (This  : Handle_Event_Type;

      pDisp : GNATCOM.Types.VARIANT;

      URL   : GNATCOM.Types.VARIANT);

   --  Override from IE.DWebBrowserEvents2_Events.DWebBrowserEvents2_Event

 

end Tutorial23_Handle_Events;

 

Next implement event handlers we have overriden:

 

with GWindows.Message_Boxes; use GWindows.Message_Boxes;

with GWindows.GStrings;

 

package body Tutorial23_Handle_Events is

 

   ----------------------

   -- DocumentComplete --

   ----------------------

 

   procedure DocumentComplete

     (This  : Handle_Event_Type;

      pDisp : GNATCOM.Types.VARIANT;

      URL   : GNATCOM.Types.VARIANT)

   is

   begin

      Message_Box ("Tutorial23",

                   GWindows.GStrings.To_GString_From_VARIANT

                     (URL, Clear => false) &

                     " - Document has been loaded.");

      --  Do not clear or free parameters passed in from events

   end DocumentComplete;

 

end Tutorial23_Handle_Events;

 

Now it is time to connect our event object to the ActiveX control. We start out with the same basic code as the last tutorial with a few additions:

 

with GWindows.Windows.Main; use GWindows.Windows.Main;

with GWindows.ActiveX; use GWindows.ActiveX;

with GWindows.GStrings;

with GWindows.Base;

with GWindows.Application;

 

with GNATCOM.Initialize;

with GNATCOM.Create.COM_Interface;

with GNATCOM.Events;

 

with IE;

with IE.IWebBrowser_Interface;

with IE.DWebBrowserEvents2_Events;

 

with Tutorial23_Handle_Events;

 

procedure Tutorial23 is

   Main_Window : Main_Window_Type;

   IE_Control  : Activex_Type;

   IE_COM      : IE.IWebBrowser_Interface.IWebBrowser_Type;

  

  

   Handle_Event_Object : aliased Tutorial23_Handle_Events.Handle_Event_Type;

   -- Create event object

  

   Handle_Event : GNATCOM.Create.COM_Interface.Pointer_To_COM_Interface_Type :=

     IE.DWebBrowserEvents2_Events.Create

     (Handle_Event_Object'Unchecked_Access);

   --  Create COM interface wrapper around event object

  

   Handle_Events_Connection_Point : GNATCOM.Events.IConnectionPoint_Type;

   --  Interface to connection point with in COM object

   --  Used to connect and disconnect event object

   --  Disconnect is performed automaticly when Handle_Events is finalized

 

begin

   GNATCOM.Initialize.Initialize_COM;

 

   Create (Main_Window, "My Web Browser");

 

   Create (IE_Control, Main_Window,

           IE.CLSID_WebBrowser,

           1, 1, 1, 1);

   Dock (IE_Control, GWindows.Base.Fill);

 

   Visible (Main_Window);

 

   IE.IWebBrowser_Interface.Query (IE_COM, Interface (IE_Control));

  

   IE.DWebBrowserEvents2_Events.Set_Events

     (Handle_Events_Connection_Point,

      For_Object      => IE_COM,

      Event_Interface => Handle_Event);

  

  

   IE.IWebBrowser_Interface.Navigate (IE_COM,

                                      GWindows.GStrings.To_BSTR_From_GString

                                        ("http://www.adapower.com"));

 

   GWindows.Application.Message_Loop;

end Tutorial23;

 

 

The additions to the code are

 

1.       Turn our event object in to an ActiveX object (a.k.a a COM object).

First we create an aliased instance of our object, in this case Handle_Event_Object.

Then we use the Create procedure from the  package we derived our event object from (IE.DWebBrowserEvents2). This new COM object we called Handle_Event.

 

2.       Events are connected to ActiveX controls through what are called connection points. Se we need to set up an interface to it. We call this interface in our tutorial, Handle_Event_Connection_Point.

 

3.       To actually connect everything together, we use the Set_Events procedure from the package we derived our event object from (IE.DWebBrowserEvents2).

 

There may be a bit of typing involved to set up the event, but it is cookie cutter code just waiting to be copied!

 

 


(c) 1999-2004 All Rights Reserved David Botton