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 7846×

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ů

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

18.6.2018 0:43 /František Kučera
Červnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 21. 6. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: F-Droid, aneb svobodný software do vašeho mobilu. Kromě toho budou k vidění i vývojové desky HiFive1 se svobodným/otevřeným čipem RISC-V.
Přidat komentář

23.5.2018 20:55 /Ondřej Čečák
Od pátku 25.5. proběhne na Fakultě informačních technologií ČVUT v Praze openSUSE Conference. Můžete se těšit na spostu zajímavých přednášek, workshopů a také na Release Party nového openSUSE leap 15.0. V na stejném místě proběhne v sobotu 26.5. i seminář o bezpečnosti CryptoFest.
Přidat komentář

20.5.2018 17:45 /Redakce Linuxsoft.cz
Ve čtvrtek 31. května 2018 připravuje webový magazín BusinessIT ve spolupráci s Best Online Média s.r.o. pátý ročník odborné konference Firemní informační systémy 2018. Akce proběhne v kongresovém centru Vavruška (palác Charitas), Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 15 hod. odpoledne. Konference je zaměřena na efektivní využití firemních informačních systémů a na to, jak plně využít jejich potenciál. Podrobnější informace na webových stránkách konfrence.
Přidat komentář

14.5.2018 7:28 /František Kučera
Květnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 17. 5. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát na téma: Audio – zvuk v GNU/Linuxu.
Přidat komentář

7.5.2018 16:20 /František Kučera
Na stránkách spolku OpenAlt vyšla fotoreportáž Pražské srazy 2017 dokumentující srazy za uplynulý rok. Květnový pražský sraz na téma audio se bude konat 17. 5. 2018 (místo a čas ještě upřesníme).
Přidat komentář

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

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

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

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