12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 1
12. Swing - kontenery
12.1
JApplet
12.2
JFrame
12.3
JRootPane
12.4 Panel warstwowy -
JLayeredPane, JDesktopPane
12.5
JInternalFrame
12.6 Kontenery ogólne pośredniego poziomu -
JPanel
i inne:
JScrollPane, JSplitPane, JTabbedPane, JToolBar
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 2
12.1 Klasa
JApplet
Ka
ż
dy aplet zawieraj
ą
cy komponenty
Swing
-a musi by
ć
utworzony jako
klasa pochodna od klasy
JApplet
, która dziedziczy z klasy
java.applet.Applet
.
1) Cechy
JApplet
Jako kontener główny klasa
JApplet
posiada "
root pane
", "
content pane
" i
opcjonalnie
pasek menu
.
Ró
ż
nice pomi
ę
dzy apletem w Swing-u a apletem
Applet
:
komponenty dodawane s
ą
do "content pane" apletu;
menad
ż
er układu ustawiany jest dla "content pane" a nie dla apletu
bezpo
ś
rednio;
domy
ś
lnym menad
ż
erem układu dla "content pane" apletu jest
BorderLayout
(dla
Applet
jest nim
FlowLayout
);
kod malowania nie powinien znajdowa
ć
si
ę
bezpo
ś
rednio w obiekcie
klasy
JApplet
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 3
2) W
ą
tki w apletach
Typowa
konstrukcja
apletów
korzysta
z
w
ą
tków,
tymczasem
komponenty Swing-a nie s
ą
zabezpieczone przed w
ą
tkami.
Komponenty tworzymy i ustawiamy w metodzie
init
- takie rozwi
ą
zanie
uznaje si
ę
za bezpieczne.
Metody
start, stop, destroy
mog
ą
sprawia
ć
kłopoty i nale
ż
y je
zabezpieczy
ć
przed w
ą
tkami. Np. nie powinny by
ć
one wołane z w
ą
tku
rozdziału zdarze
ń
i nie powinny odwoływa
ć
si
ę
do komponentów
bezpo
ś
rednio. Zamiast tego powinny posłu
ż
y
ć
si
ę
one metod
ą
SwingUtilities.invokeLater
przy dost
ę
pie do komponentu.
3) Korzystanie z obrazów w aplecie Swing-a
Klasa
Applet
posiada metod
ę
getImage
dla ładowania obrazów do
apletu. Tworzy ona obiekt klasy
Image
reprezentuj
ą
cy załadowany
obraz. W Swing-u zamiast
Image
stosuje si
ę
klas
ę
Icon
- aplety Swing-a
z zasady nie korzyst
ą
z
getImage
. Zamiast tego aplety Swing-a tworz
ą
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 4
obiekty klasy
ImageIcon
- ikona załadowana z pliku z obrazem. Zalet
ą
stosowania
ImageIcon
jest to,
ż
e klasa automatycznie
ś
ledzi ładowanie
obrazu.
Przykład 12.1.
W
ą
tek apletu implementowany w postaci obiektu pewnej
klasy
SwingWorker
odpowiada za załadowanie 17 ró
ż
nych obrazów
stosuj
ą
c jeden obiekt ImageIcon dla jednego obrazu. Aplet ładuje obrazy
w metodzie
init
.
public void init() {
...
imgs = new ImageIcon[nimgs];
...
final SwingWorker worker = new SwingWorker() {
public Object construct() {
// Indeksy obrazów: od 1 do nimgs, indeksy tablicy - od 0 do nimgs-1.
for (int i = 0; i < nimgs; i++) {
imgs[i] = createFrame(i+1);
}
finishedLoading = true;
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 5
return imgs;
}
...
};
worker.start();
}
protected ImageIcon createFrame(int imageNum) {
String path = dir + "/T" + imageNum + ".gif";
URL imgURL = this.getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
}
else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 6
12.2 Klasa
JFrame
(klasa głównego okna)
Typowy obiekt klasy
JFrame
(ramka) posiada okno udekorowane
brzegiem, tytułem, przyciskami dla zamykania, zmniejszania i
powi
ę
kszania okna.
Aplikacje posiadaj
ą
ce GUI korzystaj
ą
z przynajmniej jednej ramki.
Równie
ż
aplety
mog
ą
korzysta
ć
z ramek.
Okna zale
ż
ne od innego okna (okno zanika, gdy inne jest zmniejszane
lud zamykane) mo
ż
na uzyska
ć
stosuj
ą
c
JDialog
zamiast
JFrame
.
Umieszczenie jednego okna w drugim oknie umo
ż
liwia klasa
JInternalFrame
.
1) Reakcje na zdarzenie zamkni
ę
cia okna
Je
ś
li u
ż
ytkownik zamyka okno, zostaje ono ukryte, ale obiekt mo
ż
e
istnie
ć
dalej w programie i okno mo
ż
e zosta
ć
pó
ź
niej przywrócone.
Jest to domy
ś
lna reakcja, która mo
ż
e zosta
ć
zmieniona:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 7
przez zarejestrowanie procedury obsługi zdarzenia zamkni
ę
cia okna;
przez
specyfikacj
ę
reakcji
na
zamkni
ę
cie
okna
metod
ą
setDefaultCloseOperation
;
lub podanie obu rozwi
ą
za
ń
jednocze
ś
nie – pierwsza wykona sie
obsługa zdarzenia a nast
ę
pnie domy
ś
lna reakcja na zamkni
ę
cie.
Argumentem metody
setDefaultCloseOperation
musi by
ć
jedna z
podanych ni
ż
ej warto
ś
ci (3 pierwsze zdefiniowano w interfejsie
WindowConstants
implementowanym przez
JFrame, JInternalPane,
JDialog
):
DO_NOTHING_ON_CLOSE ,
HIDE_ON_CLOSE
(domy
ś
lne dla
JDialog
i
JFrame
) ,
DISPOSE_ON_CLOSE
(domy
ś
lne dla
JInternalFrame
),
EXIT_ON_CLOSE
(zdefiniowana w
JFrame
) – zako
ń
czy aplikacj
ę
wywołaniem
System.exit(0)
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 8
2) Reakcja na inne zmiany stanu
Procedury obsługi zdarze
ń
mog
ą
te
ż
reagowa
ć
na zdarzenia zmiany
stanu okna takie, jak zmniejszenie i aktywowanie okna.
Utworzenie i pokazanie ramki
Przykład 12.2
//1. Opcjonalnie: dekoracje ramki zgodne z domy
ś
lnym
ś
rodowiskiem
// "look and feel". Domy
ś
lnie dekoracje dostarczane s
ą
przez system
// zarz
ą
dzaj
ą
cy oknami.
JFrame.setDefaultLookAndFeelDecorated(true);
//2. Utwórz ramk
ę
podaj
ą
c jako argument tytuł ramki.
JFrame frame = new JFrame("FrameDemo");
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 9
//3. Opcjonalnie: co dzieje si
ę
z programem w chwili zamykania ramki –
// ma on si
ę
zako
ń
czy
ć
.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//4. Utwórz komponenty i dodaj je do ramki.
//...utwórz pustą etykietę ... dodaj ją do panelu zawartości dla ramki
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
// Opcjonalnie: umieść na środku ekranu
frame.setLocationRelativeTo(null);
//5. Realizacja ramki - wyznacz rozmiar i układ ramki.
frame.pack();
//6. Poka
ż
ramk
ę
- narysuj j
ą
.
frame.setVisible(true);
Ustawienie dekoracji ramki
Domy
ś
lnie za dekoracje okna odpowiada system nadzoruj
ą
cy okna.
Mo
ż
na zastosowa
ć
te
ż
dekoracje zgodne z domy
ś
lnym „look and feel”.
Mo
ż
liwe s
ą
te
ż
rozwi
ą
zania:
-
bez dekoracji,
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 10
-
z własnymi dekoracjami u
ż
ytkownika,
-
tryb pełnego ekranu.
Mo
ż
liwy jest zawsze powrót do domy
ś
lnych dekoracji systemu okien:
JFrame.setDefaultLookAndFeelDecorated(false).
Przykład 12.3
. Poni
ż
sze 3 ramki posiadaj
ą
ró
ż
ne dekoracje okien.
Korzystaj
ą
one z "Java look and feel" co wida
ć
po postaci przycisku.
Ś
rodkowa ramka korzysta z dekoracji okien dostarczanych przez system
zarz
ą
dzania oknami - w tym przypadku jest nim MS Windows ale mógłby
to by
ć
ka
ż
dy inny system dysponuj
ą
cy platform
ą
Javy.
Dekoracje zgodne z
“look and feel”
Dekoracje zgodne z
systemem okien
Ikona u
ż
ytkownika.
Dekoracje zgodne z
“look and feel”
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 11
Trzecia ramka posiada ikonk
ę
dostarczon
ą
przez u
ż
ytkownika.
// Ustawienie dekoracji okna zgodnych z “look and feel”.
JFrame.setDefaultLookAndFeelDecorated(true);
// Utwórz ramk
ę
.
JFrame frame = new JFrame("A window");
// Ustaw ikonk
ę
w postaci obrazu ładowanego z pliku.
frame.setIconImage(new ImageIcon(imgURL).getImage());
Przykład 12.4
Program
FrameDemo2.java
ilustruje tworzenie ramek o
ró
ż
nych dekoracjach i ikonkach. Opcjonalnie korzysta z pliku:
images/FD.jpg
.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class FrameDemo2 extends WindowAdapter
implements ActionListener {
private Point lastLocation = null;
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 12
private int maxX = 500;
private int maxY = 500;
… //
// Konstruktor:
public FrameDemo2() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
maxX = screenSize.width - 50;
maxY = screenSize.height - 50;
}
// Utwórz i poka
ż
obiekt obiekt klasy MyFrame
public void showNewWindow() {
JFrame frame = new MyFrame();
// Gdy nie są potrzebne dekoracje okna można też użyć Window lub JWindow
if (noDecorations) {
frame.setUndecorated(true);
// Brak dekoracji okna
}
// Ustaw położenie okna:
if (lastLocation != null) {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 13
// Przesuń okno o 40 pikseli:
lastLocation.translate(40, 40);
if ((lastLocation.x > maxX) || (lastLocation.y > maxY)) {
lastLocation.setLocation(0, 0);
}
frame.setLocation(lastLocation);
}
else { lastLocation = frame.getLocation(); }
// Wywołanie
setIconImage
- ustawia ikonk
ę
wy
ś
wietlan
ą
wtedy, gdy
// okno jest w stanie zminimalizowanym a tak
ż
e ikonk
ę
w dekoracjach
// kontrolowanych przez „look and feel”:
if (specifyIcon) {
if (createIcon) {
frame.setIconImage(createFDImage());
// Nowa ikonka
}
else {
frame.setIconImage(getFDImage());
// Ikonka z pliku
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 14
}
// Realizuj i poka
ż
ramk
ę
frame.setSize(new Dimension(170, 100));
frame.setVisible(true);
}
// Utwórz kontrolki dla opcji dekoracji i ikonek głównego okna
protected JComponent createOptionControls() {
JLabel label1 = new JLabel("Opcje dekoracji ramek:");
ButtonGroup bg1 = new ButtonGroup();
JLabel label2 = new JLabel("Icon options:");
ButtonGroup bg2 = new ButtonGroup();
// Utwórz przyciski
JRadioButton rb1 = new JRadioButton();
rb1.setText("Look and feel decorated");
rb1.setActionCommand(LF_DECORATIONS);
rb1.addActionListener(this);
rb1.setSelected(true);
bg1.add(rb1);
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 15
//
JRadioButton rb2 = new JRadioButton();
rb2.setActionCommand(WS_DECORATIONS);
// ...
JRadioButton rb3 = new JRadioButton();
rb3.setActionCommand(NO_DECORATIONS);
// ...
JRadioButton rb4 = new JRadioButton();
rb4.setActionCommand(DEFAULT_ICON);
// ...
JRadioButton rb5 = new JRadioButton();
rb5.setActionCommand(FILE_ICON);
// ...
JRadioButton rb6 = new JRadioButton();
rb6.setActionCommand(PAINT_ICON);
// ...
// Dodaj komponenty do kontenera .
…//
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 16
// Dodaj puste obramowanie
box.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
return box;
}
// Utwórz przycisk widoczny w głównym oknie
protected JComponent createButtonPane() {
JButton button = new JButton("New window");
button.setActionCommand(CREATE_WINDOW);
button.addActionListener(this);
defaultButton = button;
// Domyślny przycisk ramki
// Środkowe położenie przycisku w panelu i obramowanie.
JPanel pane = new JPanel();
// Korzysta z domyślnego FlowLayout
pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
pane.add(button);
return pane;
}
// Obsługa zdarze
ń
typu akcji ze wszystkich przycisków.
public void actionPerformed(ActionEvent e) {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 17
String command = e.getActionCommand();
// Obsługa przycisku “New window”.
if (CREATE_WINDOW.equals(command)) {
showNewWindow();
// Obsługa 1-szej grupy przycisków radiowych.
} else if (NO_DECORATIONS.equals(command)) {
noDecorations = true;
JFrame.setDefaultLookAndFeelDecorated(false);
} else if (WS_DECORATIONS.equals(command)) {
noDecorations = false;
JFrame.setDefaultLookAndFeelDecorated(false);
} else if (LF_DECORATIONS.equals(command)) {
noDecorations = false;
JFrame.setDefaultLookAndFeelDecorated(true);
// Obsługa 2-giej grupy przycisków radiowych
} else if (DEFAULT_ICON.equals(command)) {
specifyIcon = false;
} else if (FILE_ICON.equals(command)) {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 18
specifyIcon = true; createIcon = false;
} else if (PAINT_ICON.equals(command)) {
specifyIcon = true; createIcon = true;
}
}
// Utworzenie nowego obrazu
protected static Image createFDImage() {
// Utwórz obraz 16x16 pikseli.
BufferedImage bi = new BufferedImage(16, 16,
BufferedImage.TYPE_INT_RGB);
// Narysuj grafikę w obrazie.
Graphics g = bi.getGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, 15, 15);
g.setColor(Color.RED);
g.fillOval(5, 3, 6, 6);
// Wyczyść obiekt graficzny.
g.dispose();
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 19
return bi;
}
// Zwraca
Image
lub
null
.
protected static Image getFDImage() {
java.net.URL imgURL =
FrameDemo2.class.getResource("images/FD.jpg");
if (imgURL != null) {
return new ImageIcon(imgURL).getImage();
} else {
return null;
}
}
// Uruchamia program demonstracyjny.
public static void main(String[] args) {
// Korzystaj z “Java look and feel”.
try {
UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelClassName());
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 20
} catch (Exception e) { }
// Obiekt klasy steruj
ą
cej .
FrameDemo2 demo = new FrameDemo2();
// Zapewnij dekoracje domy
ś
lne
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
// Utwórz główne okno (o sterowanych dekoracjach)
JFrame frame = new JFrame("FrameDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Dodaj komponenty
Container contentPane = frame.getContentPane();
contentPane.add(demo.createOptionControls(), BorderLayout.CENTER);
contentPane.add(demo.createButtonPane(), BorderLayout.PAGE_END);
frame.getRootPane().setDefaultButton(defaultButton);
// Wyświetl okno demonstracyjne.
frame.pack();
frame.setLocationRelativeTo(null);
// Ulokuj pośrodku
frame.setVisible(true);
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 21
}
// Klasa MyFrame
class MyFrame extends JFrame implements ActionListener {
// Utwórz ramkę z przyciskiem .
public MyFrame() {
super("A window");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
// Przyciskiem tym mo
ż
emy zamkn
ąć
okno – nawet nieudekorowane
JButton button = new JButton("Close window");
button.addActionListener(this);
Container contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane,
BoxLayout.PAGE_AXIS));
contentPane.add(Box.createVerticalGlue());
// Wypełnia wolne miejsce
contentPane.add(button);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
// Wyśrodkowany w poziomie
contentPane.add(Box.createVerticalStrut(5));
// spacje
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 22
}
// Obsługa zdarzenia dla przycisku realizuje to samo co domyślna operacja
// dla zamknięcia okna – (DISPOSE_ON_CLOSE).
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
}
}
// Koniec MyFrame
}
// Koniec FrameDemo2
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 23
12.3
JRootPane
1) Obiekt klasy
JRootPane
tworzony jest wraz z obiektem klasy
JInternalFrame
lub kontenera głównego Swing-a
: JApplet, JDialog,
JFrame.
Obiekt klasy
JRootPane
zawiera cztery dalsze obiekty:
“Glass pane” - jest domy
ś
lnie przezroczysty i ukryty.
“Layered pane” – rozmieszcza “content pane” i opcjonalny pasek menu
oraz dalsze komponenty w porz
ą
dku odpowiadaj
ą
cym „głebi” – o
ś
Z.
“Content pane” –
zawiera wszystkie widoczne komponenty kontenera.
Pasek menu – miejsce dla menu kontenera panelu “root pane”.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 24
Przykład 12.5.
Program
GlassPaneDemo.java
- je
ś
li “glass pane” staje si
ę
“widoczny” wtedy blokuje on wszelkie zdarzenia dla “zasłanianych”
komponentów zawartych w “content pane”, w przeciwnym razie maluje
czerwon
ą
kropk
ę
w miejscu wyst
ą
pienia ostatniej wykrytej akcji.
W programie tworzony jest własny obiekt typu “glass pane” i ustawiany
metod
ą
klasy
JFrame -
setGlassPane
. W ten sposób zdefiniujemy własny
kod malowania tego komonentu – w domy
ś
lnym „glass pane” wyst
ę
puje
pusty kod malowania.
...// Inicjalizacja własnego “glass pane” w miejscu inicjalizacji GUI:
myGlassPane = new MyGlassPane(...);
frame.setGlassPane(myGlassPane);
...
// W naszej klasie
MyGlassPane
definiujemy metod
ę
paint
:
class MyGlassPane extends JComponent {
Point point = null;
// Będzie ustawiany aktualną pozycją kursora
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 25
public void paint(Graphics g) {
if (point != null) {
g.setColor(Color.red);
g.fillOval(point.x - 10, point.y - 10, 20, 20);
}
}
...
}
// Wizualizacja “glass pane” po wci
ś
ni
ę
ciu przycisku.
JCheckBox changeButton = new JCheckBox("Glass pane \"visible\"");
changeButton.setSelected(false);
changeButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
myGlassPane.setVisible(e.getStateChange()
==
ItemEvent.SELECTED);
}
});
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 26
Alernatywne rozwi
ą
zanie dla poprzednego przykładu to doł
ą
czenie
własnych metod obsługi zdarze
ń
do domy
ś
lnego “glass pane”
pobranego uprzednio metod
ą
getGlassPane
.
Przykład 12.5A.
Własna obsługa
zdarze
ń
zwi
ą
zanych z mysz
ą
dla
domy
ś
lego panelu “glass pane”. Niech nasza obsługa polega na
ponownym „rozesłaniu” zdarzenia do wła
ś
ciwych komponentów
kontenera „root pane” – listy wysuwnej lub menu.
...// Obsługa zdarzenia w “glass pane” :
public void mouseMoved(MouseEvent e) {
redispatchMouseEvent(e, false);
}
.../* Metody :
mouseDragged,
mouseClicked,
mouseEntered,
mouseExited,
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 27
mousePressed
implementowane s
ą
w identyczny sposób
jak powy
ż
sza metoda
mouseMoved
*/.
// Implementacja metody
mouseReleased
:
public void mouseReleased(MouseEvent e) {
redispatchMouseEvent(e, true);
inDrag = false;
}
// Definicja metody obsługi – rozesłania obsług do komponentów:
private void redispatchMouseEvent(MouseEvent e, boolean repaint) {
boolean inButton = false;
boolean inMenuBar = false;
Point glassPanePoint = e.getPoint();
Component component = null;
Container container = contentPane;
Point containerPoint = SwingUtilities.convertPoint(
glassPane, glassPanePoint, contentPane);
int eventID = e.getID();
if (containerPoint.y < 0) {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 28
inMenuBar = true;
//... tu ustawić należy odpowiednio container i containerPoint ...
testForDrag(eventID);
}
component = SwingUtilities.getDeepestComponentAt(
container, containerPoint.x, containerPoint.y);
if (component.equals(liveButton)) {
inButton = true;
testForDrag(eventID);
}
if (inMenuBar || inButton || inDrag) {
...// wyślij zdarzenie do komponentu ...
}
if (repaint) {
toolkit.beep();
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 29
}
private void testForDrag(int eventID) {
if (eventID == MouseEvent.MOUSE_PRESSED) {
inDrag = true;
}
}
2) Warstwy funkcjonalne w GUI
Panel typu “
root pane
” przekazuje swoje komponenty – pasek menu i
komponenty zawarte w panelu typu “content pane” – do obiektu obiektu
klasy
panelu warstwowego
JLayeredPane
pełni
ą
cego rol
ę
zarz
ą
dcy
„gł
ę
bi poło
ż
enia” komponentu w GUI za pomoc
ą
wyró
ż
nienia
warstw
malowania
.
Im wy
ż
szy
indeks warstwy
"tym pó
ź
niej" i "tym bli
ż
ej wierzchu" jest ona
malowana.
W ramach tej samej warstwy o kolejno
ś
ci malowania komponentów
decyduje indeks ich
poło
ż
e
ń
w ramach warstwy
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 30
Dodaj
ą
c komponent do panelu zawarto
ś
ci kontenera głównego mo
ż
emy
okre
ś
la
ć
jego przynale
ż
no
ść
do warstwy malowania.
panelWarstwowy.add(label, new Integer(i));
// Dodaj komponent do
//
warstwy
i
panelu warstwowego.
Do zmiany warstwy komponentu słu
ż
y metoda
setLayer
:
panelWarstwowy.setLayer(komponent, indeksWarstwy);
panelWarstwowy.setLayer(komponent, indeksWarstwy, pozycjaWWarstwie);
Pewne warto
ś
ci warstw
zarezerwowane s
ą
dla
specyficznych obiektów.
Nazwa zarezerwowanej warstwy i odpowiadaj
ą
ca jej stała, zdefiniowana
w klasie
JLayeredPane
:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 31
FRAME_CONTENT_LAYER
new Integer(-30000)
To warstwa przeznaczona dla “content pane” i paska menu ramki.
DEFAULT_LAYER
new Integer(0)
Tutaj umieszczane s
ą
komponenty u
ż
ytkownika, którym nie nadał on
indeksu warstwy.
PALETTE_LAYER
new Integer(100)
Ta warstwa jest dogodna dla tymczasowo widocznych pasków narz
ę
dzi
i zestawów danych.
MODAL_LAYER
new Integer(200)
W tej warstwie umieszczane s
ą
okna dialogowe otwierane w trybie
wył
ą
czno
ś
ci (modalne) dla obiektu klasy
JInternalFrame
.
POPUP_LAYER
new Integer(300)
W tej warstwie wyst
ę
puj
ą
wysuwane menu typu „pop-up”, powinny one
wyst
ą
pi
ć
nad wszystkimi pozostałymi komponentami.
DRAG_LAYER
new Integer(400)
W tej warstwie umieszczany jest “uchwycony” mysz
ą
komponent
(„drag”). Po „porzuceniu” („drop”) komponentowi powinna by
ć
przywrócona jego normalna warstwa.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 32
12.4 Panel warstwowy ("layered pane")
1) Klasy paneli warstwowych
W Swingu zdefiniowano dwie klasy paneli warstwowych:
JLayeredPane
- klasa dla panelu "
root pane
" kontenera głównego;
JDesktopPane
- klasa pochodna od
JLayeredPane
, specjalizowana dla
zawierania "wewn
ę
trznych ramek".
Utworzenie własnego panelu warstwowego lub korzystanie z
domy
ś
lnego dla kontenera typu
JFrame
:
// Własny
// Domy
ś
lny
panelWarstw = new JLayeredPane();
panelWarstw = getLayeredPane();
... // Ustawienia panelu warstw
... // Ustawienia panelu warstw
// Własny panel warstwowy kontenera
frame.setLayeredPane(panelWarstw);
frame.pack();
frame.pack();
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 33
Przykład 12.6.
Program
LayeredPaneDemo
tworzy panel warstwowy i
rozmieszcza ró
ż
nokolorowe etykiety w ró
ż
nych warstwach.
W danej chwili obrazek “Duke”
rysowany jest
pod
zielon
ą
i czerwon
ą
etykiet
ą
ale
nad
pozostałymi trzema.
W kontrolce wysuwnych opcji mo
ż
na
zmieni
ć
warstw
ę
Duke-a
a
przyciskiem
radiowym
–
mo
ż
na
przenie
ść
go na pierwsze miejsce w
danej warstwie (pozycja 0).
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 34
// Utworzenie panelu warstwowego:
layeredPane = new JLayeredPane();
// Jedyny konstruktor w tej klasie
layeredPane.setPreferredSize(new Dimension(300, 310));
// Rozmiar
layeredPane.setBorder(BorderFactory.createTitledBorder(
// Brzeg
"Move the Mouse to Move Duke"));
// z tytułem
layeredPane.addMouseMotionListener(new MouseMotionAdapter() {
... // Obsługa zdarze
ń
myszy
});
// Dodaj komponent do okre
ś
lonej warstwy komponentów
for (int i = 0; i < ...number of labels...; i++) {
JLabel label = createColoredLabel(...);
// Metoda własna – tworzy
// obiekt klasy JLabel o pewnym kolorze, z brzegiem i tekstem.
layeredPane.add(label, new Integer(i));
// Dodaj komponent do
//
warstwy i panelu warstwowego
...
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 35
// Dynamiczna zmiana pozycji dla obiektu “dukeLabel” – w procedurze
//
actionPerformed
zarejestrowanej dla listy wysuwanych opcji:
public void actionPerformed(ActionEvent e) {
int position = onTop.isSelected() ? 0 : -1;
// Ustaw 0 lub -1
layeredPane.setLayer(dukeLabel,
// Komponent, który ustawiamy
layerList.getSelectedIndex(),
// Nowa warstwa
position);
// Nowa pozycja w warstwie – „góra” lub „dół
”
}
// Ustawienie pozycji w ramach warstwy
final ImageIcon icon = createImageIcon("images/dukeWaveRed.gif");
...
dukeLabel = new JLabel(icon);
// Utwórz etykiet
ę
zawieraj
ą
c
ą
ikon
ę
...
dukeLabel.setBounds(15, 225,
// Ustaw brzeg obiektu
icon.getIconWidth(),
icon.getIconHeight());
...
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 36
// Trzy-argumentowa wersja metody
add
:
layeredPane.add(dukeLabel,
// dodawany komponent
new Integer(2),
// obiekt Integer podaje indeks warstwy
0);
// warto
ść
int podaje pozycj
ę
w ramach warstwy
.
Pozycje w ramach warstwy numerowane
s
ą
od -1 do (n - 1), gdzie n jest liczb
ą
komponentów
warstwy.
Im
mniejsza
pozycja tym „wy
ż
ej” znajduje si
ę
dany
komponent. -1 jest równowa
ż
ne (n – 1) –
wskazuje „najni
ż
sz
ą
” pozycj
ę
.
// Metoda
actionPerformed
zarejestrowana dla listy wysuwanych opcji:
public void actionPerformed(ActionEvent e) {
if (onTop.isSelected())
layeredPane.moveToFront(dukeLabel);
// Ustaw pozycję 0
else
layeredPane.moveToBack(dukeLabel);
// Ustaw pozycje -1
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 37
2) Romieszczanie komponentów w warstwowym panelu
Domy
ś
lnie warstwowy panel
nie posiada menad
ż
era układu
. Nale
ż
y
samemu ustawi
ć
rozmiary i poło
ż
enia komponentów.
Np. z wykorzystaniem metody
setBounds
:
dukeLabel.setBounds(15, 225,
icon.getIconWidth(),
icon.getIconHeight());
...
label.setBounds(origin.x, origin.y, 140, 140);
Np. dynamiczna zmiana poło
ż
enia metod
ą
setLocation
:
dukeLabel.setLocation(e.getX()-XFUDGE, e.getY()-YFUDGE);
Mo
ż
na te
ż
nada
ć
menad
ż
era układu panelowi warstwowemu. B
ę
dzie
on traktował komponenty tak, jakby wszystkie nale
ż
ały do jednej
warstwy.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 38
Np.
Program
LayeredPaneDemo2
ustawia
menad
ż
era
układu
dla
panelu
warstwowego
na
obiekt
typu
GridLayout
i korzysta z niego dla
rzmieszczenia 6 kolorowych etykiet (z
poprzedniego przykładu).
Rozwi
ą
zanie z wykorzystaniem menad
ż
erów układu dla warstw:
Stosujemy kontenery po
ś
redniego poziomu (jak np. panele) - po jednym
dla ka
ż
dej warstwy komponentów –
- mo
ż
na skorzysta
ć
z menad
ż
erów układu ka
ż
dego panelu dla osobnego
ustawienia komponentów ka
ż
dej warstwy;
- poszczególne panele rozmieszczamy stosuj
ą
c bezwgl
ę
dne warto
ś
ci
poło
ż
e
ń
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 39
12.5 Klasa
JInternalFrame
1) Klasa
JInternalFrame
umo
ż
liwia malowanie ramki wewn
ą
trz innej
ramki. Zwykle "ramki wewn
ę
trzne" dodawane s
ą
do panelu
warstwowego typu
JDesktopPane
, który z kolei staje si
ę
panelem
zawarto
ś
ci dla ramki typu
JFrame
(klasa
JDesktopPane
jest klas
ą
pochodn
ą
od klasy
JLayeredPane
).
Przykład 12.7
Program
InternalFrameDemo.java
tworzy poni
ż
szy GUI - posiada 2
wewn
ę
trzne ramki (jedna
została zminimalizowana)
wewn
ą
trz regularnej ramki.
// Tworzenie GUI -
// kod zawarty w konstruktorze klasy
InternalFrameDemo
, b
ę
d
ą
cej
// klas
ą
pochodn
ą
od klasy
JFrame
:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 40
desktop = new JDesktopPane();
// Utwórz nowy obiekt typu
JDesktopPane
...
createFrame();
// Utwórz okno wewn
ę
trzne i doł
ą
cz do panelu
desktop
...
setContentPane(desktop);
// Ustaw panel zawarto
ś
ci ramki na
desktop
...
// Zmie
ń
tryb "uchwycenia" komponentów. Tylko obrys ramki a nie jej
// cała zawarto
ść
b
ę
d
ą
rysowane podczas przeci
ą
gania. To
// przyspieszy od
ś
wie
ż
anie kosztem wygl
ą
du.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
...
.. // Metoda
createFrame()
protected void createFrame() {
MyInternalFrame frame = new MyInternalFrame();
// Klasa
// programisty - pochodna od
JInternalFrame
frame.setVisible(true);
// Ustaw widoczno
ść
wewn
ę
trznej ramki
desktop.add(frame);
// Doł
ą
cz wewn
ę
trzn
ą
ramk
ę
do ramki głównej
try {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 41
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
// W konstruktorze klasy
MyInternalFrame
pochodnej od
JInternalFrame
:
static int openFrameCount = 0;
static final int xOffset = 30, yOffset = 30;
public MyInternalFrame() {
super("Document #" + (++openFrameCount),
true,
// b
ę
dzie mo
ż
liwa zmiana rozmiaru
true,
// b
ę
dzie mo
ż
liwe zamkni
ę
cie
true,
// b
ę
dzie mo
ż
liwa maksymalizacja rozmiaru
true);
// b
ę
dzie mo
ż
liwa minimalizacja rozmiaru
//... Tworzy GUI i dodaje do ramki ...
// ... - jak na poczatku przykładu
//... Ustawia rozmiar ramki lub woła
pack()
...
// Ustaw poło
ż
enie ramki
setLocation(xOffset*openFrameCount, yOffset*openFrameCount);
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 42
2) Zasady korzystania z wewn
ę
trznych ramek
Korzystanie z wewn
ę
trznych ramek przypomina korzystanie z
regularnych ramek. Ramka wewn
ę
trzna posiada panel "root pane" i
dlatego tworzenie z niej GUI jest niemal identyczne jak dla
JFrame
.
Ale
JInternalFrame
nie jest
klas
ą
typu
Windows
ani kontenerem
głównym
- wewn
ę
trzna ramka nie jest korzeniem hierarchii
komponentów - musi by
ć
dodana do kontenera (np. typu
JDesktopPane
).
JInternalFrame
posiada metody takie, jak np.
moveToFront
, która
wymaga, aby kontenerem ramki był wła
ś
nie panel warstwowy taki, jak
JDesktopPane.
Wybieraj
ą
c wewn
ę
trzne ramki w GUI u
ż
ytkownik nie generuje zdarze
ń
dla okien systemu, lecz zdarzenia dla okna ramki głównej.
Wewn
ę
trzne ramki s
ą
zaimplementowane w
kodzie niezale
ż
nym od
platformy
i dlatego daj
ą
pewne mo
ż
liwo
ś
ci u
ż
ytkownikowi, których nie
posiadaj
ą
zwykłe ramki:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 43
-
Mo
ż
na
programowo minimalizowa
ć
lub
maksymalizowa
ć
ramk
ę
.
-
Mo
ż
na poda
ć
ikonk
ę
dla paska
z tytułem.
-
Mo
ż
na okre
ś
li
ć
, czy ramka posiada
dekoracje okien
dla zmiany
rozmiaru, minimalizacji, zamykania i maksymalizacji.
Zasady korzystania z wewn
ę
trznych ramek
1. Ustawi
ć
rozmiar wewn
ę
trznej ramki -
w przeciwnym razie b
ę
dzie ona
mie
ć
rozmiar zerowy. Metody:
setSize, pack, setBounds
.
2. Ustawi
ć
poło
ż
enie
- w przeciwnym razie lokalizacja wyniesie (0, 0)
(lewy górny róg jej kontenera). Metody:
setLocation , setBounds
.
3. Doda
ć
komponenty do "panelu zawarto
ś
ci
" wewn
ę
trznej ramki - jak
dla ramki
JFrame
.
4. Okna dialogowe
b
ę
d
ą
ce
wewn
ę
trznym ramkami
powinny by
ć
implementowane jako
JOptionPane
lub
JInternalFrame
, a nie
JDialog
.
Dla prostych dialogów nale
ż
y u
ż
y
ć
metod klasy
JOptionPane
w rodzaju:
showInternalXxxDialog.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 44
5. Wewn
ę
trzna ramka
musi by
ć
dodana do kontenera
- w przeciwnym
razie nie b
ę
dzie widoczna.
6. Nale
ż
y
wywoła
ć
show
lub
setVisible
dla wewn
ę
trznej ramki -
wewn
ę
trzne ramki s
ą
domy
ś
lnie niewidoczne. Metody:
setVisible(true)
lub
show()
.
7. Wewn
ę
trzne ramki
zgłaszaj
ą
charakterystyczne dla nich zdarzenia
.
Chocia
ż
zdarzenia te nie s
ą
zwi
ą
zane z oknami systemu, to jednak
obsługa tych zdarze
ń
jest prawie identyczna z obsług
ą
zdarze
ń
dla okien
systemu.
8. Dla zwi
ę
kszenia szybko
ś
ci od
ś
wie
ż
ania przy wielu wewn
ę
trznych
ramkach mo
ż
na zmieni
ć
tryb od
ś
wie
ż
ania podczas przeci
ą
gania.
Metoda klasy
JDesktopPane
-
setDragMode
- umo
ż
liwia ustawienie trybu
od
ś
wie
ż
ania podczas przeci
ą
gania. Np.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 45
12.6 Klasa
JPanel
JPanel
jest klas
ą
ogólnego kontenera po
ś
redniego poziomu:
-
zasadniczo rysuje tylko swoje tło;
-
mo
ż
na doda
ć
brzeg;
-
mo
ż
na doda
ć
komponenty;
-
komponenty rozmieszczane s
ą
przez menad
ż
era układu zwi
ą
zanego
z panelem;
-
panel jest domy
ś
lnie nieprzezroczysty i mo
ż
e wtedy słu
ż
y
ć
jako
„content pane” dla ramki lub apletu.
Przykład 12.8
W programie Converter zastosowano kilka obiektów klasy
JPanel
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 46
Czerwony
panel – pełni rol
ę
“content pane” dla ramki. Korzysta z
menad
ż
era układu typu
BoxLayout
dla rozmieszczenia w pionie swoich
komponentów. Posiada pusty brzeg o szeroko
ś
ci 5 pikseli.
Dwa panele
typu ConversionPanel (definiowanego przez u
ż
ytkownika)
– zawieraj
ą
komponenty i koordynuj
ą
wymian
ę
informacji mi
ę
dzy
odpwiadaj
ą
cymi sobie komponentami w obu panelach. Oba panele
posiadaj
ą
brzegi opatrzone w tytuł i kraw
ę
dzie. Korzystaj
ą
z
menad
ż
erów układu typu
BoxLayout
(rozmieszcza od lewej do prawej).
Po jednym panelu
- wyst
ę
puje w ka
ż
dym panelu konwersji dla
rozmieszczenia listy wysuwanych opcji z wykorzystaniem menad
ż
erów
konwersji typu
BoxLayout
(rozmieszczanie w pionie) (dodatkowo
wyst
ę
puje niewidoczny komponent wypełniaj
ą
cy obszar panelu).
Po jednym panelu
dla ka
ż
dego panelu konwersji grupuje dwa dalsze
komponenty – pole edycyjne i suwak — rozmieszczane w pionie
menad
ż
erem układu typu
BoxLayout
.
Menad
ż
er układu dla panelu
Domyslny menad
ż
er jest typu FlowLayout – rozmieszczanie w wierszu.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 47
Ustawienie innego menad
ż
era układu – podczas konstrukcji panelu lub
metod
ą
setLayout. Np.
JPanel p = new JPanel(new BorderLayout()); // preferowane rozwiązanie
// ale BoxLayout wymaga istnienia panelu:
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
Dodanie komponentów
// Dla menad
ż
erów układu typu FlowLayout, BoxLayout, GridLayout,
// lub SpringLayout wystarczy 1-argumentowa metoda add():
aFlowPanel.add(aComponent);
aFlowPanel.add(anotherComponent);
// Dla BorderLayout potrzebny jest argument podaj
ą
cy pozycj
ę
:
aBorderPanel.add(aComponent, BorderLayout.CENTER);
aBorderPanel.add(anotherComponent, BorderLayout.PAGE_END);
// Dla GridBagLayout mo
ż
na u
ż
y
ć
obu wersji metody add()
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 48
12.7
JScrollPane
Panel przewijany zapewnia przewijany widok komponentu, co ma
znaczenie wtedy, gdy dost
ę
pny obszar ekranu nie wystarcza na
pokazanie całego komponentu na raz.
Przykład 12.9
Program dodaje obszar tekstowy do panelu przewijania,
gdy
ż
obszar tekstowy dynamicznie ro
ś
nie.
// W konterze z menad
ż
erem układu typu Border Layout
// Utworzenie panelu przewijania z klientem – obszarem tekstowym::
textArea = new JTextArea(5, 30); // 5 wierszy i 30 kolumn tekstu
...
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 49
JScrollPane scrollPane = new JScrollPane(textArea);
...
setPreferredSize(new Dimension(450, 120)); // Rozmiar kontenera
...
add(scrollPane, BorderLayout.CENTER);
Kod dotycz
ą
cy panelu przewijania jest minimalny, gdy
ż
wszystko jest
wykonywane automatycznie przez metody klasy
JScrollPane
.
Przykład 12.10
Program
ScrollDemo
zapewnia zmodyfikowany przez
u
ż
ytkownika panel przewijania dla prezentacji du
ż
ej fotografii.
Poza obszarem centralnym – widokiem
dla komponentu – klienta (w tym
przypadku jest nim obraz) panel
przewijania zawiera te
ż
2 paski
przesuwne, nagłówek wierszy,
nagłówek kolumn i cztery rogi.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 50
// Deklaracja pola klasy:
private ScrollablePicture picture;
...
// Tworzenie GUI :
picture = new ScrollablePicture( ... ); // Utworzenie klienta
JScrollPane pictureScrollPane = new JScrollPane(picture);
Pó
ź
niejsza zmiana klienta panelu jest mo
ż
liwa metod
ą
setViewportView
.
JScrollPane
nie posiada metody getViewportView – w celu pobrania
obiektu
klienta
nale
ż
y
posłu
ż
y
ć
si
ę
wywołaniem
getViewport().getViewportView()
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 51
Widocznym obszarem klienta zarz
ą
dza obiekt klasy
JViewport
–
przeliczaj
ą
c aktualne poło
ż
enia pasków przewijania na ograniczenia
widocznego obszaru klienta.
Panel przewijania korzysta z dwóch obiektów klasy
JScrollBar
dla
zapewnienia pasków przewijania. Trzy obszary paska to:
„gałka” (“knob”) lub „kciuk” (“thumb”),
„przyciski strzałek” - ruch o 1 jednostk
ę
,
„tor” („track”) - ruch o 1 blok.
Ustawianie opcji przewijania
Ka
ż
dy pasek przewijania posiada własne ustawienia opcji. Konstruktory
klasy
JScrollPane,
umo
ż
liwiaj
ą
ce ustawienie opcji przewijania, to:
JScrollPane(Component, int, int)
JScrollPane(int, int)
Pierwszy parametr typu
int
okre
ś
la opcj
ę
dla pionowego paska a drugi
parametr typu
int
dla poziomego paska.
Dynamiczne ustawienie opcji przewijania – metodami:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 52
setHorizontalScrollBarPolicy
setVerticalScrollBarPolicy.
W interfejsie
ScrollPaneConstants
(implementowanym przez
JScrollPane
)
zdefiniowano nast
ę
puj
ą
ce stałe:
VERTICAL_SCROLLBAR_AS_NEEDED
HORIZONTAL_SCROLLBAR_AS_NEEDED
Domy
ś
lne ustawienie – pasek przewijania pojawia si
ę
w razie potrzeby
wtedy, gdy obszar widoku jest mniejszy ni
ż
obszar klienta a znika, gdy
widok jest wi
ę
kszy ni
ż
obszar klienta.
VERTICAL_SCROLLBAR_ALWAYS
HORIZONTAL_SCROLLBAR_ALWAYS
Zawsze wy
ś
wietla pasek przewijania – jedynie
ś
rodkowa cz
ęść
paska
(gałka) znika, gdy widok mo
ż
e pomie
ś
ci
ć
całego klienta.
VERTICAL_SCROLLBAR_NEVER
HORIZONTAL_SCROLLBAR_NEVER
Nigdy nie wy
ś
wietla paska przewijania.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 53
Dekoracje u
ż
ytkownika
Obszar panelu przewijania mo
ż
e składa
ć
si
ę
z
9 cz
ęś
ci:
obszaru centralnego,
czterech boków i
czterech naro
ż
ników.
Jedynie obszar centralny musi zawsze wyst
ą
pi
ć
– pozostałe s
ą
opcjonalne. W obszarach bocznych mog
ą
wyst
ą
pi
ć
paski przewijania i
nagłówki wierszy oraz kolumn. Naro
ż
niki s
ą
widoczne tylko wtedy, gdy
przecinaj
ą
si
ę
w nich po dwa widoczne komponenty.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 54
Przykład 12.11
W powy
ż
szym przykładzie 3 z 4 naro
ż
ników s
ą
wykorzystane przez u
ż
ytkownika – jeden zawiera dwustanowy przycisk,
a dwa dalsze s
ą
jedynie wypełniane kolorem linijek. Ostatni naro
ż
nik, na
przeci
ę
ciu pasków przewijania jest domy
ś
lnej postaci – mo
ż
e on zanika
ć
wtedy, gdy zaniknie przynajmniej jeden z pasków.
Nagłówki kolumn i wierszy zrealizowane s
ą
za pomoc
ą
komponentu
u
ż
ytkownika
Rule
(linijka). Mo
ż
na w tym celu u
ż
y
ć
dowolnego
komponentu. Panel przewijania umieszcza komponenty dla nagłówków
kolumn i wierszy w ich własnych widokach -
JViewport
. Te komponenty
przesuwaj
ą
si
ę
podczas przewijania synchronicznie z widokiem obszaru
klienta.
// Miejsce deklaracji pól klasy panelu:
private Rule columnView;
private Rule rowView;
...
// Miejsce inicjalizacji GUI :
ImageIcon david = createImageIcon("images/youngdad.jpeg");
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 55
...
// Utwórz nagłówki wierszy i kolumn:
columnView = new Rule(Rule.HORIZONTAL, true);
rowView = new Rule(Rule.VERTICAL, true);
if (david != null) {
columnView.setPreferredWidth(david.getIconWidth());
rowView.setPreferredHeight(david.getIconHeight());
}
...
pictureScrollPane.setColumnHeaderView(columnView);
pictureScrollPane.setRowHeaderView(rowView);
Jako klasa pochodna od
JComponent
klasa u
ż
ytkownika
Rule
definiuje
metod
ę
paintComponent
dla rysowania obiektu na ekranie. Metoda ta
sprawdza aktualny widok dla obiektu tak, aby nie rysowa
ć
cz
ęś
ci, które
wykraczaj
ą
poza ten widok.
W dwóch naro
ż
nikach umieszczane s
ą
obiekty klasy u
ż
ytkownika
Corner
a w trzecim – dwustanowy przycisk klasy
JToggleButton
:
// Utwórz obiekt dla naro
ż
nika z przyciskiem
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 56
JPanel buttonCorner = new JPanel();
// korzysta z FlowLayout
isMetric = new JToggleButton("cm", true);
isMetric.setFont(new Font("SansSerif", Font.PLAIN, 11));
isMetric.setMargin(new Insets(2,2,2,2));
isMetric.addItemListener(this);
buttonCorner.add(isMetric);
...
// Ustaw naro
ż
niki panelu przewijania
pictureScrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
buttonCorner);
pictureScrollPane.setCorner(JScrollPane.LOWER_LEFT_CORNER,
new Corner());
pictureScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
new Corner());
Rozmiar naro
ż
nika wyznaczany jest przez rozmiary boków panelu
przewijania przecinaj
ą
cych si
ę
w danym naro
ż
niku.
Stałe definiowane w interfejsie
ScrollPaneConstants
wyznaczaj
ą
poło
ż
enie naro
ż
nika:
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 57
Klient implementuj
ą
cy interfejs
Scrollable
Dla zapewnienia lepszej współpracy klienta z panelem przewijania klasa
komponentu klienta powinna implementowa
ć
interfejs
Scrollable
.
Wtedy klient okre
ś
li rozmiar widoku potrzebnego dla ogl
ą
dania go i
jednostki dla przewijania za pomoc
ą
ró
ż
nych cz
ęś
ci paska.
Innym sposobem na ustawienie jednostek paska przewijania jest
wywołanie metod w klasie
JScrollBar
:
setUnitIncrement
setBlockIncrement .
Np. ustawienie jednostki pionowego przewijania na 10 pikseli:
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 58
W powy
ż
szym programie
ScrollDemo
klientem jest obiekt klasy
u
ż
ytkownika
ScrollablePicture
, klasy pochodnej od
JLabel
. Implementuje
ona wszystkie 5 metod interfejsu
Scrollable
:
-
getScrollableBlockIncrement
-
getScrollableUnitIncrement
-
getPreferredScrollableViewportSize
-
getScrollableTracksViewportHeight
-
getScrollableTracksViewportWidth
Metoda klienta
getScrollableUnitIncrement
jest wołana wtedy, gdy
u
ż
ytkownik klika jeden z przycisków na pasku przewijania. Sensown
ą
implementacj
ą
tej metody byłoby zwrócenie liczby pikseli pomi
ę
dzy
kolejnymi działkami na linijce. W klasie
ScrollablePicture
podano jednak
troch
ę
inn
ą
implementacj
ę
: zwracana jest liczba pikseli potrzebna do
umieszczenia obrazu na najbli
ż
szym znaczniku podziałki.
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation,
int direction) {
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 59
// Pobierz aktualne poło
ż
enie.
int currentPosition = 0;
if (orientation == SwingConstants.HORIZONTAL) {
currentPosition = visibleRect.x;
} else {
currentPosition = visibleRect.y;
}
// Wynikiem jest liczba pikseli pomi
ę
dzy
currentPosition
// a najbli
ż
szym znacznikiem w podanym kierunku .
if (direction < 0) {
int newPosition = currentPosition -
(currentPosition / maxUnitIncrement)
* maxUnitIncrement;
return (newPosition == 0) ? maxUnitIncrement : newPosition;
} else {
return ((currentPosition / maxUnitIncrement) + 1)
* maxUnitIncrement - currentPosition;
}
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 60
Je
ś
li obraz znajduje si
ę
ju
ż
na znaczniku linijki ta metoda zwraca liczb
ą
pikseli pomi
ę
dzy dwoma znacznikami.
Panel przewijania wywołuje metod
ę
klienta
getScrollableBlockIncrement
je
ś
li potrzebna jest jednostka przewini
ę
cia o blok. Implementacja tej
metody w przykładowej klasie u
ż
ytkownika:
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation,
int direction) {
if (orientation == SwingConstants.HORIZONTAL)
return visibleRect.width - maxUnitIncrement;
else
return visibleRect.height - maxUnitIncrement;
}
Powy
ż
sza metoda zwraca wysoko
ść
widoku zmniejszon
ą
o odległo
ść
pomi
ę
dzy znacznikami linijki. Jest to typowe podej
ś
cie. W ten sposób
pozostaje widoczny jeszcze w
ą
ski fragment poprzedniego widoku.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 61
Klasa u
ż
ytkownika
ScrollablePicture
implementuje te
ż
procedur
ę
obsługi
zdarzenia myszy, która pozwala na przewijanie obrazu metod
ą
“uchwycenia” i wyj
ś
cia kursorem poza obszar obrazu:
public class ScrollablePicture extends JLabel
implements Scrollable, MouseMotionListener {
...
public ScrollablePicture(...) {
...
setAutoscrolls(true);
// Dla zdarzenia sztucznego przesuni
ę
cia
addMouseMotionListener(this);
// Obsługa przesuni
ę
cia mysz
ą
}
...
public void mouseDragged(MouseEvent e) {
// U
ż
ytkownik “przeci
ą
ga” klienta, wi
ę
c przewijaj go:
Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
scrollRectToVisible(r);
}
...
}
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 62
Metoda
setAutoscrolls,
zdefiniowana w
JComponent,
ma na celu
asystowanie przy procesie “przewijania przez przeci
ą
ganie”. Po nadaniu
własno
ś
ci
autoscrolls
warto
ś
ci
true
komponent b
ę
dzie zgłaszał zdarzenia
typu “
mouse-dragged
” wtedy, gdy mysz jest zatrzymana poza
komponentem w stanie „uchwycenia” klienta komponentu.
Okre
ś
lenie rozmiaru panelu przewijania
Je
ś
li rozmiar panelu przewijania nie jest ustawiony jawnie to zostanie on
obliczony na podstawie preferowanych rozmiarów jego 9 cz
ęś
ci.
Najistotniejszy jest tu rozmiar widoku klienta.
Je
ś
li klient nie jest przygotowany do przewijania (nie implementuje
Scrollable) wtedy stosowanie panelu przewijanie staje si
ę
nadmiarowe –
rozmiar panelu jest wystarczaj
ą
co du
ż
y, aby prezentowa
ć
preferowany
rozmiar klienta, czyli cało
ść
.
Je
ś
li klient jest przygotowany do przewijania to panel przewijania
pobiera
jego
preferowany
rozmiar
widoku
metod
ą
klienta
getPreferredScrollableViewportSize .
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 63
Np. w klasie
JList
implementacja
getPreferredScrollableViewportSize
umo
ż
liwia widok 8 wierszy.
Dynamiczna zmiana rozmiaru klienta
Je
ś
li w czasie wykonywania programu rozmiar klienta musi ulec zmianie
to nale
ż
y o tym równie
ż
powiadomi
ć
panel przewijania:
-
najpierw nadawany jest nowy preferowany rozmiar klientowi,
-
nast
ę
pnie wywołana jest metoda
revalidate
dla klienta co zmusi panel
przewijania do od
ś
wie
ż
enia swojego wygl
ą
du, w tym pasków .
Np. klient nazywa si
ę
drawingArea
:
if (changed) {
drawingArea.setPreferredSize(/*nowy rozmiar*/);
drawingArea.revalidate();
// Powiadom o zmianie panel przewijania
}
Do zmiany rozmiaru klienta dopasowuj
ą
si
ę
suwaki panelu przewijania,
ale ani panel przewijania ani rozmiar widoku klienta nie ulegaj
ą
zmianie.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 64
12.8
JSplitPane
– panel dzielony
Obiekt klasy
JSplitPane
rysuje dwa poł
ą
czone ze sob
ą
komponenty,
jeden obok drugiego lub jeden nad drugim.
Przesuwaj
ą
c podziałk
ę
oddzielaj
ą
c
ą
komponenty mo
ż
na zmienia
ć
podział obszaru panelu na dwie jego cz
ęś
ci.
Panele dzielone mog
ą
by
ć
zagnie
ż
d
ż
ane co pozwala na dzielenie
obszaru ekranu na wi
ę
ksz
ą
liczb
ę
cz
ęś
ci.
Komponenty składowe dodawane s
ą
zwykle najpierw do paneli
przesuwnych a dopiero te staj
ą
si
ę
cz
ęś
ciami panelu dzielonego.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 65
Przykład 12.12
. Aplikacja korzysta z panelu dzielonego dla prezentacji
listy i obrazu obok siebie. Program pobiera dane – wektor nazw plików i
umo
ż
liwia prezentacj
ę
obrazów odpowiadaj
ą
cych nazwom.
// Utworzymy panel dzielony zawieraj
ą
cy dwa panele przewijane
splitPane = new JSplitPane (
JSplitPane.HORIZONTAL_SPLIT,
// Kierunek podziału
listScrollPane,
// 1-szy komponent składowy
pictureScrollPane);
// 2-gi komponent składowy
splitPane.setOneTouchExpandable(true);
// Przywró
ć
strzałki
splitPane.setDividerLocation(150);
// Ustal poło
ż
enie podziałki
// Okre
ś
lamy minimalne rozmiary dla składowych panelu
Dimension minimumSize = new Dimension(100, 50);
listScrollPane.setMinimumSize(minimumSize);
pictureScrollPane.setMinimumSize(minimumSize);
Kierunek podziału:
-
JSplitPane.HORIZONTAL_SPLIT
lub
JSplitPane.VERTICAL_SPLIT
,
-
pó
ź
niejsza zmiana metod
ą
setOrientation( ).
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 66
Dwie małe strzałki na górze podziałce:
-
pojedynczym klikni
ę
ciem mo
ż
na zupełnie zwin
ąć
lub przywróci
ć
ka
ż
dy
ze składników .
-
w
ś
rodowisku “Java Look & Feel” s
ą
one domy
ś
lnie niewidoczne;
-
mo
ż
na przywróci
ć
strzałki metod
ą
setOneTouchExpandable( )
.
Dynamiczne ustawianie składników panelu dzielonego
-
Metody
słu
ż
ace
do
zmiany
komponentu
składowego:
setLeftComponent
,
setRightComponent
,
setTopComponent,
setBottomComponent
.
Interpretacja metod zale
ż
y od aktualnego kierunku podziału panelu
dzielonego. Lewy odpowiada górnemu a prawy dolnemu poło
ż
eniu i na
odwrót.
-
Mo
ż
na korzysta
ć
z metody
add()
dziedziczonej po JComponent ale po
uprzednim usuni
ę
ciu zast
ę
powanych komponentów metod
ą
remove()
.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 67
-
Przekazanie tylko jednego komponentu do panelu dzielonego sprawi,
ż
e zajmie on miejsce lewe lub górne a podziałka znajdzie si
ę
odpowiednio z prawej strony lub na dole obszaru panelu.
Ustawianie podziałki i ograniczanie jego zakresu
-
Metoda
setDividerLocation
słu
ż
y do ustawiania podziałki – w pikselach
lub w procentach.
-
Dla pobrania aktualnego poło
ż
enia podziałki wyra
ż
onego w pikselach
słu
ż
y metoda
getDividerLocation
.
Np.
// Ustaw podziałke na pikselu 150
splitPane.setDividerLocation(150);
// Ustaw podziałk
ę
na 25% cało
ś
ci dla lewego lub górnego składnika
splitPane.setDividerLocation(0.25);
-
Metoda
resetToPreferredSizes
ustawia podziałk
ę
, tak aby składowe
posiadały preferowane rozmiary. Taka jest te
ż
pocz
ą
tkowa, domy
ś
lna
podziałka.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 68
-
Podziałk
ę
mo
ż
na przesuwa
ć
za pomoc
ą
myszy. Ograniczeniem sa
minimalne rozmiary składników panelu. Zwykle nalezy ustawi
ć
te
minimalne rozmiary (metoda
setMinimumSize
), gdy
ż
w przeciwnym
razie panel kieruje si
ę
preferowanymi rozmiarami i nie zezwala na
zmian
ę
podziałki.
Zagnie
ż
d
ż
anie paneli dzielonych
Przykład 12.13
. Kolejny program dzieli obszar UI aplikacji na trzy
cz
ęś
ci zagnie
ż
d
ż
aj
ą
c jeden panel
dzielony (utworzony w poprzednim
przykładzie w kierunku poziomym) w
drugim
(tworzonym
w
kierunku
pionowym). Pierwszym składnikiem
nowego panelu dzielonego jest
poprzedni panel dzielony a drugim
zwykła etykieta.
// Utwórz obiekt klasy SplitPaneDemo zawieraj
ą
cy panel dzielony
// z poprzedniego przykładu
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 69
SplitPaneDemo splitPaneDemo = new SplitPaneDemo();
JSplitPane top = splitPaneDemo.getSplitPane();
...
// Utwórz zwykł
ą
etykiet
ę
label = new JLabel("Click on an image name in the list.",
JLabel.CENTER);
// Utwórz panel dzielony i dodaj do niego panel oraz etykiet
ę
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
top, label);
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 70
12.9
JTabbedPane
Klasa
JTabbedPane
umo
ż
liwia zgrupowanie szeregu komponentów
(zwykle s
ą
nimi panele) dziel
ą
cych mi
ę
dzy sob
ą
ten sam obszar ekranu.
U
ż
ytkownik otwiera jedn
ą
z kart odpowiadaj
ą
c
ą
jednemu panelowi
wybieraj
ą
c zwi
ą
zan
ą
z ni
ą
metk
ę
(„tab”).
Przykład 12.14.
GUI aplikacji o jednym obiekcie
JTabbedPane
zawieraj
ą
cym cztery metki.
Metka mo
ż
e wy
ś
wietla
ć
ikonk
ę
i tekst a tak
ż
e zawiera
ć
wskazówk
ę
(„tool
tip”). Do zmiany poło
ż
enia metek słu
ż
y metoda
setTabPlacement
.
Nie jest wymagana własna obsługa zdarze
ń
, gdy
ż
klasa
JTabbedPane
obsługuje zdarzenia myszy.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 71
// Konstrukcja obiektu klasy JTabbedPane
ImageIcon icon = new ImageIcon("images/middle.gif");
JTabbedPane tabbedPane = new JTabbedPane();
// Dodaj karty z panelami
Component panel1 = makeTextPanel("Blah");
tabbedPane.addTab("One", icon, panel1, "Does nothing");
tabbedPane.setSelectedIndex(0);
Component panel2 = makeTextPanel("Blah blah");
tabbedPane.addTab("Two", icon, panel2, "Does twice as much nothing");
Component panel3 = makeTextPanel("Blah blah blah");
tabbedPane.addTab("Three", icon, panel3, "Still does nothing");
Component panel4 = makeTextPanel("Blah blah blah blah");
tabbedPane.addTab("Four", icon, panel4, "Does nothing at all");
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 72
12.10
Klasa JToolBar –
pasek narz
ę
dzi
Kontener klasy
JToolBar
grupuje i ustawia komponenty (zwykle s
ą
to
przyciski zaopatrzone w ikony) w wierszu lub w kolumnie. Jej zdaniem
jest ułatwienie wyboru i wywołania operacji przez u
ż
ytkownika – zbli
ż
one
zadanie do menu (klasy
JMenu
i
JMenuItem
).
Przykład 12.15
. GUI aplikacji
ToolBarDemo
posiadaj
ą
cej zestaw narz
ę
dzi
umieszczony nad obszarem tekstowym.
U
ż
ytkownik mo
ż
e przeci
ą
ga
ć
zestaw do ró
ż
nych kraw
ę
dzi kontenera, w
którym jest zawarty, a tak
ż
e przeci
ą
ga
ć
zestaw do własnego okna.
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 73
Ograniczenia:
-
Dla zapewnienia operacji “przeci
ą
gnij do własnego okna” (“drag-out”)
kontener zawieraj
ą
cy zestaw musi posiada
ć
menad
ż
era BorderLayout.
-
Zestaw narz
ę
dzi musi by
ć
obok komponentu dla centralnego obszaru,
jedynym pozostałym komponentem w kontenerze i nie mo
ż
e by
ć
w
centralnym obszarze.
// Ikonki powinny by
ć
pobrane z magazynu np. dla „Java Look and Feel”
String imgLocation = "toolbarButtonGraphics/navigation/Back24.gif";
URL imageURL = getClass().getResource(imgLocation);
if (imageURL != null) {
button = new JButton(new ImageIcon(imageURL));
}
// Utwórz i dodaj oba komponenty do kontenera
public ToolBarDemo() {
...
JToolBar toolBar = new JToolBar();
addButtons(toolBar); // Metoda własna użytkownika
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 74
...
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
...
contentPane.add(toolBar, BorderLayout.NORTH);
contentPane.add(scrollPane, BorderLayout.CENTER);
...
}
// Dodaj przyciski do zestawu narz
ę
dzi
protected void addButtons(JToolBar toolBar) {
JButton button = null;
// 1-szy przycisk
button = new JButton(new ImageIcon("images/left.gif"));
...
toolBar.add(button);
// 2-gi przycisk
button = new JButton(new ImageIcon("images/middle.gif"));
...
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 75
toolBar.add(button);
// Trzeci przycisk
button = new JButton(new ImageIcon("images/right.gif"));
...
toolBar.add(button);
}
Przykład 12.16.
Program
ToolBarDemo2
. Kilka dodatkowych własno
ś
ci
zestawu
narz
ę
dzi:
unieruchomienie
zestawu
(metoda
setFloatable(false)), dodanie separatora , dodanie komponentu innego
ni
ż
przycisk.
W widoku zestawu narz
ę
dzi nie ma
ju
ż
„zderzaka”, gdy
ż
zestaw nie
mo
ż
e by
ć
przeci
ą
gany.
Wył
ą
czenie „przeci
ą
galno
ś
ci” zestawu narz
ę
dzi:
toolBar.setFloatable(false);
Dodanie separatora – spacji:
toolBar.addSeparator();
12. Swing – kontenery.
W. Kasprzak: Programowanie zdarzeniowe
12 - 76
Dodanie nowych komponentów:
// Czwarty przycisk
button = new JButton("Another button");
...
toolBar.add(button);
// Piąty komponent
JTextField textField = new JTextField("A text field");
...
toolBar.add(textField);
Komponenty ustawione s
ą
w sposób
wy
ś
rodkowany
wzgl
ę
dem siebie.
Mog
ą
by
ć
dopasowane swoimi dolnymi lub górnymi kraw
ę
dziami (przy
ustawieniu ich w poziomie) metod
ą
setAlignmentY
.
Np. wywoła
ć
nale
ż
y
setAlignmentY(TOP_ALIGNMENT)
dla ka
ż
dego
komponentu.
Podobnie metoda
setAlignmentX
słu
ż
y do zwi
ą
zania bokami wtedy, gdy
komponenty ustawione s
ą
w pionie.
Generalnie zestaw narz
ę
dzi korzysta z menad
ż
era układu
BoxLayout
.