====== Drag and Drop ======
Vytvoříme nový projekt **Designer**, přidáme okno **DesignerWindow** typu **JFrame**
* do okna vložíme prvek se záložkami **JTabbedPane**, proměnnou pojmenujeme **toolbarTabs**
* jako první záložku umístíme **JToolBar** pojmenovaný **componentToolbar** (pravou myší na prázdné záložky, "Add From Palette", "Swing Containers", "Toolbar")
* vlastost **Tab Title** nastavíme na **Components**
* jako druhou záložku opět **JToolBar** pojmenovaný **colorToolbar**
* vlastost **Tab Title** nastavíme na **Colors**
* do dolní části vložíme **JPanel**, pojmenovaný **designer**
{{dnd_window.png}}
===== Toolbar se jmény jednotlivých grafických prvků =====
Do "toolbaru" na první záložce přidáme tlačítka se jmény tříd, které chceme pomocí myši "táhnout a vhazovat" do našeho pabelu //designer//.
* Funkce **addComponent** vytvoří nové tlačítko
* Tlačítku nastaví zobrazovaný text
* Vytvoří **TransferHandler** a předá ho tlačítku
* parametr **"text"** určuje, že během //drag and drop// bude předávána vlastnost (//property//) //text// tvořená metodami tlačítka **getText** a **setText**
* Tlačítku ještě předáme **MouseMotionListener** reagující na "tažení myši", který bude vysvětlen později
* Přidáme tlačítko na toolbar
private void addComponent (String name)
{
JButton btn = new JButton ();
btn.setText (name);
btn.setTransferHandler (new TransferHandler ("text"));
btn.addMouseMotionListener (new LocalMouseMotion ());
componentToolbar.add (btn);
}
V konstruktoru okna zaloláme funkci **addComponents**, která přidá několik tlačítek do toolbaru
private void addComponents ()
{
addComponent ("JButton");
addComponent ("JTree");
addComponent ("JTable");
addComponent ("JTextArea");
}
==== Reakce na tažení knoflíku pomocí myši ====
Funkce **btn.addMouseMotionListener** přiřadí tlačítku reakci na pohyb a "tažení" myši. \\
Funkce je deklarována ve třídě **Component**, ze které je odvozena třída **JButton**
class Component
{
...
public synchronized void addMouseMotionListener (MouseMotionListener ml) { ... }
...
}
class JButton extends Component
{
...
}
Každé volání metody //addMouseMotionListener// přidá tlačítku dalšího //posluchače//, \\
který bude informován o pohybech myši nad naším tlačítkem.
=== synchronizované metody ===
Klíčové slovo **synchronized** zajišťuje, že pokud zmíněná metoda našeho tlačítka bude v jeden okamžik volána z více //vláken//, \\
budou volání zpracována postupně jedno po druhém, aby v seznamu osluchačů nevznikly chyby. \\
* ( Pro různá tlačítka může být metoda zavolána současně. )
* ( Pro jedno tlačítko nemohou být současně zavolány dvě //synchronized// metody. )
* ( Výjimkou je situace kdy jedna //synchronized// metoda volá jinou //synchronized// metodu. )
==== Rozhraní (interface) ====
Parametrem metody //addMouseMotionListener// je odkaz na rozhraní **MouseMotionListener**
Rozhraní připomíná třídu, \\
smí obsahovat jen deklarace funcí bez implementace \\
( a případně deklarace konstant ).
Všechny deklarované metody jsou automaticky verřejně dostupné, nemusíme psát //public// před metodami.
* V Javě jsou všechny metody (tříd i rozhraní) automaticky //virtuální//, pokud nepoužijeme klíčové slovo **final**.
* U deklarací proměnných //final// znamená, že proměnná po inicializaci již nepůjde změnit.
* Proměnné označená //static// //final// jsou konstantami.
* Z třídy označené //final// není dovoleno odvozovat jiné třídy
Klíčové slovo //public// před //interface// znamená, že rozhraní je přístupné i z jiných balíčků (packages).
Rozhraní v Javě je obdobou čistě virtuální třídy v C++.
Rozhraní //MouseMotionListener// má dvě metody **mouseDragged** a **mouseMoved**.
public interface MouseMotionListener
{
void mouseDragged (MouseEvent me);
void mouseMoved (MouseEvent me);
}
Všechnny metody rozhraní, které je použito jako //listener// grafického prvku, \\
obvykle mají jeden parametr stejného typu, v našem případě **MouseEvent**, \\
který obsahuje detailní informace o události (např. souřadnice myši).
==== Třída implementující rozhraní ====
Rozhraní se používá při deklaraci třídy. \\
Třída může deklarovat, že implementuje rozhraní
class MouseMotionAdapter implements MouseMotionListener { ... }
V Javě třída může být odvozena jen z jedné třídy
class B extends A { ... }
Ale třída může implementovat několik rozhraní
class B extends A implements I1, I2, I3 { ... }
Třídy, které implementují rozhraní musí implementovat jednotlivé metody, třeba jako metody co nic nedělají.
public class MouseMotionAdapter implements MouseMotionListener
{
public MouseMotionAdapter ()
{
}
public void mouseDragged (MouseEvent me)
{
}
public void mouseMoved (MouseEvent me)
{
}
}
Identifikátor rozhraní můžeme použít jako jméno typu, \\
do kterého můžeme ukládat ukazatele na instance tříd, které rozhraní implementují.
MouseMotionListener p = new MouseMotionAdapter ();
V našem případě to bude parameter typu //MouseMotionListener// u metody //addMouseMotionListener//
=== Třída Object z které jsou odvozeny všehnny ostatní třídy ===
Pokud deklarace třídy neuvádí třídu ze které je odvozena
class B { ... }
Java použije jako základní třídu **java.lang.Object** \\
(leda, že by se jednalo právě o třídu //java.lang.Object//, která není odvozena z jiné třídy )
Balíček **java.lang** obsahuje základní deklarace, je vždy dostupný a nemusíme psát **import java.lang.* **
Proto stačí napsat identifikátor **Object** bez jména balíčku.
Z typu //Object// jsou tedy odvozeny všechy další třídy. \\
Také pole jsou odvozeny z typu //Object//. \\
Proměnné typu //Object// tedy mohou obsahovat ukazatele na libovolný objekt (připomínají **void * ** v C++)
=== Abstraktní metody ===
Metodu můžeme označit jako abstraktní klíčovýn slovem **abstract** na začátku deklarace. \\
Taková metoda nesmí obsahovat kód ve složených závorkách, ale za deklarací je jen středník. \\
Metodu potom musí implementovat odvozená třída.
public abstract class A
{
public abstract void func ();
}
public class B extends A
{
public void func () { /* implementace funkce */ }
}
=== Abstraktní třídy ===
Třídu můžeme označit jako abstraktní (klíčové slovo **abstract**) a potom z ní nelze vytvářet instance pomocí **new**. \\
Můžeme vytvářet až instance z odvozených tříd, které implementaci všech metod doplnily.
Třídu musíme označit jako //abstraktní//, pokud :
* pokud třída obsahuje nějakou abstraktní metodu
* nebo je odvozena ze třídy která má abstraktní metody
* nebo implementuje rozhraní, ale některou jeho metodu neimplementovala
==== Naše lokální třída rozšiřující výše uvedenou třídu ====
Třídu můžeme deklarovat i uvnitř jiné třídy. \\
Například třídu **LocalMouseMotion** použitou pro náš knoflík z toolbaru
btn.addMouseMotionListener (new LocalMouseMotion ());
Třídu //LocalMouseMotion// je rozšířením třídy //MouseMotionAdapter//, která implementuje rozhraní //MouseMotionListener//, \\
proto ji můžeme použít jako parametr metody //addMouseMotionListener//, který je typu //MouseMotionListener//.
public class DesignerWindow
{
...
class LocalMouseMotion extends MouseMotionAdapter
{
public void mouseDragged (java.awt.event.MouseEvent evt)
{
JButton button = (JButton) evt.getSource ();
TransferHandler handler = button.getTransferHandler ();
handler.exportAsDrag (button, evt, TransferHandler.COPY);
}
}
...
}
Metoda //mouseDragged//
* z parametru //evt// získá odkaz ma grafický prvek, který je zdrojem události
* odkaz je obecného typu //Object//, my ale víme, že jde o tlačítko, tak odkaz přetypujeme
* pokud by se přetypování **(JButton) výraz** nepovedlo, vznikne výjimka
* některé velmi časté výjimky nás Java ani nenutí zachycovat do bloku **try ... catch**
* z tlačítka si vyzvedneme **TransferHandler**
* zahájíme "drag and drop"
===== Barevné knoflíky =====
Podobně vytvoříme barevná tlačítka, která při "tažení" pomocí myši přenášejí barvu.
Barvu zadanou jako parametr funkce **addColor** použijeme pro obarvení podkladu talčítka. \\
Tlačítku nastavíme //TransferHandler// pracující s vlastností **"background"**
private void addColor (Color c)
{
JButton btn = new JButton ();
btn.setText (" ");
btn.setBackground (c);
btn.setTransferHandler (new TransferHandler ("background"));
btn.addMouseMotionListener
(new java.awt.event.MouseMotionAdapter ()
{
public void mouseDragged(java.awt.event.MouseEvent evt)
{
JButton button = (JButton) evt.getSource();
TransferHandler handle = button.getTransferHandler();
handle.exportAsDrag (button, evt, TransferHandler.COPY);
}
}
);
colorToolbar.add (btn);
}
private void addColors ()
{
addColor (new Color (255, 0, 0));
addColor (new Color (0, 255, 0)) ;
addColor (new Color (0, 0, 255)) ;
addColor (new Color (255, 255, 0)) ;
}
==== Anonymní třída ====
Na místo lokální třidy použité v předchozích odstavcích, \\
vytvoříme **anonymní třídu** následující kostrukcí:
new MouseMotionAdapter ()
{
kód rošiřující původní třídu o nové metody nebo proměnné
}
Vzniklá třída nemá ani svůj identifikátor, víme jen, že je odvozena ze třídy //MouseMotionAdapter//. \\
Konstrukce začíná obvyklým **new IdentifikátorTypu ()**. \\
A následují složené závorky s deklaracemi, o které je původní třída (nebo jen rozhraní) rozšířeno.
Běžné se //anonymní třída// používá jako parametr jiné metody.
btn.addMouseMotionListener (
new java.awt.event.MouseMotionAdapter ()
{
public void mouseDragged (java.awt.event.MouseEvent evt)
{
// reakce na tažení pomocí myši
}
}
);
===== Konstruktor =====
Konstruktor okna
* umístí tlačítka na obě lišty s nástroji
* vytvoří objekty DesignerDropListener a DropTarget, které budou reagovat data vhozená na dolní panel
* dolnímu panelu nastaví **null layout**, který dovoluje libovolně umístǒvat grafické prvky na plochu panelu
public DesignerWindow ()
{
initComponents ();
addComponents ();
addColors ();
DesignerDropListener listener = new DesignerDropListener ();
DropTarget target = new DropTarget (designer, listener);
designer.setDropTarget (target);
designer.setLayout (null);
}
===== Reakce na vhození objektu ======
==== Lokální třída si pamatuje vňější třídu kam patří ====
Pokud lokální třída není označena klíčovým slovem **static**, tak si pamatuje instanci vnější třídy, ve které byla vytvořena.
Například třída **DesignerDropListener** může ve své metodě **drop** zavolat metodu **addDesignerObject** \\
a metoda //addDesignerObject// patří do vnější třídy **DesignerWindow**
public class DesignerWindow
{
class DesignerDropListener implements DropTargetListener
{
public void drop (DropTargetDropEvent evt)
{
addDesignerObject ();
}
public void dragEnter () { }
public void dragOver () { }
...
}
private void addDesignerObject () { ... }
}
Naše lokální třída implementuje rozhraní **DropTargetListener**, které má několik metod. \\
Musíme všechnny metody implementovat, ačkoliv některé implementace nic nedělají. \\
( To je také smysl pomocné třídy //MouseMotionAdapter//, která nám usnadňuje implementaci jen jedné metody rozhraní //MouseMotionListener//. )
public interface DropTargetListener extends EventListener
{
public void dragEnter (DropTargetDragEvent dtde);
public void dragOver (DropTargetDragEvent dtde);
public void dropActionChanged (DropTargetDragEvent dtde);
public void dragExit (DropTargetEvent dte);
public void drop (DropTargetDropEvent dtde);
}
=== Ukazatel na vnější třídu ====
Pokud uvnitř metod vnitřní třídy potřebujeme odkaz na vnější třídu, použijeme výraz
DesignerWindow.this
Tedy uvniř **drop** metody je
* obyčejné **this** je ukazatel na instanci __vnitřní__ třídy typu **DesignerDropListener**
* **DesignerWindow.this** je ukazatel na instanci __vnější__ třídy typu **DesignerWindow**
Pokud zavoláme v metodě //drop// metodu //addDesignerObject// překladač hledá identifikátor
* nejprve mezi lokálními proměnnými a parametry
* potom ve vniřní třídě
* nakonec ve vnější třídě
* pokud ani tam nenalezne identifikátor, prohledá aktuální balíček a importované balíčky
Pokud je vniřní třída označená klíčovým slovem **static**, tak si vnitřní třída nepamatuje odkaz na vnější třídu
=== Vytvoření instance vnitřní třídy ====
Uvnitř vnější třídy vytvoříme instanci obvyklým
new DesignerDropListener ()
a nově vzniklá vnitřní třída si uloží odkaz na vnější třídu.
Pokud je to v jiném balíčku vnější i vniřní třída musí být **public**, \\
musíme mít připravenu nějakou instanci vnější třídy (**w** v následujícím příkladu) \\
a instanci vytváříme výrazem
instance_vnější_třídy.new jméno_vnitřní_třídy ( )
DesignerWindow w = new DesignerWindow ();
...
DesignerWindow.DesignerDropListener t = w.new DesignerDropListener ();
==== Informace o typu tažených nebo vhozených dat ====
Parametr **evt** metody **drop** nám poskytne objekt typu **Transferable**. \\
Z tohoto objektu získáme pole typu **DataFlavor []** o přenášených formátech dat.
Podobně jako při práci se schránkou (clipboard) můžeme během "drag and drop" přenášet data v několika formátech. \\
Například můžeme přenášet jak text tak i obrázek. Cílové okno si vybere formát dat, který mu vyhovuje.
Náš příklad ale bude pracovat jen s jedním formátem.
Ověříme si, že pole obsahuje jen jeden prvek.
Předdefinovaná třída **Class** (**java.lang.Class**, velké písmeno C na rozdíl od klíčového slova **class**) obsahuje informace o jiných typech v Javě. \\
Do proměnné **cls** typu //Class// si uložíme informace o přenášeném typu dat.
Přenášená data uložíme do proměnné **data** obecného typu **Object**. \\
Vyzvednutí dat z objektu typu //Transferable// se nemusí podařit a Java zde vyžaduje //try catch// blok zabycující případné výjimky.
Transferable transfer = evt.getTransferable();
DataFlavor [] flavors = transfer.getTransferDataFlavors ();
if (flavors.length == 1)
{
DataFlavor flavor = flavors[0];
Class cls = flavor.getRepresentationClass ();
Object data = null;
try
{
data = transfer.getTransferData (flavor);
}
catch (UnsupportedFlavorException ex) { System.out.println (ex); }
catch (IOException ex) { System.out.println (ex); }
==== Vhození barvy nebo jména třídy ====
Otestujeme zda proměnná **cls** obsahuje ukazatel na popis typu //String//. \\
Odkaz na popis typu //String// získáme **String.class**. \\
A případně zavoláme funkci **addDesignerObject** popsanou v následujícím odstavci.
Nebo **cls** je rovno **Color.class**. \\
V tom případě přetypujeme //data// na typ //Color//. \\
Získanou barvu použijeme na obarvení grafického prvku, \\
který se nachází právě pod myší (může to být i celý podkladový panel).
Point point = evt.getLocation ();
if (cls == String.class)
{
addDesignerObject (point, data.toString ());
}
if (cls == Color.class)
{
Color color = (Color) data;
Component comp = designer.getComponentAt (point);
comp.setBackground (color);
}
==== Celá lokální třída reagující na vhozená data ====
class DesignerDropListener implements DropTargetListener
{
public void drop (DropTargetDropEvent evt)
{
// System.out.println ("drop");
Transferable transfer = evt.getTransferable();
DataFlavor [] flavors = transfer.getTransferDataFlavors ();
/*
for (DataFlavor f : flavors)
{
System.out.println ("flavor " + f);
System.out.println ("class " + f.getRepresentationClass ());
}
*/
if (flavors.length == 1)
{
DataFlavor flavor = flavors[0];
Class cls = flavor.getRepresentationClass ();
Object data = null;
try
{
data = transfer.getTransferData (flavor);
}
catch (UnsupportedFlavorException ex) { System.out.println (ex); }
catch (IOException ex) { System.out.println (ex); }
if (data != null)
{
Point point = evt.getLocation ();
if (cls == String.class)
{
addDesignerObject (point, data.toString ());
}
if (cls == Color.class)
{
Color color = (Color) data;
Component comp = designer.getComponentAt (point);
comp.setBackground (color);
}
}
}
};
public void dragEnter(DropTargetDragEvent dtde) { }
public void dragOver(DropTargetDragEvent dtde) { }
public void dropActionChanged(DropTargetDragEvent dtde) { }
public void dragExit(DropTargetEvent dte) { }
};
==== Již uvedené instrukce z konstruktoru okna vytvářející instanci lokální třídy ====
DesignerDropListener listener = new DesignerDropListener ();
DropTarget target = new DropTarget (designer, listener);
designer.setDropTarget (target);
===== Přidání grafického prvku na plochu panelu =====
==== Vytvoření instance třídy, jméno třídy máme zadáno proměnnou typu string ====
Pokud máme jméno třídy zadané jen jako řetězec znaků, \\
můžeme použít statickou metodu **Class.forName ()**, \\
která se pokusí najít přeloženou třídu zadaného jména a \\
vrátí popis nalezené třídy jako typ **Class**.
Ve třídě **Class** je pak metoda **newInstance ()**, \\
která se pokusí vytvořit instanci zadané třídy. \\
( Pokud zadaná třída má verějně dostupný konstruktor bez parametrů. )
String className = "javax.swing.JButton";
Class cls = Class.forName (className);
Object obj = cls.newInstance();
Ještě musíme zachytit případné výjimky.
Object obj = null;
try
{
toolName = "javax.swing." + toolName;
Class cls = Class.forName (toolName);
obj = cls.newInstance();
}
catch (ClassNotFoundException ex) { System.out.println (ex); }
catch (InstantiationException ex) { System.out.println (ex); }
catch (IllegalAccessException ex) { System.out.println (ex); }
==== Vložení grafického prvku na plochu panelu ====
Náš panel má "nulový layout".
designer.setLayout (null);
Nový prvek přidáme do panelu metodou **add**.
Pomocí **setBounds** nastavíme souřadnici a velikost prvku.
designer.add (comp);
comp.setBounds (point.x, point.y, 100, 100);
Ještě otestujeme zda prvek //comp// není např. typu //JButton// \\
a provedeme drobné úpravy aby byl prvek k poznání.
if (comp instanceof JButton)
==== Celá funkce addDesignerObject ====
private void addDesignerObject (Point point, String toolName)
{
Object obj = null;
try
{
toolName = "javax.swing." + toolName;
Class cls = Class.forName (toolName);
obj = cls.newInstance();
// System.out.println ("new object " + obj);
}
catch (ClassNotFoundException ex) { System.out.println (ex); }
catch (InstantiationException ex) { System.out.println (ex); }
catch (IllegalAccessException ex) { System.out.println (ex); }
if (obj instanceof Component)
{
Component comp = (Component) obj;
designer.add (comp);
comp.setBounds (point.x, point.y, 100, 100);
if (comp instanceof JButton)
{
((JButton)comp).setText ("text");
// System.out.println ("button");
}
if (comp instanceof JTree)
{
// ((JTree)comp).setMinimumSize(new Dimension (100, 100));
// System.out.println ("tree");
}
if (comp instanceof JTable)
{
JTable table = (JTable) comp;
DefaultTableModel m = (DefaultTableModel) table.getModel ();
m.setColumnCount (2);
m.addRow (new String [] {"1", "abc" });
m.addRow (new String [] {"2", "klm" });
// System.out.println ("table");
}
if (comp instanceof JTextArea)
{
((JTextArea)comp).setText("some text");
// System.out.println ("edit");
}
}
}
===== Celý program =====
package designer;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.table.*;
public class DesignerWindow extends javax.swing.JFrame
{
public DesignerWindow ()
{
initComponents ();
addComponents ();
addColors ();
DesignerDropListener listener = new DesignerDropListener ();
DropTarget target = new DropTarget (designer, listener);
designer.setDropTarget (target);
designer.setLayout (null);
}
/* Tooolbar */
class LocalMouseMotion extends MouseMotionAdapter
{
public void mouseDragged (java.awt.event.MouseEvent evt)
{
JButton button = (JButton) evt.getSource ();
TransferHandler handle = button.getTransferHandler ();
handle.exportAsDrag (button, evt, TransferHandler.COPY);
}
}
private void addComponent (String name)
{
JButton btn = new JButton ();
btn.setText (name);
btn.setTransferHandler (new TransferHandler ("text"));
btn.addMouseMotionListener (new LocalMouseMotion ());
componentToolbar.add (btn);
}
private void addComponents ()
{
addComponent ("JButton");
addComponent ("JTree");
addComponent ("JTable");
addComponent ("JTextArea");
}
private void addColor (Color c)
{
JButton btn = new JButton ();
btn.setText (" ");
btn.setBackground (c);
btn.setTransferHandler (new TransferHandler ("background"));
btn.addMouseMotionListener
(new java.awt.event.MouseMotionAdapter ()
{
public void mouseDragged(java.awt.event.MouseEvent evt)
{
JButton button = (JButton) evt.getSource();
TransferHandler handle = button.getTransferHandler();
handle.exportAsDrag (button, evt, TransferHandler.COPY);
}
}
);
colorToolbar.add (btn);
}
private void addColors ()
{
addColor (new Color (255, 0, 0));
addColor (new Color (0, 255, 0)) ;
addColor (new Color (0, 0, 255)) ;
addColor (new Color (255, 255, 0)) ;
}
/* Designer */
class DesignerDropListener implements DropTargetListener
{
public void drop (DropTargetDropEvent evt)
{
// System.out.println ("drop");
Transferable transfer = evt.getTransferable();
DataFlavor [] flavors = transfer.getTransferDataFlavors ();
/*
for (DataFlavor f : flavors)
{
System.out.println ("flavor " + f);
System.out.println ("class " + f.getRepresentationClass ());
}
*/
if (flavors.length == 1)
{
DataFlavor flavor = flavors[0];
Class cls = flavor.getRepresentationClass ();
Object data = null;
try
{
data = transfer.getTransferData (flavor);
}
catch (UnsupportedFlavorException ex) { System.out.println (ex); }
catch (IOException ex) { System.out.println (ex); }
if (data != null)
{
Point point = evt.getLocation ();
if (cls == String.class)
{
addDesignerObject (point, data.toString ());
}
if (cls == Color.class)
{
Color color = (Color) data;
Component comp = designer.getComponentAt (point);
comp.setBackground (color);
}
}
}
};
public void dragEnter(DropTargetDragEvent dtde) { }
public void dragOver(DropTargetDragEvent dtde) { }
public void dropActionChanged(DropTargetDragEvent dtde) { }
public void dragExit(DropTargetEvent dte) { }
};
private void addDesignerObject (Point point, String toolName)
{
Object obj = null;
try
{
toolName = "javax.swing." + toolName;
Class cls = Class.forName (toolName);
obj = cls.newInstance();
// System.out.println ("new object " + obj);
}
catch (ClassNotFoundException ex) { System.out.println (ex); }
catch (InstantiationException ex) { System.out.println (ex); }
catch (IllegalAccessException ex) { System.out.println (ex); }
if (obj instanceof Component)
{
Component comp = (Component) obj;
designer.add (comp);
comp.setBounds (point.x, point.y, 100, 100);
if (comp instanceof JButton)
{
((JButton)comp).setText ("text");
// System.out.println ("text");
}
if (comp instanceof JTree)
{
// ((JTree)comp).setMinimumSize(new Dimension (100, 100));
// System.out.println ("tree");
}
if (comp instanceof JTable)
{
JTable table = (JTable) comp;
DefaultTableModel m = (DefaultTableModel) table.getModel ();
m.setColumnCount (2);
m.addRow (new String [] {"1", "abc" });
m.addRow (new String [] {"2", "klm" });
// System.out.println ("table");
}
if (comp instanceof JTextArea)
{
((JTextArea)comp).setText("some text");
// System.out.println ("edit");
}
}
}
private void quitClick(java.awt.event.ActionEvent evt)
{
System.exit (0);
}
public static void main (String args[])
{
/* Do not use Nimbus look and feel */
...
}
}
{{dnd.png}}
[[https://gitlab.fjfi.cvut.cz/culikzde/java-priklady/-/tree/master/Designer|gitlab]]