GWindows User Guide

# Table of Contents

Table of Contents. 1

Getting Started. 2

Introduction. 2

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.. 33

Tutorial 23 – ActiveX Events. 34

Tutorial 24 – Drag and Drop. 36

# 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 0 (prerequisite)

Download and install the GNAT development environment, from http://libre.adacore.com,

or the GNAT Pro version, or the MinGW version.

##### Step 1

Download and install the latest "GWindows Setup DD-Mmm-YYYY.exe" installer from

http://sf.net/projects/gnavi/ .

##### Step 2

Go to the gwindows directory and start gwindows_tutorials.gpr with GPS ─ or "gnatmake -P gwindows_tutorials.gpr" from the command line ─ to get started.

#

# Using GWindows

## GWindows Overview

GWindows is the Professional Open Source Ada 95 Windows 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 until now are dominated by C#, 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, XP, Vista, 7, ... 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! However, it is possible to concentrate on GWindows only; some GNATCOM components are just passively used, then.

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

Framework

Location of GWindows source code[1].

Contrib

Additional source code contributed by GWindows users

Docs

Documentation

Redist

Redistributable binary components

Samples

Samples of different uses of GWindows

Test

Code used to test different areas of GWindows

Testing

Code used to testing your software from 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 gwindows\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!

## Tutorial 24 – Drag and Drop

This example deals with the dragging of items from a control to another one, or to another window, or to another application (e.g. Windows explorer or the desktop).

[1] To relocate GWindows projects, it is sufficient to reference or copy the entire framework directory and also the gnatcom\framework directory. Actually you can put contents of both folders together for convenience into a dedicated subdirectory in your projects.