GRIDPLUS2 - Example 5 | ![]() |
||||||
|
Example Of a Complete Simple Application |
This is an example of a complete "Phonebook" application using the gpdb command to access a TDBC based SQL 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. |
It is also possible to select a record for edit by double-clicking the required record.
Selecting a record with a right-click will pop-up the following menu:-
The record can be edited or deleted by selecting the required option form the menu.
![]() | 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 . -windowcommand toolbar,exit gridplus menu .phonebook:menu { ~ {"Edit" .toolbar,edit :edit16} ~ {"Delete" .toolbar,delete :actitemdelete16} } gridplus button .toolbar -style Toolbutton { {.add :actitemadd16 "?Add Record"} {.delete :actitemdelete16 "?Delete Record"} \ {.edit :edit16 "?Edit Record"} | {.find :viewmag16 "Find" 6} {&e .find-string 20 ~toolbar,find + #} | \ {.help :acthelp16 "?Display Phonebook Help"} {.exit :actexit16 "?Exit Phonebook"} } gridplus tablelist .phonebook \ -action double \ -command toolbar,edit \ -maintainsort 1 \ -menu .phonebook:menu \ -scroll y \ -selectfirst 1 \ -selectpage 1 \ -tableoptions stripe \ -takefocus 1 \ -width 80 { 0 id integer hide 0 "First Name" =firstname 0 "Last Name" =lastname 0 "Phone" 0 "Department" } gridplus layout .main -padding 0 -pady 0 -wtitle "Phonebook" { .toolbar = .phonebook } pack .main } #-------------------------# # Procedure To Add Record # #-------------------------# proc toolbar,add {} { gridplus window .add -modal 1 -windowcommand add:phone,close gridplus entry .add.phone -width 30 -validatepopup 1 -wtitle "Add Record" { {|#Toolbutton .save :filesave16 "?Save Record" ! |: .close :fileclose16 "?Close"} = {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} } pack .add.phone } #----------------------------# # Procedure To Delete Record # #----------------------------# proc toolbar,delete {} { global {} if {! [info exists (.phonebook)]} { 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: [.phonebook firstname+lastname]" -type okcancel] if {$action eq "ok"} { gpdb phonedb . {delete from phonebook where id = :(.phonebook:id)} gpdelete .phonebook } } } #--------------------------# # Procedure To Edit Record # #--------------------------# proc toolbar,edit {} { global {} if {! [info exists (.phonebook)]} { tk_messageBox -icon error -title "Phonebook: Edit" -message "No record selected for edit" -type ok return } gridplus window .edit -modal 1 -windowcommand edit:phone,close gridplus entry .edit.phone -width 30 -validatepopup 1 -wtitle "Edit Record" { {|#Toolbutton .save :filesave16 "?Save Record" ! |: .close :fileclose16 "?Close"} = {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} } gpmap { .edit.phone,firstname .edit.phone,lastname .edit.phone,phone .edit.phone,department } [.phonebook firstname>department] pack .edit.phone } #------------------------------------# # Procedure To Find Matching Records # #------------------------------------# proc toolbar,find {} { global {} gpdb phonedb . { select * from phonebook where firstname||lastname||phone||department like %:(.toolbar,find-string)% } .phonebook gpset .toolbar,find-string {} } #--------------------------------# # Procedure To Display Help Text # #--------------------------------# proc toolbar,help {} { if {! [gridplus window .help -windowcommand help:toolbar,close]} { return } gridplus button .help.toolbar -style Toolbutton { {.top :playstart16 "?Top"} {.previous :nav1leftarrow16 "?Previous Topic"} \ {.next :nav1rightarrow16 "?Next Topic"} {.bottom :playend16 "?Bottom"} | \ {.close :fileclose16 "?Close Phonebook Help"} } gridplus text .help.text -scroll y -tags 1 -linkcolor blue/red -linkstyle underline -height 15 -width 50 gridplus layout .help.main -padding 0 -pady 0 -wtitle "Phonebook Help" { .help.toolbar = .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 2014 </bgcolor>} } #-------------------------------# # Procedure To Exit Application # #-------------------------------# proc toolbar,exit {} { phonedb close exit } #--------------------------------# # Procedure To Save "add" Record # #--------------------------------# proc add:phone,save {} { global {} gpdb phonedb .add.phone, { insert into phonebook (firstname,lastname,phone,department) values(:(firstname),:(lastname),:(phone),:(department)) } refreshPhonebook gpselect .phonebook -max id add:phone,close } #---------------------------------# # Procedure To Close "add" Window # #---------------------------------# proc add:phone,close {} { gridplus clear .add destroy .add } #---------------------------------# # Procedure To Save "edit" Record # #---------------------------------# proc edit:phone,save {} { global {} gpdb phonedb .edit.phone, { update phonebook set firstname = :(firstname), lastname = :(lastname), phone = :(phone), department = :(department) where id = :(.phonebook:id) } gpselect .phonebook -save id refreshPhonebook gpselect .phonebook -restore edit:phone,close } #----------------------------------# # Procedure To Close "edit" Window # #----------------------------------# proc edit:phone,close {} { gridplus clear .edit destroy .edit } #---------------------------------------# # Procedure To Display Top Of Help Text # #---------------------------------------# proc help:toolbar,top {} { gpnav .help.text top } #------------------------------------------# # Procedure To Display Bottom Of Help Text # #------------------------------------------# proc help:toolbar,bottom {} { gpnav .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 ""} { gpnav .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 ""} { gpnav .help.text $previous } } #----------------------------------# # Procedure To Close "help" Window # #----------------------------------# proc help:toolbar,close {} { gridplus clear .help destroy .help } #-----------------------------------# # Procedure To Refresh Display List # #-----------------------------------# proc refreshPhonebook {} { gpdb phonedb . { select * from phonebook } .phonebook } #=======================# # Start The Application # #=======================# package require gridplus 2.11 namespace import -force gridplus::* # Require TDBC with Sqlite3 driver. package require tdbc::sqlite3 # Open database tdbc::sqlite3::connection create phonedb "C:/GRIDPLUS/gridplus211/example5.db" # Create optionset for toolbars gridplus optionset Toolbutton { -padding 0 -space 0 -takefocus 0 -widget button } # Set errormessage text gridplus set -errormessage "This field must not be blank" # Start mainDisplay refreshPhonebook
Comments |
proc mainDisplay {} { gridplus window . -windowcommand toolbar,exit
gridplus menu .phonebook:menu { ~ {"Edit" .toolbar,edit :edit16} ~ {"Delete" .toolbar,delete :actitemdelete16} }
For Example: "~ {"Edit" .toolbar,edit :edit16}".
This menu option is called "Edit", which will invoke a procedure called "toolbar,edit" and will have the ICONS image called "edit16".
gridplus button .toolbar -style Toolbutton { {.add :actitemadd16 "?Add Record"} {.delete :actitemdelete16 "?Delete Record"} \ {.edit :edit16 "?Edit Record"} | {.find :viewmag16 "Find" 6} {&e .find-string 20 ~toolbar,find + #} | \ {.help :acthelp16 "?Display Phonebook Help"} {.exit :actexit16 "?Exit Phonebook"} }
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. Next to this button is an entry called ".find-string" which is "20" characters wide. This content of this entry can be accessed as "$(.toolbar,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. The "#" option specifies the style for the entry. As the style name is not specified, the default style is used. This is neccessary here because the button grid is set to use the "Toolbutton" style which will cause the entry to be "invisible".
gridplus tablelist .phonebook \ -action double \ -command toolbar,edit \ -maintainsort 1 \ -menu .phonebook:menu \ -scroll y \ -selectfirst 1 \ -selectpage 1 \ -tableoptions stripe \ -takefocus 1 \ -width 80 { 0 id integer hide 0 "First Name" =firstname 0 "Last Name" =lastname 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 record "id" value. By default, Tablelist column names are created based on the column title. In this application "=firstname" and "=lastname" are used to set specific column names.
gridplus layout .main -padding 0 -pady 0 -wtitle "Phonebook" { .toolbar = .phonebook } pack .main
proc toolbar,add {} { gridplus window .add -modal 1 -windowcommand add:toolbar,close
::ttk::label .add.errormessage -foreground red
gridplus entry .add.phone -width 30 -validatepopup 1 -wtitle "Add Record" { {|#Toolbutton .save :filesave16 "?Save Record" ! |: .close :fileclose16 "?Close"} = {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} }
Two buttons are created in an Embedded Grid. The widget grid ("|#Toolbutton ...) uses a style called "Toolbutton". Each button has an explicitly defined name, an icon and associated pop-up/balloon help.
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.
The buttons are separated from the entries by a horizontal line ("=").
pack .add.phone
proc toolbar,delete {} { global {}
if {! [info exists (.phonebook)]} { 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: [.phonebook firstname+lastname]" -type okcancel] if {$action eq "ok"} { gpdb phonedb . {delete from phonebook where id = :(.phonebook:id)} gpdelete .phonebook } }
If a record has been selected the user is asked to confirm the action using "tk_messageBox". The name of the person is returned by the ".phonebook" widget command.
If the user clicks the "OK" button the record is deleted from the database using the gpdb command.
gpdb phonedb . {delete from phonebook where id = :(.phonebook:id)}
...which deletes the record from the "phonebook" table where the "id" column matches the "id" column of the selected row in the ".phonebook" Tablelist.
Note: Here, the window name for the gpdb command is not relevent. Were this is the case it is recommended that the root window (".") be specified.
The selected row in the Tablelist is deleted using the gpdelete command.
proc toolbar,edit {} { global {}
if {! [info exists (.phonebook)]} { tk_messageBox -icon error -title "Phonebook: Edit" -message "No record selected for edit" -type ok return }
gridplus window .edit -modal 1 -windowcommand edit:toolbar,close
gridplus entry .edit.phone -width 30 -validatepopup 1 -wtitle "Edit Record" { {|#Toolbutton .save :filesave16 "?Save Record" ! |: .close :fileclose16 "?Close"} = {"First Name" .firstname +} {"Last Name" .lastname !notnull} {"Phone" .phone !notnull} {"Department " .department} }
Two buttons are created in an Embedded Grid. The widget grid ("|#Toolbutton ...) uses a style called "Toolbutton". Each button has an explicitly defined name, an icon and associated pop-up/balloon help.
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.
The buttons are separated from the entries by a horizontal line ("=").
gpmap { .edit.phone,firstname .edit.phone,lastname .edit.phone,phone .edit.phone,department } [.phonebook firstname>department]
pack .edit.phone
proc toolbar,find {} { global {}
gpdb phonedb . { select * from phonebook where firstname||lastname||phone||department like %:(.toolbar,find-string)% } .phonebook
Note: Here, the window name for the gpdb command is not relevent. Were this is the case it is recommended that the root window (".") be specified.
gpset .toolbar,find-string {}
proc toolbar,help {} { if {! [gridplus window .help -windowcommand help:toolbar,close]} { return }
gridplus button .help.toolbar -style Toolbutton { {.top :playstart16 "?Top"} {.previous :nav1leftarrow16 "?Previous Topic"} \ {.next :nav1rightarrow16 "?Next Topic"} {.bottom :playend16 "?Bottom"} | \ {.close :fileclose16 "?Close Phonebook Help"} }
gridplus text .help.text -scroll y -tags 1 -linkcolor blue/red -linkstyle underline -height 15 -width 50
gridplus layout .help.main -padding 0 -pady 0 -wtitle "Phonebook Help" { .help.toolbar = .help.text } pack .help.main
The buttons are separated from the text by a horizontal line ("=").
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 2014 </bgcolor>}
proc toolbar,exit {} { phonedb close exit }
proc add:phone,save {} { global {}
gpdb phonedb .add.phone, { insert into phonebook (firstname,lastname,phone,department) values(:(firstname),:(lastname),:(phone),:(department)) }
The gpdb query window is set to ".add.phone,". As the window name ends with a comma this is used as a default prefix to define the full names of the GRIDPLUS items for the purpose of item/variable/result mapping.
For Example: ":(firstname)" will be replaced by the value of the ".add.phone,firstname" entry.
refreshPhonebook gpselect .phonebook -max id
add:phone,close
proc add:phone,close {} { gridplus clear .add destroy .add }
proc edit:phone,save {} { global {}
gpdb phonedb .edit.phone, { update phonebook set firstname = :(firstname), lastname = :(lastname), phone = :(phone), department = :(department) where id = :(.phonebook:id) }
The gpdb query window is set to ".edit.phone,". As the window name ends with a comma this is used as a default prefix to define the full names of the GRIDPLUS items for the purpose of item/variable/result mapping.
For Example: ":(firstname)" will be replaced by the value of the ".edit.phone,firstname" entry.
gpselect .phonebook -save id
refreshPhonebook gpselect .phonebook -restore
edit:phone,close
proc edit:phone,close {} { gridplus clear .edit destroy .edit }
proc help:toolbar,top {} { gpnav .help.text top }
proc help:toolbar,bottom {} { gpnav .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 ""} { gpnav .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 ""} { gpnav .help.text $previous }
proc help:toolbar,close {} { gridplus clear .help destroy .help }
proc refreshPhonebook {} {
gpdb phonedb . { select * from phonebook } .phonebook
Note: Here, the window name for the gpdb command is not relevent. Were this is the case it is recommended that the root window (".") be specified.
package require gridplus 2.11 namespace import -force gridplus::* # Require TDBC with Sqlite3 driver. package require tdbc::sqlite3 # Open database tdbc::sqlite3::connection create phonedb "C:/GRIDPLUS/gridplus211/example5.db" # Create optionset for toolbars gridplus optionset Toolbutton { -padding 0 -space 0 -takefocus 0 -widget button } # Set errormessage text gridplus set -errormessage "This field must not be blank" # Start mainDisplay refreshPhonebook
Below is the script used to create the database used for the examples on this page.
Copyright © 2015 Adrian Davis.
Example Database
package require tdbc::sqlite3
tdbc::sqlite3::connection create phonedb "C:/GRIDPLUS/gridplus211/example5.db"
set sql [phonedb prepare {
create table phonebook (id INTEGER PRIMARY KEY AUTOINCREMENT,firstname TEXT collate nocase, lastname TEXT collate nocase, phone TEXT, department TEXT collate nocase);
insert into phonebook (firstname,lastname,phone,department) values('Alan','Markham','555 9912','Sales');
insert into phonebook (firstname,lastname,phone,department) values('Debbie','Hibbert','555 0192','Support Services');
insert into phonebook (firstname,lastname,phone,department) values('Fredrick','Blinkington-Smythe','555 9876','Client Team');
insert into phonebook (firstname,lastname,phone,department) values('John','Smith','555 4321','Accounts');
insert into phonebook (firstname,lastname,phone,department) values('Margaret','Clarke','555 6677','Southern Area Office');
insert into phonebook (firstname,lastname,phone,department) values('Mary','Jones','555 1234','Customer Services');
insert into phonebook (firstname,lastname,phone,department) values('Matthew','Wolfe','555 8449','Sales');
insert into phonebook (firstname,lastname,phone,department) values('Peter','Huntington','555 6758','Head Office');
insert into phonebook (firstname,lastname,phone,department) values('Robert','Irving','555 7621','Customer Services');
insert into phonebook (firstname,lastname,phone,department) values('Robert','Smith','555 0133','Northern Area Office');
insert into phonebook (firstname,lastname,phone,department) values('Simon','Lambert','555 6789','Accounts');
}]
$sql execute
$sql close
phonedb close