pave

Example of pave
aplsimple | Login

Simple example of pave usage

Here we use the pave to make the following dialog:

Find and Replace dialog

It's created by this code:

package require Tk
ttk::style theme use clam
source paveme.tcl
PaveMe create pave
set win .win
pave makeWindow $win.fra "Find and Replace"
set v1 [set v2 1]
set c1 [set c2 [set c3 0]]
set en1 [set en2 ""]
pave window $win.fra {
  {lab1 - - 1 1    {-st es}  {-t "Find: "}}
  {ent1 lab1 L 1 9 {-st wes} {-tvar ::en1}}
  {lab2 lab1 T 1 1 {-st es}  {-t "Replace: "}}
  {ent2 lab2 L 1 9 {-st wes} {-tvar ::en2}}
  {labm lab2 T 1 1 {-st es} {-t "Match: "}}
  {radA labm L 1 1 {-st ws} {-t "Exact" -var ::v1 -value 1}}
  {radB radA L 1 1 {-st ws} {-t "Glob" -var ::v1 -value 2}}
  {radC radB L 1 1 {-st es} {-t "RE  " -var ::v1 -value 3}}
  {h_2 radC L 1 2  {-cw 1}}
  {h_3 labm T 1 9  {-st es -rw 1}}
  {seh  h_3 T 1 9  {-st ews}}
  {chb1 seh  T 1 2 {-st w} {-t "Match whole word only" -var ::c1}}
  {chb2 chb1 T 1 2 {-st w} {-t "Match case"  -var ::c2}}
  {chb3 chb2 T 1 2 {-st w} {-t "Wrap around" -var ::c3}}
  {sev1 chb1 L 3 1 }
  {lab3 sev1 L 1 2 {-st w} {-t "Direction:"}}
  {rad1 lab3 T 1 1 {-st we} {-t "Down" -var ::v2 -value 1}}
  {rad2 rad1 L 1 1 {-st we} {-t "Up"   -var ::v2 -value 2}}
  {sev2 ent1 L 8 1 }
  {but1 sev2 L 1 1 {-st we} {-t "Find" -com "::pave res $win 1"}}
  {but2 but1 T 1 1 {-st we} {-t "Find All" -com "::pave res $win 2"}}
  {but3 but2 T 1 1 {-st we} {-t "Replace"  -com "::pave res $win 3"}}
  {but4 but3 T 1 1 {-st nwe} {-t "Replace All" -com "::pave res $win 4"}}
  {seh3 but4 T 1 1 {-st ewn}}
  {but5 seh3 T 3 1 {-st we} {-t "Close" -com "::pave res $win 0"}}
}
set res [pave showModal $win -focus $win.fra.ent1 -geometry +200+200]
puts "
  Entry1=$en1
  Entry2=$en2
  E/G/R=$v1
  CheckBox1=$c1
  CheckBox2=$c2
  CheckBox3=$c3
  Direction=$v2
  Result=$res
  "
pave destroy
destroy $win

Below we'll consider this code line by line.

The 1-2 lines are preparatory for using Tk widgets. The 3-6 lines initialize pave object that makes the .win window with "Find and Replace" title. The 7-9 lines initialize the variables used in the dialog. Still nothing special:

1  package require Tk
2  ttk::style theme use clam
3  source paveme.tcl
4  PaveMe create pave
5  set win .win
6  pave makeWindow $win.fra "Find and Replace"
7  set v1 [set v2 1]
8  set c1 [set c2 [set c3 0]]
9  set en1 [set en2 ""]


The 10 line calls pave window method that is passed two arguments: the window name and the list of widgets' options. The pave window does all layout work.
Note that the window name is passed as .win.fra, so we create a window named .win and a ttk::frame named .win.fra, thus we'll have the themed background. This way we save the keypressing like this: pack [ttk::frame $w] -expand 1 -fill both.
The 11 line creates lab1 label with text "Find:". It begins the layout so it has no neighbors and as such has "-" standing for neighborhood. The "-st es" means the "-sticky es" option.
The 12 line creates an entry ent1 where the "find string" would be entered. The neighbor of ent1 is the left (L) lab1. We expect that the ent1 would be expanded while resizing the window so we set its columnspan to "9" and "-st wes". The textvariable receiving the input is ::en1. Note that the variable should be fully qualified.
The 13-14 lines create the label and the entry for "replace string" and are similar to the previous.

10  pave window $win.fra {
11    {lab1 - - 1 1    {-st es}  {-t "Find: "}}
12    {ent1 lab1 L 1 9 {-st wes} {-tvar ::en1}}
13    {lab2 lab1 T 1 1 {-st es}  {-t "Replace: "}}
14    {ent2 lab2 L 1 9 {-st wes} {-tvar ::en2}}

Stopped by now we'd see the following dialog:

Lines 10-14


The 15-18 lines set the prompt and the radiobuttons titled "Exact", "Glob", "RE" (the matching modes at finding). Each of them has a left (L) neighbor, spans 1 row and 1 cell and has the textvariable ::v1 that would receive the input from them.

15    {labm lab2 T 1 1 {-st es} {-t "Match: "}}
16    {radA labm L 1 1 {-st ws} {-t "Exact" -var ::v1 -value 1}}
17    {radB radA L 1 1 {-st ws} {-t "Glob" -var ::v1 -value 2}}
18    {radC radB L 1 1 {-st es} {-t "RE  " -var ::v1 -value 3}}

Stopped by now we'd see the following dialog:

Lines 15-18


The 19-20 lines set the horizontal spacers that are necessary to make the clear resizing of the window.
The h_2 spacer has "-cw 1" grid option which means that its spanned cells would be expanded while resizing the window. It's just we need because the cells would expand also the entry fields.
The h_3 spacer is located under the previous labm label and has "-rw 1" grid option which means that its row would be expanded while resizing the window.
The 21 line sets the horizontal separator seh that spans 9 columns.
Just under the separator are located the checkboxes of find options. They are located one under another (T) and have the variables ::c1, ::c2, ::c3 for receiving their input.

19    {h_2 radC L 1 2  {-cw 1}}
20    {h_3 labm T 1 9  {-st es -rw 1}}
21    {seh  h_3 T 1 9  {-st ews}}
22    {chb1 seh  T 1 2 {-st w} {-t "Match whole word only" -var ::c1}}
23    {chb2 chb1 T 1 2 {-st w} {-t "Match case"  -var ::c2}}
24    {chb3 chb2 T 1 2 {-st w} {-t "Wrap around" -var ::c3}}

Stopped by now we'd see the following dialog:

Lines 19-24


The 25 line sets the vertical separator sev1 that has the left (L) neighbor chb1 (checkbox "Match whole word only") and spans 3 rows.
In 26-28 lines we have a label ("Direction") and two radiobuttons of find direction.
The 29 line sets the vertical separator sev2 that has the left (L) neighbor ent1 (find entry) and spans 8 rows.

25    {sev1 chb1 L 3 1 }
26    {lab3 sev1 L 1 2 {-st w} {-t "Direction:"}}
27    {rad1 lab3 T 1 1 {-st we} {-t "Down" -var ::v2 -value 1}}
28    {rad2 rad1 L 1 1 {-st we} {-t "Up"   -var ::v2 -value 2}}
29    {sev2 ent1 L 8 1 }

Stopped by now we'd see the following dialog:

Lines 25-29


At last, we lay out the buttons. The first but1 ("Find") has a left neighbor sev2, all others are located one under another. There is also a horizontal separator seh3 to separate the "Close" button from others.
The buttons have the commands ("-com") that set an internal variable of pave to the corresponding value (e.g. "::pave res $win 1" sets it to 1). Changing this variable would stop the window's event cycle.

30    {but1 sev2 L 1 1 {-st we} {-t "Find" -com "::pave res $win 1"}}
31    {but2 but1 T 1 1 {-st we} {-t "Find All" -com "::pave res $win 2"}}
32    {but3 but2 T 1 1 {-st we} {-t "Replace"  -com "::pave res $win 3"}}
33    {but4 but3 T 1 1 {-st nwe} {-t "Replace All" -com "::pave res $win 4"}}
34    {seh3 but4 T 1 1 {-st ews}}
35    {but5 seh3 T 3 1 {-st we} {-t "Close" -com "::pave res $win 0"}}
36 }

So, in 36 lines we have created the full-featured "Find and Replace" dialog shown above.

While being resized the dialog behaves rather decently:

Resizing


The line:

37  set res [pave showModal $win -focus $win.fra.ent1 -geometry +200+200]
calls the dialog as modal passing it the window name, the focused field name and the geometry arguments (the last two may be omitted).
The main result (i.e. the pressed button's number) is returned to res variable.
Other results are returned as the values of corresponding variables.
We should also delete the pave object if it would not be used farther.

38  puts "
39    Entry1=$en1
40    Entry2=$en2
41    E/G/R=$v1
42    CheckBox1=$c1
43    CheckBox2=$c2
44    CheckBox3=$c3
45    Direction=$v2
46    Result=$res
47    "
48  pave destroy
49  destroy $win


The most remarkable feature of pave is the easy way of modifications.
Let's imagine e.g. we need the "Stay on top" checkbox in our Find/Replace dialog. As for the layout, we should only include 1 and modify 3 lines, this way:

.......
25  {chb4 chb3 T 1 2 {-st w} {-t "Stay on top" -var ::c4}}
26  {sev1 chb1 L 4 1 }
.......
30  {sev2 ent1 L 9 1 }
.......
36  {but5 seh3 T 4 1 {-st we} {-t "Close" -com "::pave res $win 0"}}
Note that we made only those modifications that are relevant indeed: inserting the new widget and incrementing the row spans of existing widgets. No calculations of rows, columns, weights etc.

The result:

Resizing

Well done :)