Realizacja funkcji bibliotecznych w Javie#
Java posiada bogatą bibliotekę standardowych pakietów, i tak do podstawowych należą:
- java.lang - jest podstawowym pakietem języka Java, domyślnie importowanym dla każdej definiowanej klasy,
- java.applet - zawiera klasy potrzebne do tworzenia apletów zamieszczanych na stronach WWW,
- java.awt - Abstract Window Toolkit, jest to pakiet zawierający niezależny od platformy systemowej zestaw klas do projektowania aplikacji w środowisku graficznym,
- java.io - w pakiecie tym zebrano klasy implementujące operacje wejścia / wyjścia (ang. input / output),
- java.net - jest pakietem zawierającym klasy służące do realizacji operacji wejścia / wyjścia w sieci Internet na niskim poziomie,
- java.util - zawiera różne przydatne klasy jak np. Date, która jest używana do operacji na datach, niezależnie od platformy systemowej.
W dalszej części rozdziału omówimy następujące pakiety biblioteczne: java.awt, java.io i java.net. Pozostałe, zawierają klasy, z których część wykorzystano w pracy, natomiast dokładne omówienie wszystkich klas tych pakietów można znaleźć w dokumentacji dostarczanej z każdym środowiskiem programistycznym lub w Internecie pod adresem: http://java.sun.com/products/jdk/1.1/api/packages.html
Biblioteka AWT#
Wprowadzenie#
W każdym aplecie (lub aplikacji używającej elementów graficznego interfejsu użytkownika, ang. Graphic User Interface, GUI) pojawiają się elementy pakietu java.awt.. Pakiet Abstract Window Toolkit dostarcza komponentów graficznych używanych w programach Javy oraz elementów sterujących ich zachowaniem (generacja i obsługa zdarzeń). Biblioteka AWT składa się z następujących pakietów:
java.awt
java.awt.datatransfer
java.awt.event
java.awt.image
java.awt.peer
Klasą, z której dziedziczy większość klas pakietu AWT jest klasa Component. W rzeczywistości także klasa Applet jest częścią AWT. Klasy dziedziczące z klasy Component zestawiono poniżej:
* nowa klasa w JDK 1.1
Rysunek 2-9 Klasy dziedziczące z klasy Component
Przedstawione na rysunku klasy AWT możemy podzielić na dwa rodzaje: proste komponenty (np. Button, Label) i pojemniki przeznaczone do przechowywania prostych komponentów (np. Panel, Frame).
Zastosowanie przykładowych komponentów#
Klasa Applet jest podklasą klasy Component, może więc zawierać komponenty AWT. Dodajmy więc kilka komponentów do apletu:
Ilustracja 2-21 Możliwy wygląd apletu Komponenty
Jak widać, aplet ten zawiera znaczniki (ang. checkbox), przełączniki (ang. radio button), przycisk (ang. button), pole wyboru (ang. choice) i etykietę (ang. label). Poszczególne komponenty są częścią paneli (pojemników) oznaczonych kolorami, prócz etykiety, która wraz z innymi pojemnikami przypisana jest bezpośrednio do pojemnika apletu. Kod apletu Komponenty wraz z opisem przedstawiono poniżej.
Przykład 2.38 Użycie prostych komponentów
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Komponenty extends Applet implements ActionListener, ItemListener
{
Label lblEtykieta; // etykieta
Button btnPrzycisk; // przycisk
Choice chcTakNie; // pole wyboru
// panele na których umieszczone zostaną: znaczniki (p1),
// przełączniki (p2) oraz przycisk i pole wyboru (p3),
Panel p1, p2, p3;
Checkbox cb1, cb2; // znaczniki
Checkbox cb3, cb4; // przełączniki
CheckboxGroup cbg; // grupa przełączników
public void init()
{
//Budowanie pierwszego panelu zawierającego znaczniki
cb1 = new Checkbox();
cb1.setLabel("Checkbox 1");
cb2 = new Checkbox("Checkbox 2");
cb2.setState(true); // znacznik cb2 domyślnie zaznaczony
p1 = new Panel();
// ustawienie zarządcy rozmieszczenia komponentów dla panelu p1
p1.setLayout(new FlowLayout());
p1.setBackground(Color.yellow); // panel p1 kolor żółty
p1.add(cb1);
p1.add(cb2);
// Budowanie drugiego panelu zawierającego przełączniki
cbg = new CheckboxGroup();
cb3 = new Checkbox("RadioBtn 1", cbg, false);
cb4 = new Checkbox("RadioBtn 1", cbg, false);
p2 = new Panel();
// ustawienie zarządcy rozmieszczenia komponentów dla panelu p2
p2.setLayout(new FlowLayout());
p2.setBackground(Color.blue); // panel p1 kolor niebieski
p2.add(cb3);
p2.add(cb4);
// Budowanie trzeciego panelu zawierającego
// pole wyboru i przycisk
btnPrzycisk = new Button("Button");
chcTakNie = new Choice();
chcTakNie.add("Tak");
chcTakNie.add("Nie");
p3 = new Panel();
// ustawienie zarządcy rozmieszczenia komponentów dla panelu p3
p3.setLayout(new FlowLayout());
p3.setBackground(Color.red); // panel p3 kolor czerwony
p3.add(btnPrzycisk);
p3.add(chcTakNie);
// Budowanie i oprawka etykiety zawierającej informację o wybranych opcjach
lblEtykieta = new Label();
lblEtykieta.setFont(new Font("TimesRoman", Font.BOLD, 16));
lblEtykieta.setForeground(Color.green);
// rozmieszczenie paneli na głównym panelu apletu
setLayout(new GridLayout(4, 1));
add(p1);
add(p2);
add(p3);
add(lblEtykieta);
// ustawienie początkowego tekstu etykiety
ustawEtykiete();
// przyporządkowanie obsługi zdarzeń
// odnotuj, że jest przypisywana aktualna instancja apletu (this),
// aplety implementują w tym przypadku interfejsy ActionListener i ItemListener
btnPrzycisk.addActionListener(this);
cb1.addItemListener(this);
cb2.addItemListener(this);
cb3.addItemListener(this);
cb4.addItemListener(this);
chcTakNie.addItemListener(this);
}
// OBSŁUGA ZDARZENIA NACIŚNIĘCIA PRZYCISKU
public void actionPerformed(ActionEvent evt)
{
if(evt.getSource() == btnPrzycisk)
{
ustawEtykiete();
}
}
// OBSŁUGA ZDARZENIA WYBORU/ODRZUCENIA ZNACZNIKA ORAZ PRZEŁĄCZNIKA
public void itemStateChanged(ItemEvent evt)
{
ustawEtykiete();
}
// POMOCNICZA METODA OPISYWANA W ETYKIECIE AKTUALNIE WYBRANE OPCJE
void ustawEtykiete()
{
StringBuffer sb = new StringBuffer();
if(cb1.getState())
sb.append("Checkbox 1, ");
if(cb2.getState())
sb.append("Checkbox 2, ");
if(cb3.getState())
sb.append("RadioBtn 1, ");
if(cb4.getState())
sb.append("RadioBtn 2, ");
sb.append(chcTakNie.getSelectedItem());
lblEtykieta.setText(sb.toString());
}
}
W kolejnych podrozdziałach omówimy zarządców rozmieszczenia, ponieważ są one wymagane do efektywnego wykorzystania komponentów AWT oraz klasy i komponenty, które zostały dodane do AWT w wersji 1.1.
Zarządcy rozmieszczenia#
W języku Java komponenty graficzne nie są umieszczane na pulpicie przy określaniu koordynatów bezwzględnych. Taki sposób projektowania interfejsu użytkownika byłby zależny od platformy systemowej oraz rozdzielczości ekranu. W zamian za to język Java używa tzw. zarządców rozmieszczenia (ang. layout managers), które ustalają rozmieszczenie komponentów. Każdy pojemnik (kontener) ma swojego zarządcę rozmieszczenia. Do zarządców dostarczanych przez język Java należą: FlowLayout, BorderLayout, GridLayout, CardLayout oraz GridBagLayout.
Zarządcę rozmieszczenia dla danego pojemnika ustawia się przy pomocy metody setLayout(). Jeśli zarządca rozmieszczenia nie zostanie jawnie ustalony, to używany jest zarządca domyślny. Dla klasy Applet oraz Panel domyślnym zarządcą jest FlowLayout, a dla klasy Frame jest to BorderLayout.
FlowLayout#
Zarządca FlowLayout rozmieszcza komponenty w rzędach. W danym rzędzie komponenty są centrowane, a gdy brak jest miejsca na dodanie kolejnego komponentu, to tworzony jest nowy rząd. Komponenty mają swój preferowany rozmiar lub minimalny rozmiar.
Ilustracja 2-22 Przykład rozmieszczenia komponentów przez FlowLayout
BorderLayout#
Zarządca BorderLayout rozmieszcza komponenty w 5 regionach: North (północy), South (południe), East (wschód), West (zachód), Center (środek). Gdy dodawany jest komponent do pojemnika używającego BorderLayout, określa się także region, w którym ma zostać umieszczony komponent.
Ilustracja 2-23 Przykład rozmieszczenia komponentów przez BorderLayout
Przykład 2.39 Użycie zarządcy BorderLayout
import java.applet.*;
import java.awt.*;
public class BorderLayoutDemo extends Applet
{
public void init()
{
// ustawienie zarządcy rozmieszczenia
setLayout(new BorderLayout());
add("North", new Button("North"));
add("South", new Button("South"));
add("East", new Button("East"));
add("West", new Button("West"));
add("Center", new Button("Center"));
}
}
GridLayout#
Zarządca GridLayout rozmieszcza komponenty w siatce złożonej z rzędów i kolumn. Wszystkie komponenty mają ten sam rozmiar.
Ilustracja 2-24 Przykład rozmieszczenia komponentów przez GridLayout
Przykład 2.40 Użycie zarządcy GridLayout
import java.applet.*;
import java.awt.*;
public class GridLayoutDemo extends Applet
{
public void init()
{
// ustawienie zarządcy rozmieszczenia
// 3 rzędy i 2 kolumny
setLayout(new GridLayout(3, 2));
add(new Button("Button 1"));
add(new Button("Button 2"));
add(new Button("Button 3"));
add(new Button("Button 4"));
add(new Button("Button 5"));
add(new Button("Button 6"));
}
}
CardLayout#
Zarządca CardLayout rozmieszcza komponenty podobnie jak leżące na sobie karty. W danym momencie widoczna jest tylko jedna “karta”. Karty można przełączać programowo.
Przykład 2.41 Użycie zarządcy CardLayout
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class CardLayoutDemo extends Applet implements ActionListener
{
CardLayout cl;
Panel cards;
public void init()
{
setLayout(new BorderLayout());
Button first = new Button("Pierwsza");
Button second = new Button("Druga");
first.addActionListener(this);
second.addActionListener(this);
Panel buttons = new Panel();
buttons.add(first);
buttons.add(second);
add("South", buttons);
cl = new CardLayout();
cards = new Panel();
cards.setLayout(cl);
cards.add("first", new Button("To jest pierwsza karta"));
cards.add("second", new Button("To jest druga karta"));
add("Center", cards);
}
public void actionPerformed(ActionEvent evt)
{
cl.next(cards);
}
}
Nowe komponenty w AWT 1.1#
W wersji 1.1 AWT zostały dodane nowe komponenty. Należą do nich PopupMenu oraz ScrollPane.
PopupMenu#
PopupMenu jest to menu, które pojawia się w wybranym miejscu (zwykle przy naciśnięciu prawego przycisku myszy). Może być dodane do dowolnego komponentu.
Przykład 2.42 Użycie PopupMenu
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class PopupMenuDemo extends Applet implements ActionListener, MouseListener
{
PopupMenu popup;
public void init()
{
popup = new PopupMenu("Opcje");
MenuItem mi1 = new MenuItem("Opcja 1");
MenuItem mi2 = new MenuItem("Opcja 2");
mi1.addActionListener(this);
mi2.addActionListener(this);
popup.add(mi1);
popup.add(mi2);
add(popup);
addMouseListener(this);
}
public void actionPerformed(ActionEvent evt)
{
showStatus("Wybrano: " + evt.getActionCommand());
}
public void mousePressed(MouseEvent evt)
{
if (evt.isPopupTrigger())
popup.show(this, evt.getX(), evt.getY());
}
public void mouseReleased(MouseEvent evt)
{
if (evt.isPopupTrigger())
popup.show(this, evt.getX(), evt.getY());
}
public void mouseClicked(MouseEvent evt) {}
public void mouseEntered(MouseEvent evt) {}
public void mouseExited(MouseEvent evt) {}
}
ScrollPane#
ScrollPane jest pojemnikiem z paskami przewijania. Może zawierać jeden komponent, który może być większy niż sam ScrollPane.
Przykład 2.43 Użycie ScrollPane
import java.applet.*;
import java.awt.*;
public class ScrollPaneDemo extends Applet
{
public void init()
{
setLayout(new BorderLayout());
ScrollPane sp = new ScrollPane();
TextArea ta = new TextArea(10, 30);
ta.setText("To jest przykład użycia ScrollPane.\n");
for (int i = 0; i < 100; i++)
ta.append("Linia " + i + "\n");
sp.add(ta);
add("Center", sp);
}
}
Biblioteka java.io#
Biblioteka java.io zawiera klasy służące do obsługi operacji wejścia/wyjścia. Klasy te można podzielić na strumienie bajtowe i strumienie znakowe.
Strumienie bajtowe#
Podstawowe klasy do obsługi strumieni bajtowych:
- InputStream - abstrakcyjna klasa bazowa dla strumieni wejściowych
- OutputStream - abstrakcyjna klasa bazowa dla strumieni wyjściowych
- FileInputStream - strumień wejściowy z pliku
- FileOutputStream - strumień wyjściowy do pliku
- DataInputStream - strumień wejściowy z dodatkowymi metodami do odczytu typów podstawowych
- DataOutputStream - strumień wyjściowy z dodatkowymi metodami do zapisu typów podstawowych
Przykład 2.44 Użycie strumieni do kopiowania pliku
import java.io.*;
public class TestIO
{
public static void main(String args[])
{
try
{
FileInputStream fis = new FileInputStream("plik_we.txt");
FileOutputStream fos = new FileOutputStream("plik_wy.txt");
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
String linia;
while ((linia = dis.readLine()) != null)
{
dos.writeBytes(linia);
dos.writeByte('\n');
}
fis.close();
fos.close();
}
catch (IOException e)
{
System.err.println("Błąd I/O: " + e);
}
}
}
Strumienie połączone (pipes)#
Java dostarcza mechanizm pipes (rur), który umożliwia przesyłanie danych między wątkami. Składa się z PipedInputStream i PipedOutputStream.
Przykład 2.45 Użycie PipedStreams
import java.io.*;
public class PipeStreams extends Thread
{
PipedInputStream pis;
PipedOutputStream pos;
DataInputStream dis;
DataOutputStream dos;
PipeStreams()
{
try
{
pis = new PipedInputStream();
pos = new PipedOutputStream(pis);
dis = new DataInputStream(pis);
dos = new DataOutputStream(pos);
}
catch (IOException e) {}
}
public void run()
{
try
{
for (int i = 0; i < 10; i++)
{
dos.writeBytes("Wiadomość " + i + "\n");
Thread.sleep(1000);
}
}
catch (Exception e) {}
}
public static void main(String args[])
{
PipeStreams ps = new PipeStreams();
ps.start();
try
{
String linia;
while ((linia = ps.dis.readLine()) != null)
{
System.out.println("Odebrano: " + linia);
}
}
catch (IOException e) {}
}
}
Biblioteka java.net#
Biblioteka java.net zawiera klasy służące do programowania sieciowego. Podstawowe klasy to Socket, ServerSocket, URL oraz URLConnection.
Socket i ServerSocket#
Socket reprezentuje gniazdo klienta, a ServerSocket gniazdo serwera. Umożliwiają komunikację TCP.
Przykład 2.46 Prosty serwer
import java.io.*;
import java.net.*;
public class Server
{
public static void main(String args[])
{
try
{
ServerSocket ss = new ServerSocket(8080);
System.out.println("Serwer nasłuchuje na porcie 8080");
while (true)
{
Socket s = ss.accept();
System.out.println("Połączenie z: " + s.getInetAddress());
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
String linia = dis.readLine();
dos.writeBytes("Echo: " + linia + "\n");
s.close();
}
}
catch (IOException e)
{
System.err.println("Błąd serwera: " + e);
}
}
}
Przykład 2.47 Prosty klient
import java.io.*;
import java.net.*;
public class Client
{
public static void main(String args[])
{
try
{
Socket s = new Socket("localhost", 8080);
DataInputStream dis = new DataInputStream(s.getInputStream());
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
dos.writeBytes("Witaj serwer!\n");
String odpowiedz = dis.readLine();
System.out.println("Odpowiedź: " + odpowiedz);
s.close();
}
catch (IOException e)
{
System.err.println("Błąd klienta: " + e);
}
}
}
DatagramSocket i DatagramPacket#
Dla komunikacji UDP Java dostarcza DatagramSocket i DatagramPacket.
Przykład 2.48 Serwer UDP
import java.io.*;
import java.net.*;
public class UDPServer
{
public static void main(String args[])
{
try
{
DatagramSocket ds = new DatagramSocket(8080);
byte[] buffer = new byte[1024];
while (true)
{
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);
String wiadomość = new String(dp.getData(), 0, dp.getLength());
System.out.println("Odebrano: " + wiadomość);
String odpowiedz = "Echo: " + wiadomość;
byte[] odpData = odpowiedz.getBytes();
DatagramPacket odpPakiet = new DatagramPacket(odpData, odpData.length, dp.getAddress(), dp.getPort());
ds.send(odpPakiet);
}
}
catch (IOException e)
{
System.err.println("Błąd serwera UDP: " + e);
}
}
}
URL i URLConnection#
URL reprezentuje adres zasobu internetowego, a URLConnection umożliwia połączenie z tym zasobem.
Przykład 2.49 Użycie URL
import java.net.*;
import java.io.*;
public class URLDemo
{
public static void main(String args[])
{
try
{
URL url = new URL("http://java.sun.com/");
URLConnection uc = url.openConnection();
DataInputStream dis = new DataInputStream(uc.getInputStream());
String linia;
while ((linia = dis.readLine()) != null)
{
System.out.println(linia);
}
dis.close();
}
catch (Exception e)
{
System.err.println("Błąd URL: " + e);
}
}
}
Przykład 2.50 Użycie URL w aplecie
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
public class UrlAplet extends Applet implements ActionListener
{
TextField tf;
Button btn;
public void init()
{
setLayout(new BorderLayout());
tf = new TextField("http://java.sun.com/");
btn = new Button("Idź");
btn.addActionListener(this);
add("North", tf);
add("South", btn);
}
public void actionPerformed(ActionEvent evt)
{
try
{
URL url = new URL(tf.getText());
getAppletContext().showDocument(url);
}
catch (Exception e)
{
showStatus("Błędny URL: " + e);
}
}
}