Rendez-vous sur Arrakis

C'est lorsque nous croyons savoir quelque chose qu'il faut justement réfléchir un peu plus profondément. F. Herbert

tk and tkinter snippets

Tk est génial pour faire des interfaces graphiques ! Il est léger, rapide et surtout très pratique pour coder.

En python :

from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk

Barre de progression en tk

    canvas=Canvas(parentframe, width=300,  height=20,  bg='ivory')
    canvas.configure(bd=2,  relief='groove')
    canvas.pack()
    perc = float(perc[0].strip("%")) # this is a percent
    canvas.create_rectangle(0, 0, perc/100*300, 20, fill='green')
    canvas.update()

Récupérer le presse-papier et le mettre dans une saisie

try :
    c = self.root.clipboard_get().strip()
    if c:
        self.entry.delete(0, END)
        self.entry.insert(0, c)
except:
    c= ""

Avoir une fenêtre pour choisir un fichier

    def chdir(self):
        dldir = filedialog.askdirectory(\
            initialdir=(os.path.expanduser("~")),\
            title="Télécharger dans",\
            parent=self.root)
        if dldir != ():
            self.dldir = dldir
            self.chgbtn.configure(text="Téléchargement dans {}".format(\
                            self.dldir))

Afficher une information dans une popup

messagebox.showinfo(message = txt)

Déplacer des widget dans un treeview

    def bMove(self, event):
    # To move item in treeview
    # https://stackoverflow.com/questions/11570786/tkinter-treeview-drag-and-drop
        tv = event.widget
        moveto = tv.index(tv.identify_row(event.y))    
        for s in tv.selection():
            tv.move(s, '', moveto)

Remplacer zenity

# replace zenity --title=$1 --text=$2 --entry
from tkinter import *
from tkinter import simpledialog
def help():
    print("usage : ")
    print("{} <Title> <Question>".format(sys.argv[0]))
    sys.exit(1)
def main():
    if len(sys.argv) == 3:
        root = Tk()
        root.withdraw()
        ans = simpledialog.askstring(sys.argv[1], sys.argv[2])
        if str(ans) != "" :
            print(ans)
        return 0
    else:
        help()
if __name__ == '__main__':
    main()

Enlever la barre de la fenêtre

self.root.overrideredirect(True)

Centrer une fenêtre

def center(self):
        self.root.update_idletasks()
        w = self.root.winfo_screenwidth()
        h = self.root.winfo_screenheight()
        size = tuple(int(_) for _ in self.root.geometry().split('+')[0].split('x'))
        x = w/2 - size[0]/2
        y = h/2 - size[1]/2
        self.root.geometry("%dx%d+%d+%d" % (size + (x, y)))

Support du systray

Il faut tktray d'installé

class Icon(tkinter.BaseWidget, tkinter.Wm):
    def __init__(self, master=None, cmd = None, cnf={}, **kw):
        if not master:
            if tkinter._support_default_root:
                if not tkinter._default_root:
                    tkinter._default_root = tkinter.Tk()
                master = tkinter._default_root
        self.TktrayVersion = master.tk.call('package', 'require', 'tktray')
        # stolen from tkinter.Toplevel
        if kw:
            cnf = tkinter._cnfmerge((cnf, kw))
        extra = ()
        for wmkey in ['screen', 'class_', 'class', 'visible', 'colormap']:
            if wmkey in cnf.keys():
                val = cnf[wmkey]
                # TBD: a hack needed because some keys
                # are not valid as keyword arguments
                if wmkey[-1] == '_': opt = '-'+wmkey[:-1]
                else: opt = '-'+wmkey
                extra = extra + (opt, val)
                del cnf[wmkey]
        tkinter.BaseWidget.__init__(self, master, 'tktray::icon', cnf, {}, extra)
        self.protocol("WM_DELETE_WINDOW", self.destroy)
        if cmd:
            self.bind("<ButtonPress-1>", lambda x: Popen(cmd))

Changer l'icône de la fenêtre

# set window icon
image = Image.open(icon)
imgicon = ImageTk.PhotoImage(image)
self.root.tk.call('wm', 'iconphoto', self.root._w, imgicon)  

Simple demande d'entrée par l'user

from tkinter import simpledialog
pw = simpledialog.askstring(txt_passphrase,txt_passphrase)

Simple dialog

from tkinter import simpledialog
class Dialogue(simpledialog.Dialog):
    def __init__(self, parent, title=None, other_args=""):
            super().__init__(parent,title)
            self.args = other_args

    def body(self, master):
        frame = ttk.Frame(master)
        titlelabel = ttk.Label(frame, text=txt_configuration)
        titlelabel.grid(sticky=N, column=0, columnspan=2, row=0, pady=5, padx=5)
        wlanlabel = ttk.Label(frame, text=txt_wlanlabel)
        wlanlabel.grid(column=0, row=1, sticky=W, pady=5, padx=5)
        wlan_ifaces = [ i for i in get_ifaces() if get_iface_type(i) == "wlan" ]
        self.wlan_box_value = StringVar()
        self.wlan_box = ttk.Combobox(frame, textvariable=self.wlan_box_value)
        self.wlan_box['values'] = wlan_ifaces
        self.wlan_box.current(0)
        self.wlan_box.grid(column=1, row=1, pady=5, padx=5)
        ethlabel = ttk.Label(frame, text=txt_ethlabel)
        ethlabel.grid(column=0, row=2, sticky=W, pady=5, padx=5)
        eth_ifaces = [ i for i in get_ifaces() if get_iface_type(i) == "eth" ]
        self.eth_box_value = StringVar()
        self.eth_box = ttk.Combobox(frame, textvariable=self.eth_box_value)
        self.eth_box['values'] = eth_ifaces
        self.eth_box.current(0)
        self.eth_box.grid(column=1, row=2, pady=5, padx=5)
        for child in master.winfo_children():
            child.grid_configure(padx=5, pady=5)
        return self.wlan_box # initial focus
    def apply(self):
        wlaniface = self.wlan_box.get()
        ethiface = self.eth_box.get()
        saveconfig("DEFAULT", "wlaniface", wlaniface)
        saveconfig("DEFAULT", "ethiface", ethiface)

Console dans la fenêtre

root = Tk()
termf = Frame(root, height=700, width=1000)
termf.pack(fill=BOTH, expand=YES)
wid = termf.winfo_id()

f=Frame(root)
cmd('xterm -into {} -geometry 160x50 -sb -bg black -fg grey -e "ls; ksh" &'.format(wid))

root.mainloop()

Icône de la fenêtre en base64

    from PIL import Image, ImageTk
    from io import BytesIO
    import base64
    # set window icon
    imgicon = Image.open(BytesIO(base64.b64decode(tkmenuicon)))
    imgicon = ImageTk.PhotoImage(imgicon)