× Aktuálně z oboru

Programátoři po celém světě dnes slaví Den programátorů [ clanek/2018091300-programatori-po-celem-svete-dnes-slavi-den-programatoru/ ]
Celá zprávička [ clanek/2018091300-programatori-po-celem-svete-dnes-slavi-den-programatoru/ ]

Barevná syntaxe v udělátku Text

[ http://programujte.com/profil/1835-jakub-vojacek/ ]Google [ ?rel=author ]       [ http://programujte.com/profil/118-zdenek-lehocky/ ]Google [ ?rel=author ]       28. 9. 2007       12 643×

Ukázka, jak docílit barevné syntaxe v udělátku Text pomocí tagů.

Naprogramovat barevnou syntaxi v Tkinteru není nic tak složitého. Použijeme několik nových metod souvisejících s tagy a naučíme se používat Tkinterovské výrazy. Jako vzor budeme mít IDLE, ale budeme obarvovat pouze řetězce, klíčová slova a názvy vybraných funkcí.

Další způsoby indexace

V první lekci o textovém editoru jsme si ukazovali některé způsoby indexace. Dnes si tento seznam rozšíříme o několik dalších:

  • CURRENT – Jedná se o index, který je nejbližší aktuální poloze myši.
  • "@x,y" – Zjistí, jaký textový index je na souřadnicích x,y.

Výrazy

Pomocí výrazů můžete upravovat jakýkoliv textový index. Tyto výrazy jsou:

  • "+2 chars" – přičte k indexu 2 znaky. Takže z 1.0 se stane 1.2
  • "-2 chars" – odečte z indexu 2 znaky. Takže z 1.2 se stane 1.0
  • "+ 2 lines" a "- 2 lines" – posouvá pozici po celých řádcích dopředu nebo dozadu. Je-li to možné, pozice sloupce se zachovává, je-li řádek příliš krátký, je pozice na konci toho řádku.
  • "wordstart" a "wordend" – posune pozici na začátek nebo konec slova. Slova jsou posloupnosti znaků, číslic a podtržítka nebo jediného nemezerového znaku.

Je možné používat pro chars zkratku c a pro lines zkratku l. Takže pár příkladů:

"%s wordstart" % CURRENT#Vrátí začátek slova, na kterém se právě nachází myš
"insert -5c" #značí 5 znaků před aktuální pozicí

A tady už je praktická ukázka:


# -*- coding: cp1250 -*-
#Po kliknutím myši vypíše text, na kterém se právě nachází kurzor myši.

from Tkinter import*
okno=Tk()
text=Text()
text.pack()

def akce(akce):
    print text.get(text.index("%s wordstart" % CURRENT),text.index("%s wordend"%CURRENT))

text.bind('<1>',akce)
mainloop()

Kostra třídy

Princip celého programu bude v tom, že se bude obarvovat pouze ta řádka, na které právě píšeme, protože barvení celého obsahu udělátka při každém stisknutí klávesy by bylo časově náročné. Takže pokud vložíte do Textu nějaký text, neobarví se. Tento nedostatek se pokusíme opravit v další lekci.

# -*- coding: cp1250 -*-
from Tkinter import*
import __builtin__,keyword#Z těchto modulů budeme načítat slova k obarvení.

class BarevnaSyntax:
    def __init__(self,text,slovnik):
        self.slovnik=slovnik
        self.text=text
        self.text.bind_class("Text","<Key>",self.klavesa)
    def klavesa(self,evt):

        pass
    def obarvi_radek(self,radek):

        pass
    def obarvi_str(self,co,radek):

        pass


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()

Ve funkci __init__ jsme použili metodu bind_class(udělátko, akce, funkce). Rozdíl mezi bind_class a bind je ten, že v případě bind("") se nejprve zavolá vámi definovaná funkce a pak teprve standardní metoda udělátka na vložení písmena. Pokud ale použijeme bind_class, nezavolá se žádná interní metoda, která by písmeno do textu vložila, takže ho tam budeme muset vložit my. Proto upravíme metodu klavesa:

def klavesa(self,akce):
    #Smaž vybraný text.
    self.text.insert(INSERT,akce.char)#v akce.char je uloženo písmeno, které jsme zmáčkli.
    #Tady později zavoláme metodu na obarvení řádku.

Ještě bychom měli ošetřit událost, co se stane, pokud je nějaký text vybraný a uživatel zmáčkne klávesu. V takové situaci by se měl vybraný text před vložením stisknutého znaku smazat.

Obarvení řetězce

Řetězec bude moci být uvozen klasickými uvozovkami (") a apostrofem ('). Ze všeho nejdříve musíme zjistit, jaké části textu přiřadíme tag. Na to použijeme metodu udělátka Text text.search(co,start, stopindex). Program se vždy bude snažit najít dvě párové uvozovky. Tím pádem můžou nastat 3 případy:

  • Program nalezne dvě párové uvozovky – obarví prostor mezi nimi.
  • Program nalezne pouze jednu uvozovku – obarví prostor od uvozovky až do konce řádku.
  • Program nenalezl žádnou uvozovku – program vyskočí z cyklu.
def obarvi_str(self,co,radek):
    start='%s.0' % radek#řádek, který obarvuji
    
    while 1:
        seznam=[]
        for x in range(2):
            pos=self.text.search(co,start, stopindex='%s.end'%self.text.index(radek).split('.')[0])
            
            if not pos:#Program nic nenalezl...
                break
            seznam.append(pos)
        #Seznam nyní obsahuje maximálně 2 indexy. Nyní by měla následovat kontrola, jakou jsem načrtl před chvílí.

Obarvení funkcí a klíčových slov

Programu budeme data předávat ve tvaru slovníku, který by mohl vypadat takto:

slovnik={"None":"funkce","if":"klicove_slovo", "del":"klicove_slovo"}
#"funkce" a "klicove_slovo" budou předdefinované tagy

Nyní musíme vymyslet, jak poznat, kterou část obarvit. Nejlepší řešení je asi použít wordstart a wordend. Tedy, procházet všechna slova na řádce a pokud je nějaké ve slovníku slov k obarvení, obarvit ho.

def obarvi_radek(self,radek):
    radka=self.text.get('%s.0'%radek,'%s.end' % radek)#aktuální řádek

    start='%s.1'%radek#začni hledat na prvním slově

    while 1:
        #zacatek=začátek aktuálního slova
        #konec=konec aktuálního slova
        slovo=self.text.get(zacatek,konec)#aktuální slovo
        
        #Kontrola, jestli nalezené slovo není v self.slovnik.
        
        #Zvětšení hodnoty start.

        if self.text.compare(self.text.index(start),">",self.text.index('%s.end'%radek)):
            break

    self.obarvi_str("'",radek)
    self.obarvi_str('"',radek)

Než začneme obarvovat, musíme odstranit všechny tagy z aktuálního řádku, aby bylo obarvení korektní. O to by se měly postarat metody tag_names [ http://www.tkintercz.wz.cz/text.htm#Tkinter.Text.tag_names-method ] a tag_remove [ http://www.tkintercz.wz.cz/text.htm#Tkinter.Text.tag_remove-method ]. Jelikož metoda tag_names přijímá jako argument pouze jeden index, musíme s ní prozkoumat celý řádek znak po znaku:

for x in range(len(radka)):
    jmena=self.text.tag_names('%s.%s' % (radek,x))

Nyní je na vás, abyste nalezené tagy odstranili. Problém obarvení slova se dá vyřešit pomocí metod has_key a tag_add. Teď stačí zvýšit hodnotu start a metoda je hotová. Nejjednodušší řešení by bylo prostě:

start=start+"+1c"

Ale toto by bylo zbytečně časově náročné, protože každé slovo by se obarvovalo víckrát. Proto navrhuji k hodnotě start přičíst délku nalezeného slova.

Ještě jedna metoda vám je neznámá, a to metoda compare [ http://www.tkintercz.wz.cz/text.htm#Tkinter.Text.compare-method ]. S její pomocí můžeme zjistit vztah mezi dvěma indexy (větší, menší, rovno, …). V našem případě kontroluje, jestli je vyhledávaný index pořád na stejné řádce. Pokud není, program vyskočí z cyklu. Nyní musíme dopsat volání metody self.obarvi_radek z metody self.klavesa:

#Přidejte tento kód na konec metody self.klavesa.
self.obarvi_radek(self.text.index(INSERT).split('.')[0])#Jako argument předej číslo řádku

Tím je naše třída hotova.

Náš program má stále určité nedostatky, v dalším díle se je pokusíme opravit.


Článek stažen z webu Programujte.com [ http://programujte.com/clanek/2007092003-barevna-syntaxe-v-udelatku-text/ ].