Updated 2017-09-06 00:57:34 by Jorge


This page is made to share your tips and tricks on this page that can help in making Android applications using AndroWish. Please try to be as specific as you can about AndroWish specific commands e.g. borg and [sdltk] . and touch screen events Please give as many relevant examples as you can.

Superlinux: An example on using <<PinchToZoom>> .

A simple way to zoom the size of your app by changing the default font of the whole GUI made by Tk :
set font_size 3 ;# default starting font size is set to 3 .

set old_fingers_pinch_to_zoom_distance 0 ;# keeps track of the distance between the pinching fingers before moving the fingers to do the pinch move

proc pinch_to_zoom { fingers_distance } {
    global old_fingers_pinch_to_zoom_distance
    global font_size
    if { $fingers_distance > $old_fingers_pinch_to_zoom_distance } {
         incr font_size
         font configure TkDefaultFont -size $font_size
         set old_fingers_pinch_to_zoom_distance $fingers_distance
    if { $fingers_distance < $old_fingers_pinch_to_zoom_distance } {
            if { $font_size <=3 } {
                  set font_size 3
            incr font_size -1
            font configure TkDefaultFont -size $font_size
            set old_fingers_pinch_to_zoom_distance $fingers_distance

font configure TkDefaultFont -size $font_size

bind . <<PinchToZoom>> { pinch_to_zoom %x } ;# remember that %x is the distance between pinching fingers

# Activate <<PinchToZoom>> virtual event and disable auto zooming
sdltk touchtranslate 3

HaO 2015-03-16: Thanks for the example. The following example takes the font size at the pinch start as reference for the pinch distance. In addition, it scales the distance by the screen size, as screen resolution is highly variant on smart phones.
sdltk touchtranslate 3
set PinchStartFontSize 3
set PinchStartValue 0
bind . <<PinchToZoom>> {+PinchToZoomDo %x %s}

proc PinchToZoomDo {X State} {
    global PinchStartFontSize
    global PinchStartValue
    # State values: 0:Motion, 1:Start, 2:End 1st Finger, 2:End Both Fingers
    switch -exact .. $State {
        1 { # Start
            set PinchStartValue $X
            set PinchStartFontSize [font actual TkDefaultFont -size]
        0 - 2 { # Motion, End
            set FontSize [expr { $PinchStartFontSize + ($X - $PinchStartValue) * 10 / [winfo screenwidth .] }]
            if {$FontSize < 3} {set FontSize 3}
            font configure TkDefaultFont -size $FontSize

JM 3/21/2014, If you use Windows PC to edit your scripts, having SSHDroid on your Android device works very well with pscp launched like this from the DOS command line:
 pscp -P 2222 C:\Tcl\code\logo2.tcl [email protected]:/sdcard/

In the example I am copying my logo2.tcl script to /sdcard/ on the Android device which IP address is in this case. "admin" is the default password.

JM 8/9/2014, my set of rc files...
 set env(HOME) /sdcard
 cd ~
 source wishrc.tcl

"copywrc.tcl", which I only use when I install a new Androwish version:
 file delete /data/data/tk.tcl.wish/files/.wishrc
 file copy .wishrc /data/data/tk.tcl.wish/files

"wishrc.tcl", this is used to immediately get a file browser dialog to select the script I want to run:
 sdltk textinput on
 set script [tk_getOpenFile]
 if {$script != ""} {
   source $script
   console hide
 } else {
   puts "hello!"

JM 8/9/2014, Connecting to an Andriod device when it is running SSHDroid:
I am using Ubuntu:
 ssh -p 2222 [email protected]

See you specific port and ip address on the SSHDroid screen running on your Android.
default password is "admin"

Superlinux - 2014-03-27 10:35:07

This is an example on how to send your text or HTML file to printing on paper using PrintBot.

You can find PrintBot in this link here

PrinterBot is a network printer driver for Android. It can run Internet Printing Protocol (IPP).

On Linux, as a test, install CUPS-PDF and CUPS printer server and make it shared on the local network.
 borg activity net.jsecurity.printbot.action.PRINT "file:///mnt/sdcard/test-page.txt" "text/html" {} {} {
   borg toast "Printing completed"


Well, AW made my first android tablet purchase worth every penny.

So, here's my .wishrc, with some console fun. Also handy for fat fingers. It adds buttons to the console window.

Warning, careful here if you mangle this, you might not have a console to use to correct your .wishrc file in the protected zone.

I have followed the lead here of having files in /sdcard/home which I can modify, and then copy as needed to the protected AW zone. So, it goes there first, and if wishrc.tcl is found, sources it after it modifies the console window.

The copyit button on the console window will do that for you if you use these folder conventions. It does want a confirmation. Same with exit. The +x/-x resize the x size of the console window. Bottom scrolls you to the bottom, and you can disable scrolling with the checkbox. I also increase the number of lines to 1000.

update: Fixed problem with width adjustments, seems wm geom . is different here than on my winxp system
    if { $tcl_platform(os) != "Windows NT" } { # to test on winxp before going live on android
        set env(HOME) /sdcard/home
        cd ~
    } else {        
        console show
    package require Tk
    # a menu item runs this, it's defined here, not inside the console eval
    proc menudo {} {
        puts "pressed-menu"
    if [catch {
        console eval {
            if { ![info exist ::tk::do_scroll] } {
                set menuincr 0 ;# some consoles have an extra item in the edit menu (a font...) AW doesn't, so leave at 0 for now
                set fontsz {times 9}
                pack forget .console .sb .consoleframe
                pack [frame  .frame -bg black] -side left -fill y -ipady 2 -pady 2
                pack [button .frame.clear -bg blue -fg white -text Clear -command {.menubar.file invoke 2} -font $fontsz] -side top -fill x
                pack [button .frame.smaller   -bg white -text {font -} -font $fontsz -command {.menubar.edit invoke [expr ( $menuincr+6 )];after 100 {.frame.repos invoke}}] -side top -fill x
                pack [button .frame.bigger    -bg white -text {font +}  -font $fontsz -command {.menubar.edit invoke [expr ( $menuincr+5 )];after 100 {.frame.repos invoke}}] -side top -fill x
                pack [button .frame.exit     -bg red -fg white -text Exit  -font $fontsz -command {exiter}] -side top -fill x
                pack [button .frame.repos -bg white -text Bottom -font $fontsz -command {.console see end; .console mark set insert end}] -side top -fill x
                pack [frame  .frame.frame -bg black] -side top  -fill x
                pack [button .frame.frame.m10 -bg gray  -fg white  -font $fontsz   -text -x -command {
                    if { [.console cget -width] > 30 } {
                        .console config -width [expr ( [.console cget -width]-10 )]
                }] -side top -fill x -expand 1
                pack [button .frame.frame.p10 -bg gray  -fg white  -font $fontsz   -text +x -command {
                    if { [.console cget -width] < 120 } {
                        .console config -width [expr ([.console cget -width]+10)]
                }] -side top -fill x -expand 1
                pack [checkbutton .frame.scroll -bg white -fg black  -text scroll  -font $fontsz -variable ::tk::do_scroll] -side top -fill x
                pack [button .frame.frame.mit -bg green  -fg white  -font $fontsz   -text copyit -command copyit] -side top -fill x -expand 1
                pack .consoleframe -in . -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 0 -pady 0 -side left
                pack .console -in .consoleframe -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 1 -pady 1 -side left
                pack .sb -in .consoleframe -anchor center -expand 1 -fill both -ipadx 0 -ipady 0 -padx 1 -pady 1 -side right
                #puts "console width now [.console config -width]   [wm geom .]" ;# hmmm, seems wm geom different across platforms here
                proc copyit {} {
                    set answer [tk_messageBox -message "Please confirm\nto copy .wishrc"  -icon question -type yesno]
                    if { $answer == "yes" } {
                        file copy -force .wishrc /data/data/tk.tcl.wish/files/
                        puts copied
                proc exiter {} {
                    set answer [tk_messageBox -message "Please confirm to Exit."  -icon question -type yesno]
                    if { $answer == "yes" } {
                set ::tk::console::maxLines 1000
                .menubar add casc -label Extra -menu [menu .menubar.extra -tearoff 0]
                proc menu+ {head label cmd} {
                    set cmd2 [list consoleinterp eval $cmd]
                    .menubar.$head add command -label $label -command $cmd2 ;# note this is defined outside the console eval... its in the normal namespace
                menu+ extra menu menudo
                proc ::tk::ConsoleOutput {dest string} {
                    set w .console
                    $w insert output $string $dest
                    ::tk::console::ConstrainBuffer $w $::tk::console::maxLines
                    if {$::tk::do_scroll} {$w see insert}
                set ::tk::do_scroll 1
    } err_code] {
        puts $err_code
    if { $tcl_platform(os) != "Windows NT" } {
        if { [file exist wishrc.tcl] } {
            puts "sourcing wishrc.tcl"
            source wishrc.tcl
        } else {
            puts stderr "wishrc.tcl not found"

Here's some more fun with the console and a little test of flashing a button. It should run on any 8.6 setup. I call it wishrc.tcl to test it on my tablet.
button  .b    -text "push me\nafter I stop" -command {wm wi .} -bg black -fg white
pack    .b    -fill both -expand true 

proc uniqkey { } {
    set key   [ expr { pow(2,31) + [ clock clicks ] } ]
    set key   [ string range $key end-8 end-3 ]
    set key   [ clock seconds ]$key
    return $key

proc sleep { ms } {
    set uniq [ uniqkey ]
    set ::__sleep__tmp__$uniq 0
    after $ms set ::__sleep__tmp__$uniq 1
    vwait ::__sleep__tmp__$uniq
    unset ::__sleep__tmp__$uniq

proc cputs {dest string} {
    if { ! [info exist ::tk::my_color_set] } {
        set ::tk::my_color_set 1
        console eval {
            .console tag configure green             -foreground \#00ff00 -background black
            .console tag configure yellowonblack     -foreground yellow -background black -font {courier 14 bold}
            .console tag configure yellow            -foreground yellow
            .console tag configure whiteonred        -foreground white -background red
            .console tag configure red               -foreground red
    console eval [list ::tk::ConsoleOutput $dest $string]

sleep 1000
wm geom . 200x200+100+100
sleep 2000
for {set m 0} {$m < 5} {incr m} {
    .b config -bg red -fg white
    sleep 50
    .b config -bg white  -fg red
    sleep 50
parray env
console show
cputs whiteonred "white on red "
cputs yellowonblack " And yellow on black and big\n"

Superlinux - 2014-05-05 12:29:55

I want to highlight a little thing which comes handy, and I know to any programmer this would look silly after you read it.

Now how about hearing the message of [ tk_messageBox ] ? Yes! I know there's [ borg speak $message ] ; but this is how you should utilize it:

  • If you want to hear the $message while the [tk_messageBox] is still on the screen first you start [borg speak $message] then run [tk_messageBox] . Example:
set message "Warning! You are trespassing Java in Android using Tcl/Tk and AndroWish!"
borg speak $message
tk_messageBox -message $message -icon warning

  • If you want to hear the $message after the [tk_messageBox] vanishes from the screen first you start [tk_messageBox] then run [borg speak $message] . Example:
set message "Warning! You are trespassing Java in Android using Tcl/Tk and AndroWish!"
tk_messageBox -message $message -icon warning
borg speak $message

This should show and prove you that [borg speak] works in a separate thread. -- RS 2014-05-08: As I just tested in an interactive wish on Windows 7, tk_messageBox just blocks until dismissed with the OK button.

HE 2014-08-17 I played today with menu and found it difficult to use them with the default font. I could read them but using them was quit difficult. The same with text inside entries and buttons. Comparing with windows I saw also that we can't be sure that we have STANDARD FONTS defined as a default value. And I saw that the font size results nearly to the same size regardless of the screen (at least on the both android devices, one 4" and one 8", and the win7 device). The following code changes the default value when used at the beginning of the code
option add *Menu.Font   TkMenuFont widgetDefault
option add *Button.Font TkTextFont widgetDefault
option add *Entry.Font  TkTextFont widgetDefault
option add *Label.Font  TkTextFont widgetDefault
font configure TkMenuFont -size 12
font configure TkTextFont -size 12

I have to use 'font configure' because I couldn't find out how to change the named standard fonts with the option command.

The other value which is to small for me is the default width of the scrollbars. Looking for a device independent way I come to the following solution as a first draft:
set stdPixProMm 4
option add *Scrollbar.width [expr {16 * [winfo screenwidth .] * 1.0 / ([winfo screenmmwidth .] * $stdPixProMm)}] widgetDefault

The stdPixProMm defines the amount of pixels per mm on a standard screen. I'm not sure if this is the best value for it because I also found out that 'winfo screenmmwidth' and 'screenmmheight' on the win7 doesn't return the correct values. But the result provides on all three devices scrollbars with a width which is usable with fingers.

[kc] - 2014-09-30 03:17:15

Can anyone tell how to adjust screen brightness in androwish? I tried "borg content update" but it won't work.May be done with wrong parameter.Please help!

[JDA] - 2015-01-16 17:15

Is there a means in androwish to access openGL libraries?

Androwish rocks! I just discovered Androwish. I was able to download, install, and build the sample helloTclTk example and run it on my Motorola cell phone in addition to porting a small Tcl script. This all in less than a few hours (did not know how to build an android app). Androwish is simply awesome. Thank-you!!

HaO 2015-02-27: Scroll canvas with finger.

Here is a solution skeleton to scroll a canvas so it follows the finger.
set canvas [canvas $base.canvas -xscrollincrement 1 -yscrollincrement 1]
bind $canvas <<FingerDown>> [list +motion start $canvas %W %x %y %s]
bind $canvas <<FingerMotion>> [list +motion motion $canvas %W %x %y %s]

proc motion {mode path W X Y finger} {
        global movex
        global movey
        if {$finger != 1} {return}
        if {$mode eq "motion" && [winfo exists $path]  &&  [string match $path* $W] } {
                $path xview scroll [expr { ($movex - $X) * [winfo screenwidth .] / 10000 } ] units
                $path yview scroll [expr { ($movey - $Y) * [winfo screenheight .] / 10000 } ] units
        set movex $X
        set movey $Y

chw 2015-02-27: there's even a shorter solution which works OOTB due to the default setting of "sdltk touchtranslate ...". It uses the middle mouse button emulation for panning the entire canvas with fast wipes. Slow wipes deliver still left mouse button events e.g. for moving the currently active canvas item.
set canvas [canvas $base.canvas -xscrollincrement 1 -yscrollincrement 1]
# following lines borrowed from /assets/sdl2tk8.6/demos/items.tcl:
bind $canvas <2> "$canvas scan mark %x %y"
bind $canvas <B2-Motion> "$canvas scan dragto %x %y 1"

chw 2015-09-11: Minimalist webcam using AndroWish's borg camera command
# http://<ip-of-device>:8080/.... takes a JPEG picture
proc init {} {
    destroy .label
    borg camera close
    catch {image delete img}
    image create photo img -width 640 -height 480
    borg camera open
    borg camera parameters picture-size 640x480 jpeg-quality 80
    bind . <<ImageCapture>> {borg camera image img}
    borg camera start
    pack [label .label -image img]
    socket -server request 8080
proc request {sock args} {
    chan configure $sock -translation binary -blocking 0 -buffering none
    after 100
    catch {chan read $sock 1000} err
    chan configure $sock -blocking 1
    if {![borg camera takejpeg]} {
        chan close $sock
    bind . <<PictureTaken>> [list send_jpeg $sock]
    chan puts -nonewline $sock \
        "HTTP/1.0 200 OK\rConnection: close\r\nContent-Type: image/jpeg\r\n\r\n"
proc send_jpeg {sock} {
    bind . <<PictureTaken>> {}
    catch {chan puts -nonewline $sock [borg camera jpeg]}
    catch {chan close $sock}
    borg camera start

JM 9/5/2017, when using the webcam example from the VFS mounted assets folder, something does not work on my phone to get the IP address and appears OFFLINE, but it is actually ONLINE.
Other than that, knowing the IP address by means of SSHDroid, the sample works great.

How to get a device's dhcp data, ip address, e.t.c

Provided wifi hardware exists, and the device is connected by dhcp:
    borg systemproperties   wifi.interface        ;# find wifi interface, here 'wlan0'
    borg systemproperties   dhcp.wlan0.ipaddress  ;# find device ip address for the given interface, i.e. 'wlan0'
    borg systemproperties   dhcp.wlan0.server     ;# find access point address

dzach 2015-11-18: chw's creative frenzy continuously sprouts new functionality and tips. Here is his reply to a request for turning on|off the camera's LED:
    [Camera's LED c]an be controlled with "borg camera" command but is device dependent.

    On my smartphone (HTC One V) this sequence works:

    borg camera open
    # LED on
    borg camera parameter flash-mode torch
    # LED off
    borg camera parameter flash-mode off

How to get contact info

dzach 2015-12-26: chw mentions the source code of Android as a place to find more uses for content://.... Indeed, using the source code is the fastest way to get some guidance in the class hell of Android. Here is how to gain access to the contacts content, found in .../android-sdk-linux/sources/android-23/android/provider/ContactsContract.java:
    set cursor [borg content query content://com.android.contacts/contacts]
    while {[$cursor move 1]} {
        puts [$cursor getrow]
    $cursor close


to get the contacts phones listed, or use
    content://com.android.contacts/contacts/filter/<put filter data here>
    content://com.android.contacts/data/phones/filter/<put filter data here>

to get filtered contact results.

If, instead, you want to bring up the contact picker to select a contact from there, and return it to your app, then you can use the following:
    borg activity android.intent.action.PICK {} "vnd.android.cursor.dir/contact" {} {} {} callback

    borg activity android.intent.action.PICK content://contacts/people {} {} {} {} callback

and then, after having picked a contact, use the result returned by the callback in a borg content query content://... call to get the contact info needed.