Hlavní navigace

PyGTK 4: Kalkulačka a prohlížeč

25. 8. 2008
Doba čtení: 8 minut

Sdílet

Čtvrtý díl seriálu o PyGTK. Dnešní díl bude zaměřen již více na praxi. Probereme pár nových prvků a natrénujeme si dosavadní poznatky na vytvoření jednoduché kalkulačky a na vytvoření ještě jednoduššího textového prohlížeče.

Ještě než se vrhneme na kalkulačku a onen prohlížeč, je nutné si představit gtk.Entry(). gtk.Label(), gtk.TextView() a gtk.ScrolledWin­dow(), aneb teorii neutečete.

Popis jednotlivých widgetů není úplný, a to ani zdaleka. Jednotlivé widgety jsou plně popsány v referenční příručce.

gtk.Label()

Klasický nápis. Zatímco v Qt tento widget dokáže fungovat i jako zobrazovač obrázků a další možnosti, v GTK slouží jen a pouze svému účelu.
Přesto je dost věcí, co s ním lze dělat (natáčet, ohýbat…). Nás bude nejvíce zajímat zadání a přečtení textu.

vytvoření

nas_napis = gtk.Label(labe­max=0)

max – Maximální počet znaků. Výchozí je 0 – maximum. Jinak vkládat hodnotu mezi 0 a 65 536.

metody

set_label(str) – Nastavit text. Parametr je klasický řetězec.
get_label() – Získat text. Text je získán ve formátu klasický řetězec.

gtk.Entry()

Je to klasický widget pro získávání jednoduchých a jednořádkových údajů od uživatele. Jiná prostředí tomu říkají LineEdit, neboli editační linka.
Zde se zaměříme jen na základ, a to je vytvoření, přečtení obsahu a zápis obsahu.

vytvoření

nas_entry = gtk.Entry(max=0)

max – Maximální počet znaků. Výchozí je 0 – maximum. Jinak vkládat hodnotu mezi 0 a 65 536.

metody

set_text(text) – Nastavit text. Parametr je klasický řetězec.
get_text() – Získat text. Text je získán ve formátu klasický řetězec.
insert_text(text, position=0) – Vložit text. text je řetězec a position je index.

signály

„activate“ – editační linka byla aktivována (většinou stiskem Enteru)

gtk.TextView()

Další klasický widget. Tentokráte nejen řádka, ale celé textové pole, někde označované jako TextBox. To nám slouží k dvěma účelům. První a častější je zobrazení textu. Druhý, méně častý, je pak jeho editace. Získávání textu je ovšem složitější, proto jej zatím vynechám a v následujícím příkladu se omezím jen na zadávání.
Samotný TextView() je „rozdělen“ na dvě části. TextBuffer(), kde máme samotný text a TextView(), který nám slouží k jeho zobrazení. Od toho se odvíjí i jejich metody.

vytvoření

textovy_editor = gtk.TextView(buf­fer=None)

buffer – Onen textový buffer. Pokud jej nepřiřadíme při vytvoření, je nutno jej přiřadit později pomocí set_buffer().

gtk.TextBuffer()

vytvoření

textovy_buffer = gtk.TextBuffer(ta­ble=None)

table – Tabulka tagů pro formátování textu. Toto nás zatím zajímat nebude.

metody

set_text(text) – Nastavit text. Parametr je klasický řetězec.

Těch metod je u obou text objektů velké množství. To abyste se mohli dokonale v textovém editoru vyřádit. Pokud ale už teď myslíte na napsání vlastního editoru zdrojového kódu (třebas ten Python), tak zadržte. Onu práci správně nastavit textview a nějaké „fičurky“ navíc za vás už někdo udělal. Vznikl gtk.SourceView() a jak odkaz dokazuje, v PyGTK na něj máme binding a jistojistě se na něj později podíváme.

gtk.ScrolledWin­dow()

Jak na to si řekneme v jiném díle. Samotné GTK se dost drží unixové filosofie, každý -něco- bude dělat jen svou práci a bude ji dělat dobře. Toto je tedy widget, který umí „scrollovat“ prvky v sobě vložené. On totiž samotný TextView se roztáhne na velikost textu a to, že je to už hrubě mimo prostor obrazovky, ho nikterak nezajímá. Proto jej musíme vložit do toho widgetu, který přidává posuvníky a podle jejich pozice ukazuje část vloženého widgetu.

vytvoření

posuvnikove_okno = gtk.ScrolledWin­dow(hadjustmen­t=None, vadjustment=None)

hadjustment, vadjustment – Chování samotného posuvníkového okna (min. velikost, max.velikost, krok), zatím necháme výchozí.

metody

add_with_view­port(child) – vložit widget-child do ScrollWindow set_policy(hscro­llbar_policy, vscrollbar_policy) – Kdy se mají posuvníky objevit. Možnosti jsou:

  • gtk.POLICY_ALWAYS – vždy
  • gtk.POLICY_AU­TOMATIC – když je to třeba
  • gtk.POLICY_NEVER – nikdy

kalkulacka.py

#!/usr/bin/env python
#-*- coding: UTF-8 -*-
from __future__ import division

import sys

try:
    import pygtk
    pygtk.require("2.0")
    import gtk
except:
    print "Error: PyGTK and GTK 2.xx must be installed to run this application. Exiting"
    sys.exit(1)

class kalkulacka(gtk.Window):

    def __init__(self):
        gtk.Window.__init__(self)

        # Pomocná proměnná
        self.zadano = False

        # Hlavní prvky, linka a klávesnice
        self.zadavani = gtk.Entry()
        self.nakresli_klavesnici()

        # VBox
        self.vbox = gtk.VBox(False, 10)
        self.vbox.pack_start(self.zadavani, False)
        self.vbox.pack_end(self.tabulka)

        # Okno
        self.add(self.vbox)
        self.set_border_width(10)
        self.set_title("Kalkulačka")
        self.set_default_size(200, 200)
        self.connect("destroy", gtk.main_quit)

        self.show_all()

    def nakresli_klavesnici(self):
        " Vytvoření tabulky a její naplnění tlačítky"

        self.tabulka = gtk.Table(4, 4, True)
        self.tabulka.set_col_spacings(5)
        self.tabulka.set_row_spacings(5)

        self.klavesnice = []

        # Vytvoření a napojení tlačítek 0 - 9
        for i in xrange(10):
            self.klavesnice.append(gtk.Button(str(i)))
            self.klavesnice[i].connect("clicked", self.vloz_znak, str(i))

        # Vložení devíti kláves do tabulky
        for radek in xrange(3):
            for sloupec in xrange(3):
                klavesa = 3*radek+sloupec+1
                self.tabulka.attach(self.klavesnice[klavesa], sloupec, sloupec+1, 2-radek, 2-radek+1)

        self.tabulka.attach(self.klavesnice[0], 0, 1, 3, 4) # Vložení klávesy 0

        # Početní klávesy
        pocetni_klavesy = ["+", "-", "*", "/"]
        for radek in xrange(len(pocetni_klavesy)):
            klavesa = pocetni_klavesy[radek]
            self.klavesnice.append(gtk.Button(klavesa))
            self.tabulka.attach(self.klavesnice[10+radek], 3, 4, radek, radek+1)
            self.klavesnice[10+radek].connect("clicked", self.ukon, klavesa)

        # Nakonec klávesa = přes dvě políčka
        self.klavesnice.append(gtk.Button("="))
        self.klavesnice[14].connect("clicked", self.vysledek)
        self.tabulka.attach(self.klavesnice[14], 1, 3, 3, 4)

    def vloz_znak(self, widget, znak):
        " Obsluha vložení znaku - vykreslení jej na lince "

        # Pokud je toto druhé číslo/vstup, vymažeme předchozí
        if self.zadano:
            self.zadavani.set_text("")
            self.zadano = False

        # Text rozšíříme o náš znak (-1 je poslední pozice)
        self.zadavani.insert_text(znak, -1)

    def ukon(self, widget, ukon=None):
        " Přečtení úkonu a uložení prvního číslo k počítání "

        self.ukon = ukon
        self.x = self.zadavani.get_text()
        self.zadano = True

    def vysledek(self, widget):
        " Zobrazení výsledku "

        self.y = self.zadavani.get_text()

        self.vysledek = eval(self.x + self.ukon + self.y)
        self.zadavani.set_text(str(self.vysledek))

        self.zadano = True

if __name__ == "__main__":

    aplikace = kalkulacka()
    gtk.main()
pygtk4-kalkulačka

Rozbor

#-- coding: UTF-8 --

Informování Pythonu, že celý kód je v Unicode formátu a jako takový jej má i zpracovat, tudíž mohu dle libosti využívat české znaky jak v komentářích, tak řetězcích… i v proměnných, ale to se nedělá.

from __future__ import division

Vypůjčení si dělení z nadcházející verze Pythonu, která výsledek nevrací celočíselně, ale v desetinných místech.

def __init__(self)

Zde není co říci. Snad jen poznámka, že samotné kreslení klávesnice jsem dal do samostatné funkce, aby mi to __init__() příliž neznepřehlednilo.

# Vytvoření a napojení tlačítek 0 – 9

Zde předvádím, že prvky nemusí být jen samostatné proměnné, ale mohou být klidně i, v souladu s filosofií Pythonu, prvky v seznamu. Ten seznam generuji, abych nemusel psát hodně zbytečně se opakujícího se kódu.
Dále abych nemusel v callbacku zjišťovat, jaké že to tlačítko bylo stisknuto (hromada ifů), stejnak mě to zajímá jen kvůli vložení znaku do linky, předávám onen znak rovnou jako parametr ( str(i) )

# Vložení devíti kláves do tabulky

Opět se snažím si ulehčit práci. Takže i onu základní matici 3×3 tlačítek generuji.
Nejdřív musím zjistit, s jakou klávesou budu pracovat. To je 3*řádek (rozdělení kláves do trojic) + sloupec (jednotlivá klávesa z oné trojce) + 1 (nechci začínat od nuly, ale od jedničky).
Tlačítka pak umisťuji do tabulky. To sice fungovalo, ale řazena byla odshora dolů, což je pravý opak numerické klávesnice. Proto řádek v tabulce „invertuji“ 2-radek ⇒ místo 0,1,2 získám 2, 1, 0. Počítám si jen levou čáru políčka. Pravá je to samé + 1.

# Početní klávesy

Samotné klávesy jsem si hodil do seznamu, který pak probírám.

self.zadano

Pomocná proměnná, kterou si zjišťuji, zda při vkládání znaku do linky mám přidávat k existujícímu textu nebo ten text vymazat a začít od začátku.

root_podpora

prohlizec.py

#!/usr/bin/env python
#-*- coding: UTF-8 -*-

import sys

try:
    import pygtk
    pygtk.require("2.0")
    import gtk
except:
    print "Error: PyGTK and GTK 2.xx must be installed to run this application. Exiting"
    sys.exit(1)

class jednoduchy_textovy_prohlizec:

    def __init__(self):

        self.okno = gtk.Window()
        self.okno.set_title("Textový editor")
        self.okno.set_border_width(10)

        # Menu
        self.adresa = gtk.Entry()
        self.napis_adresa = gtk.Label("Adresa:")
        self.tlacitko_otevrit = gtk.Button("Otevřít")

        # Editor
        self.textovy_buffer = gtk.TextBuffer()
        self.textovy_prohlizec = gtk.TextView(self.textovy_buffer)
        self.posuvnikove_okno = gtk.ScrolledWindow()
        self.posuvnikove_okno.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.posuvnikove_okno.add_with_viewport(self.textovy_prohlizec)

        # Zabalení menu do HBoxu
        self.hbox_menu = gtk.HBox(False, 5)
        self.hbox_menu.pack_start(self.napis_adresa, False)
        self.hbox_menu.pack_start(self.adresa)
        self.hbox_menu.pack_start(self.tlacitko_otevrit, False)

        # Zabalení menu a editoru do VBoxu
        self.vbox = gtk.VBox(False, 5)
        self.vbox.pack_start(self.hbox_menu, False)
        self.vbox.pack_end(self.posuvnikove_okno)

        self.okno.add(self.vbox)
        self.okno.show_all()

        self.okno.connect("destroy", gtk.main_quit)
        self.adresa.connect("activate", self.precti_soubor)
        self.tlacitko_otevrit.connect("clicked", self.precti_soubor)

    def precti_soubor(self, widget):

        try:
            cesta_k_souboru = self.adresa.get_text()
            nazev_souboru = cesta_k_souboru.split("/")[-1]
            soubor = file(cesta_k_souboru, "r")
            self.textovy_buffer.set_text(soubor.read())
            soubor.close()
            self.okno.set_title(nazev_souboru)
        except:
            self.adresa.set_text("")
            self.okno.set_title("Textový editor")
            self.textovy_buffer.set_text("")

if __name__ == "__main__":

    aplikace = jednoduchy_textovy_prohlizec()
    gtk.main()
pygtk4-prohlizec

Rozbor

Zde snad ani není co rozebírat. Vše již bylo řečeno.

Příště

Budeme zkoumat samotné PyGTK a jeho referenční příručku.

Byl pro vás článek přínosný?