Java GUI

Java Swing Swing bez grafického návrháře Java GUI

Dnes si upravíme naší primitivní kalkulačku. Naučíme se hlavně nový Layout a obsluhovat více tlačítek. Výsledná kalkulačka by měla vypadat takhle:

vysledek

Shrnutí

Myslím, že by neuškodilo lehké shrnutí:

Abychom vytvořili okno, vytvoříme si vlastní třídu, která dědí ze třídy JFrame. Dále naší instanci nadefinujeme různé parametry (velikost okna, defaultní operaci – zavření, viditelnost). Do okna přidáváme tzv. komponenty (tlačítka, labely, textová pole atd.). To jsou instance tříd (JLabel, JTextField …). Přidáváme je do okna metodou add. Teď pozor! Až doposud jsme je přidávali přímo do okna. To můžeme samozřejmě dělat i nadále. Problém však nastane, budeme-li chtít změnit pozadí okna. Na to existuje metoda setBackground (parametr barva). Pokud ji však přidáme přímo, nestane se nic. Musíme použít tzv. kontejner. Kontejner si můžeme představit jako papír, který vyplní celé okno. Získáme ho přes metodu getContentPane(). Pozadí pak nastavíme konejneru a budeme do něho i nadále přidávat všechny komponenty. Barvu již vytvořit umíme, nadefinujeme ji tedy na nějakou příjemnou barvičku pomocí číslic RGB. Přidáme komponenty stejně jako v předchozích dílech:

public class Gui extends JFrame{

    private JLabel labCislo1, labCislo2, labVysledek;
    private JButton butSecti, butOdecti, butVydel, butVynasob;
    private JTextField tfCislo1;
    private JTextField tfCislo2;

    public Gui()
    {
        super("Kalkulačka");

        Container con = getContentPane();
        con.setBackground(new Color(210, 244, 255));
}

GridBagLayout

FlowLayout, který jsme používali do teď, je jednoduchý, ale není moc použitelný. Mnohem mocnějším nástrojem je tzv. GridBagLayout. Okno nám rozdělí na tabulku s buňkami. K buňkám přistupujeme podle souřadnicového systému X,Y. Vytvoříme instanci třídy GridBagLayout. Další nutnou věcí je instace třídy GridBagConstraints, která slouží k určení souřadnic. Layout nastavíme stejně. Pěkné by bylo, kdyby byl mezi buňkami nějaký prostor. Toho docílíme příkazem:

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

Znázornění pro lepší pochopení:

gbLayout

Přidáme na kontejner komponenty. U každého komponentu musíme určit polohu X a Y. Další změnou je parametr metody add(). Na druhé místo přidáme objekt gbc. To nám zaručí správnost rozmístění.

labCislo1 = new JLabel("Zadejte první číslo:");
gbc.gridx = 0;
gbc.gridy = 0;

con.add(labCislo1, gbc);

tfCislo1 = new JTextField(4);
gbc.gridx = 1;
gbc.gridy = 0;
con.add(tfCislo1, gbc);

labCislo2 = new JLabel("Zadejte druhé číslo:");
gbc.gridx = 0;
gbc.gridy = 1;
con.add(labCislo2, gbc);

tfCislo2 = new JTextField(4);
gbc.gridx = 1;
gbc.gridy = 1;
con.add(tfCislo2, gbc);

butSecti = new JButton("+");
gbc.gridx = 0;
gbc.gridy = 2;
con.add(butSecti, gbc);

butOdecti = new JButton("-");
gbc.gridx = 1;
gbc.gridy = 2;
con.add(butOdecti, gbc);

butVynasob = new JButton("/");
gbc.gridx = 0;
gbc.gridy = 3;
con.add(butVynasob, gbc);

butVydel = new JButton("*");
gbc.gridx = 1;
gbc.gridy = 3;
con.add(butVydel, gbc);

labVysledek = new JLabel("Výsledek:");
gbc.gridx = 1;
gbc.gridy = 4;
con.add(labVysledek, gbc);

Obsluha tlačítek

Nyní se dostáváme k samotné funkčnosti. Ke každému z tlačítek musíme přidat posluchač události z nějaké třídy, do které implementuje rozhraní ActionListeneru. Asi nás napadne, že bychom mohli vytvořit čtyři třídy. Jedna by sčítala, druhá odčítala atd., ale byl by v tom zbytečný zmatek a navíc bychom dospěli k duplicitě kódu. Proto vytvoříme jenom jednu třídu - Event. Instanci event přidáme na všechna tlačítka.

Event event = new Event();
butOdecti.addActionListener(event);
butSecti.addActionListener(event);
butVydel.addActionListener(event);
butVynasob.addActionListener(event);

Metoda actionPerformed má jako parametr instanci třídy ActionEvent. Díky ní můžeme zjistit podrobnosti o tlačítku, které jsme stiskli a s něčím je porovnat. K informaci se dostaneme přes metodu getActionComand(), kterou metodou equals() porovnáme s nápisem na tlačítku. Můžeme tedy rozlišit, které tlačítko bylo stisknuto.

public class Event implements ActionListener {

       public void actionPerformed(ActionEvent e)
       {
           if(e.getActionCommand().equals("+"))
           {

           }
           else if(e.getActionCommand().equals("-"))
           {

           }
           else if(e.getActionCommand().equals("/"))
           {

           }
           else if(e.getActionCommand().equals("*"))
           {

           }
       }

Teď se dostáváme k logice programu. Samozřejmě bychom mohli všechno nabouchat mezi “ify“, ale jelikož nejsme žádní amatéři, uděláme to hezky OOP. Vytvoříme si tedy novou třídu Vypocet. Bude vypadat takto:

public class Vypocet {

        int cislo1;
        int cislo2;

        public Vypocet(int cislo1, int cislo2)
        {
                this.cislo1 = cislo1;
                this.cislo2 = cislo2;
        }

        public int secti()
        {
                return cislo1 + cislo2;
        }

        public int odecti()
        {
                return cislo1 - cislo2;
        }

        public int vydel()
        {
                return cislo1 / cislo2;
        }

        public int vynasob()
        {
                return cislo1 * cislo2;
        }
}

Všimněme si, že dělení nulou není ošetřené. K tomu se však ještě dostaneme. Vrátíme se do metody actionPerformed, která bude vypadat následovně:

public void actionPerformed(ActionEvent e)
{
        int cislo1 = Integer.parseInt(tfCislo1.getText());
        int cislo2 = Integer.parseInt(tfCislo2.getText());
        String text = "";

        Vypocet v = new Vypocet(cislo1, cislo2);

    if(e.getActionCommand().equals("+"))
    {
        text = String.valueOf(v.secti());

    }
    else if(e.getActionCommand().equals("-"))
    {
        text = String.valueOf(v.odecti());
    }
    else if(e.getActionCommand().equals("/"))
    {
        text = String.valueOf(v.vydel());
    }
    else if(e.getActionCommand().equals("*"))
    {
        text = String.valueOf(v.vynasob());
    }

    labVysledek.setText(text);
}

Výjimka

Nyní by program měl fungovat. Co se ale stane, pokud budu dělit nulou nebo nezadám celá čísla? GUI program sice nespadne, ale v terminálu nám chyby samozřejmě vyskočí. Jelikož bychom museli ošetřovat všude vstupy a k tomu ještě dělení nulou, bylo by to pěkných pár podmínek navíc. Mnohem lepším způsobem jsou tzv. Výjimky. Výjimka má dva bloky – try a catch.

try
{
// běh bez chyby
}
catch(Exception ex)
{
// běh s chybou
}

Jednoduše, pokud nenastane chyba, provede se blok try, pokud nastane jakákoliv chyba, nastane blok catch – chyby můžeme ještě dál dělit, ale o tom snad někdy příště. Za catch je parametrem objekt nějaké z výjimkových tříd. My použijeme třídu Exception. Finální kód bude tedy vypadat následovně:

public void actionPerformed(ActionEvent e)
{
        try
        {
                int cislo1 = Integer.parseInt(tfCislo1.getText());
                int cislo2 = Integer.parseInt(tfCislo2.getText());
                String text = "";

                Vypocet v = new Vypocet(cislo1, cislo2);

            if(e.getActionCommand().equals("+"))
            {
                text = String.valueOf(v.secti());

            }
            else if(e.getActionCommand().equals("-"))
            {
                text = String.valueOf(v.odecti());
            }
            else if(e.getActionCommand().equals("/"))
            {
                text = String.valueOf(v.vydel());
            }
            else if(e.getActionCommand().equals("*"))
            {
                text = String.valueOf(v.vynasob());
            }

            labVysledek.setText(text);
        }
        catch(Exception ex)
        {
                labVysledek.setText("Chyba");
        }

}

 

Stáhnout

Staženo 666x (5.98 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (1)

Článek pro vás napsal Samik11
Avatar
Autor se věnuje primárně programování v jazyce Java. Nestraní se ani C# nebo PHP.

Jak se ti líbí článek?
Celkem (7 hlasů) :
3.428573.428573.42857 3.428573.42857


 


Miniatura
Předchozí článek
Java GUI - událost
Miniatura
Všechny články v sekci
Java Swing bez grafického návrháře
Miniatura
Následující článek
Layouty v Java Swing

 

 

Komentáře
Zobrazit starší komentáře (11)

Avatar
Luboš Běhounek (Satik):

Máš pravdu, zapomněl jsem, že se mi výjimky vypisují do konzole, bez toho výpisu se jich stihne provést víc, cca 50 000 za sekundu, ale pořád jsou mnohem mnohem pomalejší, než cokoliv jiného.

Pošli kód, protože pokud cyklus s výjimkami byl rychlejší než cyklus s podmínkou, tak tam máš nějakou chybu, protože už z logiky fungování výjimek je to úplný nesmysl - vždyť porovnání hodnoty, jestli není nula, je jedna jednoduchá jnz nebo jz instrukce navíc, zatímco u výjimek se (kromě uložení stavů některých registrů procesoru) přidávají nějaká data pro obsluhu výjimky na zásobník...

Editováno 30.3.2013 14:39
Odpovědět 30.3.2013 14:38
:)
Avatar
Kit
Redaktor
Avatar
Odpovídá na Luboš Běhounek (Satik)
Kit:

Zkusím opsat z hlavy kód, který jsem použil. S podmínkou:

int x;
for (int i = 0; i < 1000000000; i++) {
   if (i != 0) {
      x = 2000000000 / i;
   } else {
      x = 0;
   }
}

S výjimkou:

int x;
for (int i = 0; i < 1000000000; i++) {
   try {
      x = 2000000000 / i;
   } catch (Exception e) {
      x = 0;
   }
}

S výjimkou to bylo cca o 1 % rychlejší než s podmínkou.

Odpovědět 30.3.2013 17:36
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
martinkobelka
Redaktor
Avatar
martinkobelka:

Když chcu přidávat do formuláře prvky pomocí GridBagConstraints, tak mi to zobrazuje výjmku, nevíte čím to je? kod :

package snake;

import java.awt.Color;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JLabel;

class Windows extends JFrame{
    public void kresli(){
        setTitle("Kalkulačka");
        setSize(450, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Container con = getContentPane();

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

        JLabel labCislo1 = new JLabel("Zadejte první číslo:");
        gbc.gridx = 1;
        gbc.gridy = 1;

        con.add(labCislo1, gbc);



        setVisible(true);
    }
}
 
Odpovědět 30.3.2013 23:09
Avatar
Samik11
Redaktor
Avatar
Odpovídá na martinkobelka
Samik11:

Nikde jsi layout nepřidal, to se dělá metodou:

setLayout()

Popravdě moc nechápu jak máš ten kód členěný. Podstatou je, že si vytvoříš třídu která dědí z JFrame, v tvém případě Windows a pak v hlavní metodě vytvoříš objekt této třídy. Zkus si projít ty předchozí díly. Případně stáhni zdrojáky. :-)

Odpovědět 30.3.2013 23:32
„Radost vidět a rozumět, to je nejkrásnější dar přírody.“ Albert Einstein
Avatar
niveses
Redaktor
Avatar
niveses:

Co lze udělat pro výsledky v mínusech?

 
Odpovědět 31.5.2013 17:22
Avatar
dNtichy
Člen
Avatar
dNtichy:

Mozem natiahnut component aj cez viac buniek tabulky gridbaglayoutu ako len cez 1?

 
Odpovědět 29.10.2013 23:55
Avatar
D0ll0k
Člen
Avatar
D0ll0k:

Já jsem tu nový a začínám "programovat". Chci se zeptat kam přesně mám vložit řádky po tom, co se zpátky vracíme k actionPerformed. Já jsem je vložil do třídy Event. Jenomže mi to hlásí chybu: Source not found. Mohl by prosím někdo říct kam je mám vložit?

Odpovědět 25.5.2014 21:08
Ten, co se snaží "programovat"
Avatar
D0ll0k
Člen
Avatar
Odpovídá na D0ll0k
D0ll0k:

Tak už nic. Našel jsem to. Zapoměl jsem přidal GridBagLayout. Toto tady chybi, jak to zapsat. Musel jsem si to stáhnout a podívat se.

Odpovědět 11.6.2014 7:24
Ten, co se snaží "programovat"
Avatar
reguluscentauri:

Zdravím,
chtěl bych se jen zeptat, kde dělám chybu
Když vložím GridBagConstraints gbc = new GridBagConstra­ints(), tak mi to vypíše chybu, vytvořím tedy podle návrhu Netbeans class pro gbc, do toho pak musim vložit
Insets insets;
int gridx;
int gridy;
A umazat tam final

A při spuštění mi netbeans vypíše
Exception in thread "main" java.lang.Ille­galArgumentEx­ception: cannot add to layout: constraints must be a GridBagConstraint

Kód jsem porovnal se zdrojákem odsud a je stejný až na to, že autor tam nemá class pro gbc. Je nějaká varianta, jak to obejít, která mi unikla nebo v čem může být problém?

Předem děkuji

 
Odpovědět 29.11.2015 22:21
Avatar
reguluscentauri:

Tak už jsem chybu objevil, jsem vůl a byl tam překlep v jednom písmenku, akorát zrovna nejspíš nešťastná náhoda nebo nevim, že to Netbeans identifikoval a řešil takhle přes externí class

 
Odpovědět 1.12.2015 17:51
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 21. Zobrazit vše