Frequently Asked Questions about Win32Lib
2. What do I need to know to program for Windows?
3. How do I make a program for Windows?
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?
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?
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.).
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.
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:
Write "include win32lib.ew" (without the quotes) at the beginning of your program ;
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;
then you create routines (procedures & functions) to respond appropriately to the users use of the controls;
then you create "event links" to make the users use of a control in fact activate the proper procedure or function;
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 )
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
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:
the first part is the word setHandler followed by a brace;
the second part is the name of at least one control to which the event applies, followed by a comma;
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);
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" ) )
6. How do I create an "event link"?
Answer: To create an "event link",
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);
then look in the list of events in the Win32Lib manual for the one you want to use (w32HClick, w32HKeyPress, w32HChange, w32HOpen, etc);
write “setHandler(” without the quotes;
followed by the name of the control which might be acted upon ;
write the Win32Lib name for the event ( w32H followed by the name) ;
write "routine_id";
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" ) )
7. Where are the "event links" PLACED in the program?
Answer: The "event links" must go AFTER the routine they point to.
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,
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.
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.
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 )
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.
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” ) ) -------------------------------------------------------
…
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).