Swift týden
Pouze tento týden sleva až 80 % na e-learning týkající se Swift
30 % bodů zdarma na online výuku díky naší Slevové akci!

Lekce 2 - Java Swing pod pokličkou

V minulém dílu seriálu tutoriálů o Java Swing, Úvod do formulářových aplikací v Java Swing, jsme naprogramovali, tedy spíše naklikali, svou první formulářovou aplikaci v Javě.

V dnešním dílu si vysvětlíme, jak funguje uvnitř.

Pod pokličkou

Samotný formulář je samozřejmě objekt (jak jinak :) ). Je definován třídou HlavniJFrame, kterou nalezneme v souboru HlavniJFrame.java.

Přepněme se do kódu třídy pomocí tlačítka "Source". Některé části kódu jsou zašedlé a sklapnuté. Když ho celý rozbalíme a odstraníme komentáře, vypadá asi takto (nelekněte se :)):

public class HlavniJFrame extends javax.swing.JFrame {

    public HlavniJFrame() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Pozdrav");

        jLabel1.setText("Pozdrav z formuláře");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(41, 41, 41)
                .addComponent(jLabel1)
                .addContainerGap(47, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(45, Short.MAX_VALUE)
                .addComponent(jLabel1)
                .addGap(43, 43, 43))
        );

        pack();
    }// </editor-fold>

    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(HlavniJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(HlavniJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(HlavniJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(HlavniJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new HlavniJFrame().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JLabel jLabel1;
    // End of variables declaration
}

Vidíme, že formulář je třída, dědící z třídy JFrame. To je právě třída reprezentující okno. V konstruktoru se volá podivná metoda initComponents(), jejíž kód byl sklapnutý. I když ho rozbalíme, NetBeans nám do této části třídy neumožní psát.

Metodu initComponents() automaticky generuje NetBeans podle toho, co na formulář naklikáme. I když vypadá složitě, nedělá nic jiného, než že vytvoří postupně všechny prvky na formuláři a nastaví jim patřičné vlastnosti, které jsme zvolili. Vidíme zde, jak se tvoří náš label a nastavují se mu vlastnosti. Metoda se poté volá v konstruktoru, čímž se formulář inicializuje. Nezasvěcený programátor je tedy plně odstíněn od kódu, co generuje návrhář. Je to samozřejmě hlavně proto, aby ho nemohl rozbít :) Nicméně je důležité vědět, jak to funguje, abyste byli schopni např. přidávat kontrolky za běhu aplikace.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Protože Swing používá stejně jako např. HTML relativní pozicování prvků, generuje NetBeans spoustu dalších neviditelných komponent, jako jsou různé mezery, oddělovače a tzv. layouty. V tomto kurzu se jim věnovat nebudeme, jelikož to kvůli přítomnosti grafického návrháře nebudeme potřebovat. Jsou však detailně vysvětleny v kurzu o ručním návrhu formulářů v Java Swing, kde se nepoužívá grafický návrhář a je tedy důležité, aby programátor rozuměl přesně tomu, jak se prvky na formulář umisťují, protože to musí dělat on sám.

Ve třídě nalezneme dále hlavní metodu main(), která vytvoří formulář a nastaví mu tzv. Look and Feel. To je jednoduše řečeno Skin. Jako výchozí je v NetBeans vzhled Nimbus, hodnotu můžete přepsat na Windows, vaše aplikace poté bude vypadat jako jste zvyklí z Windows. Na konci metody se vytváří instance hlavního formuláře.

Úprava pozice a velikosti okna

Ve výchozím nastavení se okno aplikace po jejím spuštění objeví v levém horním rohu obrazovky. Uživatel by ho očekával spíše uprostřed a bohužel to nelze nastavit v Properties. Podobně je to s velikostí okna. Ukažme si, jak se tyto vlastnosti okna mění.

Vycentrování okna

Proto kód vytvoření formuláře upravíme a přidáme jeho vycentrování:

public void run() {
    HlavniJFrame hlavniJFrame = new HlavniJFrame();
    hlavniJFrame.setLocationRelativeTo(null);
    hlavniJFrame.setVisible(true);
}

Když aplikaci spustíme, bude okno uprostřed obrazovky.

Zakázání zmenšování okna

Na stejném místě můžeme specifikovat i další vlastnosti hlavního okna. Někdy třeba budeme chtít, aby uživatel nemohl okno aplikace zvětšovat či zmenšovat, to se dělá pomocí setResizable():

hlavniJFrame.setResizable(false);

Minimální velikost

Občas se nám může hodit nastavit oknu minimální velikost. To je velikost, pod kterou už nepůjde okno ručně zmenšit. Můžeme k tomu použít metodu setMinimumSize(). Tato metoda bere jako parametr objekt typu Dimension, takže pokud bychom chtěli, aby naše okno mělo minimální velikost 100x100 pixelů, tak bychom zadali:

hlavniJFrame.setMinimumSize(new Dimension(100,100));

Obvykle ale chceme, aby tato minimální velikost byla právě ta velikost, jakou má naše okno hned po spuštění aplikace. Swing totiž vytváří nová okna tak, aby byla co nejmenší, ale zároveň byly vidět všechny komponenty. Toto je mimochodem účel volání pack() v samotném závěru initComponents(), přepočítá a nastaví optimální velikost okna podle velikostí komponent v něm. Velikost okna vrací metoda getSize(), takže aby naše okno nešlo zmenšit pod jeho optimální velikost, stačí ihned po jeho vytvoření zavolat:

HlavniJFrame hlavniJFrame = new HlavniJFrame();
hlavniJFrame.setMinimumSize(hlavniJFrame.getSize());

Takto vytvořené okno půjde ručně libovolně zvětšovat, ale zmenšit půjde jen do velikosti, v jaké se otevřelo.

Ikona

Nakonec si ukážeme, jak se dá nastavit ikonka, která se zobrazuje v levém horním rohu okna. Defaultně je použita standardní javovská ikonka. Abychom to změnili, je třeba mít vlastní ikonku nejlépe ve formátu .png. Soubor s ikonkou pojmenovaný například ikona.png umístíme do složky src/. V metodě run() poté provedeme:

public void run() {
    HlavniJFrame hlavniJFrame = new HlavniJFrame();
    ImageIcon icon = new ImageIcon(getClass().getResource("/ikona.png"));
    hlavniJFrame.setIconImage(icon.getImage());
}

Na úplném konci souboru nalezneme samotné komponenty, které jsme na formulář naklikali. Všimněme si, že název jejich tříd vždy začíná na J, např. JLabel. Je to z toho důvodu, aby se odlišily od starších komponent z AWT a také proto, že se jedná o Java třídy.

Dnešní projekt je ke stažení v příloze článku včetně zdrojových kódů.

Příště, Jednoduchá kalkulačka v Java Swing, si vysvětlíme, jak fungují události a naprogramujeme si jednoduchou kalkulačku.


 

Stáhnout

Staženo 332x (19.61 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Úvod do formulářových aplikací v Java Swing
Všechny články v sekci
Základy Java Swing
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
7 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn university Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (5)

 

 

Komentáře

Avatar
Tomhaus
Člen
Avatar
Tomhaus:16.7.2014 16:29

mě se nechce zobrazit ten vypsanej text

package clicker.graphics;

import java.awt.Dimension;

import javax.swing.JLabel;
import javax.swing.JPanel;

public class Screen extends JPanel {
        private static final long serialVersionUID = 1L;

        private static final int WIDTH = 300, HEIGHT = 200;

        private JLabel panel01;

        public Screen(){
                setFocusable(true);
                setPreferredSize(new Dimension(WIDTH, HEIGHT));

                display();
        }

        public void display(){
                panel01 = new JLabel();
                panel01.setText("ahoj");

        }

}
Editováno 16.7.2014 16:32
Odpovědět
16.7.2014 16:29
Být lepší a chytřejší je důležité, ale někdy se musíme spokojit s tím, co máme.
Avatar
Tomhaus
Člen
Avatar
Odpovídá na Tomhaus
Tomhaus:16.7.2014 16:49

ahh.. už sem na to přišel, musim to přidat add

Odpovědět
16.7.2014 16:49
Být lepší a chytřejší je důležité, ale někdy se musíme spokojit s tím, co máme.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Djejsi
Člen
Avatar
Djejsi:21.1.2019 19:59

Zdravim preco ked urobim to ze pridam vycentrovanie tak mi to vypisuje errory ale tebe v tom HelloSwing2 ked stiahnem tak to ide bez chyby? Pritom som nic neupravoval podla seba.

public class HlavniJframe extends javax.swing.JFrame {

    /**
     * Creates new form HlavniJframe
     */
    public HlavniJframe() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Pozdrav");

        jLabel1.setText("Pozdrav z formulare");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(156, 156, 156)
                .addComponent(jLabel1)
                .addContainerGap(148, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(134, 134, 134)
                .addComponent(jLabel1)
                .addContainerGap(152, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(HlavniJframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(HlavniJframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(HlavniJframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(HlavniJframe.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                HlavniJFrame hlavniJFrame = new HlavniJFrame();
                hlavniJFrame.setLocationRelativeTo(null);
                hlavniJFrame.setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify
    private javax.swing.JLabel jLabel1;
    // End of variables declaration
}

Errory:

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Uncompilable source code - Erroneous tree type: HlavniJFrame
        at HlavniJframe$1.run(HlavniJframe.java:86)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
 
Odpovědět
21.1.2019 19:59
Avatar
Martin Velc
Člen
Avatar
Odpovídá na Djejsi
Martin Velc:11.8.2019 10:08

Máš třídu nazvanou HlavniJframe, ale dole nastavuješ HlavniJFrame. Rozdíl je velké/malé F ve slově Frame.

 
Odpovědět
11.8.2019 10:08
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 4 zpráv z 4.