GUI v Javě

Z MiS
(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
(Třída JLabel: Zjednodušení popisu JLabel)
 
(Není zobrazeno 26 mezilehlých verzí od 1 uživatele.)
Řádka 1: Řádka 1:
[[Category:VSE]]
+
[[Category:VSE]][[Category:Škola]][[Category:Informatika]][[Category:Programování]][[Category:Java]][[Category:GUI]]
[[Category:Informatika]]
+
[[Category:Programování]]
+
[[Category:Java]]
+
  
== Vytvoření okna ==
+
Následující poznámky jsou jen velmi stručnou osnovou. Možností při vytváření grafického rozhraní je mnohem více. Pokud chcete více než jen minimalistický návod, doporučuji:
 +
[http://download.oracle.com/javase/tutorial/uiswing/ tutoriál ze stránek Oracle.com]
  
=== Třída <code>JFrame</code>: ===
 
* realizuje okno s titulním pruhem a tlačítky.
 
  
Vlastnosti okna
+
 
 +
 
 +
== Okno aplikace: <tt>JFrame</tt> ==
 +
 
 +
* Pro vytvoření okna aplikace používáme třídu <code>JFrame</code>. Okno má titulní pruh s&nbsp;nadpisem a tlačítka pro minimalizaci, maximalizaci a zavření.
 +
* Vytvoříme si vlastní třídu <code>PrvniOkno</code>, která bude potomkem třídy <tt>JFrame</tt> (<code>extends JFrame</code>).
 +
* Ve třídě <code>PrvniOkno</code> nastavíme popis a velikost okna. Později přidáme tlačítka, textová pole a další komponenty, které budou v&nbsp;okně obsaženy.
 +
 
 +
<div class="Priklad">
 +
; Příklad 1)
 +
* Vytvoř aplikaci s&nbsp;oknem, které půjde přesunovat, minimalizovat a při jehož zavření se aplikace ukončí.
 +
* V&nbsp;titulním pruhu bude zobrazen text ''„První aplikace!“''.
 +
 
 +
; Okno.java
 +
public class PrvniOkno extends JFrame {
 +
    public Okno() {
 +
      this.initComponents();
 +
    }
 +
    public void initComponents() {
 +
      this.setTitle("První aplikace!");
 +
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +
      this.setSize(300, 200);
 +
    }
 +
}
 +
; Main.java
 +
public static void main(String[] args) {
 +
    Okno okno = new Okno();
 +
    okno.setVisible(true);
 +
}
 +
</div>
 +
 
 +
; Vlastnosti okna
 
* <code>setTitle(String ''titulek'')</code>
 
* <code>setTitle(String ''titulek'')</code>
** nastavuje titulek okna (text v titulním pruhu).
+
** nastaví titulek okna (text v&nbsp;titulním pruhu).
 
* <code>setDefaultCloseOperation(int akce)</code>
 
* <code>setDefaultCloseOperation(int akce)</code>
** říká co se bude dít při stlačení zavíracího tlačítka.
+
** reakce na zavírací tlačítko.
** naše aplikace většinou mají jediné okno, chceme tedy, aby se při zavření okna zavřela celá aplikace.
+
** v&nbsp;jednoduchých příkladech obvykle chceme při stisknutí zavíracího tlačítka zavřít celou aplikaci:
*** k tomu slouží konstanta JFrame.EXIT_ON_CLOSE.
+
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  
Velikost okna
+
; Velikost okna
 
* <code>pack()</code>
 
* <code>pack()</code>
 
** zmenší velikost okna tak, aby se do něj vlezly komponenty, které jsou aktuálně v okně.
 
** zmenší velikost okna tak, aby se do něj vlezly komponenty, které jsou aktuálně v okně.
 +
* <code>setSize(sirka, vyska)</code>
 +
** Nastaví velikost okna na stanovený rozměr.
 +
* <code>setBounds(poziceX, poziceY, sirka, vyska)</code>
 +
** Umístí okno levým horním rohem na souřadnice <code>poziceX, poziceY</code> a nastaví jeho rozměry.
  
Zobrazení okna
+
; Zobrazení okna
 
* <code>setVisible(boolean maBytViditelne)</code>
 
* <code>setVisible(boolean maBytViditelne)</code>
 
** Zobrazí nebo zneviditelní okno.
 
** Zobrazí nebo zneviditelní okno.
  
=== Vkládání komponent do okna ===
+
; Metoda <tt>initComponents()</tt>
 +
* Je zvykem v&nbsp;konstruktoru okna zavolat soukromou (<code>private</code>) metodu <tt>initComponents()</tt>.
 +
* V rámci této metody připravíme všechny komponenty, které mají být součástí okna.
  
* Okno se skládá z dílčích součástí (komponent). Jsou to tlačítka, zatrhávací políčka, panely, tabulky,...
+
<div class="Ukol">
* Seskládání okna obvykle provádíme v soukromé metodě <code>initComponents()</code>, kterou pro tento účel vytvoříme.
+
; Úkol 1)
 +
* Vytvořte aplikaci s&nbsp;oknem velikosti 400×200 pixelů. Okno půjde přesunovat, minimalizovat. Při zavření okna se aplikace ukončí.
 +
* V titulním pruhu bude zobrazen text ''„Hello world!“''.
  
Vložení komponenty do okna
+
[[#Příklad 1|Řešení viz dále]]
* <code>getContentPane().add(Component komponentaVOkne)</code>
+
</div>
** vloží do okna komponentu. Pokud chceme mít komponent v okně více, je třeba je uspořádat pomocí [[GUI v Javě#Layout Manager | „layout manageru“]].
+
  
=== Příklad ===
+
== Základní komponenty ==
* Vytvořte aplikaci s oknem, které půjde přesunovat, minimalizovat a při jehož zavření se aplikace ukončí.
+
* V titulním pruhu bude zobrazen text „Hello world!“.
+
  
== Textová pole, tlačítka ==
+
* Do okna vkládáme grafické prvky &mdash; komponenty. Nejběžnější komponenty jsou tlačítka (<code>JButton</code>), textová pole (<code>JTextField</code>) a popisky (<code>JLabel</code>).
 +
* Je-li komponent v okně mnoho, můžeme je [[Layout v Javě|uspořádat]]. K tomu slouží panely (<code>JPanel</code>) a případně správci rozložení (<code>LayoutManager</code>).
 +
* My budeme rozložení komponent řešit pomocí vizuálního návrháře v&nbsp;IntelliJ IDEA. Nezapomeň hlavní panel formuláře pojmenovat a vložit ho do okna pomocí:
 +
setContentPane(mainPanel);
  
Do okna vkládáme součásti (komponenty). Komponenty jsou potomky třídy <code>JComponent</code>.  
+
=== Tlačítko <code>JButton</code> ===
 +
* Tlačítka realizuje třída <code>JButton(String popisTlacitka)</code>
 +
* Text na tlačítku zadáme jako parametr konstruktoru:
 +
JButton tlStart = new JButton("Start");
 +
* Tlačítku nastavíme ''listener''. Ten v&nbsp;reakci na stisk tlačítka provede akci:
 +
tlStart.addActionListener(e -> provedAkci());
  
Nejběžnější komponenty jsou:
+
<div class="Priklad">
* tlačítka (<code>JButton</code>),
+
Připravte okno s&nbsp;jedním tlačítkem. Po stisknutí tlačítka objeví vyskakovací okno s&nbsp;pozdravem:
** parametrem konstruktoru je text na tlačítku.
+
* textová pole (<code>JTextField</code>),
+
** volitelným parametrem konstruktoru je délka pole, vyjádřená jako počet znaků.
+
* popisky (<code>JLabel</code>).
+
  
Je-li komponent v okně mnoho, můžeme je uspořádat na
+
import javax.swing.*;
* panely (<code>JPanel</code>).
+
 +
public class Pozdrav extends JFrame {
 +
    private JPanel mainPanel;
 +
    private JButton btPozdrav;
 +
    public Pozdrav() {
 +
        initComponents();
 +
    }
 +
    private void initComponents() {
 +
        setContentPane(mainPanel);
 +
        setTitle("Pozdrav!");
 +
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +
        setSize(400, 300);
 +
        btPozdrav.addActionListener(e -> pozdrav());
 +
    }
 +
    private void pozdrav() {
 +
        JOptionPane.showMessageDialog(this, "Ahoj světe!");
 +
    }
 +
}
 +
</div>
  
Příklad
+
; Další metody tlačítka:
 +
* <code>String getText()</code>, <code>setText(String novy)</code>
 +
** vrací/nastavuje popis tlačítka.
 +
* <code>setIcon(ImageIcon obr)</code>
 +
** Nastavení obrázku místo textu.
 +
<div class="Priklad">
 +
ImageIcon obr;
 +
obr = new ImageIcon("res/krizek.png");
 +
JButton tlacitko = ...
 +
...
 +
tlacitko.setIcon(obr);
 +
</div>
 +
 
 +
=== Popisky <code>JLabel</code> ===
 +
* Informativní text můžeme zobrazit pomocí třídy <code>JLabel(String textPopisu)</code>.
 +
* Text popisky zadáme jako parametr konstruktoru
 +
JLabel lCisloA = new JLabel("Zadejte číslo A:");
 +
 
 +
=== Třída <code>JTextField</code> ===
 +
* <code>JTextField(int pocetZnaku)</code>
 +
** volitelným parametrem konstruktoru je délka pole, vyjádřená početem znaků, které do pole vlezou.
 +
* <code>String getText()</code>
 +
** vrací aktuální text v textovém poli
 +
* <code>setText(String text)</code>
 +
** nastaví do textového pole zadaný text
 +
* <code>setEditable(boolean lzeUpravovat)</code>
 +
** nastaví, zda do textového pole lze psát, nebo zda je šedivé a úpravy jsou zakázány.
 +
; Další nastavení
 +
* <code>setFont(new java.awt.Font("Lucida Sans", 0, 24))</code>
 +
** Nastavení fontu.
 +
* <code>setHorizontalAlignment(javax.swing.JTextField.RIGHT)</code>
 +
** nastaví zarovnání vpravo.
 +
* Ve vývojovém prostředí je určitě pohodlnější nastavit vše přes grafický nástroj Properties.
 +
 
 +
Pokud potřebujete z textového pole načíst číslo, můžete použít následující metodu:
 +
<code>
 +
    /**
 +
    * Získá číslo z textového pole
 +
    *
 +
    * @param textovePole Textové pole, jehož hodnota se má převést na číslo
 +
    * @return Vrátí hodnotu čísla, zapsaného v textovém poli.
 +
    *    Pokud text v poli nelze převést na číslo (pole je prázdné apod.),
 +
    *      vrátí 0
 +
    *      a navíc do textového pole zapíše výzvu k vložení čísla.    */
 +
    private int ziskejCislo(JTextField textovePole) {
 +
        int vysledek;
 +
        try {
 +
            vysledek = Integer.parseInt(textovePole.getText());
 +
        } catch (NumberFormatException e) {
 +
            textovePole.setText("Nastavte platné číslo!");
 +
            vysledek = 0;
 +
        }
 +
        return vysledek;
 +
    }
 +
</code>
 +
 
 +
=== Vkládání komponent do okna ===
 +
* Abychom komponentu zobrazili, musíme ji umístit do některého okna.
 +
* Seskládání okna obvykle provádíme v soukromé metodě <code>initComponents()</code> okna, kterou pro tento účel vytvoříme.
 +
* Pokud chceme mít komponent v okně více, je třeba je uspořádat pomocí [[Layout v Javě | „layout manageru“]].
 +
 
 +
=== Třída <code>JFrame</code> ===
 +
* <code>getContentPane().add(Component komponentaVOkne)</code>
 +
** vloží do okna komponentu.
 +
 
 +
=== Příklad ===
 
* Vytvořte okno s jediným tlačítkem.
 
* Vytvořte okno s jediným tlačítkem.
 
* Na tlačítku bude text „Superokno!“
 
* Na tlačítku bude text „Superokno!“
 +
 +
<div class="Poznamka">
 +
Všechny komponenty jsou potomky třídy <code>JComponent</code>, ale o to se nemusíme starat. To nás bude zajímat až v&nbsp;okamžiku, kdy budeme chtít vytvořit vlastní komponenty.
 +
</div>
  
 
== Zpracování událostí, posluchač ==
 
== Zpracování událostí, posluchač ==
 +
* Pro zpracování událostí prvků GUI (tlačítek, textových polí,...) používá Java [[Návrhový vzor Pozorovatel | návrhový vzor Pozorovatel (Observer)]].
 +
 +
=== Postup zpracování události tlačítka ===
 +
# uživatel klikne na tlačítko
 +
# objekt reprezentující tlačítko ''vygeneruje událost'' (event)
 +
#: prakticky vytvoří novou instanci třídy <code>ActionEvent</code>), která nese podrobnější informace (které tlačítko myši bylo stisknuto, na jakých souřadnicích,...
 +
# objekt reprezentující tlačítko událost pošle všem svým „posluchačům“ (posluchači jsou objekty, které splňují rozhraní (interface) <code>ActionListener</code>)
 +
#: prakticky se „poslání události“ realizuje tak, že tlačítko zavolá metodu <code>actionPerformed(ActionEvent e)</code>, kterou předepisuje rozhraní <code>ActionListener</code>. Jako parametr metody se předá objekt události
 +
# posluchač provede akci, která se má provést
 +
#: programátor tedy akci popíše v kódu metody <code>actionPerformed(ActionEvent e)</code> v posluchači
 +
 +
=== Aby bylo možné na stisk tlačítka reagovat, musíme: ===
 +
# mít třídu posluchače (interface <code>ActionListener</code>)
 +
# vytvořit instanci třídy posluchače
 +
# zaregistrovat instanci třídy posluchače u tlačítka.
 +
 +
=== <code>class ActionEvent</code> ===
 +
* <code>public Object getSource()</code>
 +
** vrací objekt, který událost vyvolal. V našem případě instanci třídy <code>JButton</code>, reprezentující tlačítko, které bylo stisknuto.
 +
** je potřeba provést [[Java: Abstraktní třídy, dědičnost a rozhraní#Přetypování | přetypování]] z <code>Object</code> na <code>JButton</code>.
 +
 +
=== <code>interface ActionListener</code> ===
 +
* <code>public void actionPerformed(ActionEvent e)</code>
 +
** v této metodě popíšeme, co se má stát při stisku tlačítka
 +
 +
=== Ukázka kódu ===
 +
 +
* V&nbsp;metodě <code>initComponents</code> nebo obdobné:
 +
JButton tlacitko = new JButton("Popis");
 +
tlacitko.addActionListener(event -> metodaPoStisknuti(event));
 +
 +
* Dále přidejte metodu:
 +
private void metodaPoStisknuti(ActionEvent event) {
 +
    // ... co se má stát po stisku tlačítka
 +
}
 +
 +
* Parametr <code>event</code> můžete vynechat, pokud nepotřebujete získávat informace o tlačítku, které událost vyvolalo.
 +
 +
 +
=== Příklad ===
 +
* Přidejte k tlačítku z příkladu v předchozím odstavci reakci.
 +
* Při stisku tlačítka se do textového výstupu programu opíše text z popisu tlačítka.
 +
 +
<div class="Priklad">
 +
Příklad
 +
* Přidejte k předchozímu příkladu dvě textová pole s popiskami (label) „Originál“ a „Kopie“.
 +
* Textové okno s popisem „Kopie“ nebude editovatelné.
 +
* Tlačítko upravte tak, že na něm bude popis „Kopíruj“.
 +
* Při stisknutí tlačítka se text z pole „Originál“ zkopíruje do pole „Kopie“.
 +
* Při stisku tlačítka se do textového výstupu programu opíše text z popisu tlačítka.
 +
</div>
 +
 +
 +
== Rozšíření ==
 +
 +
=== Umístění okna na střed obrazovky ===
 +
 +
    private static void setToTheMiddle(JFrame frame) {
 +
        GraphicsConfiguration gc = frame.getGraphicsConfiguration();
 +
        Rectangle bounds = gc.getBounds();
 +
        Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
 +
        Rectangle effectiveScreenArea = new Rectangle();
 +
 +
        effectiveScreenArea.x = bounds.x + screenInsets.left;
 +
        effectiveScreenArea.y = bounds.y + screenInsets.top;
 +
        effectiveScreenArea.height = bounds.height - screenInsets.top - screenInsets.bottom;
 +
        effectiveScreenArea.width = bounds.width - screenInsets.left - screenInsets.right;
 +
 +
        // Umístění doprostřed:
 +
        int middleX = effectiveScreenArea.x + (effectiveScreenArea.width - frame.getWidth()) / 2;
 +
        int middleY = effectiveScreenArea.y + (effectiveScreenArea.height - frame.getHeight()) / 2;
 +
        frame.setLocation(middleX, middleY);
 +
    }
 +
 +
 +
== Související stránky ==
 +
* [[Layout v Javě]], [[Dialogy a vyskakovací okna]], [[Menu v Javě]], [[Tabulky v Javě]]
 +
 +
== Další zdroje ==
 +
* [https://www.youtube.com/watch?v=vuQdLKq2LaY Youtube.com > First Java Swing GUI Application with IntelliJ IDEA IDE (2022)]
 +
  
== Layout Manager ==
+
== Řešení příkladů ==
 +
=== Příklad 1 ===
 +
; Okno.java
 +
public class Okno extends JFrame {
 +
    public Okno() {
 +
      this.initComponents();
 +
    }
 +
    public void initComponents() {
 +
      this.setTitle("Hello world!");
 +
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +
      this.pack();
 +
    }
 +
}
 +
; Main.java
 +
public static void main(String[] args) {
 +
    Okno okno = new Okno();
 +
    okno.setVisible(true);
 +
}

Aktuální verze z 27. 1. 2025, 07:47


Následující poznámky jsou jen velmi stručnou osnovou. Možností při vytváření grafického rozhraní je mnohem více. Pokud chcete více než jen minimalistický návod, doporučuji: tutoriál ze stránek Oracle.com



Obsah

Okno aplikace: JFrame

Příklad 1)
  • Vytvoř aplikaci s oknem, které půjde přesunovat, minimalizovat a při jehož zavření se aplikace ukončí.
  • V titulním pruhu bude zobrazen text „První aplikace!“.
Okno.java
public class PrvniOkno extends JFrame {
   public Okno() {
      this.initComponents();
   }
   public void initComponents() {
      this.setTitle("První aplikace!");
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setSize(300, 200);
   }
}
Main.java
public static void main(String[] args) {
   Okno okno = new Okno();
   okno.setVisible(true);
}
Vlastnosti okna
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Velikost okna
Zobrazení okna
Metoda initComponents()
Úkol 1)
  • Vytvořte aplikaci s oknem velikosti 400×200 pixelů. Okno půjde přesunovat, minimalizovat. Při zavření okna se aplikace ukončí.
  • V titulním pruhu bude zobrazen text „Hello world!“.

Řešení viz dále

Základní komponenty

setContentPane(mainPanel);

Tlačítko JButton

JButton tlStart = new JButton("Start");
tlStart.addActionListener(e -> provedAkci());

Připravte okno s jedním tlačítkem. Po stisknutí tlačítka objeví vyskakovací okno s pozdravem:

import javax.swing.*;

public class Pozdrav extends JFrame {
   private JPanel mainPanel;
   private JButton btPozdrav;
   public Pozdrav() {
       initComponents();
   }
   private void initComponents() {
       setContentPane(mainPanel);
       setTitle("Pozdrav!");
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       setSize(400, 300);
       btPozdrav.addActionListener(e -> pozdrav());
   }
   private void pozdrav() {
       JOptionPane.showMessageDialog(this, "Ahoj světe!");
   }
}
Další metody tlačítka
ImageIcon obr;
obr = new ImageIcon("res/krizek.png");
JButton tlacitko = ...
...
tlacitko.setIcon(obr);

Popisky JLabel

JLabel lCisloA = new JLabel("Zadejte číslo A:");

Třída JTextField

Další nastavení

Pokud potřebujete z textového pole načíst číslo, můžete použít následující metodu:

   /**
    * Získá číslo z textového pole
    *
    * @param textovePole Textové pole, jehož hodnota se má převést na číslo
    * @return Vrátí hodnotu čísla, zapsaného v textovém poli.
    *     Pokud text v poli nelze převést na číslo (pole je prázdné apod.),
    *      vrátí 0
    *      a navíc do textového pole zapíše výzvu k vložení čísla.     */
   private int ziskejCislo(JTextField textovePole) {
       int vysledek;
       try {
           vysledek = Integer.parseInt(textovePole.getText());
       } catch (NumberFormatException e) {
           textovePole.setText("Nastavte platné číslo!");
           vysledek = 0;
       }
       return vysledek;
   }

Vkládání komponent do okna

Třída JFrame

Příklad

Všechny komponenty jsou potomky třídy JComponent, ale o to se nemusíme starat. To nás bude zajímat až v okamžiku, kdy budeme chtít vytvořit vlastní komponenty.

Zpracování událostí, posluchač

Postup zpracování události tlačítka

  1. uživatel klikne na tlačítko
  2. objekt reprezentující tlačítko vygeneruje událost (event)
    prakticky vytvoří novou instanci třídy ActionEvent), která nese podrobnější informace (které tlačítko myši bylo stisknuto, na jakých souřadnicích,...
  3. objekt reprezentující tlačítko událost pošle všem svým „posluchačům“ (posluchači jsou objekty, které splňují rozhraní (interface) ActionListener)
    prakticky se „poslání události“ realizuje tak, že tlačítko zavolá metodu actionPerformed(ActionEvent e), kterou předepisuje rozhraní ActionListener. Jako parametr metody se předá objekt události
  4. posluchač provede akci, která se má provést
    programátor tedy akci popíše v kódu metody actionPerformed(ActionEvent e) v posluchači

Aby bylo možné na stisk tlačítka reagovat, musíme:

  1. mít třídu posluchače (interface ActionListener)
  2. vytvořit instanci třídy posluchače
  3. zaregistrovat instanci třídy posluchače u tlačítka.

class ActionEvent

interface ActionListener

Ukázka kódu

JButton tlacitko = new JButton("Popis");
tlacitko.addActionListener(event -> metodaPoStisknuti(event));
private void metodaPoStisknuti(ActionEvent event) {
    // ... co se má stát po stisku tlačítka
}


Příklad

Příklad

  • Přidejte k předchozímu příkladu dvě textová pole s popiskami (label) „Originál“ a „Kopie“.
  • Textové okno s popisem „Kopie“ nebude editovatelné.
  • Tlačítko upravte tak, že na něm bude popis „Kopíruj“.
  • Při stisknutí tlačítka se text z pole „Originál“ zkopíruje do pole „Kopie“.
  • Při stisku tlačítka se do textového výstupu programu opíše text z popisu tlačítka.


Rozšíření

Umístění okna na střed obrazovky

   private static void setToTheMiddle(JFrame frame) {
       GraphicsConfiguration gc = frame.getGraphicsConfiguration();
       Rectangle bounds = gc.getBounds();
       Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
       Rectangle effectiveScreenArea = new Rectangle();

       effectiveScreenArea.x = bounds.x + screenInsets.left;
       effectiveScreenArea.y = bounds.y + screenInsets.top;
       effectiveScreenArea.height = bounds.height - screenInsets.top - screenInsets.bottom;
       effectiveScreenArea.width = bounds.width - screenInsets.left - screenInsets.right;

       // Umístění doprostřed:
       int middleX = effectiveScreenArea.x + (effectiveScreenArea.width - frame.getWidth()) / 2;
       int middleY = effectiveScreenArea.y + (effectiveScreenArea.height - frame.getHeight()) / 2;
       frame.setLocation(middleX, middleY);
   }


Související stránky

Další zdroje


Řešení příkladů

Příklad 1

Okno.java
public class Okno extends JFrame {
   public Okno() {
      this.initComponents();
   }
   public void initComponents() {
      this.setTitle("Hello world!");
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.pack();
   }
}
Main.java
public static void main(String[] args) {
   Okno okno = new Okno();
   okno.setVisible(true);
}
Osobní nástroje
Jmenné prostory
Varianty
Akce
Výuka
Navigace
Nástroje