Java (28) - renderery a editory
Při tvorbě GUI si většinou vystačíme s tím, co nám poskytují existující
grafické komponenty. Někdy je ale lepší chování komponent nějak změnit
- a jejich modulární stavba to velice dobře umožňuje. Pojďme se podívat na to,
jak upravit způsob vykreslování a editace dat.
2.10.2006 06:00 |
Lukáš Jelínek
| Články autora
| přečteno 25222×
Vykreslovače čili renderery
Složitější grafické komponty ve Swingu jsou hierarchicky složeny z komponent
menších, jednodušších. Například minule popisované tabulky mají vnitřní
strukturu poměrně komplikovanou, skládají se z řady různých grafických
objektů. Patří mezi ně i objekty, které slouží k vykreslování dat obsažených
v tabulce (resp. jiné komponentě, pokud bychom to brali obecně). Říká se jim
renderery a používají se proto, že mít samostatnou komponentu pro každou
hodnotu by bylo pomalé a paměťově náročné. A protože mají renderery jednoduché
a snadno implementovatelné rozhraní, není vůbec problém nahrazovat je jinými
implementacemi.
Na začátku myšlenky vytvoření vlastního rendereru je nějaký požadavek, který
nelze stávajícími prostředky realizovat. Můžeme například potřebovat, aby se
záporná čísla v tabulce (třeba jen v některých buňkách) zobrazovala červeně.
Lze se vydat dvěma cestami - buď si třídu napsat kompletně celou, nebo využít
nějakou hotovou implementaci (nejčastěji tu výchozí) a jen změnit potřebné věci.
První cesta se používá pro změny zásadního charakteru, často bude vhodnější ta
druhá.
Podívejme se nyní, jak by vypadal onen zmíněný případ, že bychom chtěli
zobrazovat záporná čísla červeně. Upravená implementace rendereru bude
vycházet z té výchozí (DefaultTableCellRenderer ) a bude fungovat pro všechny
číselné datové typy.
class MyRenderer extends DefaultTableCellRenderer {
public MyRenderer() {
super();
setHorizontalAlignment(RIGHT);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
c.setForeground(null);
if (Number.class.isAssignableFrom(value.getClass())) {
if (((Number) value).doubleValue() < 0.0) {
c.setForeground(Color.RED);
}
}
return c;
}
}
Nejprve je nutné si říci, jak se vlastně renderer zvenku používá. Z tabulky
se zavolá metoda getTableCellRendererComponent() , ve které renderer vrátí
grafickou komponentu (odvozenou od java.awt.Component ) určenou pro vykreslení
dané buňky. Třída DefaultTableCellRenderer je potomkem JLabel , je tedy
schopna zobrazovat hodnoty a vrátí proto referenci přímo na sebe.
Při implementaci začneme konstruktorem. Ten zavolá konstruktor předka a pak
nastaví zarovnávání textu (vpravo). To je důležité, jinak by se zarovnávalo výchozím
způsobem, tedy nalevo. Všimněte si, že pokud tabulce nenastavíte žádný renderer,
budou se číselné hodnoty zarovávat automaticky vpravo. JTable totiž nepoužívá
přímo třídu DefaultTableCellRenderer , nýbrž její speciální verze pro jednotlivé
datové typy (třeba pro třídy Float a Double bere v úvahu ještě nastavený formát
desetinných čísel). Tady se ale o nastavení musíme postarat sami.
Nyní už se pustíme do hlavní metody - getTableCellRendererComponent() . Stačí
zjistit, že je hodnota ze třídy Number (resp. nějakého potomka, což jsou všechny
číselné třídy) a provést test na zápornost hodnoty. Lze to provést různě, zde
v příkladu se testuje kompatibilita hodnoty s třídou Number metodou
isAssignableFrom() , ale šlo by to udělat i prostým přetypováním a odchycením
výjimky ClassCastException , protože výskyt nesprávného typu může být pouze
výsledkem nesprávného použití. Následně se pak provede porovnání pro zjištění
zápornosti.
Velice důležité je správné naložení s nastavením barvy. Pokud bychom totiž
pouze nastavili barvu popředí (červenou) v těch případech, kdy to potřebujeme,
dočkali bychom se nepříjemného efektu. Červená barva by se použila i u
dalších buněk (pokud by nebyly vybrány). Proto je potřeba barvu resetovat -
můžeme klidně použít null , protože pak se automaticky použije výchozí barva
tabulky (což je vhodnější přístup než hádat nebo nějak komplikovaně zjišťovat,
jaká barva se má ve výchozím případě použít).
Tak to by byla implementace, a teď to ještě musíme použít v tabulce. Třeba
takto:
MyRenderer mr = new MyRenderer();
JTable table = new JTable();
table.setDefaultRenderer(Number.class, mr);
Vytvoří se instance rendereru a ta se přiřadí tabulce k použití pro hodnoty
třídy Number (všechna čísla). Při kreslení se totiž tabulka dotáže (metodou
getColumnClass() modelu) na třídu sloupce a podle toho zvolí renderer. Svůj
renderer může mít ovšem také objekt třídy TableColumn - toto nastavení má
přednost před nastavením v tabulce.
Změna barvy je jen jednou z mnoha věcí, které můžeme v rámci vlastní
implementace rendereru provádět. Mezi další časté patří změna písma, zvláštní
formátování, speciální chování pro některé třídy atd. Chcete-li s tím
experimentovat, inspirujte se třeba v nějakém tabulkovém procesoru nebo jiném
programu a zkuste stejnou
věc realizovat zde. Není to složité. Zde je další příklad:
class LsRenderer extends DefaultTreeCellRenderer {
public LsRenderer() {
super();
try {
URL url = new URL("http://www.linuxsoft.cz/img/sipka1.png");
ImageIcon ic = new ImageIcon(url);
setLeafIcon(ic);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(this, "Chyba v URL ikony: "
+ e.getLocalizedMessage(), "Chyba", JOptionPane.ERROR_MESSAGE);
}
}
}
Jistě každý poznal, že tento renderer načte ze serveru Linuxsoftu obrázek
a použije ho jako ikonu - v tomto případě ikonu listu ve stromě. Vlastní
renderery pro stromy se totiž vytvářejí v podstatě stejně jako u tabulek. Totéž
platí i pro seznamy.
Editory
Kromě vlastního přístupu k vykreslování někdy potřebujeme něco podobného
uplatnit i pro editaci. Ať už se to týká třeba validace hodnoty nebo
způsobu samotné editace. Plané řeči nemají smysl, pojďme rovnou na příklad:
class MyEditor extends DefaultCellEditor {
private double minVal = Double.NEGATIVE_INFINITY;
private double maxVal = Double.POSITIVE_INFINITY;
MyEditor() {
super(new JTextField());
}
MyEditor(double min, double max) {
this();
minVal = min;
maxVal = max;
}
public boolean stopCellEditing() {
Object o = getCellEditorValue();
try {
double d = Double.parseDouble(o.toString());
if (d >= minVal && d <= maxVal)
return super.stopCellEditing();
} catch (NumberFormatException e) {}
JOptionPane.showMessageDialog(null, "Vložte prosím číslo v rozsahu "
+ minVal + " .. " + maxVal, "Chyba", JOptionPane.ERROR_MESSAGE);
return false;
}
}
Příklad ukazuje, jak by vypadal editor akceptující pouze reálná čísla, případně
s omezením jejich rozsahu. Předefinováváme metodu stopCellEditing() , která
se volá v okamžiku, kdy se ukončuje editace a připravuje se uložení hodnoty.
Vrátí-li metoda true , je hodnota přijata, v případě false nikoliv a editace
pokračuje.
V tomto případě se nejprve zkusí editovaný řetězec parsovat podle
formátu typu double. Selže-li to (nejedná se o číslo), skončí to výjimkou
NumberFormatException , kterou zde tiše ignorujeme (což se obecně nemá dělat,
ale tady to nevadí). Pak se zkontroluje hodnota vůči platnému rozsahu, a pokud
číslo vyhoví, vrátí se hodnota z metody stopCellEditing() předka. Nevyhoví-li
hodnota při první nebo druhé kontrole, nejen že se vrátí false , ale navíc
ještě vyskočí panel s upozorněním na chybu (všimněte si, že se ve volání
používá null jako odkaz na rodiče dialogu; třída DefaultCellEditor totiž není
potomkem třídy Component ). Často je takový "výřečný" způsob
signalizace chyby lepší než pouhé červené orámování, které používají
standardní editory třídy JTable .
Použití editoru je velice podobné jako v případě rendereru. Prostě se nastaví
tabulce (setDefaultEditor() ) nebo sloupci (setCellEditor() ). Obdobné to bude
také u stromu a seznamů. Pozor ovšem na několik věcí, které jsou zde odlišné
od rendererů. Jednak výchozí implementace vyžaduje předat editační komponentu
(v příkladu to byla instance třídy JTextField ), s čímž je třeba počítat
a již při vytváření vědět, co bude potřeba.
Dále je potřeba si uvědomit, že abstraktní třída všech editorů je společná
- AbstractCellEditor . Implementuje však jen obecné rozhraní CellEditor , kdežto
specializovaná rozhraní TreeCellEditor a TableCellEditor nikoli. Výchozí
implementace DefaultTreeCellEditor je potomkem AbstractCellEditor a implementuje
obě rozhraní. A aby byl guláš dokonalý, je tu ještě třída DefaultTreeCellEditor ,
která mj. nevyžaduje poskytnutí editační komponenty.
Za esteticky vypadajícími aplikacemi...
...se vydáme v příštím dílu. Ten bude zaměřen na správce rozložení (layout
managery), umožňující automatické řízení rozměrů a pozice komponent podle
uživatelské činnosti. V rychlosti se také podíváme na problematiku "zaměření"
(fokusu) komponent, protože se - možná trochu překvapivě - jedná o docela
užitečné mechanismy.
Verze pro tisk
|
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ů
28.11.2018 23:56 /František Kučera Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1
12.11.2018 21:28 /Redakce Linuxsoft.cz 22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář
6.11.2018 2:04 /František Kučera Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
4.10.2018 21:30 /Ondřej Čečák LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář
18.9.2018 23:30 /František Kučera Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář
9.9.2018 14:15 /Redakce Linuxsoft.cz 20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business.
Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář
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ář
Více ...
Přidat zprávičku
 Poslední diskuze
31.7.2023 14:13 /
Linda Graham iPhone Services
30.11.2022 9:32 /
Kyle McDermott Hosting download unavailable
13.12.2018 10:57 /
Jan Mareš Re: zavináč
2.12.2018 23:56 /
František Kučera Sraz
5.10.2018 17:12 /
Jakub Kuljovsky Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?
Více ...
|