| ||||||||||||||
| ||||||||||||||
|
||||||||||||||
|
This tutorial will introduce you to the basics of Windows programming using Win-Prolog 4100. We will simply step through the first program I created in Win-Prolog when I reviewed it - a simple GUI-based family relationship program. This tutorial assumes you have at least a decent understanding of Prolog and of Windows programming fundamentals (message handlers, control types). If not, the Prolog Tutorials should help you with the former and CodeProject should help with the latter!
The ResultSo you can get a feel for the end-result, here is a screenshot:
The CodeSo, jumping straight into the code...ft :- create_familyTree, fill_list(4000), fill_list(4001), fill_isa, wlbxsel((familyTree,5000),0,1), window_handler( familyTree, ft_handler ), call_dialog( familyTree, _ ). create_familyTree :- _S1 = [dlg_ownedbyprolog,ws_sysmenu,ws_caption], _S2 = [ws_child,ws_visible,ss_left], _S3 = [ws_child,ws_visible,ws_tabstop,ws_border,lbs_sort,ws_vscroll], _S4 = [ws_child,ws_visible,ws_tabstop,cbs_dropdown,ws_vscroll], _S5 = [ws_child,ws_visible,ws_tabstop,ws_border,lbs_sort,lbs_multiplesel,ws_vscroll], _S6 = [ws_child,ws_visible,ws_tabstop,bs_pushbutton], wdcreate( familyTree, `Family Tree`, 267, 134, 362, 221, _S1 ), wccreate( (familyTree,10000), static, `Person A:`, 10, 10, 70, 20, _S2 ), wccreate( (familyTree,4000), listbox, `PersonA`, 10, 30, 120, 160, _S3 ), wccreate( (familyTree,10001), static, `Is-A:`, 140, 40, 40, 20, _S2 ), wccreate( (familyTree,5000), combobox, `Combo1`, 140, 60, 80, 100, _S4 ), wccreate( (familyTree,10002), static, `Person(s) B:`, 230, 10, 70, 20, _S2 ), wccreate( (familyTree,4001), listbox, `PersonB`, 230, 30, 120, 160, _S5 ), wccreate( (familyTree,1000), button, `&Relationship`, 140, 90, 80, 30, _S6 ).ft is simply the predicate that is called to start the program. So here we create the family tree dialog box, make sure the two lists are filled with the family names, fill the combobox will relations, install some handlers, then call the dialog. Now, there are a few things to initially note here. fill_list takes an argument - the control ID of the list to fill. Since both lists contain the same names, fill_list simply fills the list with the corresponding ID with all the family names. Where did these IDs come from? If you look in create_familyTree, the first argument in wccreate is a list containing the dialog name and the control ID. create_familyTree was generated using the dialog editor. While some of you will not have this add-on, you can still see how the dialog is set up. The hard part for you will be to position the controls in a neat and presentable fashion, as well as entering all the control style flags manually. If you do have the dialog editor, it is incredibly simple to create your dialog boxes. Just create your dialog box, press "Export" and copy and paste the generated code into your program. fill_list( Id ) :- wlbxadd( (familyTree,Id), -1, `James` ), wlbxadd( (familyTree,Id), -1, `Jessica` ), wlbxadd( (familyTree,Id), -1, `Darryl` ), wlbxadd( (familyTree,Id), -1, `Joan` ), % Others removed for brevity... fill_isa :- wlbxadd( (familyTree,5000), -1, `Father` ), wlbxadd( (familyTree,5000), -1, `Mother` ), wlbxadd( (familyTree,5000), -1, `Son` ), wlbxadd( (familyTree,5000), -1, `Daughter` ), wlbxadd( (familyTree,5000), -1, `Brother` ), wlbxadd( (familyTree,5000), -1, `Sister` ), wlbxadd( (familyTree,5000), -1, `Aunt` ), wlbxadd( (familyTree,5000), -1, `Uncle` ), wlbxadd( (familyTree,5000), -1, `Nephew` ), wlbxadd( (familyTree,5000), -1, `Niece` ), wlbxadd( (familyTree,5000), -1, `Cousin` ), wlbxadd( (familyTree,5000), -1, `Grandfather` ), wlbxadd( (familyTree,5000), -1, `Grandmother` ).Here is where we will our controls with their respective information. Notice how fill_list uses its Id arguments, whereas fill_isa has the control ID hardcoded. Also note that the two controls use the same predicate to add information despite them being different control types. The -1 simply tells the control to append the string to the end of the list.
ft_handler( _, msg_close, _, cancel ).
ft_handler((familyTree,1000), msg_button, _, _ ) :-
wlbxsel((familyTree,4001),-1,0),
lb_getselitem((familyTree,4000), T),
cb_getselindx((familyTree,5000), R),
forall( isA(R,T, Relation),
( wlbxfnd((familyTree,4001),-1,Relation,P),
wlbxsel((familyTree,4001),P,1)
)
).
This is perhaps one of the hardest parts of the program to understand. Our ft_handler is the Windows message handler. The first predicate handles WM_CLOSE messages. The second handler specifically receives messages from the Relationship button (take a look at create_familyTree, you'll see the dialog and ID are the same). Firstly, we clear any selections in the right-hand list box (by trying to select -1). We then get the person and the relationship we're looking for (lb_getselitem and get_getselindx are defined below). We will deal with Windows handlers in more depth in a later tutorial.
Finally, we loop through all the valid isA relationships. isA returns the name of the relation in Relation. We then use wlbxfnd to find the text and the wlbxsel to select it. lb_getselitem( Window, Item ) :- sndmsg( Window, lb_getcursel, 0, 0, R ), ( R = -1 -> Item = `` ; wlbxget( Window, R, Item) ). cb_getselindx( Window, R ) :- sndmsg( Window, cb_getcursel, 0, 0, R ).Here we get the currently select items for the listbox and combobox respectively. The listbox predicate does some additional error checking. Neither of these two predicates are really necessary (in this case), but they make things more succinct in our ft_handler. isA( 0,X,Y ) :- parent( X,Y ), male( X ). isA( 1,X,Y ) :- parent( X,Y ), female( X ). isA( 2,X,Y ) :- parent( Y,X ), male( X ). isA( 3,X,Y ) :- parent( Y,X ), female( X ). isA( 4,X,Y ) :- sibling( X,Y ), male( X ). isA( 5,X,Y ) :- sibling( X,Y ), female( X ). isA( 6,X,Y ) :- sibling( X,Z ), parent( Z,Y ), female( X ). isA( 7,X,Y ) :- sibling( X,Z ), parent( Z,Y ), male( X ). isA( 8,X,Y ) :- sibling( Y,Z ), parent( Z,X ), male( X ). isA( 9,X,Y ) :- sibling( Y,Z ), parent( Z,X ), female( X ). isA( 10,X,Y ) :- parent( Z,X ), sibling( Z,W ), parent( W,Y ). isA( 11,X,Y ) :- parent( X,Z ), parent( Z,Y ), male( X ). isA( 12,X,Y ) :- parent( X,Z ), parent( Z,Y ), female( X ).Here are our isA relationships. Note that these must be in the same order that they are listed in the Relationship combobox. % If not male, then female... male(`Darryl`). male(`James`). % etc ... % Parent relationships parent( `Darryl`, `James`). parent( `Darryl`, `Jessica`). % etc ... % Force relationships. f_relation( `Darryl`, `Kevin`, sibling). % etc ... f_married( X,Y ) :- f_relation( X,Y,married ) ; f_relation( Y,X,married ). f_sibling( X,Y ) :- f_relation( X,Y,sibling ) ; f_relation( Y,X,sibling ).This is all fairly basic apart from the force relationships. Since the family tree doesn't extend up indefinitely, some relationships must be forced (not induced). For example, the fact that Darryl and Kevin are brothers cannot be ascertained from family tree as it stands, because Darryl and Kevin's parents aren't included. Forcing the relationship ensures that other family relationships (uncle, for example) can be correctly deduced by Prolog.
% Rules
female( X ) :-
not(male(X)).
sibling( X,Y ) :-
( parent(Z,X),
parent(Z,Y),
X \= Y ) ;
( f_sibling( X,Y ) ;
( f_married( X,Z ), f_sibling( Z,Y ) ;
f_married( Y,Z ), f_sibling( Z,X ))
).
Again, this is all fairly simple. sibling has been modified to allow checks on "forced siblings". The first set of parenthesises check for siblings that can be deduced by checking the parents. The second set of parenthesises check two possibilities - firstly a forced sibling relationship and secondly and "sibling-in-law" relationship.
ConclusionWe've really spent more time discussing the Prolog aspects of the program than the Windows side of things, but it is evident from this simple program just how easy Win-Prolog makes Windows development. This may seem fairly surprising, given the non-procedural nature of Prolog. Win-Prolog comes with fantastic documentation and a very helpful support team. This, combined with any future Generation5 tutorials, should help you develop your first Win-Prolog program effortlessly! Lastly, here is the source code for the tutorial program:
Submitted: 21/04/2002 Article content copyright © James Matthews, 2002.
|
|
|||||||||||||
All content copyright © 1998-2007, Generation5 unless otherwise noted.
- Privacy Policy - Legal - Terms of Use -