# TextView (JavaScript)

Taryn Fox
jewelfox@fursona.net 2012
Víceřádkový textový editor

# TextView

TextView (textové zobrazení) je ve skutečnosti, nebo alespoň většinou, sada tří vnořených objektů.

Vespod je TextBuffer. Ten uchovává vlastní text.

Uprostřed je TextView, což je widget, který umožňuje zobrazit a upravovat text z vyrovnávací paměti. Automaticky mění svoji velikost v závislosti na množství textu v něm.

Protože automatické změny mohou učinit `TextView` neprakticky použitelným, je běžnou praxí umístit jej do widgetu `ScrolledWindow`. Navzdory výrazu „window“ v názvu se nejedná o běžně známe okno se záhlavím a tlačítkem ×, ale o widget, který vložený do aplikace bude fungovat jako okno do lépe zvládnutého zobrazení textu. Když bude text ve vyrovnávací paměti delší, než se vleze, objeví se posuvníky.

Když chcete změnit text, který je v `TextView` zobrazen, musíte pracovat s objektem `TextBuffer`, protože právě v něm je text uložen. To samé platí, když chcete vidět, co někdo do něj napsal. Tato ukázková aplikace umožňuje promluvit si se (smyšleným) tučňákem a kontroluje `TextBuffer`, aby zjistila, jestli jste někde nenapsali slovo „fish“ (ryba).

Ve skutečném světe populace tučňáků rychle klesá, protože změny klimatu způsobují tání ledovců, na kterých žijí, a zabíjí ryby, které jí. Jestli si chcete v GNOME zahrát (poněkud bláznivou) hru založenou na tomto předpokladu, podívejte se na Pingus.

# Importované knihovny

#!/usr/bin/gjs

const Gtk = imports.gi.Gtk; const Lang = imports.lang;

Toto jsou knihovny, které potřebujeme naimportovat, aby aplikace běžela. Pamatujte si, že řádek, který GNOME říká, že používáme Gjs, musí být vždy na začátku.

# Vytvoření okna aplikace

const TextViewExample = new Lang.Class ({ Name: 'TextView Example',

// Vytvoří vlastní aplikaci _init: function () { this.application = new Gtk.Application ({ application_id: 'org.example.jstextview' });

// Připojí signály "activate" a "startup" k funkcím zpětného volání this.application.connect('activate', Lang.bind(this, this._onActivate)); this.application.connect('startup', Lang.bind(this, this._onStartup)); },

// Funkce zpětného volání pro signál "activate" zobrazujicí okno při aktivaci _onActivate: function () { this._window.present (); },

// Funkce zpětného volání pro signál "startup" sestavující uživatelské rozhraní _onStartup: function () { this._buildUI (); },

Všechen kód této ukázky je ve třídě `TextViewExample`. Výše uvedený kód vytvoří Gtk.Application pro naše widgety a okno, ve kterém budou.

// Sestaví uživatelské rozhraní aplikace _buildUI: function () {

// Vytvoří okno aplikace this._window = new Gtk.ApplicationWindow ({ application: this.application, window_position: Gtk.WindowPosition.CENTER, title: "Talk to a Penguin", default_height: 400, default_width: 440, border_width: 20 });

Funkce `_buildUI` je místo, ze kterého voláme všechen kód, který vytváří uživatelské rozhraní aplikace. Prvním krokem je vytvoření nového Gtk.ApplicationWindow, do kterého vložíme všechny naše widgety.

# Vytvoření TextView

// Vytvoří popisek přes který k vám bude promlouvat tučňák this._penguin = new Gtk.Label ({ height_request: 180, width_request: 400, label: "Squaaaak?", wrap: true });

Naším prvním krokem v tomto příkladu bude vytvořit Label, který tučňák používá k proslovům. Pomocí nastavení vlastnosti `wrap` na `true` zajistíme, že text se může zalamovat, ale u widgetu `TextView` použijeme jinou metodu, která nám umožní jemnější řízení.

// Vytvoří textové zobrazení, přes které můžete mluvit na tučňáka this.buffer = new Gtk.TextBuffer(); this._textView = new Gtk.TextView ({ buffer: this.buffer, editable: true, wrap_mode: Gtk.WrapMode.WORD });

Jako první krok je vytvořen `TextBuffer` pro vkládání slov. Po té zde vytvoříme `TextView` a řekneme mu, že má používat právě vytvořený `TextBuffer`. Rovněž se nastaví jako upravitelný, protože chceme mít možnost do něj psát nové věci.

Vlastnost `wrap_mode` dává možnost vybrat si ze čtyř různých režimů zalamování. Například `Gtk.WrapMode.CHAR` způsobí zalomení uprostřed slova, když budete pokračovat v psaní za okraj. Většina lidí pravděpodobně použije `Gtk.WrapMode.WORD`, který automaticky přesune psané slovo na další řádek, když je příliš dlouhé.

// Vytvoří okno s posuvníky pro vložení textového zobrazení, aby // mohlo posouvat svůj obsah this._scrolled = new Gtk.ScrolledWindow ({ hscrollbar_policy: Gtk.PolicyType.AUTOMATIC, vscrollbar_policy: Gtk.PolicyType.AUTOMATIC, shadow_type: Gtk.ShadowType.ETCHED_IN, height_request: 180, width_request: 400, });

// Vloží textové zobrazení do okna s posuvníky this._scrolled.add_with_viewport (this._textView);

Zde vytvoříme okno s posuvníky a nastavíme jej, aby automaticky poskytlo posuvníky, když dostaneme příliš velký obsah, ať už vodorovně nebo svisle. Rovněž získáme hezky vypadající okraj `ETCHED_IN` (prohnutý). Po té dovnitř vložíme `TextView` a řekneme oknu s posuvníky, aby nám pro něj poskytlo pohled.

# Vytvoření zbytku uživatelského rozhraní

// Vytvoří mřížku pro uspořádání widgetů this._grid = new Gtk.Grid ({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });

// Vloží popisek a textové zobrazení do mřížky, jeden nad druhý this._grid.attach (this._penguin, 0, 0, 1, 1); this._grid.attach (this._scrolled, 0, 1, 1, 1);

První widget Grid, který jsme vytvořili, má uvnitř jen popisek a okno s posuvníky.

// Vytvoří tlačítko pro odeslání vaší zprávy tučňákovi this._send = new Gtk.Button ({ halign: Gtk.Align.END, margin_top: 20, label: "Send" }); this._send.connect ('clicked', Lang.bind (this, this._chat));

// Vytvoří mřížku pro poddružnou mřížku nahoře a tlačítko dole this._mainGrid = new Gtk.Grid ({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });

// Přidá poddružnou mřížku a tlačítko do hlavní mřížky this._mainGrid.attach (this._grid, 0, 0, 1, 1); this._mainGrid.attach (this._send, 0, 1, 1, 1);

Vytvoříme widget Button, který odešle vaši zprávu tučňákovi, a mřížku, která bude nahoře obsahovat předchozí mřížku a dole tlačítko. Tlačítko má nahoře okraj, díky čemuž se nelepí na okno s posuvníky.

// Připojí hlavní mřížku do okna this._window.add (this._mainGrid);

// Zobrazení okno a všechny jeho synovské widgety this._window.show_all(); },

Nakonec připojíme hlavní mřížku do okna, kterému řekneme, aby sebe a vše v něm nastavilo jako viditelné, když se spustí aplikace.

# Funkce, která se stará o odpovědi tučňáka

_chat: function () {

// Vytvoří náhodné číslo, které určí, co tučňák řekne this.number = Math.floor ((Math.random() * 3) + 1);

// Řekli jste právě něco? if (this.buffer.text) {

// Zmínili jste rybu? if (this.buffer.text.match (/fish/gi)) {

// Tučňák musí zaskřehovat o rybě if (this.number == 1) this._penguin.set_label ("FISH!");

else if (this.number == 2) this._penguin.set_label ("Fish fish fish fish. Fish!");

else this._penguin.set_label ("Fish? Fish fish fish. Fish fish. FISH!");

}

// Myslím, že jsem se nezmínil o rybě else {

// Tučňák pokecá o všedních záležitostech tučňáků if (this.number == 1) this._penguin.set_label ("SQUAAK!");

else if (this.number == 2) this._penguin.set_label ("Ork ork ork ork squaak. Squaak squaak! *waves flippers*");

else this._penguin.set_label ("Ork ork ork ork ork?");

}

}

// Vymaže vyrovnávací paměť this.buffer.text = "";

// Předá zaměření zpět textovému zobrazení, abyste do něj nemuseli znovu klikat this._textView.has_focus = true;

}

});

Zde používámě některé základní funkce jazyka JavaScript k tomu, aby náš tučňák promluvil. Když na to přijde, tučňáci mají rádi ryby, takže pokud zmíníte rybu, chceme, aby na to tučňák reagoval. K tomu použijeme metodu objektu `String`, který má JavaScript zabudovaný, vůči `this.buffer.text`, což vrací obsah našeho objektu `TextBuffer`.

Protože chceme, aby se náš `TextBuffer` pokaždé, když kliknete na Send vymazal, nastavíme po té `this.buffer.text` na prázdný řetězec. Pak vrátím zaměření textovému zobrazení, takže můžete pokračovat v psaní, aniž byste na něj před tím museli klikat.

// Spustí aplikaci let app = new TextViewExample (); app.application.run (ARGV);

Nakonec vytvoříme novou instanci konečné třídy TextViewExample a aplikaci spustíme.

# Úplný kód ukázky

#!/usr/bin/gjs

const Gtk = imports.gi.Gtk; const Lang = imports.lang;

const TextViewExample = new Lang.Class ({ Name: 'TextView Example',

// Vytvoří vlastní aplikaci _init: function () { this.application = new Gtk.Application ({ application_id: 'org.example.jstextview' });

// Napojí signály "activate" a "startup" k funkcím zpětného volání this.application.connect('activate', Lang.bind(this, this._onActivate)); this.application.connect('startup', Lang.bind(this, this._onStartup)); },

// Funkce zpětného volání pro signál "activate" zobrazujicí okno při aktivaci _onActivate: function () { this._window.present (); },

// Funkce zpětného volání pro signál "startup" sestavující uživatelské rozhraní _onStartup: function () { this._buildUI (); },

// Sestaví uživatelské rozhraní aplikace _buildUI: function () {

// Vytvoří okno aplikace this._window = new Gtk.ApplicationWindow ({ application: this.application, window_position: Gtk.WindowPosition.CENTER, title: "Talk to a Penguin", default_height: 400, default_width: 440, border_width: 20 });

// Vytvoří popisek přes který k vám bude promlouvat tučňák this._penguin = new Gtk.Label ({ height_request: 180, width_request: 400, label: "Squaaaak?", wrap: true });

// Vytvoří textové zobrazení, přes které můžete mluvit na tučňáka this.buffer = new Gtk.TextBuffer(); this._textView = new Gtk.TextView ({ buffer: this.buffer, editable: true, wrap_mode: Gtk.WrapMode.WORD });

// Vytvoří okno s posuvníky pro vložení textového zobrazení, aby // mohlo posouvat svůj obsah this._scrolled = new Gtk.ScrolledWindow ({ hscrollbar_policy: Gtk.PolicyType.AUTOMATIC, vscrollbar_policy: Gtk.PolicyType.AUTOMATIC, shadow_type: Gtk.ShadowType.ETCHED_IN, height_request: 180, width_request: 400, });

// Vloží textové zobrazení do okna s posuvníky this._scrolled.add_with_viewport (this._textView);

// Vytvoří mřížku pro uspořádní widgetů this._grid = new Gtk.Grid ({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });

// Vloží popisek a textové zobrazení do mřížky, jeden nad druhý this._grid.attach (this._penguin, 0, 0, 1, 1); this._grid.attach (this._scrolled, 0, 1, 1, 1);

// Vytvoří tlačítko pro odeslání vaší zprávy tučňákovi this._send = new Gtk.Button ({ halign: Gtk.Align.END, margin_top: 20, label: "Send" }); this._send.connect ('clicked', Lang.bind (this, this._chat));

// Vytvoří mřížku pro poddružnou mřížku nahoře a tlačítko dole this._mainGrid = new Gtk.Grid ({ halign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER });

// Přidá poddružnou mřížku a tlačítko do hlavní mřížky this._mainGrid.attach (this._grid, 0, 0, 1, 1); this._mainGrid.attach (this._send, 0, 1, 1, 1);

// Připojí hlavní mřížku do okna this._window.add (this._mainGrid);

// Zobrazí okno a všechny jeho synovské widgety this._window.show_all(); },

_chat: function () {

// Vytvoří náhodné číslo, které určí, co tučňák řekne this.number = Math.floor ((Math.random() * 3) + 1);

// Řekli jste právě něco? if (this.buffer.text) {

// Zmínili jste rybu? if (this.buffer.text.match (/fish/gi)) {

// Tučňák musí zaskřehovat o rybě if (this.number == 1) this._penguin.set_label ("FISH!");

else if (this.number == 2) this._penguin.set_label ("Fish fish fish fish. Fish!");

else this._penguin.set_label ("Fish? Fish fish fish. Fish fish. FISH!");

}

// Myslím, že jsem se nezmínil o rybě else {

// Tučňák pokecá o všedních záležitostech tučňáků if (this.number == 1) this._penguin.set_label ("SQUAAK!");

else if (this.number == 2) this._penguin.set_label ("Ork ork ork ork squaak. Squaak squaak! *waves flippers*");

else this._penguin.set_label ("Ork ork ork ork ork?");

}

}

// Vymaže vyrovnávací paměť this.buffer.text = "";

// Předá zaměření zpět textovému zobrazení, abyste do něj nemuseli znovu klikat this._textView.has_focus = true;

}

});

// Spustí aplikaci let app = new TextViewExample (); app.application.run (ARGV);

# Dokumentace jdoucí do hloubky

Gtk.Application

Gtk.ApplicationWindow

Gtk.Button

Gtk.Grid

Gtk.Label

Gtk.RadioButton

Gtk.ScrolledWindow

Gtk.TextBuffer

Gtk.TextView