Cieľom kapitoly je ukázať súhru nových grafických prvkov s ich poslucháčmi. Zoznámime sa okrem iného s triedami JMenuItem, JMenu, JMenuBar, JCheckBox, JFileChooser a JOptionPane. Takisto s poslucháčmi, schopnými reagovať na udalosti, týkajúce sa kontajneru, textového poľa, poprípade kláves.
Filozofia pridávania prvkov na materskú komponentu a filozofia práce s poslucháčmi-listenermi je nám už známa. Teraz rozšírime zoznam prvkov o tie najčastejšie používané. Ukážeme na jednoduchých príkladoch, ako spolupracujú s poslucháčmi.
Nasledujúci
kód predstavuje v práci prvky JMenuItem, JMenu, JMenuBar, JtextField. Prvé
tri umožňujú pracovať s ponukami.
K riadku ponúk JmenuBar pridávame ponuky typu JMenu a ku každej
ponuke ,môžeme pridať položky ponuky typu JMenuItem. V našom prípade prvú ponuku tvoria mená hrdinov, druhú
ponuku mená hrdiniek. Keď zvolíme mená hrdinov, hrdiniek, objaví sa
v políčku text. Túto činnosť zaobstarajú poslucháči jednotlivých položiek
ponuky. Políčko má tiež svojho poslucháča. Ten pri editovaní políčka začne po
stlačení klávesy enter svoju činnosť.
Po spustení programu vyberte najprv meno hrdinu.
Potom meno hrdinky. Potom stlačte enter. Stlačte enter ešte raz a sledujte
pokyny z políčka. Na konci sa presvedčte, že do ponuky „hrdina“ pribudla
nová položka. Vyskúšajte jej činnosť. Pozrite sa potom do kódu a zistite,
ktorý poslucháč zabezpečuje činnosť novej položky.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Ponuky extends JFrame{
JTextField policko = new
JTextField(" Zvol si dvojicu. ",20);
JMenu menu1
= new JMenu("hrdina");
JMenu
menu2 = new JMenu("hrdinka");
JMenuItem[]
muzi = {new JMenuItem("Tarzan"),new JMenuItem("Conan"),new
JMenuItem("Herkules")};
JMenuItem[]
zeny = {new JMenuItem("Snehulienka"),new
JMenuItem("Popoluska"),new JMenuItem("Evita")};
Container
cp = getContentPane();
private
ActionListener uchoMenus1 = new ActionListener() {
public
void actionPerformed(ActionEvent e) {
policko.setText(((JMenuItem)e.getSource()).getText() + " a ");
}
};
private
ActionListener uchoMenus2 = new ActionListener() {
public
void actionPerformed(ActionEvent e) {
String text = policko. getText();
if(text.endsWith(" a")) {
policko.setText("Zacni pisanie
hrdinom.");
}
else
{
policko.setText(policko. getText() + " " +
((JMenuItem)e.getSource()).getText() );
}//EOElse
}//EOMethod
};
private
ActionListener uchoPolicka = new ActionListener() {
//
zisti, ci sa enter stlacil prvy raz
boolean prvyRaz = true;
public
void actionPerformed(ActionEvent e) {
String
text = policko. getText();
if(prvyRaz
== true) {
prvyRaz = false;
policko.setText(text + "? To je ale blbost!");
}
else{
if(text.startsWith("Napis svoje meno a potom stlac
enter:")){
String meno = text.substring(37,text.length());
policko.setText("Pridal som hrdinu \"" + meno +
"\" " );
JMenuItem novyHrdina = new JMenuItem(meno);
novyHrdina.addActionListener(uchoMenus1);
menu1.add( novyHrdina);
}//EOIf
else{
policko.setText("Napis svoje meno a potom stlac
enter:");
}//EOInnerElse
}//EOElse
}//EOMethod
};//EOListener
public
Ponuky(){
super("Voliace prvky ");
setSize(500,70);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
policko.setFont(new Font("plain",1,14 ));
policko.addActionListener(uchoPolicka);
//
Pridavanie JMenuItems - aj s Listenermi
for(int i
= 0; i < 3; i++) {
menu1.add(muzi[i]);
muzi[i].addActionListener(uchoMenus1);
menu2.add(zeny[i]);
zeny[i].addActionListener(uchoMenus2);
}//EOFor
//Ukladanie prvkov na kontajner
cp.setLayout(new BoxLayout(cp,BoxLayout.X_AXIS));
//
ulozenie menus na JMenuBar
JMenuBar
menus = new JMenuBar();
menus.add(menu1);
menus.add(menu2);
cp.add(Box.createHorizontalGlue());
// pridanie popisky
policko.setToolTipText(" policko ");
cp.add(policko);
cp.add(Box.createHorizontalStrut(10));
cp.add(menus);
cp.add(Box.createHorizontalGlue());
}//EndOfTheConstructor
public
static void main(String[] args){
Ponuky vb = new Ponuky();
vb.setVisible(true);
}//EOMain
}//EOClass Ponuky
Komentáre:
Ak po spustení programu podržíte kurzor myši nad políčkom, po čase sa objaví popiska s nápisom „policko“. Je to vďaka príkazu
policko.setToolTipText(" policko ");
Metóda setToolText(String s) je definovaná pre mnohé
iné grafické prvky, ako napríklad tlačítka, celkovo pre všetkých
potomkov triedy JComponent.
Riadok
policko.setFont(new Font("plain",1,14 ));
nastavil pre políčko konkrétny font.
V nasledujúcom kóde sú ukázané dve veci. Za prvé práca so
zaškrtávacími políčkami. Za druhé je tu využitá možnosť odobrať (pridať)
poslucháča počas behu aplikácie. Viď riadky
prvyCheck.removeActionListener(ucho1);
a
prvyCheck.addActionListener(ucho1);
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Volme extends JFrame{
Container
cp = getContentPane();
JTextField policko = new JTextField(26);
JCheckBox
prvyCheck = new JCheckBox();
JCheckBox
druhyCheck = new JCheckBox(" odober posluchaca",false);
private
Posluchac1 ucho1 = new Posluchac1();
private
Posluchac2 ucho2 = new Posluchac2();
class
Posluchac1 implements ActionListener {
public
void actionPerformed(ActionEvent e) {
if(prvyCheck.isSelected())
policko.setText("Prvy zaskrtnuty");
else
policko.setText("Prvy odznaceny");
}
}
class
Posluchac2 implements ActionListener {
public
void actionPerformed(ActionEvent e) {
if(druhyCheck.isSelected()){
prvyCheck.removeActionListener(ucho1);
policko.setText("Druhy zaskrtnuty, ubral posluchaca prvemu");
druhyCheck.setText("pridaj posluchaca");
}//EOIf
else {
policko.setText("Druhy odznaceny, pridal posluchaca prvemu");
prvyCheck.addActionListener(ucho1);
druhyCheck.setText("odober
posluchaca");
}//EOElse
}//EOMethod
}//EOInnerClass
public Volme(){
super("Voliace
prvky ");
setSize(500,80);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
prvyCheck.addActionListener(ucho1);
druhyCheck.addActionListener(ucho2);
cp.setLayout(new FlowLayout());
cp.add(Box.createHorizontalGlue());
cp.add(policko);
cp.add(Box.createHorizontalStrut(10));
prvyCheck.setToolTipText(" CheckBox ");
cp.add(prvyCheck);
cp.add(Box.createHorizontalStrut(10));
druhyCheck.setToolTipText(" CheckBox s textom ");
cp.add(druhyCheck);
cp.add(Box.createHorizontalGlue());
}//EOConstructor
public
static void main(String[] args){
Volme vb = new Volme();
vb.setVisible(true);
}//EOMain
Reagovanie na klávesy. Poslucháči okna textového
poľa
Po predchádyajúcich jednoduchších príkladoch sa už ľahšie zorientujeme v nasledujúcom komplexnejšom. Je to príklad zlúčenia a prepojenia viacerých reakcií na udalosti kláves a na udalosť v textovom poli.
K panelu je pridaný poslucháč, ktorý reaguje na
stlačenie a uvoľnenie kláves. Príslušný kód klávesy a jej meno sa
odosiela do textového poľa, kde sa zobrazí. Ak sa v textovom poli objaví
String „Delete“, text po piatich sekundách z poľa zmizne. Text „Delete“ sa
v poli objaví, ak napríklad klepneme na klávesu „Delete“, alebo ak ho do
textového poľa sami napíšeme.
V príklade vidno rozdiel medzi udalosťami
„keyPressed“ a „keyTyped“. Prvá nastane po stlačení ľubovoľnej klávesy, druhá
len po stlačení „znakovej“, „písmenkovej“ klávesy. Teda takej, ktorá pridá znak
na obrazovku, keď píšeme v nejakom editore.
Na tri klávesy reaguje program špeciálne: sú to
klávesy „r, g, b“. Slúžia na pridávanie červenej (red – r) , zelenej, alebo
modrej zložky farby. Všetky tri zložky, reprezentovateľné číslom od 0 do 255,
sa zmiešajú do výslednej farby, ktorú vidno na hornej polovici okna. Jednotlivé
tlačítka „R, G, B“ slúžia iba na zobrazenie sýtosti červenej (prvé tlačítko),
zelenej (druhé tlačítko) a modrej farby (samozrejme, tretie
tlačítko). Nemajú pridelených žiadnych
poslucháčov. Stredné tlačítko má k dispozícii popisku. Na tej si možno
pozrieť aktuálne nastavenú trojicu čísel RGB. Keď nechceme čísla od 0 do 255
zväčšovať, ale naopak, chceme ich zmenšovať, podržíme klávesu „Ctrl “
a opäť pracujeme s klávesami „r,g,b“ na klávesnici.
Poslucháč komponenty v našom príklade robí
niečo, čo by seriózna, konzervatívna
aplikácia asi robiť nemala: keď presunieme okno, toto najprv na tri sekundy
zmizne. Až potom sa znovu objaví, už na
novom mieste.
Kód Gr3.3
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Klavesy extends JFrame{
JButton
rButton = new JButton(" R ");
JButton
gButton = new JButton(" G ");
JButton
bButton = new JButton(" B ");
Container
cp = getContentPane();
Box
vodorovny = Box.createHorizontalBox();
TextArea
txt = new TextArea(12,40);
Posluchac
uchoKlaves = new Posluchac();
UchoTextu
uchoTextu = new UchoTextu();
UchoKomponenty uchoKomponenty = new UchoKomponenty();
int red =
0;
int green
=0;
int blue =
0;
public Klavesy(){
super(" Pokus s klavesmi ");
setSize(500,400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//
prvi dvaja posluchaci pre komponentu, treti pre textove pole
addComponentListener(uchoKomponenty);
addKeyListener(uchoKlaves);
txt.addTextListener(uchoTextu);
cp.setBackground(new Color(red,green, blue));
cp.setLayout(new BorderLayout());
// panel
s tlacitkami bude na severe
vodorovny.add(Box.createHorizontalStrut(100));
vodorovny.add(rButton);
vodorovny.add(Box.createHorizontalGlue());
vodorovny.add(gButton);
vodorovny.add(Box.createHorizontalGlue());
vodorovny.add(bButton);
vodorovny.add(Box.createHorizontalStrut(100));
cp.add(BorderLayout.NORTH,vodorovny);
//panel s
textovym polom bude na juhu
JPanel
pnText = new JPanel();
pnText.setBackground(new Color(190,130,200));
pnText.add(new
JScrollPane(txt));
cp.add(BorderLayout.SOUTH,pnText);
}//EOConstructor
//
vnutorna trieda:
class
Posluchac implements KeyListener {
int
kod = -1;
boolean ctrl = false;
public void keyPressed(KeyEvent e){
kod = e.getKeyCode();
if(kod == 17)
{ ctrl = true;
}
// rozdiel medzi keyPressed a keyTyped:
// sledujte odozvu klavesy F1 pred odkomentovanim
// a po odkomentovani nasledujucich riadkov
// txt.append("\n Kod stlacenej klavesy: "
// +
String.valueOf(kod));
}
public void keyTyped(KeyEvent e){
txt.append("\n Kod stlacenej klavesy: "
+ String.valueOf(kod));
prefarbi(kod,ctrl);
}
public
void keyReleased(KeyEvent e){
int kod2
= e.getKeyCode();
if(kod2 == 17)
{ ctrl = false;
}
String menoKlavesy = e.getKeyText(kod2);
txt.append(" \n Meno klavesy: " + menoKlavesy);
}
}//EOInnerClass
//
vnutorna trieda:
class
UchoTextu implements TextListener{
//
Akonahle sa v textovom poli objavi text "Delete"
// o 5
sekund sa vsetok text v poli vymaze:
public
void textValueChanged(TextEvent e){
String obsah = txt.getText();
if (obsah.indexOf("Delete") >
-1) {
txt.append("\n O 5 sekund vycistim textove pole.");
long
t1 = 5000 + System.currentTimeMillis();
while(System.currentTimeMillis() < t1) ;
txt.setText("");
}//EOIf
}
}
// vnutorna
trieda:
class UchoKomponenty implements
ComponentListener {
public void componentResized(ComponentEvent
e){
}
public void componentHidden(ComponentEvent
e){
}
public void componentMoved(ComponentEvent
e){
setVisible(false);
long
t1 = 3000 + System.currentTimeMillis();
while(System.currentTimeMillis() < t1) ;
setVisible(true);
}
public
void componentShown(ComponentEvent e){
}
}//EOInnerClass
// metoda
, urcujuca farbu tlacitok a hlavneho panelu cp
//
reaguje na stlacenie klaves r g b , (s
kodmi 82 71
66)
// a na
to, ci drzime / nedrzime tlacitko Ctrl
private
void prefarbi(int kod, boolean ctrl){
if(kod
== 82){
red
= zmen(red,ctrl);
rButton.setText(String.valueOf(red));
rButton.setBackground(new Color(red,0,0));
cp.setBackground(new Color(red,green, blue));
}
if(kod
== 71){
green
= zmen(green,ctrl);
gButton.setText(String.valueOf(green));
gButton.setBackground(new Color(0,green,0));
cp.setBackground(new Color(red,green, blue));
}
if(kod == 66){
blue = zmen(blue,ctrl);
bButton.setText(String.valueOf(blue));
bButton.setBackground(new Color(0,0,blue));
cp.setBackground(new Color(red,green, blue));
}
// uved udaj o cislach RGB na popiske gButtonu
String info = String.valueOf(red) + " " +
String.valueOf(green) + " " +
String.valueOf(blue);
gButton.setToolTipText(info); }
// pomocna metoda pre metodu prefarbi
// zabezpecuje zmensovanie-zvacsovanie
// kodovych cisel pre farby RGB
private
int zmen(int farba,boolean zmensit){
if(zmensit){
farba = (farba >10)? (farba-10) : farba;
}
else
{
farba = (farba < 245)? (farba+10) : farba;
}
return farba;
}//EOMethod
public
static void main(String[] args){
Klavesy kl = new Klavesy();
kl.setVisible(true);
}//EOMain
}//EOClass
Dialógové okno JFileChooser
Trieda JFileChooser poskytuje okno, grafické rozhranie, ktoré nám umožňuje vidieť adresáre a súbory. A taktiež bežným spôsobom sa medzi nimi pohybovať. Dovoľuje aj implementovať vykonanie určitej operácie so zvoleným súborom. Touto operáciou by mohlo byť napríklad preeditovanie súboru alebo prehranie audiosúboru. Celkovoa všetko, čo Java so súbormi dokáže.
V našom príklade sa najprv objaví malé okienko. Do políčka zapíšeme slovo a stlačíme tlačítko „hľadaj“. Vtedy sa objaví dialógové okno. Po výbere súboru – stlačení tlačítka „Open“ dialógové okno JFileChooser zmizne. Objaví sa okno správ, vyvolané statickou metódou
JOptionPane.showMessageDialog(...). Okno buď oznámi,
že vo vybranom súbore sa hľadaný String nenachádza, alebo vypíše prvý riadok
súboru, v ktorom program hľadaný String našiel.
// program umozni zadat String a vybrat subor
// ukaze prvy riadok, v ktorom sa String nachadza
// alebo poda spravu, ze v subore takyto String nie
je
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
// pomocna trieda , hlada ci sa v subore nachadza
zadany String
class Hladaj{
// staticka
metoda
public
static String slovo(String text,File f){
String riadok = "Vyraz \"" +text + "\" sa v subore " +
f.getName() + " nenachadza";
try{
String
docasny;
BufferedReader citaj = new BufferedReader(new FileReader(f));
while(
(docasny=citaj.readLine())!=null){
if(docasny.indexOf(text)>-1) {
riadok = docasny;
break;
}//EOIf
}//EOWhile
}//EOTry
catch(FileNotFoundException e){
return
"Subor sa nenasiel. Asi ste ziaden neoznacili." ;
}
catch(IOException e){
return
"Nastal problem pri citani suboru." ;
}
return riadok;
}//EOMethod
}//EOClass Hladaj
public class FChooser extends JFrame {
JLabel
label= new JLabel("Hladane slovo");
JTextField
policko = new JTextField(20);
JButton
tlacitko = new JButton("Hladaj");
public
FChooser(){
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(label);
cp.add(policko);
cp.add(tlacitko);
// pridany poslucahc definovany ako
//instancia vnutornej anonymnej triedy:
tlacitko.addActionListener(new
ActionListener() {
public
void actionPerformed(ActionEvent e){
String coHladas = policko.getText();
hladanie(coHladas);
}});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400,100);
this.setVisible(true);
}
private void hladanie(String hladane){
System.out.println("Spustam hladanie
slova " + hladane);
JFileChooser c = new JFileChooser();
/////////////FileChooser dalsie
metody///////////////////
/*
c.setApproveButtonText("prehladaj"); // zmeni text tlacitka
String home = System.getProperty("user.dir");
File homeDir = new File(home);
c.setCurrentDirectory(homeDir);
// zmeni vychodiskovy adresar na adresar homeDir
//////////////////////////////*/
//
Ukazka dialogu "Open":
int
rVal = c.showOpenDialog(FChooser.this);
//
pokus: zakomentujte predosly riadok, odkomentujte nasledujuci
//int
rVal = c.showOpenDialog(tlacitko);
if(rVal == JFileChooser.APPROVE_OPTION) {
File
zvolenySubor = c.getSelectedFile();
String riadok = Hladaj.slovo(hladane,zvolenySubor);
JOptionPane.showMessageDialog(null,riadok," prehladany subor:
" +
zvolenySubor.getName(), JOptionPane.INFORMATION_MESSAGE);
}
if(rVal == JFileChooser.CANCEL_OPTION) {
//
nezvolili sme ziadnu cinnost
}
}
public static void main(String[] args){
FChooser
fch = new FChooser();
}//EOMain
}//EOClass
// cvicenie :doplnte kod tak, aby vyhladavanie zacalo
// aj pri stisnuti tlacitka enter v textovom policku
Pozor na štandardnú chybu
Niekedy sa stane, že dôkladne premyslíme správanie sa poslucháča pre určitú komponentu. Príslušnú triedu – Listener vhodne impementujeme a vytvoríme konkrétnu inštanciu tohto poslucháča. Napriek tomu program nerobí to, čo sme chceli. Zabudli sme urobiť posledný krok procesu: zaregistrovať poslucháča u príslušnej komponenty, u príslušného prvku pomocou jednej z metód „add...Listener(...)“.
Cvičenia
Cv3.1
Preštudujte si dokumentáciu triedy Font. V kóde Gr3.1 meňte typ fontu, priradený textovému políčku. Nakoniec font nastavte na italiku.
Cv3.2
Doplňte Kód3.2 tak, aby sa vžy pri ubraní alebo pridaní
poslucháča objavilo okno správ, ktoré túto udalosť oznámi. Preštudujte si
dokumentáciu triedy JoptionPane a použite postupne viac podôb metódy
showMessageDialog(..).
Cv3.3
Vytvorte aplikáciu, ktorá umožní „odpočúvať“ prácu
na klávesnici a archivovať ju. Môžete vychádzať z kódu Gr3.3. Aplikácia najprv oznámi používateľovi, aby
určitú dobu stláčal klávesy na klávesnici a potom dal stlačením tlačítka
signál na ukončenie procesu. Aplikácia si zapamätá
a)
všetky
klávesy, ktoré vyvolali udalosť keyPressed a zapíše ich po poradí do
súboru.
b)
potom
do toho istého súboru zapíše všetky klávesy, ktoré vyvolali udalosť keyTyped.
Potom oznámi používateľovi,
kde má daný súbor hľadať.
Vytvorte malý „SearchBot“, prehľadávací program. Umožní vám najprv zvoliť výraz, ktorý hľadáte a adresár, v ktorom budete hľadať. Po potvrdení voľby prehľadá všetky súbory v danom adresári, ktoré majú príponu txt. Zobrazí zoznam tých, v ktorých sa zvolený výraz-String nachádza. Zároveň umožní vybrať ľubovoľný z týchto dokumentov a zobraziť jeho obsah v osobitnom okne.
Riešenia
Cv3.1.
policko.setFont(new
Font("italika",Font.ITALIC,14 ));
© Ivan Kupka
Vaše komentáre:
kupka@fmph.uniba.sk