Frequently Asked Questions about Win32Lib

 

1. What is Win32Lib?

2. What do I need to know to program for Windows?

3. How do I make a program for Windows?

4. How do I make a "control"?

5. What is an "event link"?

6. How do I create an "event link"?

7. Where are the "event links" PLACED in the program?

8. How do I write into a window?

9. How do I draw in a window?

10. How can I write data to a file, and then retrieve it to write into a window?

11. How can I use special keys like up/down arrows in windows?

12. How do I create and use a TIMER?





1. What is Win32Lib?

Answer: Win32Lib is a library of functions created by David Cuny and later expanded by Matthew Lewis and others which makes a large number of Windows programming elements available to the programmer.

Using Win32Lib, you can create one or more windows, and a variety of other "controls" (like push-buttons, menus, text fields, etc.), as well as provide for the occurrence of various common "events" (like clicking on a button, pressing a key, etc.).

(top)



2. What do I need to know to program for Windows?

Answer: Programming for Windows is somewhat different than regular Dos programming in that Windows Programming is based on the use of "controls", which have "attributes", and, it is "event" oriented. There is also a defined main processing loop.

A "control" is basically any standard visual element available to be included in the program from a pre-existing library of controls, or a non-visual element such as a timer. They include the main & other windows, push buttons, list boxes, timers, etc. You can create them, query and change their Attributes, and respond to Events which happen to them.

An "attribute" is any property a control might have, such as the size or placement of the control, its font size, or font color, etc. Various routines are provided by Win32Lib to let you inspect and alter the attributes of controls.

An "event" is any action that is available to be monitored by Windows (such as clicking on a button, or a timer reaching a preset count, etc.), which is then linked by the programmer to some routine created by the programmer to respond appropriately to that event .

The call to the main processing loop, "WinMain", is placed at the very end of the program, after all the controls have been declared , after all the routines you have written to handle all of the events you want to respond to in your program, and after all the event links.

(top)



3.How do I make a program for Windows?

Answer: To make a program for Windows, you first define what you want it to do; then you:

  1. Write "include win32lib.ew" (without the quotes) at the beginning of your program ;

  2. Establish the look of the program by creating various "controls" (windows, push-buttons, text fields, list boxes, menus, etc) that would be employed by the program user to do various things;

  3. then you create routines (procedures & functions) to respond appropriately to the users use of the controls;

  4. then you create "event links" to make the users use of a control in fact activate the proper procedure or function;

  5. then on the last line in your Windows program you write a statement which creates the main program loop ("WinMain( your_window_name, desired_window_style" ) .

Example:

-- example4.exw
--
-- This opens a window with a single button.
-- Clicking the button closes the window.

include win32lib.ew

-- create a window, and a control (a button) in the window:
constant
TheWindow = create( Window, "Close Window", 0, Default, Default, 200, 100, 0 ),
CloseButton = create( DefPushButton, "Close Window", TheWindow, 40, 10, 120, 30, 0 )

-- routine that accomplishes the desired action:
global procedure CloseButton_onClick( integer self, integer event, sequence params )
closeWindow( TheWindow )
end procedure

-- tell Windows when to do the action:
setHandler( CloseButton, w32HClick, routine_id( "CloseButton_onClick" ) )

-- hand control over to Windows:
WinMain( TheWindow, Normal )

(top)

 

4. How do I make a "control"?

Answer: You make a "control" by using the "create" function. It has the form:

constant your_control_name = create( class, title, parent, x, y, cx, cy, flags)

class is the kind of control you wish to create (Window, PushButton, Menu, etc).
title is the text that will appear in the object's caption.
parent is the name of the control this control belongs to. The parent of the main window is 0.
x and y specify the position of the object, and cx and cy specify the width and height.
flags are optional additional attributes; place a 0 here if you don't know anything else to put.

Example:
The following will create a Window called MyWindow:

      -- create a window 
      constant MyWindow = create( Window,         -- the class 
                              "My Window",        -- the caption      
                              0,                  -- the parent 
                              Default, Default,   -- x and y position 
                              60, 40,             -- width and height 
                              0 )                 -- no special flags 

The following will create a PushButton in MyWindow:

      -- create a pushbutton 
      constant MyButton = create( PushButton,     -- the class 
                                  "Push Me!",     -- the caption      
                                  MyWindow,      -- the parent 
                                  10, 10,         -- x and y position 
                                  60, 40,         -- width and height 
                                  0 )             -- no special flags 

 

5. What is an "event link"?

Answer: An "event link" is a two part statement which establishes a connection between some pre-defined event and the routine which is intended to respond to the event:

  1. the first part is the word setHandler followed by a brace;

  2. the second part is the name of at least one control to which the event applies, followed by a comma;

  3. the third part references some particular kind of event which is innately recognized by the Win32Lib library (such as "w32HClick" the mouse on some control, "w32HKeyPress", etc);

  4. the fourth part references some routine previously created in the program intended to do what you would want to have happen when that event occurred.

Example: An event link might look like this:

setHandler( CloseButton, w32HClick, routine_id( "CloseButton_onClick" ) )

(top)

 

6. How do I create an "event link"?

Answer: To create an "event link",

  1. Determine what kind of event you want to make your program respond to (a click on a button, selection of an item in a list, timer reaching a preset, etc);

  2. then look in the list of events in the Win32Lib manual for the one you want to use (w32HClick, w32HKeyPress, w32HChange, w32HOpen, etc);

  3. write “setHandler(” without the quotes;

  4. followed by the name of the control which might be acted upon ;

  5. write the Win32Lib name for the event ( w32H followed by the name) ;

  6. write "routine_id";

  7. write the name of the routine intended to handle the occurrence of the event, placed inside parenthesis and *quotes*: ("routine_name")

It should look like this in general (note the use of braces and punctuation) :

setHandler( ControlName, w32HEventName, routine_id( "event_handler_routine_name" ) )

NOTE: it helps to make the "event_handler_routine_name" reference in some way to the event and the control, like this:

setHandler( CloseButton, w32HClick, routine_id( "CloseButton_onClick" ) )

top

 

7. Where are the "event links" PLACED in the program?

Answer: The "event links" must go AFTER the routine they point to.

  1. They can be immediately after, so that every event handling routine has its own event trap/link right after it, (which is usually the easiest way to remember to create both of them), or,

  2. they can all be written near the end of the program, just before the WinMain main processing loop. This can be helpful in a large program: after you have written a number of them in your program but before you are finished with the program, if you have consolidated them near the end, you can go down to them quickly, find the one you may be interested in, and then find its related routine by highlighting the routine name & doing a "search" with your editor.

Example 1, routine and event link together:

-- a routine to handle clicking on the "CloseButton":
global procedure CloseButton_onClick( integer self, integer event, sequence params )
closeWindow( TheWindow )
end procedure

-- an event link which tells Windows when to do what action:
setHandler( CloseButton, w32HClick, routine_id( "CloseButton_onClick" ) )

Example 2, all event links grouped together (after the routines they point to):

<begin>
<includes and control creation here>

procedure Window1_onOpen( integer self, integer event, sequence params )
-- do something
end procedure

procedure StartDisplay_onClick( integer self, integer event, sequence params )
-- do something
end procedure

<all other procedures here>

--HANDLERS TO RESPOND TO EVENTS IN THIS PROGRAM:
----------------------------------------------------------
setHandler( Window1, w32HOpen, routine_id( "Window1_onOpen" )
setHandler( StartDisplayBtn, w32HClick, routine_id( "StartDisplay_onClick" ) )
setHandler( StopDisplayBtn, w32HClick, routine_id( "StopDisplay_onClick") )
setHandler( Window1, w32HTimer, routine_id( "Window1_onTimer" ) )
setHandler( btnTestaSound, w32HClick, routine_id( "btnTestaSound_onClick" ) )

-----------------------------------------------------------
-- MAIN PROCESSING LOOP: hand control over to Windows:
WinMain( Window1, Normal )

You will notice that handling routines to which any setHandler statement refers all have a parameter list that reads:

( integer self, integer event, sequence params )

You should regard this list as invariant, to always be present in handling procedures. Sometimes the handling routine will be interested in values in the parameter list, other times (and quite often) it will not.

(top)

8. How do I write into a window?

Answer: There are varying circumstances under which you might like short pieces of text to appear on a Window:

(i) As static text

Some windows have no text on them, while others seem to be covered in text. In the latter case the text is very often what looks like little labels telling the program user what the other controls on the window are and what (s)he should do with them, like “File List” over a list displaying file names, “Type your response here” under an EditText, and so on. Win32Lib has 3 such labelling controls, the Ltext, the CText and the RText. The LText left-justifies the text it displays, the CText centres the text it displays and the RText right-justifies its text. These labels are usually static (i.e., not changed during the program run) and are usually created in the bunch of commands that create all the controls for the program. Creating a label follows the same pattern as does creating a window:

      constant label_1 = create( LText,           -– the class
                                  "Type in here", -- the caption      
                                  MyWindow,       -- the parent 
                                  10, 10,         -- x and y position 
                                  60, 40,         -- width and height 
                                  0 )             -- no special flags 

Here is a typical snip of code creating a window and 2 CText labels:

   --  Window WpWindow
   constant WpWindow = create( Window,"Mini WP",0,Default,Default,468,300,0)
   constant label_1 = create( CText,"File List",WpWindow,12,4,144,20,0)
   constant label_2 = create( CText,"File Text",WpWindow,168,4,276,20, 0)

This sort of thing is easiest created using Judith Wright's EuIDE program and I encourage you to give it a try. If you read the output code of the IDE, you will quickly become familiar with it and be able to write stuff like this manually and (more important) be able to modify existing code manually.

(ii) As dynamic text, during a program run

The easiest way to write short pieces of text to a Window is to use the wPuts() command. This lets you decide where on the Window you want the piece of text to appear. The wPuts() instruction looks like this:

      -- write text on window MainWindow
      -- at pixel position { x, y }:      
      wPuts( { MainWindow, x, y }, “My piece of text” )

For instance, the next snippet of code writes 3 small items of text on a window, one under another:

   -- write 3 bits of text on window MainWindow
   -- at pixel positions { pix_col, pix_row }:      
   sequence snips = {“A silly comment”, “Another comment”, “Last comment”}
   integer pix_col = 10
   integer pix_row = 10
   
   setTextColor( MainWindow, Yellow ) -- let's give it a color   
   for i=1 to length( snips ) do
      wPuts( { MainWindow, pix_col, pix_row }, snips[i] )
      pix_row += 20   --  advance down by 20 pixels
   end for

In a real program you would probably elaborate this code into a procedure that you could call whenever you liked with differing versions of sequence snips. There are more elaborate ways of writing text on a window, but mastering this way will get you far.

I have encountered situations where a wPuts() statement failed in a program, when the program was compiled to C with euc. Using wPrintf() instead of wPuts() solved this abberation.

(top)

9. How do I draw in a window?

Answer: Win32Lib.ew has a number of procedures which let you draw simple geometric shapes on a window or on a (memory) Pixmap. An incomplete list of these is:

drawLine() drawLines() drawEllipse() drawRectangle() drawPolygon()

Of these we will look only at drawEllipse(), drawRectangle and drawPolygon()

(i) drawEllipse(): The syntax for this is:

     drawEllipse ( id,        -- handle of window or control to draw on
                   fill_flag  -- 1 to fill it, 0 not to fill it
                   x1, y1,    -- smaller coordinates for rectangle
                   x2, y2     –- larger coordinates for rectangle
                 )

The rectangle referred to is an “imaginary” one to bound the ellipse that will be drawn. If the rectangle is square the “ellipse” will be a circle.

(ii) drawRectangle(): The syntax for this is:

     drawRectangle ( id,        -- handle of window or control to draw on
                     fill_flag  -- 1 to fill it, 0 not to fill it
                     x1, y1,    -- smaller coordinates for rectangle
                     x2, y2     –- larger coordinates for rectangle
                    )

(iii) drawPolygon(): The syntax for this is:

     drawPolygon ( id,        -- handle of window or control to draw on
                   fill_flag  -- 1 to fill it, 0 not to fill it
                   polyline   -- sequence representing the polygon
                  )

The polyline is a sequence of form { {x1, y1}, {x2, y2}, {x3, y3}, … {xn, yn} } defining the boundary of the polygon. If the polyline is not closed drawPolygon() will automatically close it by drawing a straight line from {x1, y1} to {xn, yn}.

Here is the code of a program that, on each click of a PushButton, draws 1000 shapes of different colours on the MainWindow. The shapes are a 50:50 mixture of rectangles and ellipses whose dimensions and positions are calculated in a random way. Copy it into your editor and run it to see how it looks. There are lots of comments to explain what it is going on :

/* DrawShapes.ew ---------------------------------------
    Draw ellipses and rectangles on a window.
*/ ----------------------------------------------------- 
include Win32Lib.ew

    constant 
    WIN_SIZE = {400,300},
    COLORS = {Pink,Red,Blue,Green,Yellow,BrightRed,BrightBlue,Eggplant},
    N_COLORS = length(COLORS),
    FILL_FLAG = w32True
    
--  Create Window DrawWindow
constant DrawWindow = create( Window, "Draw Shapes", 0, Default, Default,  WIN_SIZE[1],  WIN_SIZE[2], 0 )
constant DrawBtn = create( PushButton, "Draw", DrawWindow, 144, 228, 88, 28, 0 )
---------------------------------------------------------

function CalcCoords()
-- Calculate needed random coords for an ellipse or a rectangle;
-- calculation is based on the window size, WIN_SIZE.
-- Returns {x1, y1, x2, y2}, representing the diagonal of a rectangle.
    integer x1 x1=0   integer y1 y1=0
    integer x2 x2=0   integer y2 y2=0
    
    -- calculate the pair {x1, y1}, based on WIN_SIZE:
    x1 = rand(WIN_SIZE[1])
    y1 = rand(WIN_SIZE[2])
    -- calculate the pair {x2, y2}, as random increments to x1 and y1
    x2 = x1 +5+rand(40)
    y2 = y1 +5+rand(40)
    
    return {x1, y1, x2, y2}
end function -- CalcCoords ---------------------------------------------------

procedure DrawOneShape()
-- Draws a single shape.
    sequence crds  crds = CalcCoords()            -- calculate the coordinate values
    
    setPenColor( DrawWindow, COLORS[rand(N_COLORS)] )    -- set the colour for a shape
    
    if rand(2) = 1 then     -- draw either an ellipse ...
    drawEllipse( DrawWindow, FILL_FLAG, crds[1], crds[2], crds[3], crds[4] )    -- coloured, filled
    setPenColor( DrawWindow, Black )
    drawEllipse( DrawWindow, not FILL_FLAG, crds[1], crds[2], crds[3], crds[4] )-- outlined in black
    else            -- ... or draw a rectangle
    drawRectangle( DrawWindow, FILL_FLAG, crds[1], crds[2], crds[3], crds[4] )  -- coloured, filled
    setPenColor( DrawWindow, Black )    -- outline it in black
    drawRectangle(DrawWindow, not FILL_FLAG, crds[1], crds[2], crds[3], crds[4])-- outlined in black
    end if
    
end procedure -- DrawOneShape --------------------------------------------------

procedure DrawBtn_onClick (integer self, integer event, sequence params)
-- User has clicked button: draw 1000 shapes.
    
    setWindowBackColor( DrawWindow, Gray )  -- clear, colour the window
    for i=1 to 1000 do
    DrawOneShape()
    end for
    
end procedure
setHandler( DrawBtn, w32HClick, routine_id("DrawBtn_onClick" ) ) ----------------

WinMain( DrawWindow,Normal )

(top)

10. How can I write data to a file, and then retrieve it to write into a window?

Answer: This is the sort of thing you would want to do if you were writing a program to act like a simple editor or a word processor, though other sorts of programs might well want such an ability too. If your intended program does not know the names of the files involved in advance, you will need to write code that asks the user of the program for the names when needed. Win32Lib has commands designed specifically to ask a user for file names. Having got a file name, the next thing to consider is code to do the actual loading of data from disk or saving of data to disk. These two activities are not jobs for Win32Lib as such, but for some “pure” Euphoria file handling code, which will depend on the nature of the data (e,g., Is the data text? Or is it numbers and if so how organised? ).

To simplify things, let's assume that we are dealing with text files. To display extended text properly Win32Lib provides two sorts of control, the MleText and the RichEdit. An MleText is the simpler of these two so we will use that. An MleText is not an impoverished version of a RichEdit; it has some useful editing features built into it. It is well to be aware of some other of its features:

1. It is designed to deal with continuous text, not with discrete “lines” of text as an old-fashioned DOS screen does. It performs automatic word-wrap on text placed in it and the text can be broken into paragraphs with '\n' (newline) characters embedded it. So when your program loads a long document into an MleText, or fetches one from an MleText, what it is dealing with is really one enormously long single string of text with (possibly) multiple newline characters in it.

Let's have a MainWindow to contain as child controls an MleText, a “Load File” button to trigger reading of a file from disk and a “Save File” button to trigger writing of a file to disk.

Here is a pseudo-code draft of a procedure to read a text file from disk:

procedure LoadFile()

  spec = Get name of file from user (Win32Lib function)
  if spec is OK then
     text = read text file (euphoria activity)
     if text is OK then
        load text to the MleEdit
end procedure

A similar draft for a procedure to save text got from an MleEdit would be:

procedure SaveFile()

  if the text in the MleEdit needs saving then
     spec = Get name of file from user (Win32Lib function)
     if spec is OK then
        text = read text file (euphoria activity)
           if text is OK then
              save text to file spec
end procedure

There are 2 Win32Lib functions available for getting a file spec from the user, getOpenFileName() to get a spec that will be used to load a file from disk and getSaveFileName() to get a spec that will be used to save a file to disk. The syntax for these 2 functions is nearly identical, so it is now given for the getOpenFileName function :

     -- getting user's designation of a spec to open a file:
     integer spec
     spec = getOpenFileName( window_id,              -- id of the owning window
                             “*.txt”,                -- default file name  
                             { “Text Files”, “” }    -- filter
                           )

…..

There is a program called MiniWp.exw with this package which implements these ideas and several others; run it and – more importantly – also read its code. All its major activities have been written into functions and routines to make it easy to understand and modify.

(top)

11. How can I use special keys like up/down arrows in windows?

Answer: Whenever you type a keyboard key, it generates one or more events that Win32Lib recognises, such as w32HKeyPress, w32HKeyDown and w32HKeyPress to name just three. You will need to write a simple event handler to trap, say, the pressing of a down-arrow key when using a control called MyMle, you could write this:

      -- handler to manage KeyDown on MyMle
      procedure MyMle_onKeyDown( integer self, integer event, sequence params )
           integer key = params[1] -- id of the key that was pressed.

           if key = WM_KEYDOWN then
               – do something, like scroll down by one page
               MyScrollDown()
           end if
      end procedure
      setHandler( MyMle, w32HKeyDown, routine_id( “MyMle_onKeyDown”  ) )
      -------------------------------------------------------  

Notice that the params sequence contains the identity of the key concerned. WM_KEYDOWN is one of several WM_ global constants that help you recognise what that key is (see constants.htm for all of them).

In the case that multiple keys may need processing Euphoria-4's switch structure helps you write such a handler in a very neat way:

      -- handler to manage KeyUp and KeyDown on MyMle
      procedure MyMle_onKeyDown( integer self, integer event, sequence params )
           integer key = params[1] -- id of the key that was pressed.

           switch key do
               case WM_KEYDOWN then
                   MyScrollDown() -- do something 
               case WM_KEYUP then
                   MyScrollUp()   -- do something else
           end switch
      end procedure
      setHandler( MyMle, w32HKeyDown, routine_id( “MyMle_onKeyDown”  ) )
      -------------------------------------------------------  



(top)



11. How do I create and use a TIMER?

Answer: Timers are used for all sorts of things in general programming. Some examples are doing such things as controlling how long a splash screen should be displayed, how long the program should wait for the user to respond to a question, how long to display each picture in an animation. There are only 2 instructions that relate to timers. These are:

    setTimer( window_id, timer_id, time_in_millisecs ) --  starts timer timer_id running

and

    killTimer( window_id, timer_id )                   -- gets rid of timer timer_id

window_id is the handle of an actual window, not of some minor control. timer_id is an integer number. time_in_millisecs is just that (1000 millisecs = 1 second).

Suppose we have a program with a main window called MainWindow and another window called SplashWiindow and we want the program to display the SplashWindow for 4 seconds when the program starts. Here is some typical code you might write to achieve this outcome. First we need to set the timer and we will do it from the MainWindow_onOpen handler.

procedure MainWindow_onOpen( integer self, integer event, sequence params )
    openWindow( SplashWindow, Modal )      -- display it
    setTimer( MainWindow, 1, 4000 )        -- set timer #1
end procedure
setHandler( MainWindow, w32HOpen, routine_id( "MainWindow_onOpen"  ) )
------------------------

From the moment this is executed, Timer 1 will fire off at 4-second intervals and every time it does a Timer Event will be generated. We need another handler to catch this:

procedure MainWindow_onTimer( integer self, integer event, sequence params )
    killTimer( MainWindow, 1 )   -- stop timer #1
    closeWindow( SplashWindow )  -- vanish the splash
end procedure
setHandler( MainWindow, w32HTimer, routine_id( "MainWindow_onTimer" ) )

A program implementing this is present as demo SimpleTimer.exw. Note that SimpleTimer.exw IS very simple and that programming issues will arise if you want to display a picture on the SplashWindow. In this case the code in MainWindow_onOpen() might better be transferred to a MainWindow_onPaint() handler and extra code to load the picture and place it on the SplashWindow be called from there. (When a windows program first displays itself, a Paint Event is automatically generated).

(top)