Image
27.6.2016 0 Comments

Programujeme v Jave /3.časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

V predchádzajúcej časti sme sa začali venovať správcom umiestnenia a v jej závere som sľúbil, že tentoraz sa zameriame na správcu GridBagLayout, takže sa do toho môžeme hneď pustiť.

Správca umiestnenia GridBagLayout

Ako som už napísal minule, správca umiestnenia GridBagLayout je asi najkomplexnejší a najzložitejší správca umiestnenia, ktorého Java poskytuje. Aj napriek tomu ide o jedného z najčastejšie používaných správcov, pretože umožňuje vytvoriť takmer akékoľvek zložité grafické používateľské rozhrania. Preto si ho rozoberieme a pokúsim sa vás naučiť, ako tohto správcu používať.

V prvom rade treba povedať, že GridBagLayout pracuje s mriežkou podobne ako GridLayout, ale dokáže ju oveľa flexibilnejšie využívať. Komponenty nemusia mať zákonite rovnakú veľkosť a môžu zaberať rôzny počet buniek tabuľky. Aby ste toto všetko mohli dosiahnuť, musíte sa naučiť používať triedu GridBagConstraints, ktorá zapuzdruje obmedzujúce vlastnosti pre pridávané komponenty. Po vytvorení inštancie tejto triedy a nastavení jej členských atribútov (nastavovanie prebieha priamym prístupom k týmto atribútom, pretože sú verejné a trieda pre ne nemá prístupové metódy) treba odovzdať metóde add() vášho kontajnera nielen odkaz na inštanciu vášho komponentu, ale aj odkaz na inštanciu triedy GridBagConstraints. Nasledujúci fragment kódu celý tento postup aj s použitím správcu umiestnenia GridBagLayout ilustruje:

JPanel kontajner = new JPanel();
kontajner.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JButton tlacidlo = new JButton(“OK”);
kontajner.add(tlacidlo, gbc);

Tento kód pridružil ku komponentu tlacidlo inštanciu triedy GridBagConstraints. Vytváranie novej inštancie GridBagConstraints nemusíte zakaždým opakovať, pretože pri pridaní komponentu do kontajnera je odovzdaná inštancia GridBagConstraints pomocou metódy clone() skopírovaná a správca umiestnenia si uchová odkaz na túto kópiu. Ide o hlbokú kópiu inštancie, čo znamená, že nie je vytvorený len nový objekt a skopírované dátové zložky primitívnych typov, ale aj dátové zložky, ktoré sú objektmi, sú nanovo skonštruované, takže v skopírovanej inštancii neukazujú na objektové dátové zložky pôvodnej inštancie. Výsledkom tohto všetkého je, že môžete pracovať stále s tou istou inštanciou GridBagConstraints. Ukážku tohto postupu uvidíte v ďalšom príklade. Teraz sa začneme venovať jednotlivým atribútom triedy GridBagConstraints.

gridx a gridy – tieto atribúty slúžia na definovanie pozície pridávaného komponentu v mriežke. Atribút gridx definuje stĺpec a gridy riadok, pozdĺž okrajov ktorých bude pridávaný komponent umiestnený. Riadky aj stĺpce sú číslované od hodnoty 0. Nasledujúci príklad ukazuje pridanie a umiestnenie troch tlačidiel použitím správcu GridBagLayout. Dve tlačidlá sú umiestnené na prvom riadku, jedno na druhom riadku pomocou atribútov gridx a gridy triedy GridBagConstraints:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
public class GridBagTest extends JApplet {
 
  public void init() {
    this.setSize(new Dimension(190, 100));
    Container kontajner = getContentPane();
    kontajner.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = 0;
    gbc.gridy = 0;
    kontajner.add(new JButton("Tlacidlo 1"), gbc);
    gbc.gridx = 1;
    gbc.gridy = 0;
    kontajner.add(new JButton("Tlacidlo 2"), gbc);
    gbc.gridx = 0;
    gbc.gridy = 1;
    kontajner.add(new JButton("Tlacidlo 3"), gbc);
  }
 
}

Atribútom gridx a gridy môžete tiež priradiť konštantu RELATIVE definovanú v triede GridBagConstraints. Pokiaľ je táto hodnota priradená k atribútu gridx, bude komponent pridaný na koniec riadka definovaného atribútom gridy. Obdobne, ak bude hodnotu RELATIVE obsahovať gridy a do gridx bude priradené nezáporné číslo, bude komponent pridaný na koniec stĺpca definovaného atribútom gridx. Pokiaľ oba tieto atribúty budú obsahovať hodnotu RELATIVE, bude komponent pridaný na koniec prvého riadka. Hodnota GridBagConstraints.RELATIVE je implicitnou hodnotou, ktorou sú atribúty gridx a gridy inicializované konštruktorom po vytvorení novej inštancie GridBagConstraints. Preto by mohla metóda init() predchádzajúceho príkladu vyzerať aj jednoduchšie, napr. takto:

  public void init() {
    this.setSize(new Dimension(190, 100));
    Container kontajner = getContentPane();
    kontajner.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    kontajner.add(new JButton("Tlacidlo 1"), gbc);
    kontajner.add(new JButton("Tlacidlo 2"), gbc);
    gbc.gridy = 1;
    kontajner.add(new JButton("Tlacidlo 3"), gbc);
  }

Výsledok bude rovnaký ako v predchádzajúcom príklade.

anchor – tento atribút slúži na ukotvenie komponentu. Trieda GridBagConstraints definuje pre hodnoty tohto atribútu konštanty CENTER, WEST, EAST, NORTH, SOUTH, NORTHWEST, NORTHEAST, SOUTHWEST a SOUTHEAST. Priradenie niektorej z týchto konštánt má za následok ukotvenie pridávaného komponentu na danú stranu bunky v mriežke. Implicitnou hodnotou je CENTER.

gridwidth a gridheight – tieto celočíselné atribúty umožňujú umiestnenie komponentu tak, aby zaberal viac ako jednu bunku mriežky. Atribút gridwidth určuje, koľko na buniek v riadku, resp. cez koľko stĺpcov bude komponent roztiahnutý. Podobne gridheight definuje počet riadkov, cez ktoré bude komponent roztiahnutý. Nasledujúci príklad je podobný tomu predchádzajúcemu, s tým rozdielom, že tretie tlačidlo obsadí dve bunky miesto jednej:

  public void init() {
    this.setSize(new Dimension(190, 100));
    Container kontajner = getContentPane();
    kontajner.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    kontajner.add(new JButton("Tlacidlo 1"), gbc);
    kontajner.add(new JButton("Tlacidlo 2"), gbc);
    gbc.gridy = 1;
    gbc.gridwidth = 2;
    kontajner.add(new JButton("Tlacidlo 3"), gbc);
  }

Ako vidíte, tretie tlačidlo obsadzuje teraz obe spodné bunky, aj keď ich nezapĺňa celé, pretože je zobrazené iba v takej veľkosti, akú potrebuje na zobrazenie svojho textového nápisu. Ako roztiahnuť komponent na celú plochu, ktorú má k dispozícii, to si povieme pri opise atribútu fill. V prípade atribútov gridwidth a gridheight treba ešte poznamenať, že je možné použiť aj preddefinované konštanty v triede GridBagConstraints RELATIVE a REMAINDER. Použitie konštanty REMAINDER v atribúte gridwidth alebo gridheight spôsobí roztiahnutie komponentu na všetky zvyšné stĺpce až do konca riadka, resp. všetky zvyšné riadky až do konca stĺpca. Konštanta RELATIVE funguje podobne s tým rozdielom, že vynechá posledný stĺpec, resp. riadok. Ak teda v riadku máme šesť stĺpcov, pričom prvé dva sú obsadené komponentmi, použitím konštanty REMAINDER v atribúte gridwidth obsadí ďalší pridaný komponent zvyšné štyri stĺpce. Pri použití konštanty RELATIVE by komponent obsadil tri stĺpce a posledný by zostal voľný. V našom príklade by sme preto riadok

    gbc.gridwidth = 2;

mohli nahradiť riadkom

    gbc.gridwidth = GridBagConstraints.REMAINDER;

a výsledok by bol rovnaký.

fill – tento atribút slúži na signalizovanie skutočnosti, či bude komponent v niektorom smere roztiahnutý na celú plochu, ktorú má k dispozícii. Môže nadobúdať hodnoty konštánt NONE, HORIZONTAL, VERTICAL a BOTH preddefinovaných v triede GridBagConstraints. Implicitnou hodnotou je NONE, ktorá znamená, že komponent nebude roztiahnutý v žiadnom smere. Pokiaľ chcete komponent roztiahnuť vodorovne (na celú šírku stĺpca alebo stĺpcov, ktoré má komponent k dispozícii), použijete konštantu HORIZONTAL. Analogicky použitím konštanty VERTICAL môže byť komponent roztiahnutý zvisle cez všetky riadky, ktoré má k dispozícii. Posledná konštanta BOTH je kombináciou VERTICAL a HORIZONTAL, takže komponent bude roztiahnutý vodorovne aj zvisle. Poďme sa pozrieť na modifikáciu predchádzajúceho príkladu – chceme, aby tretie tlačidlo bolo roztiahnuté na celú dĺžku oboch buniek, ktoré zaberá:

  public void init() {
    this.setSize(new Dimension(190, 100));
    Container kontajner = getContentPane();
    kontajner.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    kontajner.add(new JButton("Tlacidlo 1"), gbc);
    kontajner.add(new JButton("Tlacidlo 2"), gbc);
    gbc.gridy = 1;
    gbc.gridwidth = 2;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    kontajner.add(new JButton("Tlacidlo 3"), gbc);
  }

insets – tento atribút je ako jediný referenčným typom v triede GridBagConstraints. Ide o objekt typu Insets, ktorý obsahuje štyri celočíselné atribúty – top, right, left a bottom. Hodnoty týchto atribútov predstavujú veľkosti výplní na všetkých stranách komponentu, alebo ak chcete, vzdialenosti komponentu od okrajov bunky. Máte dve možnosti, ako s týmto atribútom narábať. Prvou je vytváranie vždy novej inštancie triedy Insets, ktorej konštruktoru odovzdáte ako parametre postupne hodnoty top, left, bottom a right, ktorými budú jej atribúty inicializované. Následne túto inštanciu priradíte atribútu insets vašej inštancie triedy GridBagConstraints. Tento postup ilustruje nasledujúci zápis:

GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 12, 7);

Alternatívnou možnosťou je pristupovať priamo k atribútom zložky insets, pretože pri vytvorení novej inštancie je automaticky vytvorená aj inštancia Insets. Ja budem v tomto seriáli uprednostňovať tento prístup, ale vy si môžete vybrať ten, ktorý vám viac vyhovuje. Nastavenie atribútu fill nemá vplyv na atribút insets, pretože v prípade, že definujete nejaké nenulové hodnoty atribútov insets, bude táto výplň vyhradená okolo komponentu aj vtedy, keď ho dáte roztiahnuť na celú plochu, ktorú má komponent k dispozícii. Keby sme v predchádzajúcom príklade vložili tieto riadky hneď pred posledné volanie metódy kontajner.add():

    gbc.insets.left = 10;
    gbc.insets.right = 10;

Napriek použitiu hodnoty HORIZONTAL v zložke fill je na oboch stranách tretieho tlačidla vyhradená žiadaná plocha.

ipadxipady – tieto celočíselné atribúty špecifikujú vnútornú výplň komponentu. Vďaka nim môžete zväčšiť alebo zmenšiť veľkosť komponentu vo vertikálnom alebo horizontálnom smere. Zadaním kladnej hodnoty špecifikujete zväčšenie komponentu, zadaním zápornej zasa zmenšenie komponentu. Takže keby sme chceli v predchádzajúcom príklade zmenšiť výšku tretieho tlačidla o 10 pixelov, vložili by sme nasledujúci riadok tesne pred volaním metódy kontajner.add(), ktorou tento komponent pridávame do appletu:

    gbc.ipady = -10;

weightxweighty – tieto atribúty môžu nadobúdať nezáporné reálne hodnoty typu double. Ich hodnoty predstavujú váhu komponentu v riadku, resp. v stĺpci. Váha komponentov je dôležitá vlastnosť v prípade, že kontajner nemá dostatok miesta na zobrazenie všetkých komponentov v ich požadovanej alebo minimálnej veľkosti alebo, naopak, vtedy, ak má kontajner k dispozícii nejaké prebytočné miesto. V oboch prípadoch musí správca umiestnenia rozhodnúť, ktorým komponentom miesto uberie v prípade jeho nedostatku a ktorým ho pridá v prípade prebytku. Prebytočný priestor rozdelí správca umiestnenia GridBagLayout medzi stĺpce (prípadne riadky) v závislosti od podielu ich váh na celkovom súčte váh. Váha stĺpca sa rovná maximu z váh weightx všetkých komponentov v danom stĺpci. Obdobne pre riadky platí, že váha celého riadka je rovná maximu z váh weighty všetkých komponentov v danom riadku.

Váhy komponentov predstavujú dosť zákernú záležitosť konceptu GridBagLayout, preto si ich použitie objasníme na príklade. Pre zjednodušenie budeme používať iba komponenty JButton, aj keď uvedený postup je možné aplikovať takisto na akékoľvek iné komponenty.

V našom príklade bude vytvorených šesť tlačidiel JButton, ktoré budú umiestnené v dvoch riadkoch a troch stĺpcoch. Pri pridávaní komponentov nastavujeme váhy komponentov takto (prvá hodnota prestavuje váhu v stĺpci – weightx a druhá v riadku – weighty):

Tlačidlo 1 – 0.0, 1.0
Tlačidlo 2 – 1.0, 0.0
Tlačidlo 3 – 2.0, 0.0
Tlačidlo 4 – 0.0, 1.0
Tlačidlo 5 – 0.0, 0.0
Tlačidlo 6 – 0.0, 0.0

Čo chceme týmto prístupom dosiahnuť? Ako vidíte, maximálna váha weigthy prvého riadka (tlačidlá 1 až 3) je 1.0, takisto ako v druhom riadku (tlačidlá 4 až 6). Podobne zistíme aj váhy stĺpcov weightx: váha prvého (tlačidlá 1 a 4) bude 0.0, váha druhého (tlačidlá 2 a 5) bude 1.0 a váha tretieho (tlačidlá 4 a 6) bude 2.0. Poďme sa teraz pozrieť na samotnú metódu init():

  public void init() {
    this.setSize(new Dimension(600, 70));
    Container kontajner = getContentPane();
    kontajner.setLayout(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
 
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = 0.0;
    gbc.weighty = 1.0;
    kontajner.add(new JButton("Tlacidlo 1 (0.0, 1.0)"), gbc);
    gbc.weightx = 1.0;
    gbc.weighty = 0.0;
    kontajner.add(new JButton("Tlacidlo 2 (1.0, 0.0)"), gbc);
    gbc.weightx = 2.0;
    kontajner.add(new JButton("Tlacidlo 3 (2.0, 0.0)"), gbc);
    gbc.gridy = 1;
    gbc.weightx = 0.0;
    gbc.weighty = 1.0;
    kontajner.add(new JButton("Tlacidlo 4 (0.0, 1.0)"), gbc);
    gbc.weighty = 0.0;
    kontajner.add(new JButton("Tlacidlo 5 (0.0, 0.0)"), gbc);
    kontajner.add(new JButton("Tlacidlo 6 (0.0, 0.0)"), gbc);
  }

Aby sme mohli funkciu váh sledovať, museli sme nastaviť atribút fill na BOTH. Teraz môžete skúšať zväčšovať a zmenšovať okno appletu a sledovať, ako sa menia rozmery tlačidiel. Keďže oba riadky majú rovnakú váhu weighty, zväčšujú a zmenšujú sa rovnako. V prípade stĺpcov je situácia iná. Prvý stĺpec má váhu nulovú, druhý má váhu 1.0 a tretí 2.0. Keďže váha prvého stĺpca je nulová, nebude mu pridelený žiadny zvyšný horizontálny priestor. Tento zvyšný priestor bude rozdelený medzi druhý a tretí stĺpec v pomere ich váh weightx k celkovému súčtu váh weightx stĺpcov, ktorý je rovný 0.0 + 1.0 + 2.0 = 3.0, z čoho vyplýva, že druhý stĺpec získa 1/3 z prebytočnej plochy a tretí stĺpec zvyšné 2/3. To znamená, že tretí stĺpec sa zväčšuje dvakrát rýchlejšie. Obdobné pravidlá platia však aj pri nedostatku miesta, to znamená, že tretí stĺpec sa pri zmenšovaní miesta zmenšuje dvakrát rýchlejšie ako druhý, pričom prvý si zachováva stále rovnakú veľkosť. Tretí stĺpec má len polovičnú veľkosť druhého, prvý stĺpec má stále rovnakú veľkosť. Veľkosti riadkov sú rovnaké.

Býva dobrým zvykom pre prehľadnosť nastavovať hodnoty weightx iba komponentom v prvom riadku a weighty iba komponentom v prvom stĺpci, ako ste to mohli vidieť v našom príklade.

Na záver ešte upozorním, aby ste si uvedomili, že nezáleží na tom, aké sú absolútne hodnoty váh komponentov, teda aké sú absolútne hodnoty váh stĺpcov či riadkov. Záleží iba na ich podiele na celkovom súčte váh, takže pokiaľ sú váhy stĺpcov v našom príklade 0.0, 1.0 a 2.0, je to to isté, ako keby ich váhy mali hodnoty 0.0, 50 a 100.

Záver

Po tejto časti, ktorá bola celá venovaná správcovi umiestnenia GridBagLayout, vám už azda použitie tohto komplexného správcu nebude robiť problémy. V nasledujúcom pokračovaní rozprávanie o správcoch umiestnenia zakončíme a začneme sa venovať jednotlivým komponentom a udalostnému modelu.

 

 

Autor: Andrej Chu

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

ITPro

Linux súkromne i pracovne v2.0 (14. časť): Small Business Server

09.11.2016 14:57

Pojem Small Business Server (malý firemný server) začala používať spoločnosť Microsoft ešte v roku 2000 na označenie servera, ktorý ­dokázal plniť úlohy niekoľkých samostatných serverov. Aplikačná vrs ...

ITPro

Industry 4.0: Fikcia alebo už realita?

09.11.2016 14:52

Štvrtá priemyselná revolúcia je pomenovanie rozsiahlych zmien prudko vstupujúcich do súčasného priemyslu. Nositeľom týchto zmien je digitalizácia výroby a optimalizácia všetkých podnikových procesov v ...

ITPro

Vývoj aplikácií UWP pre Xbox One II.

09.11.2016 14:47

V predošlej časti sme ukázali postup, ako si ­vytvoriť vývojársky účet a aktivovať vývojársky režim na hernej konzole Xbox One, aby ste mohli testovať svoje aplikácie. Výhodou hernej konzoly Xbox je v ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá