So you want to create a program with a graphical user interface? Using Euphoria, it used to be that you were restricted to the Microsoft Windows platform, and even then you had only two options: the Windows API and Win32Lib.* Nowadays, we've got a variety of graphical user interface libraries for Windows and Linux/FreeBSD (or both). Things are looking good for Euphoria GUI programming!
This book will serve as an introduction to GUI programming in Euphoria. We will explore a few of the currently available Euphoria GUI libraries** and give the good and bad points of each. Ultimately, it will be up to you to decide which package of code suits your purposes best.
If you'd like to print out this entire document, return to the Table of Contents and click the "Print Book" link at the bottom of the page. It will create a version of this entire document that you can print from your web browser.
If you have any comments or questions regarding anything you read here, or you want to contribute to this document, please send them to me. This book is just a start and it is ready for your input! I expect it will be dynamic, never really finished, as every day these Euphoria GUI packages are improved to make creating Euphoria GUI programs that much easier.
Also, check the Euphoria Code Archive for lots of code for GUI programming on a variety of platforms.
* If you want to get technical, there are GUI libraries for MS-DOS. These libraries allow you to add a graphical interface to your MS-DOS programs. I might add these to the discussion in the future.
** By "currently available," I mean that there is usable code available in the Euphoria program archives.
The Euphoria programming language lets you create programs for Windows, Linux, and FreeBSD. Each of these operating systems can provide output via a graphical user interface (GUI). Generally, a GUI program written for Windows will not run in Linux. Likewise, a program written for FreeBSD will not run in Windows. Generally.
There are platform-specific GUI libraries and there are cross-platform GUI libraries.
If you want your program to work across multiple operating systems (or platforms), you will need to use "cross-platform" code. This is code that will run unmodified on multiple platforms. They usually require the installation of additional code libraries/files. Currently, there are two cross-platform GUI libraries available for Euphoria programmers:
If you want to code solely for the Windows platform, you can use one of several Euphoria GUI libraries:
For the sake of length and simplicity, this book will focus on the following libraries:
If you have not installed one of the above libraries, choose one now and click on the link for it above. You will be able to download and install the library from there.
Which one should you choose? For experienced programmers, I don't think you can go wrong with any of them. The only significant considerations would be cross-platform compatibility (wxEuphoria) and the availability of an IDE (Win32Lib). For beginners, Win32Lib is probably the quickest to set up. wxEuphoria requires the installation of a "shared code" library (*.dll in Windows, *.so in Linux/FreeBSD); however, it is easy to install and there's plenty of help if you get stuck. For beginners, it doesn't matter. We're just getting our feet wet and any experience with any of these libraries will help later when and if you decide to switch.
At its most simple level, a GUI application features a graphical interface consisting of a floating "window." As soon as you start adding controls, you've moved into the realm of advanced GUIs. So, technically, any GUI with at least one button is an advanced GUI application. We'll get there shortly. First, let's see how each of our featured libraries puts a window on the screen.
First off, we want to create a window and display it. Here's the code to do that for each featured library.
|
wxEuphoria |
include wxEuphoria.e |
|
Win32Lib |
include win32lib.ew |
On the next page, we will compare the actual look and feel of the windows created by these libraries.
Our libraries create windows pretty much the same way. A call to a window creation function with a few parameters, and, presto, we have a window. When used on the Microsoft Windows OS, they all create similar looking windows because they all allow Windows to do the drawing. That is, they don't use any custom drawing routines. They use the Windows API for all window and control on-screen rendering. Here's how each library's window looks on the Windows platform.
The only difference in these windows is the icon in the title bar. The wxEuphoria icon is probably the wxWidgets application icon. Win32Lib displays the Euphoria program icon.
On the Linux/FreeBSD platform, wxEuphoria renders windows and widgets according to the user's X-windows library. The exciting thing is, the window is drawn with the exact same code as the Windows version!

In Linux/FreeBSD, the user has complete control over the look and feel of the windowing system. One system might look different than another. The good thing is, your wxEuphoria app will work the same in all of them.
As you can see, it's easy to create windows with these Euphoria GUI libraries. In its simplest form, you call the window creation function and provide a few parameters, such as name, size, position, etc.
An empty window isn't much to look at. It doesn't do a lot, either. Any application is going to need a few widgets (or "controls") to allow the user to do something. Let's create a simple application that lets us type our name in a textbox, then click a button to scramble the name and display it in a pop-up dialog box. Here's basically what we want:
So, for this simple application, we're going to allow the user to enter his name, then have him click the "Scramble" button to scramble the letters in his name and display the result in a pop-up window.
We've taken the first step in creating our GUI program and defined the look and behavior of our name-scrambling application. Let's start writing some code!
On the following pages, we'll explore how each of our featured libraries create GUIs and how they are programmed. I'll show you the code for each library first and explain some of their nuances. Then I'll explain the primary differences as well as the significant advantages and disadvantages of each.
Our sample window as it looks using wxEuphoria. The screenshot on the left was taken from Windows; on the right is a screenshot of the same program running on RedHat Linux 8.0 with the Gnome desktop:
The sample code below came straight from Matthew Lewis, the creator and maintainer of wxEuphoria. He has liberally commented the code, so it should be easy to grasp. I'll explore his code in more detail on the following page. For now, see if you can follow along with it.
REMEMBER: The following code works on both Windows and Linux. Awesome!
without warning
-- include the files needed:
include wxEuphoria.e -- main include file for the library (also wxFrame, wxPanel)
include wxButton.e -- wxButton class
include wxText.e -- wxStaticText and wxTextCtrl classes
include wxSizer.e -- wxBoxSizer class
-- Create the controls needed:
constant
main = create( wxFrame, {0, -1, "Scramble Me", -1, -1, 250, 100}),
win = create( wxPanel, main ),
label = create( wxStaticText, {win, -1, "Enter your name:"}),
name = create( wxTextCtrl, {win, -1, "", -1, -1} ),
ScrambleButton = create( wxButton, {win, -1,"Scramble Me"}),
QuitButton = create( wxButton, {win, -1, "Quit"})
procedure setup()
atom vsizer, hsizer
-- Use sizers to dynamically resize and position controls.
-- First, create a vertical sizer, and put the label and the edit
-- field into the vertical sizer:
vsizer = create( wxBoxSizer, wxVERTICAL )
-- The label will grow horizontally (but not vertically) and will have
-- a 5 pixel space on its left and top:
add_window_to_sizer( vsizer, label, 0, wxGROW + wxTOP + wxLEFT, 5 )
-- The edit field will grow both vertically and horizontally, and has
-- borders on the top, left and right of 5 pixels:
add_window_to_sizer( vsizer, name, 1, wxGROW + wxTOP + wxLEFT + wxRIGHT, 5 )
-- The buttons will be positioned next to each other, so
-- use a horizontal sizer for them:
hsizer = create( wxBoxSizer, wxHORIZONTAL )
-- The buttons will grow horizontally only, and will have 5 pixel spaces
-- on each side.
add_window_to_sizer( hsizer, ScrambleButton, 1, wxLEFT, 5 )
add_window_to_sizer( hsizer, QuitButton, 1, wxLEFT + wxRIGHT, 5 )
-- Then we put the horizontal sizer inside of the vertical sizer, leaving
-- a 5 pixel space on the top an bottom (which will apply to all controls
-- in the spacer):
add_sizer_to_sizer( vsizer, hsizer, 0, wxGROW + wxTOP + wxBOTTOM, 5 )
-- Then we assign the vertical sizer to the panel, and the controls will
-- automatically resize and reposition themselves:
set_sizer( win, vsizer )
end procedure
setup()
-- hand control to Windows
wxMain( main )
Our sample window as it looks using wxEuphoria:
The sample code below came straight from Matthew Lewis, the creator and maintainer of wxEuphoria. I've put additional comments in between to help you go with the flow of the program. I'm going to skip the includes. That should be self-explanatory at this point.
The first part of the program is simply defining the widgets. Since wxEuphoria can manage the size and position of controls for you, there are no hard-coded values for those parameters. We use the value -1 for all width, height, x-coord, and y-coord values, so wxEuphoria knows to manage those for us.
constant
main = create( wxFrame, {0, -1, "Scramble Me", -1, -1, 250, 100}),
win = create( wxPanel, main ),
label = create( wxStaticText, {win, -1, "Enter your name:"}),
name = create( wxTextCtrl, {win, -1, "", -1, -1} ),
enter = create( wxButton, {win, -1,"Scramble Me"}),
quit = create( wxButton, {win, -1, "Quit"})
When I said wxEuphoria would manage position and size for us, I didn't mean that we didn't have some say in the matter. In fact, here's what you get if you run the code above without running the setup() procedure:
What we're going to do is specify relative positions. Let's look at the setup() procedure (I've removed the comments to make it more compact).
Our first call is to create a virtual box within which we place controls. The controls we place in this virtual box will be oriented vertically (the wxVERTICAL parameter).
vsizer = create( wxBoxSizer, wxVERTICAL )
Now, into the vsizer virtual box, we're placing the label widget we created up top. We've specified that the label widget can grow horizontally, but not vertically and will have a 5-pixel space on its top and left.
add_window_to_sizer( vsizer, label, 0, wxGROW + wxTOP + wxLEFT, 5 )
Next we add the 'name' textbox to the vsizer virtual box. We've specified that the label widget can grow horizontally and vertically and will have a 5-pixel space on its top, left, and right borders.
add_window_to_sizer( vsizer, name, 1, wxGROW + wxTOP + wxLEFT + wxRIGHT, 5 )
For the buttons, we'll create another wxBoxSizer widget, but this one will orient its controls horizontally.
hsizer = create( wxBoxSizer, wxHORIZONTAL ) add_window_to_sizer( hsizer, ScrambleButton, 1, wxLEFT, 5 ) add_window_to_sizer( hsizer, QuitButton, 1, wxLEFT + wxRIGHT, 5 )
Notice that we put the label and textbox above inside the vsizer widget. Now we're going to put the hsizer widget inside there as well. It's a wxBoxSizer widget embedded in another wxBoxSizer. This is perfectly legal, valid, and useful.
add_sizer_to_sizer( vsizer, hsizer, 0, wxGROW + wxTOP + wxBOTTOM, 5 )
Now that we've built our vsizer widget, we place it on our window ('win').
set_sizer( win, vsizer )
The controls will all be automatically resized/positioned whenever the window changes size or position. For an example, here's a screenshot of an expanded version of the window. I just dragged the bottom-right corner out a bit.
This may seem insignificant, but there was a time when GUI libraries required you to manage the size and position of the widgets yourself. For newbies, it could be quite a hassle getting this working perfectly.
Our sample window as it looks using Win32Lib:
Derek Parnell, the maintainer of Win32Lib, supplied the following Win32Lib code for our sample program:
include win32lib.ew
without warning
global function main(sequence pArgs)
createForm( {
-- Initial 'Scramble Me' form
"Window, name=scramWin, caption=Scramble Me"
,
"Label, caption=Enter your name:, at=(8,8)"
,
"EditText, name=editName,"
& "at=(**, *+0)," -- left=same as previous, top=previous bottom
& "width=224"
,
"Button, Scramble Me,"
& "at=(**, *+4)," -- left=same as previous, top=previous bottom + 4
& "width=88"
,
"Button, Quit,"
& "at=(editName-88, **)," -- left=previous right - 88, top=previous top
& "width=88,"
} )
return 0
end function
include w32start.ew
For Win32Lib, I prefer the method above because it's very versatile. Win32Lib can read form definitions from an external text file. The other GUI libraries could have this functionality, but you'd have to build a parser. With Win32Lib, it's built-in.
Win32Lib also allows this "old school" method of coding (code provided by Brian Broker):
without warning
include Win32Lib.ew
constant
scramWin = create(Window,"Scramble Me",0,Default,Default,252,128,0),
lblEnter = create(LText,"Enter your name:",scramWin,8,8,92,20,0),
editName = create(EditText,"",scramWin,8,32,224,24,0),
btnScram = create(PushButton,"Scramble Me",scramWin,8,64,88,28,0),
btnQuit = create(PushButton,"Quit",scramWin,144,64,88,28,w32AUTOCLOSE)
WinMain(scramWin,Normal)
We've built our application's interface. We started with a simple window and added a textbox and two buttons. And though we can type in the textbox and click the buttons, the application doesn't do anything. We have to tell it how to respond to those "user events," or just "events."
So, first off, let's add the code that will run when the user clicks the "Quit" button.
Generally, you will create a procedure for each "event" the user can perform. In this simple name-scramble application, we're going to be concerned with two events:
So, we need to create two procedures and "attach" them to the controls or events that will call them.
wxEuphoria's Quit Procedure
Here's the code we need to add to our wxEuphoria scramble application. You will place this right after the setup() procedure.
procedure Click_QuitButton(atom this, atom event_type, atom id, atom event )
exit_main()
end procedure
set_event_handler(QuitButton, get_id(QuitButton), wxEVT_COMMAND_BUTTON_CLICKED, routine_id( "Click_QuitButton" ))
It's the set_event_handler() procedure that tells wxEuphoria what procedure to call when the user clicks the "Quit" button.
Win32Lib's Quit Procedure
Win32Lib has a built-in quit procedure we can call from any widget. Modify the 'Quit' button's definition string to the following:
"Button, Quit,"
& "at=(editName-88, **)," -- left=previous right - 88, top=previous top
& "width=88,"
& "flag=autoclose" -- This button will close the window.
Next, we'll add code for the "Scramble Me" button click event.
All we need now is code to scramble the name that the user enters and display that in a dialog box.
Our scramble() function looks like this:
function scramble(sequence s) -- it's a generic function to scramble a string sequence
sequence result
integer i
result = ""
while length(s) > 0 do
i = rand(length(s))
result &= s[i]
s = s[1..i-1] & s[i+1..length(s)]
end while
return result
end function
wxEuphoria Scramble Event
For wxEuphoria, place the scramble function right above the Click_QuitButton procedure. Then, add this procedure after the Click_QuitButton procedure:
procedure Click_ScrambleButton(atom this, atom event_type, atom id, atom event )
if message_box ( scramble(get_text_value(name)) , get_text_value(name) & " Scrambled", wxOK ) then end if
end procedure
set_event_handler(ScrambleButton, get_id(ScrambleButton), wxEVT_COMMAND_BUTTON_CLICKED, routine_id("Click_ScrambleButton"))
Run the program and you'll have a fully-functioning Euphoria GUI program!
Win32Lib Scramble Event
For Win32Lib, add the function after the form definition call, then add the following after that and before the 'include w32start.e' line:
global procedure Click_ScrambleMe(integer self, integer event, sequence parms)
VOID = message_box( scramble( getText(getNameId("editName")) ), getText(getNameId("editName")) & " Scrambled", MB_OK )
end procedure
registerRoutine("Click_ScrambleMe", routine_id("Click_ScrambleMe"))
Run the program and you'll have a fully-functioning Euphoria GUI program!
On the next few pages, you'll see the complete program for each of the featured GUI libraries. After that, I'll give you some suggestions for choosing the Euphoria GUI library that's right for your application.
without warning
include wxEuphoria.e -- main include file for the library (also wxFrame, wxPanel)
include wxButton.e -- wxButton class
include wxText.e -- wxStaticText and wxTextCtrl classes
include wxSizer.e -- wxBoxSizer class
constant
main = create( wxFrame, {0, -1, "Scramble Me", -1, -1, 250, 100}),
win = create( wxPanel, main ),
label = create( wxStaticText, {win, -1, "Enter your name:"}),
name = create( wxTextCtrl, {win, -1, "", -1, -1} ),
ScrambleButton = create( wxButton, {win, -1,"Scramble Me"}),
QuitButton = create( wxButton, {win, -1, "Quit"})
procedure setup()
atom vsizer, hsizer
vsizer = create( wxBoxSizer, wxVERTICAL )
add_window_to_sizer( vsizer, label, 0, wxGROW + wxTOP + wxLEFT, 5 )
add_window_to_sizer( vsizer, name, 1, wxGROW + wxTOP + wxLEFT + wxRIGHT, 5 )
hsizer = create( wxBoxSizer, wxHORIZONTAL )
add_window_to_sizer( hsizer, ScrambleButton, 1, wxLEFT, 5 )
add_window_to_sizer( hsizer, QuitButton, 1, wxLEFT + wxRIGHT, 5 )
add_sizer_to_sizer( vsizer, hsizer, 0, wxGROW + wxTOP + wxBOTTOM, 5 )
set_sizer( win, vsizer )
end procedure
function scramble(sequence s)
sequence result
integer i
result = ""
while length(s) > 0 do
i = rand(length(s))
result &= s[i]
s = s[1..i-1] & s[i+1..length(s)]
end while
return result
end function
procedure Click_QuitButton(atom this, atom event_type, atom id, atom event )
exit_main()
end procedure
set_event_handler(QuitButton, get_id(QuitButton), wxEVT_COMMAND_BUTTON_CLICKED, routine_id( "Click_QuitButton" ))
procedure Click_ScrambleButton(atom this, atom event_type, atom id, atom event )
if message_box ( scramble(get_text_value(name)) , get_text_value(name) & " Scrambled", wxOK ) then end if
end procedure
set_event_handler(ScrambleButton, get_id(ScrambleButton), wxEVT_COMMAND_BUTTON_CLICKED, routine_id( "Click_ScrambleButton" ))
setup()
wxMain( main )
include win32lib.ew
without warning
global function main(sequence pArgs)
createForm( {
-- Initial 'Scramble Me' form
"Window, name=scramWin, caption=Scramble Me"
,
"Label, caption=Enter your name:, at=(8,8)"
,
"EditText, name=editName,"
& "at=(**, *+0)," -- left=same as previous, top=previous bottom
& "width=224"
,
"Button, Scramble Me,"
& "at=(**, *+4)," -- left=same as previous, top=previous bottom + 4
& "width=88"
,
"Button, Quit,"
& "at=(editName-88, **)," -- left=previous right - 88, top=previous top
& "width=88,"
& "flag=autoclose" -- This button will close the window.
} )
return 0
end function
function scramble(sequence s) -- it's a generic function to scramble a string sequence
sequence result
integer i
result = ""
while length(s) > 0 do
i = rand(length(s))
result &= s[i]
s = s[1..i-1] & s[i+1..length(s)]
end while
return result
end function
global procedure Click_ScrambleMe(integer self, integer event, sequence parms)
VOID = message_box( scramble( getText(getNameId("editName")) ), getText(getNameId("editName")) & " Scrambled", MB_OK )
end procedure
registerRoutine("Click_ScrambleMe", routine_id("Click_ScrambleMe"))
include w32start.ew
You've seen that each Euphoria GUI library makes it very easy to code simple GUI apps. Each application looks almost exactly the same. So, how do you choose which library to use? Here are some suggestions:
That's the end of the Simple GUI Apps section of this booklet. The next section will include a section on how to develop a GUI application, from the ground up, and will consider more advanced topics, such as 2D and 3D graphics, database connectivity, and internet (sockets) functionality.
If this section has been helpful, please let me know. If you have anything you'd like added, removed, or changed, let me know that as well.