|
||||||||||||||||||||||||||||||||||||||||||||||||
Menu
Distributions (131)
Software (10844)
|
Java (29) - správci rozloženíRozložení komponent GUI lze definovat napevno. Má-li ale aplikační okno nebo jeho část proměnnou velikost, je pevně definované GUI na obtíž. A v tu chvíli sáhneme po správcích rozložení - layout managerech. Umožňují nám rozložení komponent automaticky přizpůsobovat aktuální situaci.
Úvod do automatické správy rozloženíGrafické uživatelské rozhraní aplikace můžeme navrhnout jednoduše tak, že si na milimetrovém papíře nakreslíme rozložení komponent a pak tento návrh přeneseme do kódu. Je to jednoduché, spolehlivé, ale má to jednu zásadní nevýhodu. Pokud může uživatel nějak měnit velikost "kontejneru" (okna, nějakého seskupovacího prvku apod.), nepůsobí pevně definované rozložení zrovna nejlíp. Pevné rozložení se hodí především pro jednoduché panely a dialogy, kde uživatel nemá možnost do GUI nějak zasahovat. Ovšem i tam si lze (s ohledem na použitý vzhled) pomoci automatickou správou. Hlavní doménou této správy jsou ovšem okna s proměnnou velikostí. Jak to fungujeJe to jednoduché. Máme specializovaný objekt, který spravuje svůj GUI kontejner a podle jeho velikosti mění polohu a velikost komponent uvnitř. Může (ale také nemusí) reflektovat též změny vlastností těchto komponent provedené uživatelem.
Základem je rozhraní Existující správci rozložení
Podívejme se nejdřív na několik implementací, které se nacházejí ve standardních
javovských balících ( FlowLayout (plovoucí rozložení)Tento správce uspořádává komponenty podobně, jako kdyby šlo o znaky v textu. Tedy začne vlevo (příp. vpravo) nahoře, pokračuje v řádku dál, a když už není místo, přejde o řádek níž. Způsob vodorovného zarovnání, stejně tak jako mezery mezi komponentami, lze nastavit. GridLayout (rozložení do mřížky)Zde se komponenty umísťují na virtuální mřížku. Plocha kontejneru se rozdělí na obdélníky stejné velikosti a v každém bude jedna komponenta. Lze nastavit počet řádků a sloupců, přičemž počet řádků (je-li nastaven jako nenulový) má přednost. GridBagLayout (rozložení do zobrazovacích oblastí)Poněkud složitější layout manager. Opět se vytvoří virtuální mřížka, ovšem komponenta může zabírat i více buněk než jen jedinou (je to podobné jako "slučování buněk" v tabulkovém procesoru). Na chování správce lze aplikovat řadu různých pravidel a získat tak velmi příjemně se chovající GUI. BoxLayout ("krabicové" rozložení)
Jednoduchý správce, umísťující komponenty do řádku nebo sloupce (podle
nastavení). Souvisí s ním také třída BorderLayout (rozložení do pěti oblastí)Rozdělí kontejner na pět oblastí - centrální oblast a čtyři okrajové. Hodí se zejména pro hlavní aplikační okna. Lze si představit např. vývojové prostředí, kde je v centrální části editor kódu, nahoře zobrazení zásobníku, vlevo strom projektu, vpravo detaily aktuální třídy a dole textová konzole. Kromě správců obsažených ve standardních balících jsou často k dispozici ještě další - například v projektu swing-layout (některé třídy budou součástí balíků Javy 6). Použití správce
Samotné použití je velmi snadné. Jen se zavolá metoda Podívejme se na následující program. Vytvoří 6 tlačítek, 6 různých správců rozložení (resp. 3, každý ve 2 verzích; ostatní správci se pro tuto ukázku nehodí), a to vše propojí tak, že stiskem tlačítka se nastaví příslušný layout manager. public class Test extends JFrame implements ActionListener { private JButton ba [] = { new JButton("FlowLayout 1"), new JButton("FlowLayout 2"), new JButton("GridLayout 1"), new JButton("GridLayout 2"), new JButton("BoxLayout 1"), new JButton("BoxLayout 2") }; private LayoutManager lma [] = { new FlowLayout(), new FlowLayout(FlowLayout.LEFT, 20, 20), new GridLayout(), new GridLayout(0, 2), new BoxLayout(getContentPane(), BoxLayout.X_AXIS), new BoxLayout(getContentPane(), BoxLayout.Y_AXIS) }; private HashMap<JButton, LayoutManager> map = new HashMap<JButton, LayoutManager>(); public Test() { super(); init(); } public void init() { setSize(400, 300); setDefaultCloseOperation(DISPOSE_ON_CLOSE); Container c = getContentPane(); for (int i=0; i<ba.length; i++) { ba[i].addActionListener(this); c.add(ba[i]); map.put(ba[i], lma[i]); } c.setLayout(lma[0]); } public void actionPerformed(ActionEvent e) { JButton but = (JButton) e.getSource(); getContentPane().setLayout(map.get(but)); getContentPane().validate(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Test t = new Test(); t.setVisible(true); } }); } }
Změny lze pozorovat v reálném čase. Všimněte si, že se po nastavení nového správce
musí zavolat metoda Tvorba vlastního správceI když si v drtivé většině případů vystačíme s těmi správci, které máme již k dispozici, někdy nastane důvod k implementaci vlastního. Není to nic složitého, jen se vyplatí při tom trochu přemýšlet.
Nejprve obecně. Každá komponenta má 4 rozměrové parametry: aktuální, minimální,
maximální a preferovanou velikost. Aktuální již známe, pracuje se s ní pomocí
metod
To však není všechno. Rozhraní
Pusťme se tedy do tvorby. Bude to správce, který bude uspořádávat komponenty
vodorovně (podobně jako class MyLayout implements LayoutManager { public void addLayoutComponent(String name, Component comp) {} public Dimension preferredLayoutSize(Container parent) { Dimension d = new Dimension(0, 0); int cc = parent.getComponentCount(); for (int i=0; i<cc; i++) { Dimension cd = parent.getComponent(i).getPreferredSize(); if (cd.width > 0) d.width += cd.width; if (cd.height > d.height) d.height = cd.height; } Insets in = parent.getInsets(); d.width += in.left + in.right; d.height += in.top + in.bottom; return d; } public Dimension minimumLayoutSize(Container parent) { Dimension d = new Dimension(0, 0); int cc = parent.getComponentCount(); for (int i=0; i<cc; i++) { Dimension cd = parent.getComponent(i).getMinimumSize(); if (cd.width > 0) d.width += cd.width; if (cd.height > 0) d.height = cd.height; } Insets in = parent.getInsets(); d.width += in.left + in.right; d.height += in.top + in.bottom; return d; } public void layoutContainer(Container parent) { Dimension csize = parent.getSize(); Insets in = parent.getInsets(); csize.width -= in.left + in.right; csize.height -= in.top + in.bottom; Component ca[] = parent.getComponents(); if (ca.length == 0) return; Dimension da[] = new Dimension[ca.length]; // zmenseni na minimalni velikost int wtot = 0; for (int i=0; i<ca.length; i++) { Dimension d = ca[i].getMinimumSize(); d.height = d.height > csize.height ? d.height : csize.height; da[i] = new Dimension(d); wtot += d.width; } // dopocet zbytku, pokud je potreba if (wtot < csize.width) { int diff = (csize.width - wtot) / ca.length; for (int i=0; i<ca.length; i++) { da[i].width += diff; } } // umisteni komponent wtot = in.left; for (int i=0; i<ca.length; i++) { ca[i].setBounds(wtot, in.top, da[i].width, da[i].height); wtot += da[i].width; } } public void removeLayoutComponent(Component comp) {} } Všimněte si několika věcí. Nejprve toho, že jsou dvě metody ponechány prázdné. Je to proto, že zde nemají význam, ačkoliv u některých správců význam mít mohou (abych byl přesný, je to ještě trochu jinak, a brzy se o tom zmíním). Za druhé je tu ten "problém" (který se objevuje i u některých standardních managerů), že v určitých případech bude za poslední komponentou malé volné místo. Je to proto, že při dělení nějaké pixely zbývají a nejsou pak nikam přiděleny. Pokud by to někomu vadilo, může o ně například rozšířit poslední komponentu nebo je nějak rozdistribuovat mezi více komponent.
Dále bych chtěl upozornit, že se nesmí zapomenout na případné vnitřní
okraje (insets) a odečíst je tedy od celkového prostoru v kontejneru.
Kromě metod uvedených v příkladu se doporučuje implementovat také metodu
Jak jsem se zmínil, dvě prázdné metody někdy mají svůj význam. Jenže většinou
se používá spíše metoda novější, nacházející se v rozhraní Fokus a věci souvisejícíSlíbil jsem přiblížit práci s fokusem ("zaměřením" komponenty), a už je to tady. Fokus je velice důležitá věc pro ovládání programů klávesnicí. Proto považuji za důležité ukázat některé věci, které se v tomto ohledu velice hodí. Základní práce s fokusem
Začneme tím nejjednodušším - vyžádáním fokusu. Potřebujeme-li zajistit, aby
ho v nějakém okamžiku získalo např. textové pole, máme k dispozici dvě metody.
První je
Vhodnější je metoda
Dále nás zajímají ještě metody Události generované změnou fokusu
Není skoro co vysvětlovat. Při získání a ztrátě fokusu komponenta generuje
události
Zvláštní případ se týká fokusu okna ( Pořadí předávání fokusu
Pro určení pořadí je k dispozici silný aparát. Nejprve si ale musíme říct něco
o stromové hierarchii, která zde platí. Každý fokusový cyklus (tedy "okruh"
v němž se fokus předává stále dokola) má svůj kořen. Kořen se chová tak, že
běžným způsobem (např. tabulátorem na klávesnici nebo metodou
Samotné pořadí určuje politika předávání fokusu, vyjádřená implementací
abstraktní třídy
Potomkem této třídy je
Politiku předávání nastavíme metodou Dočasný fokus
V některých případech je získání/ztráta fokusu jen dočasnou záležitostí.
Například při rozbalení menu nebo přetahování komponenty může dojít k dočasnému
předání fokusu - je to ale platformově závislá věc. Zda se jedná o dočasnou
změnu, lze z události zjistit pomocí Změna vzhleduI příště se zaměříme na vzhled GUI, ovšem z trochu jiné stránky. Bude řeč o tzv. Look&Feel, tedy jinak řečeno "tématech" vzhledu aplikací. Programy tak mohou snadno získat zcela jinou tvář.
|
Search Software
Search Google
|
||||||||||||||||||||||||||||||||||||||||||||||
©Pavel Kysilka - 2003-2024 | maillinuxsoft.cz | Design: www.megadesign.cz |