How to use GUI Package in Visual Prolog
A sample Graphical User Interface (GUI) application can be created by Integrated Development Environment (IDE) as a default project. In this tutorial, we will explain how to develop such application further. We will learn how to create and edit GUI components of GUI style programs directly within the Visual Prolog IDE (Visual Development Environment). We will learn principles of handling GUI package events (like clicking buttons, activating menu items, etc.), and how these are implemented within GUI style Visual Prolog programs. We will learn how to program dialogs, etc.
The GUI package presents object-oriented windows, dialogs, and controls handling. This package is built on top of the VPI package and delivers a new level of abstraction and ease of use. When using the GUI package, you can also use the VPI package.
Introduction to the GUI Package
If you have read our previous GUI programming tutorials "Fundamental Visual Prolog - Conventional GUI" and "Fundamental Visual Prolog - the Business Logical Layer", then you already knew that Visual Prolog PFC packages contain the VPI package, which can be used to program Graphical User Interface applications. But VPI package classes do not produce GUI objects. Therefore VPI does not supply the power of state handling via interface predicates.
The GUI package provides an object oriented style for working with windows, dialogs, controls, events, and other GUI features. The GUI package provides the following window system components, which supports programming of your application presentation layer (GUI of your application):
- Basic window components: windows, dialogs, controls (check buttons, edit controls, icon controls, list boxes, list buttons, list edit controls, push buttons, radio buttons, horizontal and vertical scroll controls, static text controls, custom controls, and some more complex controls like the editor, tree view and list view controls, etc. ).
- Containers - objects to which you can add controls (these are dialogs, container controls, form windows, etc.).
- Layout management system that supports sizing, positioning, and moving of GUI objects.
- The GUI package event handling system. It notices when the user interacts with one of GUI components and pass this information to the application.
- Graphic operations: draw arcs, fill polygons, clip a rectangle, etc.
Creating a New GUI Style Project
Now let us start creating a GUI style project from the very beginning.
First of all, you need to run the IDE. At this point we expect that you had already read the Environment Overview tutorial and know how to do this.
Then you should initiate creation of a new project selecting the Project | New menu command. The Project Settings dialog appears. In the Project Name edit control you should type-in the project name, in this example we use guiDemo. Keep the settings (UI Strategy, Target Type, Linker Name) in their default state. You can also select the Base Directory, which will serve as the default root directory to all your new projects. The default Sub-Directory name will be generated automatically, as you will type-in the Project Name (of course, you can manually modify this name). So we have:
- Project Name = guiDemo
- UI Strategy = Object-oriented GUI
- Target Type = EXE
Click Create to create the default project. After this the IDE will generate the initial set of project files required to a GUI style project.
Execute the Created Default Project
As you can expect the default project creates a trivial but working application, to check this let us run the generated default application. You can run it directly from the IDE using the Build | Execute command or simply press the Ctrl+F5 key combination.
How to Study the Generated Code
All components of your application are registered in the Project window. Here you can see the initial set of project files generated by the IDE to a default GUI style project in the IDE Project window (remember that previously you need to build the project using, for example, the Build | Build command or simply press the Ctrl+Shift+B key combination). You will see in the Project window the following tree of the project files:
You see that the root directory of your project contains the following files:
- main.pack this is the main package of our application.
- main.ph this is the header file of the application main package.
- main.cl this class declares the application main predicate run.
- main.pro this file implements the application main predicate run and declares the standard application goal.
- resourceidentifiers.i this file is automatically updated by the IDE after any changes of project resource identifiers. It contains definitions of symbolic constants specified for GUI components in the IDE resource editors.
- guiDemo.manifest this is the manifest file of the application. It contains some settings of the application in XML format.
Notice that you should not make any editing in it since any your changes will be overwritten while automatic update.
The $(ProDir)\PFC subdirectory contains that Prolog Foundation Classes (PFC) packages, which are used by the default GUI style applications. Each package is in a separate subdirectory. For example, the gui subdirectory contains GUI package source files and you can see implementation details of GUI package itself here. Source files of these packages will be compiled and the obtained OBJect files will be linked into the target application.
In the first step we will modify Task Window, therefore let us see which files are generated in the taskWindow package. Simply click on the '+' box before the taskWindow subdirectory and then click on the '+' box before the appeared Toolbar subdirectory. You will see the following files:
At this picture you see that the IDE generates files containing the following GUI components:
- the main Task window of the application (stored in the .\TaskWindow\TaskWindow.win file);
- the main application menu (stored in the .\TaskWindow\TaskWindow.mnu file);
- one top toolbar (stored in the .\TaskWindow\Toolbars\ProjectToolbar.tb file);
- one bottom status bar or status line (stored in the .\TaskWindow\Toolbars\StatusLine.tb file);
- the About dialog (in the .\TaskWindow\AboutDialog.dlg file).
These are text format files store resources describing GUI components generated for the project. Text descriptions stored in these files hold full information about correspondent GUI components, including resource attributes, resource layout, and settings for Code Experts. The resource files for GUI components are stored in files with .win, .frm, .ctl, .mnu, .dlg, .tb, .bmp, .ico, and .cur filename extensions.
Let us investigate contents of the TaskWindow.i file. You see that except for other code it contains the following line:
interface taskWindow supports applicationWindow
This means that the taskWindow interface supports the applicationWindow interface declared in the GUI package. Select applicationWindow and press the F1 key, the IDE will activate the Visual Prolog help and open the topic describing the applicationWindow interface. In this help you can read that the applicationWindow::new/0 predicate creates an applicationWindow type object correspondent to the Task windows of an application. Notice that the only one applicationWindow type object can be created during an application execution.
Now open the TaskWindow.pro file. You see the following clauses for the new/0:
clauses new():- applicationWindow::new(), generatedInitialize().
predicates generatedInitialize : (). clauses generatedInitialize():- setText("guiDemo"), setDecoration(titlebar([closebutton(),maximizebutton(),minimizebutton()])), setBorder(sizeBorder()), setState([wsf_ClipSiblings]), setMdiProperty(mdiProperty), menuSet(resMenu(resourceIdentifiers::id_TaskMenu)), addShowListener(generatedOnShow), addShowListener(onShow), addSizeListener(onSizeChanged), addDestroyListener(onDestroy), addMenuItemListener(resourceIdentifiers::id_help_about, onHelpAbout), addMenuItemListener(resourceIdentifiers::id_file_exit, onFileExit). ... % end of automatic code
You see that the clauses of the new/0 constructor are splitted onto two parts. The clause of the new/0 constructor itself and the generatedInitialize/0 predicate, which is declared privately in the taskWindow class implementation. You can ask - "What for the extra the generatedInitialize/0 predicate is declared?" The answer to this question is in the lines:
% This code is maintained. Do not update it manually ... end of automatic code
The IDE need them to be able to automatically change parameters, which corresponds to the settings in Code Experts.
How to Modify the Default Task Window
Before we start to add any new user defined GUI components to this default project, let us look how we can modify its default task window parameters. In the project file tree click the right mouse button on the TaskWindow.win file. In the appeared popup menu select the Attribute item. The Window Attributes dialog appears:
In this dialog you see attributes of the task window. The Title field specifies the application title (name) guiDemo, which is displayed at run time in the application title bar. Let us modify it to GUI Demo Title.
The Style Flags group of check boxes contains the style flags, which will control the look of the window. Let us set Maximized to ON. If you run the application now, then you will see that it is maximized initially and has got the title GUI Demo Title.
How to Add New GUI Dialog
Let us create a new GUI dialog in TaskWindow package. You can of course use any package for this purpose. To create the dialog it is necessary to put focus on the necessary package in Project window and choose menu command File | New in Existing Package... . You will see the dialog, where it is necessary to select Dialog type and write a name. We have chosen the name firstDialog:
After pressing Create button you will be prompted to set attributes for the new dialog. You can keep default initial attributes at creation time and change the necessary attributes later.
The new dialog should be invoked on some event, therefore we modify TaskMenu menu by changing File | New text and making it enabled:
Now we should put focus on the TaskWindow\TaskWindow.win window in Project window and activate Code Experts:
After pressing Add button the IDE will generate a default code for onFileNewDialog event. Let us modify it by invocation of firstDialog:
predicates onFileNew : window::menuItemListener. clauses onFileNew(_Source, _MenuTag):- FirstGuiDialog = firstDialog::new(This), FirstGuiDialog:show().
You can run the application now and see that the firstDialog can be invoked.
How to Manipulate Controls in GUI Dialog or Form
Let us create two edit controls Edit and EditCopy in firstDialog and update the contents of EditCopy on all changes in the contents of Edit.
We should also add event handling for onModify event of Edit control. To do this we put focus on the TaskWindow\firstDialog.dlg dialog in Project window and choose Edit:
Then we can add the code to implement our intention:
predicates onEditModified : editControl::modifiedListener. clauses onEditModified(_Source) :- editCopy_ctl:setText(edit_ctl:getText()).
Let us add a more complicated control now. Let us choose treeViewControl. IDE can insert automatically the necessary declarations, therefore we add pfc\gui\treeViewControl\treeViewControl.pack package and then build our project.
In dialog editor we choose Controls | Custom command and select treeViewControl in the list.
You can run the project now and see that the tree is empty. Let us modify the implementation of the constructor new in the TaskWindow\firstDialog.pro file. Here, we can add more code to initialize the tree view control:
constants myItemId = 10. myItemIdChild = 11. clauses new(Parent) :- dialog::new(Parent), generatedInitialize(), treeViewControl_ctl:insertItem(myItemId, treeViewControl::wcc_null, treeViewControl::sorted(), "Root", , resId(resourceIdentifiers::idb_HelpBitmap), resId(resourceIdentifiers::idb_HelpBitmap)), treeViewControl_ctl:insertItem(myItemIdChild, myItemId, treeViewControl::sorted(), "Child", , resId(resourceIdentifiers::idb_HelpBitmap), resId(resourceIdentifiers::idb_HelpBitmap)).
Now the program can show a simple tree.