Dokončení barevné syntaxe.
V předchozím díle by se leckterý čtenář mohl myslet, že je vše již hotovo, ale ti pozornější si jistě všimli, že pokud vložíme (Ctrl + V) nějaký text, neobarví se. Dnes bychom měli ošetřit tyto chyby.
Kostra třídy
Část třídy byste měli mít již hotovou z předchozí lekce (metody klavesa, obarvi_radek, obarvi_str).
from Tkinter import*
import __builtin__,keyword
class BarevnaSyntax:
def __init__(self,text,slovnik):
self.slovnik=slovnik
self.text=text
self.text.bind_class("Text","<Key>", self.klavesa)
self.text.bind_class("Text", "<BackSpace>", self.backspace)
self.text.bind_class("Text", "<Return>",self.enter)
self.text.bind_class("Text","<Delete>",lambda e:self.backspace(e,"insert"))
self.text.bind_class("Text", "<space>", self.space)
self.text.unbind("<<cut>>")
self.text.unbind("<<paste>>")
self.text.bind_class("Text", "<Control-v>",self.vloz)
self.text.bind_class("Text", "<Control-x>",self.vyjmout)
def obarvi_radky(self, i1,i2):
pass
def vloz(self, akce):
pass
def vyjmout(self, akce):
pass
def space(self, akce):
pass
def enter(self, akce):
pass
def vrat_radek(self, index):
pass
def backspace(self, akce,posun="insert-1c"):
pass
def klavesa(self,akce):
pass#Tuto metodu byste měli mít již hotovou
def obarvi_radek(self,radek):
pass#Tuto metodu byste měli mít již hotovou
def obarvi_str(self,co,radek):
pass#Tuto metodu byste měli mít již hotovou
def test():
slovnik={}
for prvek in keyword.kwlist:
slovnik[prvek]="klicove_slovo"
for prvek in dir(__builtin__):
slovnik[prvek]="funkce"
text=Text(font="Courier 10")
text.pack()
text.tag_config("funkce",foreground="#900090")
text.tag_config("klicove_slovo",foreground="#ff8000")
text.tag_config("str",foreground="#00aa00")
BarevnaSyntax(text,slovnik)
mainloop()
if __name__ == "__main__":
test()
Postupně si rozebereme všechny metody.
vrat_radek
Jelikož metoda obarvi_radek musí dostat jako parametr číslo řádku, který se má obarvit, musíme každý Textový index předtím, než ho předáme metodě obarvi_radek, rozdělit na dvě části (číslo řádku, číslo znaku). O to se právě stará metoda vrat_radek. Neměla by dělat nic jiného než:
>>> print self.vrat_radek(1.0)
1
obarvi_radky
Tato funkce přijímá jako parametry čísla dvou řádků. Text mezi nimi (včetně samotných řádků) se musí obarvit. Použijeme proto cyklus for:
for x in range(int(i1),int(i2)):
self.obarvi_radek(x)
Ale musíme se zamyslet nad speciálním případem, totiž, když se i1 == i2, tak se daný řádek neobarví. Ale toto zvládnete už určitě ošetřit sami.
backspace
Tato metoda přijímá jako parametr posun="insert-1c". Toto si vysvětlíme u akce <Delete>. Předchozí znak se vyjádří jako "insert-1c" a protože je to stejné jako parametr posun, použijeme posun.
self.text.delete(posun)
Nyní by se měl text také přebarvit. To se dá udělat jednoduše pomocí metody
self.obarvi_radek(self.vrat_radek(INSERT))
Nyní by se dalo říct, že metoda backspace je hotova, ale není tomu tak. Nesmíme zapomenout na to, že nějaký text mohl být vybraný v době, kdy uživatel zmáčkl klávesu Backspace. Proto to musíme ošetřit následujícím způsobem:
try:
i1=self.vrat_radek(SEL_FIRST)
i1=self.vrat_radek(SEL_LAST)
self.text.delete(SEL_FIRST,SEL_LAST)
self.obarvi_radky(i1,i2)
except:
pass#Smaž předchozí znak+obarvi řádek
Delete
Jistě jste si všimli, že ve funkci __init__ se místo self.delete volá
lambda e:self.backspace(e,"insert")
Je to z jednoho prostého důvodu, a to, že rozdíl mezi Delete a Backspace je pouze jeden. Backspace maže dozadu a Delete dopředu. Proto stačí, když předáme funkci self.backspace jako parametr posun "insert".
enter
Co se vlastně stane, když uživatel zmáčkne Enter? Na aktuální pozici se vloží znak nového řádku, popřípadě se ještě smaže vybraný text. Když si toto uvědomíme, není již problém napsat metodu self.enter:
def enter(self, akce):
#smaž vybraný text
#i=aktuální řádek
#vlož "\n" na aktuální pozici
#obarvi radek "i"
#obarvi aktuální řádek
pass
space
Nyní musíme trochu upravit kód v metodě self.obarvi_radek. Nahraďte
if self.text.compare(self.text.index(start),">",self.text.index('%s.end'%radek)):
break
následujícím kódem
if self.text.compare(self.text.index(start),">=",self.text.index('%s.end'%radek)):#rozdíl je v znaménku
break
Tato funkce bude prakticky stejná jako self.enter. Na začátku vložíme mezeru, pak smažeme vybraný text a nakonec obarvíme dva nebo jeden řádek (v závislosti na tom, jestli byl nějaký text vybrán).
vloz
Myslím, že po těch několika metodách, co jste dneska napsali, si již dovedete celkem slušně představit, co se v této funkci bude dít, a proto to pouze nastíním:
def vloz(self, akce):
#Smaž vybraný text
#i1=číslo řádku s INSERT
self.text.event_generate("<<Paste>>")
#i2=číslo řádku s INSERT
#obarvi řádky i1 až i2
Použili metodu event_generate, kterou jsme si představili v druhé lekci textového editoru. Pomocí ní řekneme udělátku Text, aby vložil text ze schránky.
vyjmout
Tato funkce je vlastně skoro stejná jako funkce self.vloz, až na to, že nemažeme vybraný text a místo "Paste" použijeme "Cut".
Poslední věc, co musíme udělat, je mírně upravit metodu self.klavesa. Chyba je v tom, že tato metoda se zavolá, pokud uživatel zmáčkne například Ctrl, F1, F2, atd… Tyto klávesy by se proto měly filtrovat:
if len(akce.char) == 0:#Přidejte tento kód na začátek funkce self.klavesa
return
Tímto dnešní díl končí.