Skip to content

Commit

Permalink
add keyword args
Browse files Browse the repository at this point in the history
  • Loading branch information
jverzani committed May 22, 2013
1 parent a10f37b commit 6f1b6e1
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 323 deletions.
173 changes: 45 additions & 128 deletions examples/README.md
Expand Up @@ -39,7 +39,7 @@ In addition to providing constructors, there are some convenience methods defin

* The `tk_configure`, `tk_cget`, `tclvar`, `tk_identify`, `tk_state`,
`tk_instate`, `tk_winfo`, `tk_wm`, `tk_bind` methods to simplify the
corresponding Tcl commands.
corresponding Tcl commands.

* For widget layout, we have `pack`, `pack_configure`, `forget`, `grid`,
`grid_configure`, `grid_forget`, ... providing interfaces to the appropriate Tk commands, but also
Expand All @@ -65,13 +65,13 @@ A simple "Hello world" example, which shows off many of the styles is given by:

```
w = Toplevel("Example") ## A titled top level window
f = Frame(w, {:padding => [3,3,2,2], :relief=>"groove"}) ## A Frame with some options set
pack(f, {:expand => true, :fill => "both"}) ## using pack to manage the layout of f
f = Frame(w, padding = [3,3,2,2], relief="groove") ## A Frame with some options set
pack(f, expand = true, fill = "both") ## using pack to manage the layout of f
#
b = Button(f, "Click for a message") ## Button constructor has convenience interface
grid(b, 1, 1) ## use grid to pack in b. 1,1 specifies location
#
callback(path) = Messagebox(w, "A message", "Hello World") ## A callback to open a message
callback(path) = Messagebox(w, title="A message", message="Hello World") ## A callback to open a message
tk_bind(b, "command", callback) ## bind callback to 'command' option
tk_bind(b, "<Return>", callback) ## press return key when button has focus
```
Expand Down Expand Up @@ -115,7 +115,7 @@ window may show through:
```
w = Toplevel()
f = Frame(w)
pack(f, {:expand=>true, :fill=>"both"})
pack(f, expand=true, fill="both")
```

#### Notes:
Expand All @@ -133,7 +133,7 @@ pack(f, {:expand=>true, :fill=>"both"})
w = Toplevel("title", 400, 300) ## title, width, height
pack_stop_propagate(w)
f = Frame(w)
pack(f, {:expand=>true, :fill=>"both"})
pack(f, expand=true, fill="both")
```

* resizing toplevel windows can leave visual artifacts, at least on a
Expand All @@ -146,7 +146,7 @@ pack(f, {:expand=>true, :fill=>"both"})
The `Messagebox` constructor makes a modal message box.

```
Messagebox("title", "message")
Messagebox(title="title", message="message")
```

An optional `parent` argument can be specified to locate the box near
Expand All @@ -166,7 +166,7 @@ pack(cb)
function callback(path) ## callbacks have at least one argument
value = get_value(cb)
msg = value ? "Glad to hear that" : "Sorry to hear that"
Messagebox(w, "Thanks for the feedback", msg)
Messagebox(w, title="Thanks for the feedback", message=msg)
end
tk_bind(cb, "command", callback) ## bind to command option
Expand All @@ -182,18 +182,18 @@ The `set_items` method can be used to change the label.
```
w = Toplevel()
f = Frame(w)
pack(f, {:expand=>true, :fill=>"both"})
pack(f, expand=true, fill="both")
l = Label(f, "Which do you prefer?")
rb = Radio(f, ["apples", "oranges"])
b = Button(f, "ok")
map(u -> pack(u, {:anchor => "w"}), (l, rb, b)) ## pack in left to right
map(u -> pack(u, anchor="w"), (l, rb, b)) ## pack in left to right
function callback(path)
msg = (get_value(rb) == "apples") ? "Good choice! An apple a day keeps the doctor away!" :
"Good choice! Oranges are full of Vitamin C!"
Messagebox(w, "Title:", msg)
Messagebox(w, msg)
end
tk_bind(b, "command", callback)
Expand Down Expand Up @@ -240,7 +240,7 @@ set_value(rb, "option 1") ## initialize
menu_add(omenu, rb) ## second argument is Tk_Radio instance
b = Button(w, "print selected options")
pack(b, {:expand=>true, :fill=>"both"})
pack(b, expand=true, fill="both")
function callback(path)
vals = map(get_value, (cb, rb))
Expand All @@ -260,7 +260,7 @@ The entry widget can be used to collect data from the user.

```
w = Toplevel()
f = Frame(w); pack(f, {:expand=>true, :fill=>"both"})
f = Frame(w); pack(f, expand=true, fill="both")
e = Entry(f)
b = Button(f, "Ok")
Expand All @@ -272,7 +272,7 @@ focus(e) ## put keyboard focus on widget
function callback(path)
val = get_value(e)
msg = "You have a nice name $val"
Messagebox(w, "Title", msg)
Messagebox(w, msg)
end
tk_bind(b, "command", callback)
Expand All @@ -293,20 +293,20 @@ fruits = ["Apple", "Orange", "Banana", "Pear"]
w = Toplevel("Favorite fruit?")
tcl("pack", "propagate", w, false)
f = Frame(w)
pack(f, {:expand=>true, :fill=>"both"})
pack(f, expand=true, fill="both")
f1 = Frame(f) ## need internal frame for use with scrollbars
lb = Treeview(f1, fruits)
scrollbars_add(f1, lb)
pack(f1, {:expand=>true, :fill=>"both"})
pack(f1, expand=true, fill="both")
b = Button(f, "Ok")
pack(b)
function callback(path)
fruit_choice = get_value(lb)
msg = (fruit_choice == nothing) ? "What, no choice?" : "Good choice! $(fruit_choice[1])" * "s are delicious!"
Messagebox(w, "title", msg)
Messagebox(w, msg)
end
tk_bind(b, "command", callback)
```
Expand All @@ -316,9 +316,9 @@ The value returned by `get_value` is an array or `nothing`. Returning
better?

One can configure the `selectmode`. E.g. `tk_configure(lb,
{:selectmode => "extended"})` with either `extended` (multiple
selectmode = "extended")` with either `extended` (multiple
selection possible, `browse` (single selection), or `none` (no
selection).)
selection).) The shortcut `lb[:selectmode] = "extended"` will also work.

The `Treeview` widget can also display a matrix of strings in a grid
in addition to tree-like data.
Expand All @@ -337,11 +337,11 @@ fruits = ["Apple", "Orange", "Banana", "Pear"]
w = Toplevel("Combo boxes", 300, 200)
tcl("pack", "propagate", w, false)
f = Frame(w); pack(f, {:expand=>true, :fill=>"both"})
f = Frame(w); pack(f, expand=true, fill="both")
grid(Label(f, "Again, What is your favorite fruit?"), 1, 1)
cb = Combobox(f, fruits)
grid(cb, 2,1, {:sticky=>"ew"})
grid(cb, 2,1, sticky="ew")
b = Button(f, "Ok")
grid(b, 3, 1)
Expand All @@ -350,7 +350,7 @@ function callback(path)
fruit_choice = get_value(cb)
msg = (fruit_choice == nothing) ? "What, no choice?" :
"Good choice! $(fruit_choice)" * "s are delicious!"
Messagebox(w, "title", msg)
Messagebox(w, msg)
end
tk_bind(b, "command", callback)
Expand All @@ -373,7 +373,7 @@ tcl("pack", "propagate", w, false)
f = Frame(w)
txt = Text(f)
scrollbars_add(f, txt)
pack(f, {:expand=>true, :fill => "both"})
pack(f, expand=true, fill = "both")
```

Only a `get_value` and `set_value` is provided. One can configure
Expand Down Expand Up @@ -438,14 +438,15 @@ any indication as to the value, we remedy this with a label.
```
w = Toplevel("Slider and label", 300, 200)
pack_stop_propagate(w)
f = Frame(w); pack(f, {:expand => true, :fill => "both"})
f = Frame(w); pack(f, expand = true, fill = "both")
sc = Slider(f, 1:20)
l = Label(f)
tk_configure(l, {:textvariable => tk_cget(sc, "variable") })
l[:textvariable] = sc[:variable]
pack(sc, {:side=>"left", :expand=>true, :fill=>"x", :anchor=>"w"})
pack(l, {:side=>"left", :anchor=>"w"})
pack(sc, side="left", expand=true, fill="x", anchor="w")
pack(l, side="left", anchor="w")
```

This combination above is not ideal, as the length of the label is not
Expand All @@ -462,7 +463,7 @@ two using a callback:

```
w = Toplevel("Slider/Spinbox")
f = Frame(w); pack(f, {:expand => true, :fill => "both"})
f = Frame(w); pack(f, expand = true, fill = "both")
sc = Slider(f, 1:100)
sp = Spinbox(f, 1:100)
Expand Down Expand Up @@ -493,101 +494,17 @@ fname = Pkg.dir("Tk", "examples", "weather-overcast.gif") ## https://code.google
img = Image(fname)
w = Toplevel("Icon in button")
b = Button(w, "weather", img) ## or: b = Button(w, {:text=>"weather", :image=>img, :compound=>"left"})
b = Button(w, "weather", img) ## or: b = Button(w, text="weather", image=img, compound="left")
pack(b)
```

### Graphics

The obvious desire to embed a graph into a GUI turns out to be not so
simple. Why?

* `Gadfly` makes SVG graphics. This is great for showing in a web
browser, but not so great with Tk, as there is not SVG viewer. The
example below can be easily modified.

* `Winston` can render to a `Canvas` object. This should be great, *but* for
some reason trying to show the canvas object in anything but a
toplevel window fails. When this issue is fixed, that should work out
really well.

* In the meantime, we can do the following:

- write a Winston graphic to a `png` file.

- convert this to `gif` format via imagemagick's `convert` function,
which is also used by the `Images` package

- use that `gif` file through an `Image` object.

The only issue is the asynchronous nature of the `convert` command
requires us to wait until the command is finished to update the
label. The `spawn` command below with all its arguments does this.

```
using Tk
using Winston
using Images ## not used, but installs imagemagick?
type WinstonLabel <: Tk.Tk_Widget
w
p
fname
WinstonLabel(w) = new(Tk.Label(w), nothing, nothing)
WinstonLabel(w, args::Dict) = new(Tk.Label(w, args), nothing, nothing)
end
function render(parent::WinstonLabel, p)
parent.p = p
if isa(parent.fname, Nothing)
parent.fname = nm = tempname()
## tk_bind(parent, "<Destroy>", map(rm, ("$nm.png", "$nm.gif"))) ## clean up
end
nm = parent.fname
file(p, "$nm.png")
## would use imwrite(imread("$nm.png"), "$nm.gif") but need to wait until done to update label
cmd = `convert $nm.png $nm.gif` # imagemagick convert from Images
spawn(false, cmd, (STDIN, STDOUT, STDERR), false, (self) -> begin ## spawn -- not run!
img = Tk.Image("$nm.gif")
Tk.tk_configure(parent.w, {:image=>img, :compound => "image"})
end)
end
## The interface
w = Toplevel("demo", 800, 600)
tcl("pack", "propagate", w, false)
pg = Frame(w); pack(pg, {:expand=>true, :fill=>"both"})
f = Labelframe(pg, "Controls"); pack(f, {:side=> "left", :anchor=>"nw"})
img_area = WinstonLabel(pg)
pack(img_area, {:expand => true, :fill=>"both"})
sl = Slider(f, 1:20);
formlayout(sl, "n")
function plot_val(val)
x = linspace(0, 1.0, 200)
y = x.^val
p = FramedPlot()
add(p, Curve(x, y))
render(img_area, p)
end
tk_bind(sl, "command", (path) -> plot_val(get_value(sl)))
plot_val(1) ## initial graph
```

If you try this you may find that it isn't great: sometimes the graphic is done; at times a black box
flashes across the screen as the slider is moved.

<img src="manipulate.png"></img>


In the examples directory you can find an implementation of RStudio's
`manipulate` function, which extends this example. This functions makes it very straightforward to define
basic interactive GUIs for plotting with `Winston`.
The `Canvas` widget can be placed in a GUI to embed a graphics device
(though the display is flaky with a Mac) In the examples directory you
can find an implementation of RStudio's `manipulate` function. This
functions makes it very straightforward to define basic interactive
GUIs for plotting with `Winston`.

To try it, run

Expand Down Expand Up @@ -658,11 +575,11 @@ by first creating the widgets, then managing them:

```
w = Toplevel("packing example")
f = Frame(w); pack(f, {:expand=>true, :fill=>"both"})
f = Frame(w); pack(f, expand=true, fill="both")
ok_b = Button(f, "Ok")
cancel_b = Button(f, "Cancel")
help_b = Button(f, "Help")
map(u -> pack(u, {:side => "left"}), (ok_b, cancel_b, help_b))
map(u -> pack(u, side = "left"), (ok_b, cancel_b, help_b))
```

#### grid
Expand All @@ -679,17 +596,17 @@ directions to attach. A value of `news` is like `{:expand=>true,

```
w = Toplevel("Grid")
f = Frame(w, {:padding => 10}); pack(f, {:expand=>true, :fill=>"both"})
f = Frame(w, padding = 10); pack(f, expand=true, fill="both")
s1 = Slider(f, 1:10)
s2 = Slider(f, 1:10, {:orient=>"vertical"})
s2 = Slider(f, 1:10, orient="vertical")
b3 = Button(f, "ew sticky")
b4 = Button(f, "ns sticky")
grid(s1, 1, 1:2, {:sticky=>"news"})
grid(s2, 2:3, 2, {:sticky=>"news"})
grid(s1, 1, 1:2, sticky="news")
grid(s2, 2:3, 2, sticky="news")
grid(b3, 2, 1)
grid(b4, 3, 1, {:sticky=>"ns"}) ## breaks theme
grid(b4, 3, 1, sticky="ns") ## breaks theme
```

We provide the `formlayout` method for conveniently laying out widgets
Expand All @@ -711,7 +628,7 @@ user to switch between them. The `page_add` method makes this easy:
w = Toplevel()
tcl("pack", "propagate", w, false)
nb = Notebook(w)
pack(nb, {:expand=>true, :fill=>"both"})
pack(nb, expand=true, fill="both")
page1 = Frame(nb)
page_add(page1, "Tab 1")
Expand All @@ -734,10 +651,10 @@ with `Notebook` containers, children are added through `page_add`.
```
w = Toplevel("Panedwindow", 800, 300)
tcl("pack", "propagate", w, false)
f = Frame(w); pack(f, {:expand=>true, :fill=>"both"})
f = Frame(w); pack(f, expand=true, fill="both")
pg = Panedwindow(f, "horizontal") ## orientation. Use "vertical" for up down.
grid(pg, 1, 1, {:sticky => "news"})
grid(pg, 1, 1, sticky = "news")
page_add(Button(pg, "button"))
page_add(Label(pg, "label"))
Expand Down

0 comments on commit 6f1b6e1

Please sign in to comment.