GRIDPLUS - Example 5 | ![]() |
||||||
|
Example Of a Complete Simple Application |
This is an example of a complete "Phonebook" application based on a MetaKit database. This example is mainly intended to demonstrate how a complete GRIDPLUS application may be structured.
This example assumes familiarity with the previous/earlier examples, as the more basic GRIDPLUS usage is not described in full.
User Guide |
Main Window:
The toolbar contains six buttons, each has appropriate pop-up/balloon help:-
![]() | Add new record. |
![]() | Delete selected record. |
![]() | Edit selected record. |
![]() | Find matching records. |
![]() | Display help text. |
![]() | Exit application. |
![]() | Save new record. |
![]() | Close "Add Record" window without saving record. |
The "Last Name" and "Phone" entry fields must contain data. If there is an attempt to either leave one of these fields -or- to save the record when the field is empty, a screen similar to the following will be displayed:-
![]() | Save amended record. |
![]() | Close "Edit Record" window without saving changes. |
If no record is selected when the "Edit Record" button is pressed, the following dialog is displayed:-
Pressing the "OK" button closes the dialog.
![]() | Display "Top" (begining) of help text. |
![]() | Display previous topic. |
![]() | Display next topic. |
![]() | Display "Bottom" (end) of help text. |
![]() | Close "Phonebook Help". |
The blue/underlined text are links to the various topics in the help text. When the mouse pointer is over a link its colour changes to red. When a link is "clicked" the display moves to show the selected topic.
Clicking on the "Adding New Records" link (or pressing the "Next Topic" button) will display the following screen:-
The previous/next topic buttons can also be used to step through the help text topics. The display will move to show the previous/next topic relative to the last topic selected either by clicking on a link -or- by pressing one of the top/previous/next/bottom topic buttons.
Source Code |
#----------------------------------------------# # Procedure To Display Main Application Screen # #----------------------------------------------# proc mainDisplay {} { gridplus window . -deletewindow toolbar,exit gridplus entry .find -style toolbar -size 30 { {.string + ~toolbar,find} } gridplus button .toolbar -style toolbar -pad 0 { {.add :actitemadd16 "?Add Record"} {.delete :actitemdelete16 "?Delete Record"} \ {.edit :edit16 "?Edit Record"} | {.find :viewmag16 "Find" 50} {@find} | \ {.help :acthelp16 "?Display Phonebook Help"} {.exit :actexit16 "?Exit Phonebook"} } gridplus layout .toolbar_border -relief raised { .toolbar } gridplus tablelist .phonelist -action double -options stripe -width 80 -scroll y { 0 id hide 0 "First Name" 0 "Last Name" 0 "Phone" 0 "Department" } gridplus layout .main -title "Phonebook" { .toolbar_border:ew .phonelist } pack .main } #-------------------------# # Procedure To Add Record # #-------------------------# proc toolbar,add {} { gridplus window .add -modal 1 -deletewindow add:toolbar,close gridplus set -errormessage "This field must not be blank" label .add.errormessage -foreground red gridplus button .add.toolbar -style toolbar { {.save :filesave16 "?Save Record" !} {.close :fileclose16 "?Close"} } gridplus layout .add.toolbar_border -relief raised { .add.toolbar } gridplus entry .add.phone -size 30 { {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} } gridplus layout .add.main -title "Add Record" { .add.toolbar_border:ew .add.phone .add.errormessage } pack .add.main } #----------------------------# # Procedure To Delete Record # #----------------------------# proc toolbar,delete {} { global {} if {! [info exists (.phonelist)]} { tk_messageBox -icon error -title "Phonebook: Delete" -message "No record selected for delete" -type ok return } else { set action [tk_messageBox -icon warning -title "Phonebook: Delete" -message "Delete Record: [lrange $(.phonelist) 1 2]" -type okcancel] if {$action eq "ok"} { mk::row delete db.data![lindex $(.phonelist) 0] refreshList } } } #--------------------------# # Procedure To Edit Record # #--------------------------# proc toolbar,edit {} { global {} if {! [info exists (.phonelist)]} { tk_messageBox -icon error -title "Phonebook: Edit" -message "No record selected for edit" -type ok return } gridplus window .edit -modal 1 -deletewindow edit:toolbar,close gridplus set -errormessage "This field must not be blank" label .edit.errormessage -foreground red gridplus button .edit.toolbar -style toolbar { {.save :filesave16 "?Save Record" !} {.close :fileclose16 "?Close"} } gridplus layout .edit.toolbar_border -relief raised { .edit.toolbar } gridplus entry .edit.phone -size 30 { {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} } gridplus layout .edit.main -title "Edit Record" { .edit.toolbar_border:ew .edit.phone .edit.errormessage } gpmap { .edit.phone,firstname .edit.phone,lastname .edit.phone,phone .edit.phone,department } [lrange $(.phonelist) 1 end] pack .edit.main } # **Link this proc to the "phonelist" double-click action** proc phonelist {} {toolbar,edit} #------------------------------------# # Procedure To Find Matching Records # #------------------------------------# proc toolbar,find {} { global {} set list {} foreach row [mk::select db.data -keyword {firstname lastname phone department} $(.find,string)] { lappend list "$row [mk::get db.data!$row firstname lastname phone department]" } gpset .phonelist $list gpset .find,string {} } #--------------------------------# # Procedure To Display Help Text # #--------------------------------# proc toolbar,help {} { if {! [gridplus window .help -deletewindow help:toolbar,close]} { return } gridplus button .help.toolbar -style toolbar { {.top :playstart16 "?Top"} {.previous :nav1leftarrow16 "?Previous Topic"} \ {.next :nav1rightarrow16 "?Next Topic"} {.bottom :playend16 "?Bottom"} | \ {.close :fileclose16 "?Close Phonebook Help"} } gridplus layout .help.toolbar_border -relief raised { .help.toolbar } gridplus text .help.text -scroll y -tags 1 -linkcolor blue/red -linkstyle underline -height 15 -width 50 gridplus layout .help.main -title "Phonebook Help" { .help.toolbar_border:ew .help.text } pack .help.main gpset .help.text {<label top:default><font arial:default><size 8:default><bgcolor dodgerblue><color white>\ <size +10>Phonebook Help <size +2></color><bgcolor lightgray>Topics </bgcolor> <link add>Adding New Records</link> <link delete>Deleting Records</link> <link edit>Editing Records</link> <link find>Finding Records</link> <link exit>Exiting Phonebook Application</link> <label add><bgcolor lightgray>Adding New Records </bgcolor> Press the <image :actitemadd16> button to display the <b>Add Record</b> window.\ This window has two options:- <image :filesave16> Save record. <image :fileclose16> Close window without saving record. The <b>Last Name</b> and <b>Phone</b> fields must contain data. An attempt to\ save the record -or- move to another field when one of these fields are empty\ will highlight the field with a red background and display: <color red>This\ field must not be blank</color> <label delete><bgcolor lightgray>Deleting Records </bgcolor> Press the <image :actitemdelete16> button to delete the currently selected record. A delete confirmation dialog is displayed: Press <b>OK</b> to delete the record\ -or- <b>Cancel</b> to abort the deletion. <label edit><bgcolor lightgray>Editing Records </bgcolor> Press the <image :edit16> button to display the <b>Edit Record</b> window for the\ currently selected record. This window has two options:- <image :filesave16> Save record. <image :fileclose16> Close window without saving record. The <b>Last Name</b> and <b>Phone</b> fields must contain data. An attempt to\ save the record -or- move to another field when one of these fields are empty\ will highlight the field with a red background and display: <color red>This\ field must not be blank</color> <label find><bgcolor lightgray>Finding Records </bgcolor> Enter a search string into the <b>Find</b> field then press the <image :viewmag16>\ button to display the matching records. The search string is matched anywhere in the record and is not case sensitive. <label exit><bgcolor lightgray>Exiting Phonebook Application </bgcolor> Press the <image :actexit16> button to exit the <b>Phonebook</b> application. <label bottom><bgcolor lightgray><b>Phonebook</b> - (c) Adrian Davis 2004 </bgcolor>} } #-------------------------------# # Procedure To Exit Application # #-------------------------------# proc toolbar,exit {} { mk::file commit db mk::file close db exit } #--------------------------------# # Procedure To Save "add" Record # #--------------------------------# proc add:toolbar,save {} { global {} mk::row append db.data \ firstname $(.add.phone,firstname) \ lastname $(.add.phone,lastname) \ phone $(.add.phone,phone) \ department $(.add.phone,department) refreshList add:toolbar,close } #---------------------------------# # Procedure To Close "add" Window # #---------------------------------# proc add:toolbar,close {} { gridplus clear .add destroy .add } #---------------------------------# # Procedure To Save "edit" Record # #---------------------------------# proc edit:toolbar,save {} { global {} mk::set db.data![lindex $(.phonelist) 0] \ firstname $(.edit.phone,firstname) \ lastname $(.edit.phone,lastname) \ phone $(.edit.phone,phone) \ department $(.edit.phone,department) refreshList edit:toolbar,close } #----------------------------------# # Procedure To Close "edit" Window # #----------------------------------# proc edit:toolbar,close {} { gridplus clear .edit destroy .edit } #---------------------------------------# # Procedure To Display Top Of Help Text # #---------------------------------------# proc help:toolbar,top {} { gridplus goto .help.text top } #------------------------------------------# # Procedure To Display Bottom Of Help Text # #------------------------------------------# proc help:toolbar,bottom {} { gridplus goto .help.text bottom } #-------------------------------------------# # Procedure To Display Next Help Text Topic # #-------------------------------------------# proc help:toolbar,next {} { global {} set topics [list top add delete edit find exit bottom] set current [lsearch $topics $(.help.text)] if {[set next [lindex $topics [expr {$current + 1}]]] ne ""} { gridplus goto .help.text $next } } #-----------------------------------------------# # Procedure To Display Previous Help Text Topic # #-----------------------------------------------# proc help:toolbar,previous {} { global {} set topics [list top add delete edit find exit bottom] set current [lsearch $topics $(.help.text)] if {[set previous [lindex $topics [expr {$current - 1}]]] ne ""} { gridplus goto .help.text $previous } } #----------------------------------# # Procedure To Close "help" Window # #----------------------------------# proc help:toolbar,close {} { gridplus clear .help destroy .help } #-----------------------------------# # Procedure To Refresh Display List # #-----------------------------------# proc refreshList {} { set list {} foreach row [mk::select db.data] { lappend list "$row [mk::get db.data!$row firstname lastname phone department]" } gpset .phonelist $list } #=======================# # Start The Application # #=======================# package require gridplus 1.1 namespace import -force gridplus::* # Require metakit package package require Mk4tcl # Open database mk::file open db phonebook.mk # Create a "toolbar" style gridplus style toolbar {-buttonrelief flat -borderwidth 0 -space 0 -pad 0 -takefocus 0} # Start mainDisplay refreshList
Comments |
proc mainDisplay {} { gridplus window . -deletewindow toolbar,exit
gridplus entry .find -style toolbar -size 30 { {.string + ~toolbar,find} }
The grid contains one entry called ".string". This content of this entry can be accessed as "$(.find,string)". The "+" widget option gives keyboard focus to the entry. The "~toolbar,find" option causes the "toolbar,find" procedure to be invoked if the Enter/Return key is pressed while the entry has keyboard focus. This is the same procedure as will be invoked by the "Find" toolbar button.
gridplus button .toolbar -style toolbar -pad 0 { {.add :actitemadd16 "?Add Record"} {.delete :actitemdelete16 "?Delete Record"} \ {.edit :edit16 "?Edit Record"} | {.find :viewmag16 "Find" 50} {@find} | \ {.help :acthelp16 "?Display Phonebook Help"} {.exit :actexit16 "?Exit Phonebook"} } gridplus layout .toolbar_border -relief raised { .toolbar }
For Example: "{.add :actitemadd16 "?Add Record"}".
This button will invoke a procedure called "toolbar,add", will have the ICONS image called "actitemadd16", and has "Add Record" as the pop-up/balloon help.
The ".find" button is compound; It displays both the "viewmag16" image and "Find" text. The ".find" entry grid is embedded in the toolbar next to the find button ("@find").
A GRIDPLUS Layout is used to add a "raised" border to the toolbar.
gridplus tablelist .phonelist -action double -options stripe -width 80 -scroll y { 0 id hide 0 "First Name" 0 "Last Name" 0 "Phone" 0 "Department" }
The table list has five columns. Each has a size of "0" (zero), which auto-sizes the columns to fit the column header/data (See the website of Dr Csaba Nemithi, author of the Tablelist package).
The "hide" option is a GRIDPLUS addition. This causes a hidden column to be created. In this application, the hidden column is used to store the MetaKit database row ID of the record.
gridplus layout .main -title "Phonebook" { .toolbar_border:ew .phonelist } pack .main
proc toolbar,add {} { gridplus window .add -modal 1 -deletewindow add:toolbar,close
gridplus set -errormessage "This field must not be blank" label .add.errormessage -foreground red
gridplus button .add.toolbar -style toolbar { {.save :filesave16 "?Save Record" !} {.close :fileclose16 "?Close"} } gridplus layout .add.toolbar_border -relief raised { .add.toolbar }
A GRIDPLUS Layout is used to add a "raised" border to the toolbar.
gridplus entry .add.phone -size 30 { {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} }
Four entry widgets are created: The "+" widget option for the "First Name" entry causes this option to be given keyboard focus when the window is created. The "Last Name" and "Phone" entries have the "!notnull" validation option (See Validations). In this case the user must complete both of these fields if the record is to be saved.
gridplus layout .add.main -title "Add Record" { .add.toolbar_border:ew .add.phone .add.errormessage } pack .add.main
proc toolbar,delete {} { global {}
if {! [info exists (.phonelist)]} { tk_messageBox -icon error -title "Phonebook: Delete" -message "No record selected for delete" -type ok return } else { set action [tk_messageBox -icon warning -title "Phonebook: Delete" -message "Delete Record: [lrange $(.phonelist) 1 2]" -type okcancel] if {$action eq "ok"} { mk::row delete db.data![lindex $(.phonelist) 0] refreshList } }
If a record has been selected the user is asked to confirm the action using "tk_messageBox". If the user clicks the "OK" button the record is deleted from the database and the tablelist refreshed to update its contents.
proc toolbar,edit {} { global {}
if {! [info exists (.phonelist)]} { tk_messageBox -icon error -title "Phonebook: Edit" -message "No record selected for edit" -type ok return }
gridplus window .edit -modal 1 -deletewindow edit:toolbar,close
gridplus set -errormessage "This field must not be blank" label .edit.errormessage -foreground red
gridplus button .edit.toolbar -style toolbar { {.save :filesave16 "?Save Record" !} {.close :fileclose16 "?Close"} } gridplus layout .edit.toolbar_border -relief raised { .edit.toolbar }
A GRIDPLUS Layout is used to add a "raised" border to the toolbar.
gridplus entry .edit.phone -size 30 { {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} }
Four entry widgets are created: The "+" widget option for the "First Name" entry causes this option to be given keyboard focus when the window is created. The "Last Name" and "Phone" entries have the "!notnull" validation option (See Validations). In this case the user must complete both of these fields if the record is to be saved.
gridplus layout .edit.main -title "Edit Record" { .edit.toolbar_border:ew .edit.phone .edit.errormessage }
gpmap { .edit.phone,firstname .edit.phone,lastname .edit.phone,phone .edit.phone,department } [lrange $(.phonelist) 1 end]
pack .edit.main
proc phonelist {} {toolbar,edit}
proc toolbar,find {} { global {} set list {}
foreach row [mk::select db.data -keyword {firstname lastname phone department} $(.find,string)] { lappend list "$row [mk::get db.data!$row firstname lastname phone department]" }
gpset .phonelist $list gpset .find,string {}
proc toolbar,help {} { if {! [gridplus window .help -deletewindow help:toolbar,close]} { return }
gridplus button .help.toolbar -style toolbar { {.top :playstart16 "?Top"} {.previous :nav1leftarrow16 "?Previous Topic"} \ {.next :nav1rightarrow16 "?Next Topic"} {.bottom :playend16 "?Bottom"} | \ {.close :fileclose16 "?Close Phonebook Help"} } gridplus layout .help.toolbar_border -relief raised { .help.toolbar }
A GRIDPLUS Layout is used to add a "raised" border to the toolbar.
gridplus text .help.text -scroll y -tags 1 -linkcolor blue/red -linkstyle underline -height 15 -width 50
gridplus layout .help.main -title "Phonebook Help" { .help.toolbar_border:ew .help.text } pack .help.main
gpset .help.text {<label top:default><font arial:default><size 8:default><bgcolor dodgerblue><color white>\ <size +10>Phonebook Help <size +2></color><bgcolor lightgray>Topics </bgcolor> <link add>Adding New Records</link> <link delete>Deleting Records</link> <link edit>Editing Records</link> <link find>Finding Records</link> <link exit>Exiting Phonebook Application</link> <label add><bgcolor lightgray>Adding New Records </bgcolor> Press the <image :actitemadd16> button to display the <b>Add Record</b> window.\ This window has two options:- <image :filesave16> Save record. <image :fileclose16> Close window without saving record. The <b>Last Name</b> and <b>Phone</b> fields must contain data. An attempt to\ save the record -or- move to another field when one of these fields are empty\ will highlight the field with a red background and display: <color red>This\ field must not be blank</color> <label delete><bgcolor lightgray>Deleting Records </bgcolor> Press the <image :actitemdelete16> button to delete the currently selected record. A delete confirmation dialog is displayed: Press <b>OK</b> to delete the record\ -or- <b>Cancel</b> to abort the deletion. <label edit><bgcolor lightgray>Editing Records </bgcolor> Press the <image :edit16> button to display the <b>Edit Record</b> window for the\ currently selected record. This window has two options:- <image :filesave16> Save record. <image :fileclose16> Close window without saving record. The <b>Last Name</b> and <b>Phone</b> fields must contain data. An attempt to\ save the record -or- move to another field when one of these fields are empty\ will highlight the field with a red background and display: <color red>This\ field must not be blank</color> <label find><bgcolor lightgray>Finding Records </bgcolor> Enter a search string into the <b>Find</b> field then press the <image :viewmag16>\ button to display the matching records. The search string is matched anywhere in the record and is not case sensitive. <label exit><bgcolor lightgray>Exiting Phonebook Application </bgcolor> Press the <image :actexit16> button to exit the <b>Phonebook</b> application. <label bottom><bgcolor lightgray><b>Phonebook</b> - (c) Adrian Davis 2004 </bgcolor>}
proc toolbar,exit {} { mk::file commit db mk::file close db exit }
proc add:toolbar,save {} { global {}
mk::row append db.data \ firstname $(.add.phone,firstname) \ lastname $(.add.phone,lastname) \ phone $(.add.phone,phone) \ department $(.add.phone,department)
refreshList add:toolbar,close
proc add:toolbar,close {} { gridplus clear .add destroy .add }
proc edit:toolbar,save {} { global {}
mk::set db.data![lindex $(.phonelist) 0] \ firstname $(.edit.phone,firstname) \ lastname $(.edit.phone,lastname) \ phone $(.edit.phone,phone) \ department $(.edit.phone,department)
refreshList edit:toolbar,close
proc edit:toolbar,close {} { gridplus clear .edit destroy .edit }
proc help:toolbar,top {} { gridplus goto .help.text top }
proc help:toolbar,bottom {} { gridplus goto .help.text bottom }
proc help:toolbar,next {} { global {}
set topics [list top add delete edit find exit bottom] set current [lsearch $topics $(.help.text)]
if {[set next [lindex $topics [expr {$current + 1}]]] ne ""} { gridplus goto .help.text $next }
proc help:toolbar,previous {} { global {}
set topics [list top add delete edit find exit bottom] set current [lsearch $topics $(.help.text)]
if {[set previous [lindex $topics [expr {$current - 1}]]] ne ""} { gridplus goto .help.text $previous }
proc help:toolbar,close {} { gridplus clear .help destroy .help }
proc refreshList {} { set list {}
foreach row [mk::select db.data] { lappend list "$row [mk::get db.data!$row firstname lastname phone department]" }
gpset .phonelist $list
# Require metakit package package require Mk4tcl # Open database mk::file open db phonebook.mk # Create a "toolbar" style gridplus style toolbar {-buttonrelief flat -borderwidth 0 -space 0 -pad 0 -takefocus 0} # Start mainDisplay refreshList