But, I will instead admit that tcl/tk default is ugly by default ...
Except for windows ...
I am not a designer, but I am not blind either. I noticed that flat (aka without relief) designs age fairly well compared to the others.
So, we want themes, and why ? Because they can help provide a consistent cross platform look and feel. Here is an exemple on windows linux, freeBSD with the breeze theme : The most part of the code has been publish in the post about making python and tcl/tk talk bidirectionnaly without tkinter. I am gonna focus on the theme part of the code which is mainly. Python users may want to look this posts since the available themes for python that can be installed with
pip install ttkthemeshave a good documentation on how to use ttkthemes and how they look but does not include all the available themes and where to get them.
The same themes as pypi ttkthemes can be obtained on debian with
apt install tcl-ttkthemesand they are stored in /usr/share/tcltk/ttkthemes/themes/. From there we can use tcl that has its good sides to build a combobox for choosing a theme :
set themes_dir [ glob -directory /usr/share/tcltk/ttkthemes/themes/ -type d * ] set themes [ list ] foreach dir $themes_dir { lappend themes [ file tail $dir ] } ttk::combobox .cb -textvariable theme -values [ lsort $themes ] -width 12 .cb state readonly bind .cb <<ComboboxSelected>> { set theme [%W get] catch { source /usr/share/tcltk/ttkthemes/themes/$theme/$theme.tcl }} pass ttk::style theme use $theme }
catch { code } resultis the equivalent of try:/except, except you capture the exception in result and catch return 1 on error. the bind part call a proc to change the theme. With this and a few more widgets and bindings we can appreciate that definitively the breeze theme that is not provided by default is the best one ^_^
The essential
A ttk theme is fairly easy to use in tcl:
- spot its tcl file. ex aquativo.tcl
- source it ONCE
source /usr/share/tcltk/ttkthemes/themes/aquativo/aquativo.tcl
- use it :
ttk::style theme use aquativo
- use only the ttk:: widgets in your tcl code
Annexe: full code
#!/usr/bin/env python from subprocess import Popen, PIPE from time import sleep, time, localtime import os # let's talk to tk/tcl directly through p.stdin p = Popen(['wish'], stdin=PIPE, stdout=PIPE) os.set_blocking(p.stdout.fileno(), False) os.set_blocking(p.stdin.fileno(), False) def puts(s): for l in s.split("\n"): p.stdin.flush() p.stdin.write((l + "\n").encode()) p.stdin.flush() def gets(): ret=p.stdout.read() p.stdout.flush() return ret WIDTH=HEIGHT=500 puts(f""" canvas .c -width {WIDTH} -height {HEIGHT} -bg white pack .c .c configure -background white ttk::frame .h pack .h -fill both -expand true -padx 0 -pady 0 ttk::frame .g pack .g -in .h -fill x -expand true -padx 0 ttk::button .ba -command {{ puts ch-=1 }} -text << ttk::button .bb -command {{ puts cm-=1 }} -text < ttk::button .bc -command {{ puts ch+=1 }} -text >> ttk::button .bd -command {{ puts cm+=1 }} -text > pack .ba .bb -side left -anchor w -in .g pack .bc .bd -side right -anchor e -in .g set themes_dir [ glob -directory /usr/share/tcltk/ttkthemes/themes/ -type d * ] set themes [ list ] foreach dir $themes_dir {{ lappend themes [ file tail $dir ] }} ttk::combobox .cb -textvariable theme -values [ lsort $themes ] -width 12 .cb state readonly bind .cb <<ComboboxSelected>> {{ set theme [%W get] catch {{ source /usr/share/tcltk/ttkthemes/themes/$theme/$theme.tcl }} pass ttk::style theme use $theme }} pack .cb -in .g ttk::frame .f pack .f -in .h -expand 1 -anchor s -padx 0 set h 0 set cm 0 set s 0 ttk::label .l -text "sample of label" ttk::entry .i -text "sample of input" -textvariable theme pack .l .i -anchor w -in .f -padx 5 -pady 5 ttk::scale .s -from 0 -to 24 -variable h ttk::button .bt -text Quit -command "destroy ." ttk::spinbox .sb -from -60 -to 60 -textvariable cm -width 5 -command {{ puts "cm=$cm" }} ttk::progressbar .pb -maximum 60 -variable s pack .s .sb .pb -in .f -side left -anchor se -padx 5 -pady 5 pack .bt -in .h -anchor s -pady 5 -padx 5 """) # Constant are CAPitalized in python by convention from cmath import pi as PI, e as E ORIG=complex(WIDTH/2, HEIGHT/2) # correcting python notations j => I I = complex("j") rad_per_sec = 2.0 * PI /60.0 rad_per_min = rad_per_sec / 60 rad_per_hour= rad_per_min / 12 origin_vector_hand = WIDTH/2 * I size_of_sec_hand = .9 size_of_min_hand = .8 size_of_hour_hand= .65 rot_sec = lambda sec : -E ** (I * sec * rad_per_sec) rot_min = lambda min : -E ** (I * min * rad_per_min) rot_hour= lambda hour : -E ** (I * hour * rad_per_hour) to_real = lambda c1,c2 : "%f %f %f %f" % (c1.real,c1.imag,c2.real, c2.imag) for n in range(60): direction= origin_vector_hand * rot_sec(n) start=.9 if n%5 else .85 puts(f".c create line {to_real(ORIG+start*direction,ORIG+.95*direction)}") sleep(.01) diff_offset_in_sec = (time() % (24*3600)) - \ localtime()[3]*3600 -localtime()[4] * 60.0 \ - localtime()[5] ch=cm=0 n=0 while True: n+=1 # eventually parsing tcl output t = time() s= t%60 m = m_in_sec = t%(60 * 60) + cm * 60 h = h_in_sec = (t- diff_offset_in_sec)%(24*60*60) + ch * 3600 + cm * 60 if back := gets(): back = back.decode() exec(back) puts(".c delete second") puts(".c delete minute") puts(".c delete hour") if n%10==0: puts(f"set s {int(s%60)}") puts(f"set cm {cm}") puts(f"set h {h/3600}") n%=100 c0=ORIG+ -.1 * origin_vector_hand * rot_sec(s) c1=ORIG+ size_of_sec_hand * origin_vector_hand * rot_sec(s) puts( f".c create line {to_real(c0,c1)} -tag second -fill blue -smooth true") c1=ORIG+size_of_min_hand * origin_vector_hand * rot_min(m) puts(f".c create line {to_real(ORIG, c1)} -tag minute -fill green -smooth true") c1=ORIG+size_of_hour_hand * origin_vector_hand * rot_hour(h) puts(f".c create line {to_real(ORIG,c1)} -tag hour -fill red -smooth true") puts("flush stdout") sleep(.15)
No comments:
Post a Comment