Edit detail for TkinterTriky revision 4 of 1

4
Editor: geon
Time: 2011/10/12 18:27:43 GMT+2
Note: oprava

changed:
-
..aneb co se v dokumentaci těžko hledá...

.. image:: py25.png
   :align: right
 
Bez černého konzolového okna
------------------------------------

Pokud nechceme, aby se otevíralo černé dosovské okno, stačí dát příponu programu ``*.pyw`` nebo ke spouštění použít místo python.exe pythonw.exe. Nevýhoda tohoto způsobu při vytváření aplikace je jasná: neuvidíte případné chybové hlášky a nebudete moci ani používat print. 

Řešením tohoto problému nicméně může být přesměrování stdout a stderr do okna. Následující příklad to dělá. Okno pro výpisy je po spuštění zavřené a otevře se až v případě zápisu do stdout či stderr. Výpisy na stderr zobrazuje červeně. Okno je možné zavřít, v případě potřeby se zase otevře. Příklad ::

    import sys
    from Tkinter import *


    hlavni=Tk()

    _printtext = None

    def getprinttext():
        global _printtext
        if _printtext == None:
            printwin = Toplevel()
            def reset():
                global _printtext
                _printtext = None
                printwin.destroy()
            printwin.protocol("WM_DELETE_WINDOW", reset)
            _printtext = Text(printwin)
            _printtext.pack(expand=True, fill=BOTH)
            _printtext.tag_config('out', foreground="black")
            _printtext.tag_config('err', foreground="red")
        return _printtext

    class FakeStdOut(object):
        def write(self, what):
            getprinttext().insert(END, what, 'out')

    class FakeStdErr(object):
        def write(self, what):
            getprinttext().insert(END, what, 'err')

    oldso = sys.stdout
    oldse = sys.stderr
    sys.stdout = FakeStdOut()
    sys.stderr = FakeStdErr()

    def so():
        print 'aaaaaa'

    def se():
        print >> sys.stderr, 'bbbbbbb'

    try:
        Button(text="stdout", command=so).pack()
        Button(text="stderr", command=se).pack()
        Button(text="Sbohem", command='exit').pack()
        hlavni.mainloop()
    except SystemExit:
        pass
    except:
        sys.stdout = oldso
        sys.stderr = oldse
        import traceback
        traceback.print_exc()

 

Schování widgetu
---------------------

Ukrytí widgetu se dá udělat pomocí metody widget.pack_forget() a následné zobrazení pomocí widget.pack(). U grid manageru je to widget.grid_remove() a zobrazení pak s widget.grid() a mělo by to být na tom samém místě.

Ukázka::

    # -*- coding: utf8 -*-
    """Ukazkovy priklad v Tkinter."""
    
    from Tkinter import *
    priznak=True 
    
    def tisk():
       global priznak
       print priznak
       if priznak:
           listbox.pack_forget()
           tisk['text']='Zobrazit!'
       else:
           listbox.pack()
           tisk['text']='Schovat!'
       priznak = not priznak
    
    hlavniOkno=Tk()
    hlavniOkno.title('Aplikace v Tk')
    ramec=Frame(hlavniOkno)
    ramec.pack()
    
    listbox=Listbox(ramec, selectmode=MULTIPLE)
    seznam=['Python','C++', 'Java', 'Pascal', 'Basic']
    
    for prvek in seznam:
       listbox.insert(END, prvek)
    
    listbox.pack()
    tisk=Button(hlavniOkno, text='Schovat!', command=tisk)
    tisk.pack(ipadx=40)
    
    mainloop() 


Změna systémové ikony
-----------------------

Tak na tohle má Tkinter metodu iconbitmap. Použití je např. následující: ``root.iconbitmap("cherry.ico")``, cherry.ico je soubor s ikonou ve formatu ``*.ico``

Okno pořád na vrchu, okno nejde zavřít 
---------------------------------------------

Chcete aby bylo okno pořád vidět, aby se nedalo schovat za ostatní? a ještě aby nešlo standardním způsobem (křížek nebo Alt+F4) zavřít? Použijte následující kod::

    root=Tk()                                      # okno
    root.protocol('WM_DELETE_WINDOW', 0 ) # aby nešlo zavřít, místo 0 možno použít nějakou funkci na případnou hlášku
    root.protocol('WM_TAKE_FOCUS', root.update )   # aby se stalo aktivním
    root.wait_visibility(root)                     # aby fungoval následující řádek 
    root.attributes('-topmost',1)                  # aby bylo pořád navrchu 
  
Okno bez rámu, bez ikony, bez title a bez ovládacích prvků
------------------------------------------------------------

::


   from Tkinter import *

   root = Tk()
   Label(root, text='No wm decorations').pack(padx=10, pady=10)
   root.overrideredirect(1)
   root.mainloop()

Pokud ještě potřebujete zobrazit aplikaci přes celou obrazovku a neznáte předem rozlišení, je možné přidat v předchozím kódu před mainloop()::
   
   w, h = root.winfo_screenwidth(), root.winfo_screenheight()
   root.geometry("%dx%d%+d%+d" % (w,h,0,0))

Hromadná změna vzhledu u všech widgetů
---------------------------------------

"Ošklivý" vzhled standardního vzhledu Tk oken můžete změnit pomocí databáze   voleb (option database). Dá se to provést buď přímo v programu::

    # -*- coding: utf8 -*- 
    from Tkinter import *
    
    hlavni=Tk()
    
    hlavni.option_add('*background','#797778')
    hlavni.option_add('*Font', 'Verdana 20 bold')

    # dalsi moznosti
    # hlavni.option_add('*background','#797778')
    # hlavni.option_add('*foreground','#fdfd02')
    # hlavni.option_add('*EntryField.Entry.background', 'white')
    # hlavni.option_add('*Entry.background', 'white')        
    # hlavni.option_add('*MessageBar.Entry.background', 'gray85')
    # hlavni.option_add('*Listbox*background', 'dark green')
    # hlavni.option_add('*Listbox*selectBackground', 'dark slate blue')
    # hlavni.option_add('*Listbox*selectForeground', 'white')
    
    w=Label( text="Ahoj světe!")
    w.pack()
    
    mainloop()

nebo načtením z externího souboru s nastaveními::
  
    *font : Helvetica -12
    *Entry*background : white
    *Listbox*background : white
    *Listbox*exportSelection : 0
    *selectBackground : blue4
    *selectForeground : white
    *Scrollbar*takeFocus : 0
    *Scrollbar*highlightThickness : 0
    *Menu*tearOff : 0
    atd.
  
Když uložíte toto jako "optionDB", tak pak následně v programu můžete nastavení načíst takto::
  
    root = Tk()
    root.option_readfile(<cesta-k-optionDB>)

Tk podporuje i barevná schémata. Následující kód nastaví modrý vzhled, ostatní barvy se vypočítají tak, aby byl zajištěn barevný kontrast všech prvků uživatelského rozhraní::

    root = Tk()
    root.tk_setPalette('blue') 

Scrollování kolečkem myši
------------------------------
  
Scrolování textu pomocí kolečka myši umožňuje nedokumentovaná událost na Linuxech 'Button-4' a 'Button-5' a na Windows <!MouseWheel>, kde existuje atribut 'delta', který udává směr.::

    import Tkinter
    
    def priRolovani(udalost):
        print "udalost:", udalost,"  ---  smer:", udalost.delta
    
    okno=Tkinter.Tk()
    okno.bind('<MouseWheel>', priRolovani)
    text=Tkinter.Label(okno, text="SCROLUJ a ROLUJ!", font="Arial 20")
    text.pack(padx=40, pady=40)
    
    okno.mainloop()


   
Poloha kurzoru v textu
-----------------------------

::
  
    text.get(INSERT)  # zjisteni
    text.mark_set(INSERT, "2.7")  # nastaveni


Místní nabídka aneb menu na pravém tlačítku
-------------------------------------------
::

    from Tkinter import *
    root = Tk()
    
    def hello():
        print "hello!"
    
    def popup(event):
        menu.post(event.x_root, event.y_root)
    
    menu = Menu(root, tearoff=0)
    menu.add_command(label="Undo", command=hello)
    menu.add_command(label="Redo", command=hello)
    
    frame = Frame(root, width=512, height=512)
    frame.pack()
    
    frame.bind("<Button-3>", popup)
    
    mainloop()

Ovládání kurzoru myši
-----------------------
::

   widget.event_generate("<Motion>", warp=1, x=..., y=...) 


Aby podokno bylo aktivní
---------------------------
::

    podokno.focus_set()         # aby bylo okno aktivní
    podokno.transient(hlavni)   # je považováno za dialogové okno  - s minimalizací hlavního okna 
                                # se minimalizuje také, není vidět na hlavní liště 
    podokno.grab_set()          # aby nešlo zpátky přepnout do hlavního okna, dokud se neukončí podokno

Vycentrování okna na střed obrazovky
-----------------------------------------
::

    from Tkinter import *
    root = Tk()
    w=root.winfo_screenwidth()
    h=root.winfo_screenheight()
    sirka=400
    vyska=200
    root.geometry("%dx%d+%d+%d" % ( sirka, vyska, (w-sirka)/2, (h-vyska)/2 ) )
    root.mainloop()

Přesměrování výstupu do okna
---------------------------------
::

    # -*- coding: utf-8 -*- 
    
    from Tkinter import *
    from ScrolledText import ScrolledText
    import sys
    
    class py_message_box:
    
      def __init__(self, parent):
    
        self.frame = Frame(parent)
        self.frame.pack()
    
        self.text = ScrolledText(self.frame, background='black',
                    foreground='green', font=("Courier", 9))
        self.text.pack()
    
      def write(self, s):
        self.text.insert(END, s)
        self.text.see(END)  
    
    root=Tk() 
    text_window = py_message_box(root) 
    sys.stdout = text_window 
    sys.stderr = text_window
    
    for i in range(44):
        print i, "Toto je pokus o presmerovanie printu do okna"   # toto se vytiskne do GUI okna
    print tojealechyba  # a toto taky
    
    root.mainloop()

Maximalizace okna (win)
--------------------------
::

    from Tkinter import *
    okno=Tk()
    okno.wm_state('zoomed')
    mainloop()



..aneb co se v dokumentaci těžko hledá...

py25.png

Bez černého konzolového okna

Pokud nechceme, aby se otevíralo černé dosovské okno, stačí dát příponu programu *.pyw nebo ke spouštění použít místo python.exe pythonw.exe. Nevýhoda tohoto způsobu při vytváření aplikace je jasná: neuvidíte případné chybové hlášky a nebudete moci ani používat print.

Řešením tohoto problému nicméně může být přesměrování stdout a stderr do okna. Následující příklad to dělá. Okno pro výpisy je po spuštění zavřené a otevře se až v případě zápisu do stdout či stderr. Výpisy na stderr zobrazuje červeně. Okno je možné zavřít, v případě potřeby se zase otevře. Příklad

import sys
from Tkinter import *


hlavni=Tk()

_printtext = None

def getprinttext():
    global _printtext
    if _printtext == None:
        printwin = Toplevel()
        def reset():
            global _printtext
            _printtext = None
            printwin.destroy()
        printwin.protocol("WM_DELETE_WINDOW", reset)
        _printtext = Text(printwin)
        _printtext.pack(expand=True, fill=BOTH)
        _printtext.tag_config('out', foreground="black")
        _printtext.tag_config('err', foreground="red")
    return _printtext

class FakeStdOut(object):
    def write(self, what):
        getprinttext().insert(END, what, 'out')

class FakeStdErr(object):
    def write(self, what):
        getprinttext().insert(END, what, 'err')

oldso = sys.stdout
oldse = sys.stderr
sys.stdout = FakeStdOut()
sys.stderr = FakeStdErr()

def so():
    print 'aaaaaa'

def se():
    print >> sys.stderr, 'bbbbbbb'

try:
    Button(text="stdout", command=so).pack()
    Button(text="stderr", command=se).pack()
    Button(text="Sbohem", command='exit').pack()
    hlavni.mainloop()
except SystemExit:
    pass
except:
    sys.stdout = oldso
    sys.stderr = oldse
    import traceback
    traceback.print_exc()

Schování widgetu

Ukrytí widgetu se dá udělat pomocí metody widget.pack_forget() a následné zobrazení pomocí widget.pack(). U grid manageru je to widget.grid_remove() a zobrazení pak s widget.grid() a mělo by to být na tom samém místě.

Ukázka:

# -*- coding: utf8 -*-
"""Ukazkovy priklad v Tkinter."""

from Tkinter import *
priznak=True

def tisk():
   global priznak
   print priznak
   if priznak:
       listbox.pack_forget()
       tisk['text']='Zobrazit!'
   else:
       listbox.pack()
       tisk['text']='Schovat!'
   priznak = not priznak

hlavniOkno=Tk()
hlavniOkno.title('Aplikace v Tk')
ramec=Frame(hlavniOkno)
ramec.pack()

listbox=Listbox(ramec, selectmode=MULTIPLE)
seznam=['Python','C++', 'Java', 'Pascal', 'Basic']

for prvek in seznam:
   listbox.insert(END, prvek)

listbox.pack()
tisk=Button(hlavniOkno, text='Schovat!', command=tisk)
tisk.pack(ipadx=40)

mainloop()

Změna systémové ikony

Tak na tohle má Tkinter metodu iconbitmap. Použití je např. následující: root.iconbitmap("cherry.ico"), cherry.ico je soubor s ikonou ve formatu *.ico

Okno pořád na vrchu, okno nejde zavřít

Chcete aby bylo okno pořád vidět, aby se nedalo schovat za ostatní? a ještě aby nešlo standardním způsobem (křížek nebo Alt+F4) zavřít? Použijte následující kod:

root=Tk()                                      # okno
root.protocol('WM_DELETE_WINDOW', 0 ) # aby nešlo zavřít, místo 0 možno použít nějakou funkci na případnou hlášku
root.protocol('WM_TAKE_FOCUS', root.update )   # aby se stalo aktivním
root.wait_visibility(root)                     # aby fungoval následující řádek
root.attributes('-topmost',1)                  # aby bylo pořád navrchu

Okno bez rámu, bez ikony, bez title a bez ovládacích prvků

from Tkinter import *

root = Tk()
Label(root, text='No wm decorations').pack(padx=10, pady=10)
root.overrideredirect(1)
root.mainloop()

Pokud ještě potřebujete zobrazit aplikaci přes celou obrazovku a neznáte předem rozlišení, je možné přidat v předchozím kódu před mainloop():

w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d%+d%+d" % (w,h,0,0))

Hromadná změna vzhledu u všech widgetů

"Ošklivý" vzhled standardního vzhledu Tk oken můžete změnit pomocí databáze voleb (option database). Dá se to provést buď přímo v programu:

# -*- coding: utf8 -*-
from Tkinter import *

hlavni=Tk()

hlavni.option_add('*background','#797778')
hlavni.option_add('*Font', 'Verdana 20 bold')

# dalsi moznosti
# hlavni.option_add('*background','#797778')
# hlavni.option_add('*foreground','#fdfd02')
# hlavni.option_add('*EntryField.Entry.background', 'white')
# hlavni.option_add('*Entry.background', 'white')
# hlavni.option_add('*MessageBar.Entry.background', 'gray85')
# hlavni.option_add('*Listbox*background', 'dark green')
# hlavni.option_add('*Listbox*selectBackground', 'dark slate blue')
# hlavni.option_add('*Listbox*selectForeground', 'white')

w=Label( text="Ahoj světe!")
w.pack()

mainloop()

nebo načtením z externího souboru s nastaveními:

*font : Helvetica -12
*Entry*background : white
*Listbox*background : white
*Listbox*exportSelection : 0
*selectBackground : blue4
*selectForeground : white
*Scrollbar*takeFocus : 0
*Scrollbar*highlightThickness : 0
*Menu*tearOff : 0
atd.

Když uložíte toto jako "optionDB", tak pak následně v programu můžete nastavení načíst takto:

root = Tk()
root.option_readfile(<cesta-k-optionDB>)

Tk podporuje i barevná schémata. Následující kód nastaví modrý vzhled, ostatní barvy se vypočítají tak, aby byl zajištěn barevný kontrast všech prvků uživatelského rozhraní:

root = Tk()
root.tk_setPalette('blue')

Scrollování kolečkem myši

Scrolování textu pomocí kolečka myši umožňuje nedokumentovaná událost na Linuxech 'Button-4' a 'Button-5' a na Windows <MouseWheel>, kde existuje atribut 'delta', který udává směr.:

import Tkinter

def priRolovani(udalost):
    print "udalost:", udalost,"  ---  smer:", udalost.delta

okno=Tkinter.Tk()
okno.bind('<MouseWheel>', priRolovani)
text=Tkinter.Label(okno, text="SCROLUJ a ROLUJ!", font="Arial 20")
text.pack(padx=40, pady=40)

okno.mainloop()

Poloha kurzoru v textu

text.get(INSERT)  # zjisteni
text.mark_set(INSERT, "2.7")  # nastaveni

Místní nabídka aneb menu na pravém tlačítku

from Tkinter import *
root = Tk()

def hello():
    print "hello!"

def popup(event):
    menu.post(event.x_root, event.y_root)

menu = Menu(root, tearoff=0)
menu.add_command(label="Undo", command=hello)
menu.add_command(label="Redo", command=hello)

frame = Frame(root, width=512, height=512)
frame.pack()

frame.bind("<Button-3>", popup)

mainloop()

Ovládání kurzoru myši

widget.event_generate("<Motion>", warp=1, x=..., y=...)

Aby podokno bylo aktivní

podokno.focus_set()         # aby bylo okno aktivní
podokno.transient(hlavni)   # je považováno za dialogové okno  - s minimalizací hlavního okna
                            # se minimalizuje také, není vidět na hlavní liště
podokno.grab_set()          # aby nešlo zpátky přepnout do hlavního okna, dokud se neukončí podokno

Vycentrování okna na střed obrazovky

from Tkinter import *
root = Tk()
w=root.winfo_screenwidth()
h=root.winfo_screenheight()
sirka=400
vyska=200
root.geometry("%dx%d+%d+%d" % ( sirka, vyska, (w-sirka)/2, (h-vyska)/2 ) )
root.mainloop()

Přesměrování výstupu do okna

# -*- coding: utf-8 -*-

from Tkinter import *
from ScrolledText import ScrolledText
import sys

class py_message_box:

  def __init__(self, parent):

    self.frame = Frame(parent)
    self.frame.pack()

    self.text = ScrolledText(self.frame, background='black',
                foreground='green', font=("Courier", 9))
    self.text.pack()

  def write(self, s):
    self.text.insert(END, s)
    self.text.see(END)

root=Tk()
text_window = py_message_box(root)
sys.stdout = text_window
sys.stderr = text_window

for i in range(44):
    print i, "Toto je pokus o presmerovanie printu do okna"   # toto se vytiskne do GUI okna
print tojealechyba  # a toto taky

root.mainloop()

Maximalizace okna (win)

from Tkinter import *
okno=Tk()
okno.wm_state('zoomed')
mainloop()