25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
1/6
Na dzisiejszych zajeciach troche porysujemy na panelach. Wykorzystamy Java 2D API.
Nauczymy sie rowniez obslugiwac nasluchy na akcje myszy, tj. wykorzystamy interfejsy
MouseListener i MouseMotionListener
Wspomnimy takze o klasach adaptacyjnych
MouseAdapter i MouseMotionAdapter
Wykonamy jedno zadanie na zajeciach ktore bedzie zadaniem skladajacym sie z czterech etapow:
===========================================
| Etap 1 (Konstrukcja okienka do rysowania) |
===========================================
Wykonaj okienko przedstawione na rysunku z pliku przyklad1.jpg. Wszystkie potrzebne pliki graficzne masz dostarczone.
A zatem:
1) Utworz wlasne okno jako klase dziedzczaca po JFrame.
Ustaw jego szerokosc i wysokosc na polowe szerokosci i wysokosci ekranu oraz ustaw go na srodku ekranu.
Ustaw ikone na pasku tytulowym, tj. zbuduj obiekt klasy BufferedImage i ustaw ikone dla okna:
Image ikona = ImageIO.read(new File("nazwa_pliku_ikony"));
setIconImage(ikona);
Ustaw widocznosc okna i akcje zamykajaca okno po kliknieciu krzyzyka znajdujacego sie w prawym gornym rogu okna.
Uwaga!!! W razie problemow zajrzyj do zajec nr. 6 i 7
2) Utworz pasek menu jako obiekt klasy JMenuBar z menu Plik i Pomoc.
Ustaw odpowiednie klawisze skrotow (akceleracje Ctrl+O itp.) oraz klawisze skrotow (mnemoniki Alt+P itp.)
Spraw aby po wybraniu z menu Plik polecenia Zakończ lub klawisza skrotu Ctrl+K glowne okno aplikacji sie zamykalo.
Spraw aby po wybraniu z menu Pomoc polecenia O Autorze lub klawisza skrotu F1 pojawialo sie modalne okienko
dialogowe
wyswietlajace Imie i Nazwisko autora aplikacji.
Uwaga!!! W razie problemow zajrzyj do zajec nr. 7
3) Utworz pasek narzedzi jako obiekt klasy JToolBar.
Na pasku narzedziowym mozesz stosowac dowolne komponenty Swinga juz poznane np. JButton.
Zastosuj komponent JToogleButton, da Ci to mozliwosc imitowania wcisnietego przycisku.
A zatem np.
JToggleButton przyciskLinia = new JToggleButton(new ImageIcon("linia.png"));
Przyciski standardowo podpinamy do paska narzedzi tj. za pomoca metody add.
Ustaw rowniez dymki podpowiedzi do przyciskow:
przyciskLinia.setToolTipText("linia");
4) Podepnij pasek menu do okna.
Podepnij pasek narzedzi do okna ustawiajac go na BorderLayout.North.
Stworz i podepnij obiekt klasy JPanel do okna i ustaw go na BordeyLoyot.Center.
Uwaga!!! Mozesz wykorzystac nastepujacy fragment kodu:
public class Malarz extends JFrame implements ActionListener
{
private JPanel p = new JPanel();
Malarz() throws IOException
{
25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
2/6
Toolkit zestaw = Toolkit.getDefaultToolkit();
Dimension rozmiarEkranu = zestaw.getScreenSize();
int szerEkranu = rozmiarEkranu.width;
int wysEkranu = rozmiarEkranu.height;
setTitle("Malarz");
setSize(szerEkranu/2,wysEkranu/2);
setLocation(szerEkranu/4,wysEkranu/4);
setResizable(true);
BufferedImage ikona = ImageIO.read(new File("ikona.gif"));
setIconImage(ikona);
add(doToolBar(),BorderLayout.NORTH);
add(p,BorderLayout.CENTER);
setJMenuBar(doMenu());
}
public JMenuBar doMenu()
{
JMenuBar mb = new JMenuBar();
//do zaimplementowania
return mb;
}
public JToolBar doToolBar()
{
JToolBar jtb = new JToolBar("Kształty");
//do zaimplementowania
return jtb;
}
public void actionPerformed(ActionEvent e)
{
switch (Integer.parseInt(e.getActionCommand()))
{
//do zaimplementowania
}
}
public static void main(String[] args) throws IOException
{
Malarz1 m = new Malarz();
m.setVisible(true);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
=============================================
| Etap 2 (rysowania prostych figur na panelu) |
=============================================
Narysuj teraz na panelu glownym figury widoczne w pliku przyklad2.jpg.
W tym celu najlepiej stworzyc wewnetrzna klase rozszerzajaca JPanel np.
private class PanelDoRysowania extends JPanel
{
}
W niej przedefiniowac metode
public void paintComponent(Graphics g)
{
}
dziedziczona z abstrakcyjnej klasy JComponent bedacej nadklasa JPanel. Nalezy pamietac zeby samoczynnie nie wywolywac
metody
painComponent();
25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
3/6
- wywoluje sie ona automatycznie. Czasem aby zainicjalizowac jeszcze raz jej wywolanie wywolujemy metode
repaint();
Aby narysowac cos na panelu poslugujemy sie obiektem klasy Graphics.
Kolor rysowanego obiektu zmieniamy metoda:
g.setColor(Color c);
Figury lini, prostokata i elipsy bez wypelnienia narysujemy za pomoca metod:
g.drawLine(int x1, int y1, int x2, int y2);
g.drawRec(int x1, int y1, int x2, int y2);
g.drawOval(int x1, int y1, int x2, int y2);
Wypelnione figury prostokata i elipsy narysujemy za pomoca komend:
g.fillRect(int x1, int y1, int x2, int y2);
g.fillOval(int x1, int y1, int x2, int y2);
Tekst na panelu narysujemy za pomoca polecenia:
g.setString("Tekst", int x, int y);
Wielkosc i styl czcionki zmieniamy za pomoca polecenia:
g.setFont(Font f);
=========================
| Etap 3 (obsluga myszy) |
=========================
Narysujemy teraz na panelu glownym figury widoczne w pliku przyklad3.jpg.
Ogolnie do oslugi nasluchow na mysz uzywamy dwoch interfejsow:
MouseListener i MouseMotionListener
MouseListener dostarcza piec metod do zaimplementowania:
public void mouseClicked(MouseEvent e);
public void mousePressed(MouseEvent e);
public void mouseReleased(MouseEvent e);
public void mouseEntered(MouseEvent e);
public void mouseExited(MouseEvent e);
1) Sprobuj najpierw rysowac linie na panelu wedlug zasady, tzn. najezdzasz na jakis punkt panelu, wciskasz lewy
przycisk myszy,
i przy wcisnietym przycisku myszy przesuwasz ja do innego punktu panelu, puszczasz przycisk i rysuje sie linia.
A zatem musisz obsluzyc metody:
public void mousePressed(MouseEvent e);
public void mouseReleased(MouseEvent e);
Najprosciej zrobic to tak. W metodzie:
mousePressed(MouseEvent e);
jesli wystapi zdarzenie to je przechwytujemy:
25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
4/6
Point startPoint = e.getPoint();
Jesli wystapi zdarzenie w metodzie mouseReleased(MouseEvent e) to je przechwytujemy:
Point endPoint = e.getPoint();
I dalej w metodzie mouseReleased() wykonujemy:
Graphics g = getGraphics();
g.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y);
2) Jesli to dziala to zakomentarzuj w metodzie mouseReleased() blok rysowania lini i narysuj prostokat a pozniej
elipse.
Uwaga!!! Zauwazmy ze rysujac prostokat albo elipse musimy podac lewy gorny rog i ich wymiary tj. szerokosci i
wysokosc.
To czasem moze byc klopotliwe jesli np. drugie klikniecie (drugi punkt) lezy po prawo i ponizej pierwszego.
Mozna to latwo zaimplementowac wybierajac na lewy gorny rog minimalna z kazdych wspolrzednych oraz na dugosc i
szerokosc boku wartosc bezwgledna odpowiednich dlugosci.
Ale mozna tez inaczej. Jest klasa Graphics2D ktora rozszerza klase Graphics. Mozna zatem np. dla wykreslenia
prostokata z
dwoch dowolnych punktow zrobic tak:
Jesli mamy juz
startPoint i endPoint
to w metodzie mouseReleased() piszemy:
//pobieramy kontekst graficzny panelu uzyskujac dostep do obiektu typu Graphics2D
Graphics2D g2 = (Graphics2D)getGraphics();
//budujemy pusty prostokat (w klasie Graphics2D fugury rysujemy z punktow typu Float i
Double)
Rectangle2D prostokat = new Rectangle2D.Double();
//tworzymy prostokat z przekatnej
prostokat.setFrameFromDiagonal(startPoint,endPoint);
//rysujemy go
g2.draw(prostokat);
3) Rysowanie jest ciagle nienaturalne. Powinno byc tak jak pod prawdziwym edytorem graficznym, tj. wybierasz punkt,
wciskasz
lewy klawisz myszy, przeciagasz mysz do innego punktu - wtedy linia, prostokat czy elipsa sie rysuja (tj. rozciagaja
lub
zmniejszaja) puszczasz przycisk myszy i figura zostaje na ekranie.
Aby to zrobic potrzebujesz metody:
public void mouseDragged(MouseEvent e);
ktora znajdziesz w interfejsie MouseMotionListener. Swoja droga jest tam jeszcze jedna metoda:
public void mouseMoved(MouseEvent e);
Zaimplementuj zatem ta metode aby program dzialal poprawnie, tj. tak jak opisano powyzej.
- Najpierw rysuj linie o poczatku startPoint i koncu pobieranym za pomoca getPoint. Zauwaz ze sie one zamazuja. Np.
Point startPoint;
public void mousePressed(MouseEvent e)
{
startPoint=e.getPoint();
}
public void mouseReleased(MouseEvent e)
{
Graphics2D g2 = (Graphics2D)getGraphics();
25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
5/6
g2.drawLine(startPoint.x, startPoint.y, e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e)
{
Graphics2D g2 = (Graphics2D)getGraphics();
g2.drawLine(startPoint.x, startPoint.y, e.getX(), e.getY());
}
- Teraz rysuj linie a kazda poprzednia scieraj, tj. rysuj na kolor tla panelu:
Point startPoint;
Point prePoint;
public void mousePressed(MouseEvent e)
{
startPoint=e.getPoint();
prePoint=startPoint;
}
public void mouseReleased(MouseEvent e)
{
Graphics2D g2 = (Graphics2D)getGraphics();
g2.setColor(Color.BLACK);
g2.drawLine(startPoint.x, startPoint.y, e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e)
{
Graphics2D g2 = (Graphics2D)getGraphics();
g2.setColor(g2.getBackground());
g2.drawLine(startPoint.x, startPoint.y, prePoint.x,prePoint.y);
g2.setColor(Color.BLACK);
g2.drawLine(startPoint.x, startPoint.y, e.getX(), e.getY());
prePoint=e.getPoint();
}
- Widac jednak, ze i to nie dziala do konca, tj. scieraja sie nakladane na siebie punkty.
Rozwiazaniem problemujest zmodyfikowanie funkcji mouseDragged(MouseEvent e) w nastepujacy sposob:
public void mouseDragged(MouseEvent e)
{
Graphics2D g2 = (Graphics2D)getGraphics();
g2.setXORMode(Color.BLACK);
g2.setColor(g2.getBackground());
g2.drawLine(startPoint.x, startPoint.y, prePoint.x,prePoint.y);
g2.setXORMode(g2.getBackground());
g2.setColor(Color.BLACK);
g2.drawLine(startPoint.x, startPoint.y, e.getX(), e.getY());
prePoint=e.getPoint();
}
============================================================
| Etap 4 (zapisywanie rysowanych obiektow na mapie bitowej) |
============================================================
Zauwaz ze jest jeszcze jeden problem, tj. jesli przeslonimy np. innym oknem nasze okienko to wszystko z panela na
ktorym rysujemy znika.
Wyjscia sa conajmniej dwa.
Pierwsze to utworzyc liste obiektow np. ArrayList i je rysowac od nowa z kazdym nowo pojawiajacym sie obiektem.
Drugie to utworzyc obiekt typu:
BufferedImage
i tez uaktualniac go ciagle i rysowac na nowo na panelu.
Mozna zatem zrobic tak:
1) Po metodzie setVisible() glownego okna, powolac do zycia obiekt klasy BufferedImage()
BufferedImage bi= new
BufferedImage(p.getWidth(),p.getHeight(),BufferedImage.TYPE_INT_RGB);
gdzie wielkosc ustalamy mu jako wielkosc calego panelu (p - to uchwyt do Panelu na ktorym rysujemy).
Nastepnie tworzymy kontekst graficzny na obiekcie bi klasy BufferedImage, ustalamy kolor na bialy i wyrysowujemy
25.04.2018
math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
http://math.uni.lodz.pl/~kowalcr/Java1/PlikWC12.txt
6/6
bialy prostokat na calym obiekcie bi.
Graphics2D g2 = bi.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0,0,p.getWidth(),p.getHeight());
Teraz kolejne rysowane figury powstajace w metodzie mouseReleased() beda zapisywane do bi dzieki wpisowi w tej
metodzie:
Graphics2D g2=bi.createGraphics();
A samo odrysowywanie figur na panelu bedzie odbywalo sie za pomoca metody paintComponent(), tj. definiujemy w
panelu:
@Override
public void paintComponent(Graphics g)
{
g.drawImage(bi, 0, 0, null);
}
Pamietac trzeba jeszcze ze jesli chcemy aby na ekranie, czyli i panelu figury odswiezaly sie caly czas w metodzie
mouseReleased() musimy uzyc metody repaint();
===========================
| Zadanie 6 (na zaliczenie) |
===========================
Dokoncz Malarza oraz dodaj piec ponizszych funkcjonalnosci, tj.:
1) Obsluz mozliwosc zapisywania do pliku i odczytywania z pliku mapy bitowej (tj. formatu bmp, jesli dasz rade to
obsluz tez
inne formaty graficzne). Posluz sie obiektem typu BufferedImage.
2) Obsluz mozliwosc ustalania grubosci rysowanej lini. Wykorzystaj obiekt typu JSlider lub JSpinner.
3) Obsluz gumke.
4) Dodaj mozliwosc zmiany koloru rysowanej lini. Wykorzystaj np. JColorChooser.
5) Dodaj jeszce jedno menu Edycja i dodaj w nim polecenie Cofnij oraz spraw, ze ono zadzila. Zastosuj np. ArrayList.