LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (126) - Gtk2 - textové okno a práce s pozicemi

Perl Základním widgetem pro zobrazování a editaci textu v Gtk2 je textové pole. Umí řadu zajímavých věcí - mimo očekávaných funkcionalit také formátování textu a vkládání widgetů. Na to vše je potřeba dobře rozumět reprezentaci pozic, což jsou objekty určující místa v textovém poli.

27.1.2011 00:00 | Jiří Václavík | Články autora | přečteno 6671×

Gtk2::TextView je často používaný widget na zobrazování a editaci textu. Tento widget má ještě podstatně více různých funkcí a nastavení, než textová pole v Tk a Wx, která jsme si již představovali.

Na úvod se podívejme na základní použití.

$text = Gtk2::TextView->new;
$buffer = $text->get_buffer();
$buffer->set_text("zkus sem neco napsat");

Právě jsme vytvořili textové pole a napsali do něj text. Uživatel ho může libovolně editovat.

.

Ukázka Gtk2::TextView

Na první pohled je kód zdánlivě zbytečně složitý (Proč nepoužít něco jako Gtk2::TextView->set_text? Proč to musíme řešit přes buffer?). Uvidíme, že to zas o tolik složitější není a že lze takto s textem pohodlně manipulovat. Text (společně s informací, jak má být zobrazen) je zde reprezentován speciálním widgetem Gtk2::TextBuffer a až ten můžeme nastavit pomocí set_buffer.

Podívejme se na úvod jen ve stručnosti na některé základní metody Gtk2::TextView.

MetodaVýznam
set_wrap_modemetoda zalamování; možné hodnoty jsou none, char nebo word
set_editablefalse pro read-only, true pro editaci
set_cursor_visibleviditelnost kurzoru (kurzor bychom měli schovat vždy, když používáme read-only režim)
set_justificationzarovnání textu; možné hodnoty jsou left, right, center
set_left_margin, set_right_marginokraje
set_indentodsazení

Existuje-li metoda s názvem set_něco, pak také často existuje metoda get_něco, která detekuje aktuální nastavení.

Objekt typu Gtk2::TextIter reprezentuje pozici v bufferu. Pozice je platná vždy jen do okamžiku, kdy se obsah bufferu (tj. text v Gtk2::TextView) změní. Protože často chceme pozice zachovat i po změně obsahu bufferu, byly vytvořeny objekty typu Gtk2::TextMark, což jsou hýbající se pozice.

Vlastnosti TextBufferu

Gtk2::TextBuffer je vytvořen vždy, když vytvoříme Gtk2::TextView. Samozřejmě si ale můžeme standardní cestou vytvořit TextBuffer vlastní.

$textbuffer = Gtk2::TextBuffer->new;

Podívejme se na metody, kterými lze s textem v TextBufferu manipulovat.

MetodaVýznam
set_textnastaví text
insert($textiter, $text)vloží $text na pozici $textiter (jak víme, pozice je objekt typu Gtk2::TextIter; více o tom dále)
insert_at_cursorvloží text na aktuální pozici
insert_range($kam, $zacatek, $konec)výsek určený dle $zacatek, $konec se uloží na pozici $kam
get_text($zacatek, $konec, $ukazat_skryte)vrátí výsek
get_slice($zacatek, $konec, $ukazat_skryte)vrátí výsek, obrázky budou vráceny jako znak 0xFFFC; více o tom dále
get_line_count, get_char_count zjistí počet řádků, resp. znaků

Práce s pozicemi

Již víme, že pozici v TextBufferu uchovává objekt Gtk2::TextIter. Podívejme se na to, jak s pozicemi pracovat. Pozici v bufferu definujeme jednou z následujících metod zavolaných nad TextBufferem.

PříkazKde se vytvoří TextIter?
$textiter=$textbuffer->get_start_iter;před prvním znakem
$textiter=$textbuffer->get_end_iter;za posledním znakem
$textiter=$textbuffer->get_iter_at_offset(50);před padesátým znakem
$textiter=$textbuffer->get_iter_at_line($radek);před prvním znakem řádku č. $radek
$textiter=$textbuffer->get_iter_at_line_offset(5, 10);před 10. znak na 5. řádku
$textiter=$textbuffer->get_iter_at_mark($mark);na pozici existujícícho Gtk2::TextMark
($ti1,$ti2)=$buffer->get_selection_bounds;na hranice vybrané oblasti

Nad objekty typu Gtk2::TextIter lze pak volat obrovské množství dalších metod. Podívejme se na seznam těch, které se mohou hodit.

MetodaVýznam
Detekce pozice v kontextu slov a řádků
starts_word, ends_word, inside_word, starts_sentence, ends_sentence, inside_sentence, starts_line, ends_line, is_end, is_start, is_cursor_positionzjišťování informací o pozici
in_range($zacatek, $konec)jsme v daném rozmezí?
Zjišťování absolutní pozice
get_offsetvrátí číslo znaku
get_linevrátí číslo řádku
get_line_offsetvrátí číslo znaku na řádku
Pohyb TextIterů
forward_char, backward_char, forward_word_end, backward_word_start, forward_sentence_end, backward_sentence_start, forward_line, backward_line, forward_to_line_end, forward_cursor_position, backward_cursor_position, forward_to_endpohyb na pozici v kontextu slov a řádků
forward_chars($kolik), backward_chars($kolik), forward_word_ends($kolik), backward_word_starts($kolik), forward_sentence_ends($kolik), backward_sentence_starts($kolik), forward_lines($kolik), backward_lines($kolik), forward_cursor_positions($kolik), backward_cursor_positions($kolik)to samé vícenásobně
set_offset($offset)nastaví na danou pozici
set_line($radek)nastaví na daný řádek
set_line_offset($offset_na_radku)nastaví na pozici na aktuálním řádku
Získávání textu z TextBufferu
get_char vrátí znak
get_text($do)vrátí úsek textu
get_slice($do)vrátí úsek textu
Detekce dalších objektů na dané pozici
get_marksvrátí seznam objektů Gtk2::TextMark
get_tagsvrátí seznam tagů, tj. objektů typu Gtk2::TextTag
get_pixbufvrátí seznam objektů Gtk2::PixBuf
get_child_anchorvrátí seznam objektů Gtk2::TextChildAnchor
has_tag, begins_tag, ends_tagdetekce tagů
Hledání v textu
forward_search($retezec, 'text-only', $kam_az)vrátí dvouprvkový seznam s počáteční a koncovou pozicí typu Gtk2::TextIter, hledání dopředu; druhý parametr je typu Gtk2::TextSearchFlags
backward_search($retezec, 'text-only', $kam_az)vrátí dvouprvkový seznam s počáteční a koncovou pozicí typu Gtk2::TextIter, hledání dozadu; druhý parametr je typu Gtk2::TextSearchFlags
Ostatní
get_attributesvrátí objekt typu Gtk2::TextAttributes

Gtk2::TextMark je podobný jako Gtk2::TextIter, avšak zachovává pozice při změnách TextBufferu.

Podívejme se opět, jak lze vytvořit objekt typu Gtk2::TextMark.

PříkazKde se vytvoří TextMark?
$textmark = $textbuffer->get_insertaktuální pozice kurzoru
$textmark = $textbuffer->get_selection_bounddruhý konec výběru (prvním koncem je pozice kurzoru)
$textmark = $textbuffer->create_mark($nazev, $textiter, $zleva)Gtk2::TextMark s názvem $nazev se vytvoří na pozici $textiter s tím, že při vkládání na tuto pozici se posouvá/neposouvá doleva

TextMarky lze ručně posouvat pomocí TextIterů jedním z následujících příkazů.

$textbuffer->move_mark($mark, $kam);
$textbuffer->move_mark_by_name($nazev, $kam); 

Metodou get_mark získáme objekt typu Gtk2::TextMark na základě svého názvu.

Tagy - formátování textu

Objekty typu Gtk2::TextTag jsou dalším obsahem TextBufferů. Obsahují informace o formátování. Každý tag funguje na daných pozicích a má nějaký svůj efekt (například zvětšuje písmo na druhém řádku).

Společně s bufferem se vždy vytvoří i objekt typu Gtk2::TextTagTable. Zde je uchováván seznam tagů.

Tag vytvoříme metodou create_tag zavolanou nad TextBufferem.

$tag = $textbuffer->create_tag($nazev, %vlastnosti); 

Poté jsou dvě možnosti, jak tagy aplikovat. Buď přímo nebo opět podle názvu.

$textbuffer->apply_tag($tag, $zacatek, $konec); 
$textbuffer->apply_tag_by_name($nazev, $zacatek, $konec);

Stejně tak můžeme tagy odstraňovat.

$textbuffer->remove_tag($tag, $zacatek, $konec); 
$textbuffer->remove_tag_by_name($nazev, $zacatek, $konec);

Vlastnosti lze nastavovat metodou set_property.

Pomocí set_priority nastavujeme pro tag prioritu mezi 0 a velikostí Gtk2::TextTagTable.

Podívejme se na hash parametrů, které ovlivňují chování tagu. Jaké všechny paramety můžeme používat?

KlíčVýznam a hodnoty
background, background-gdkbarva pozadí pomocí řetězce, resp, Gtk2::Gdk::Color
foreground, foreground-gdkbarva popředí pomocí řetězce, resp, Gtk2::Gdk::Color
background-stipple, foreground-stipplepoužije se na pozadí / popředí maska (bitmapa)
fontpísmo (například Times 12)
size, size-pointsvelikost písma v Pango bodech, resp. v bodech
scalerelativní velikost písma oproti okolí
font-descstyl písma (jako objekt typu Gtk2::Pango::FontDescription)
familynapříklad Times
underlinepodtržené písmo
style, variant, weight, stretchhodnoty jsou v dokumentaci
pixels-above-lines, pixels-below-linesmezera v pixelech nad / pod řádkem
wrap-modejak zalamovat (none, word, char)
justificationleft, right, center
directionsměr toku textu (right-to-left, left-to-right)
left-margin, right-marginokraje
indentodsazení odstavce
strikethroughdělení
riseposunutí nahoru (dolů při záporném parametru)
background-full-heightmá-li tag ovlivnit celý řádek ve smyslu barvy pozadí

Zkusíme si vytvořit nějaký tag.

$tag = $buffer->create_tag("zvyrazneny_text",
    "font" => "Helvetica 30",
    "underline" => PANGO_UNDERLINE_DOUBLE,
    "foreground" => "darkgreen",
    "background-gdk" => Gtk2::Gdk::Color->new(60, 0, 200)); 
$buffer->apply_tag($tag, $buffer->get_iter_at_offset(3), $buffer->get_iter_at_offset(7)); 

Výsledek spatříme po spuštění aplikace.

TextView s otagovaným úsekem textu

Vkládání widgetů

Do textového pole lze vkládat také obrázky nebo rovnou celé widgety. Obrázky reprezentované jako Gtk2::PixBuf můžeme vkládat metodou insert_pixbuf na danou pozici. Takový obrázek se bude chovat jako unicodový znak 0xFFFC.

$textbuffer->insert_pixbuf($textiter, $pixbuf) 

S widgety je to trochu složitější, ale v zásadě podobné. Vytvoříme objekt typu Gtk2::TextChildAnchor na místě, kde chceme, aby byl widget. Poté na toto místo widget vložíme.

$anchor = Gtk2::TextChildAnchor->new;
$textbuffer->insert_child_anchor($iter, $anchor);
$textview->add_child_at_anchor($widget, $anchor);

Ukážeme si konkrétnější příklad - TextView, do kterého vložíme text, obrázek a tlačítko.

$textview = Gtk2::TextView->new;
$buffer = $textview->get_buffer();
$buffer->set_text("nejaky text");

$tlacitko = Gtk2::Button->new("tlacitko");

$anchor = Gtk2::TextChildAnchor->new;
$buffer->insert_child_anchor($buffer->get_start_iter, $anchor);
$textview->add_child_at_anchor($tlacitko, $anchor);

$buffer->insert_pixbuf($buffer->get_start_iter, Gtk2::Gdk::Pixbuf->new_from_file("./Ghost.png"));

Text pak můžeme samozřejmě libovolně editovat. Vložené objekty se chovají jako znaky.

TextView s widgetem a obrázkem

Příklad - zvýraznění textu pod kurzorem myši

Ukážeme si, jak lze zachytávat pozici myši a manipulovat s textem (popřípadě tagem) na jejím aktuálním místě.

Díky signálu motion_notify_event, který je emitován při změně pozice myši nad daným widgetem můžeme vyvolat akci. Ta bude například zvýrazňovat místo, kde je aktuálně myš.

$textview->signal_connect(motion_notify_event => \&akce);

Díky metodě window_to_buffer_coords zjistíme pixelové souřadnice. Ty nám metoda get_iter_at_location převede na pozici v textu, tj. objekt typu Gtk2::TextIter. Pak není nic jednoduššího, než s danou pozicí manipulovat.

Vytvoříme tedy tag, kterým budeme zvýrazňovat aktuální znak.

my $tag = $buffer->create_tag(undef, "foreground" => "white", "background" => "black");

Aplikujeme ho. Na to ovšem musíme mít dva TextItery (potřebujeme začátek i konec tagu). Vytvoříme si tedy kopii našeho TextIteru a posuneme ho o pozici vpřed. TextIter nemá vhodný konstruktor na kopírování objektů a poradíme si tak trochu oklikou.

my $textiter2 = $buffer->get_iter_at_offset($textiter->get_offset);
$textiter->forward_char;
$buffer->apply_tag($tag, $textiter2, $textiter); 

Ještě bychom měli uchovávat starý tag a mazat ho po opuštění pozice. Zavedeme si tedy proměnnou $kurzor_tag, která bude reprezentovat týž objekt jako $tag do doby, než $tag zapomeneme. Tag pak smažeme přes tabulku tagu, kterou získáme z bufferu.

my $table = $buffer->get_tag_table;
$table->remove($kurzor_tag) if defined $kurzor_tag;

Podívejme se na celý zdrojový kód naší akce.

sub akce {
    my($textview, $udalost) = @_;
    my $textiter = $textview->get_iter_at_location(
$textview->window_to_buffer_coords("widget",$udalost->x, $udalost->y));
    my $textiter2 = $buffer->get_iter_at_offset($textiter->get_offset);
    $textiter->forward_char;
    my $tag = $buffer->create_tag(undef, "foreground" => "white", "background" => "black");
    my $table = $buffer->get_tag_table;
    $table->remove($kurzor_tag) if defined $kurzor_tag;
    $buffer->apply_tag($tag, $textiter2, $textiter); 
    $kurzor_tag=$tag;
}

Vidíme, že na místě kurzoru se aplikoval náš tag

tag pod kurzorem myši

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

5.3.2017 19:12 /Redakce Linuxsoft.cz
PR: 23. března proběhne v Praze konferenci na téma Cloud computing v praxi. Hlavními tématy jsou: Nejžhavější trendy v oblasti cloudu a cloudových řešení, Moderní cloudové služby, Infrastruktura současných cloudů, Efektivní využití cloudu, Nástrahy cloudových řešení a jak se jim vyhnout.
Přidat komentář

27.2.2017 22:12 /František Kučera
Pozvánka na 137. sraz OpenAlt – Praha: Tentokrát jsme si pro vás připravili neobvyklou akci. Ve středu 1.3. v 17:30 nás přivítá sdružení CZ.NIC ve svých prostorách v Milešovské ulici číslo 5 na Praze 3, kde si pro nás připravili krátkou prezentaci jejich činnosti. Následně navštívíme jejich datacentrum pod Žižkovskou věží. Provedou nás prostory, které jsou běžnému smrtelníkovi nedostupné!
Po ukončení prohlídky se všchni odebereme do hostince U vodoucha, Jagelonská 21, Praha 3 pochutnat si na některém z vybraných piv či dát si něco na zub. Rezervaci máme od 19:30, heslo je OpenAlt.
Ale pozor! Do prostor datového centra máme omezený přístup, dostane se tam pouze 10 lidí! Takže kdo přijde dříve, ten má přednost, a občanky s sebou! Kdo nebude chtít na prohlídku datového centra, může se pomalu přesunout do hostince U vodoucha a u nepřeberné nabídky piv počkat na ostatní.
Přidat komentář

18.1.2017 0:49 /František Kučera
Členové a příznivci spolku OpenAlt se pravidelně schází v Praze a Brně. Fotky z pražských srazů za uplynulý rok si můžete prohlédnout na stránkách spolku. Příští sraz se koná už 19. ledna – tentokrát je tématem ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. Také budete mít příležitost si prohlédnout pražský hackerspace Brmlab.
Přidat komentář

8.1.2017 17:51 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 19. ledna od 18:30 v pražském hackerspacu Brmlab. Tentokrát je tématem srazu ergonomie ovládání počítače – tzn. klávesnice, myši a další zařízení. K vidění bude mechanická klávesnice dasKeyboard, trackball Logitech nebo grafický tablet (a velký touchpad) Wacom. Přineste i vy ukázat svoje zajímavé klávesnice a další HW. V 18:20 je sraz před budovou, v 18:30 jdeme společně dovnitř, je tedy dobré přijít včas. Podle zájmu se později přesuneme do nějaké restaurace v okolí.
Přidat komentář

1.12.2016 22:13 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Přijď na sraz spolku OpenAlt, který se bude konat ve čtvrtek 8. prosince od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Sraz bude tentokrát tématický. Bude retro! K vidění budou přístroje jako Psion 5mx nebo Palm Z22. Ze svobodného hardwaru pak Openmoko nebo čtečka WikiReader. Přijďte se i vy pochlubit svými legendami, nebo alespoň na pivo. Moderní hardware má vstup samozřejmě také povolen.
Komentářů: 1

4.9.2016 20:13 /Pavel `Goldenfish' Kysilka
PR: Dne 22.9.2016 proběhne v Praze konference Cloud computing v praxi. Tématy bude např. nejnovější trendy v oblasti cloudu a cloudových řešení, provozování ERP v cloudu, o hostování různých typů softwaru, ale třeba i o zálohování dat nabízeném podnikům formou služby.
Přidat komentář

1.9.2016 11:27 /Honza Javorek
Česká konference o Pythonu, PyCon CZ, stále hledá přednášející skrz dobrovolné přihlášky. Máte-li zajímavé téma, neváhejte a zkuste jej přihlásit, uzávěrka je již 12. září. Konference letos přijímá i přednášky v češtině a nabízí pomoc s přípravou začínajícím speakerům. Řečníci mají navíc vstup zadarmo! Více na webu.
Přidat komentář

27.8.2016 8:55 /Delujek
Dnes po 4 letech komunitního vývoje vyšla diaspora 0.6.0.0
diaspora* je open-source, distribuovaná sociální síť s důrazem na soukromý
Více v oficiálním blog-postu
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

24.3.2017 11:54 / Hui
country cottages

16.3.2017 16:33 / BezvaDesign.cz
Re: Hledám grafika do teamu

9.3.2017 11:44 / Jaromir Obr
Re: chyba

18.1.2017 20:18 / martin horky
Spolupraca linuxu a microsoftu

17.1.2017 9:57 / Pavel Hrubeš
Re: Externí USB televizní karta

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2017) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze