Java: jednoduchý prohlížeč obrázků #2
V minulém díle jsme si vytvořili první část prohlížeče, která umožňuje výběr adresáře a spuštění presentace. V tomto díle navážeme na to co je již hotové a zaměříme se na zobrazování obrázků.
V minulém díle jsme si vytvořili třídu pro výběr adresáře s fotografiemi, jejich načtení a zobrazení možnosti spuštění presentace.
V tomto následujícím díle si vytvoříme další třídu, ve které si uděláme zobrazování fotografií s možností přepínání se mezi nimi a navíc možností spuštění presentace, která bude automaticky přepínat načtené fotografie.
Jako první začneme grafickým rozhraním, ve kterém budeme muset vytvořit některé z tlačítek. Jak jsem napsal, třída bude umožňovat přepínání se mezi fotografiemi, tudíž budeme potřebovat 5 tlačítek. Jedno tlačítko pro přepnutí o fotografii vpřed, druhé pro přepnutí na konec a další dvě pro opačný posun.
Poslední tlačítko bude pro spuštění presentace. Nakonec si ještě vytvoříme Jlabel, ve kterém budeme zobrazovat informace na kolikáté fotografii z kolika se nacházíme.
Informace o zobrazené fotografii budeme zobrazovat například v titulku okna.
Konstruktor třídy bude mít jeden vstupní parametr, který bude obsahovat adresář s fotkami. Toto je zbytečné, protože budeme muset projít celý adresář znova, tak jsme si to již udělali v minulém díle, takže by stačilo předat si rovnou jenom adresy fotografií, ale napíši to tak z důvodu, že by někdo nečetl předchozí článek.
Do konstruktoru si tedy předáme adresář s fotografiemi, zavoláme metodu pro jejich načtení a vytvoříme si grafické okno, pro zobrazování fotografií:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class PicturesViewer extends JFrame implements ActionListener, Runnable { public PicturesViewer( final String directory ) { this.directory = directory; selectimages(directory); setSize(width, height); setTitle("Image Viewer"); BorderLayout bl = new BorderLayout(); this.setLayout(bl); Container cont = getContentPane(); cont.setBackground(Color.red); setContentPane(cont); BorderLayout layout = new BorderLayout(); cont.setLayout(layout); Panel panel = new Panel(); panel.setBackground(Color.white); cont.add(panel, BorderLayout.SOUTH); status = new JLabel(""); JButton begin = new JButton("<<"); JButton prew = new JButton("<"); JButton next = new JButton(">"); JButton end = new JButton(">>"); JButton presentation = new JButton("Presentace"); panel.add(begin); panel.add(prew); panel.add(status); panel.add(next); panel.add(end); panel.add(presentation); toolkit = Toolkit.getDefaultToolkit(); mediaTracker = new MediaTracker(cont); } } |
Na začátku voláme metodu selectimages, která je obdobou metody z minulého dílu pro výběr všech fotografií. V této metodě nám vznikne pole fotografií.
Velikost okna se nastaví automaticky dle proměnných width a height, čili nebudeme řešit velikost okna, dle rozměrů fotografie. Tyto proměnné jsou globální.
Nyní je nutné si na všechny potřebné tlačítka přidat ActionListenery. Ve všech budeme volat metodu public void show_next_image(String imgname), která se bude starat o zobrazení následující nebo předchozí fotografie.
Všechny fotografie si načteme do pole LinkedList, ve kterém budou mít své indexy. O zobrazené fotografii nám bude rozhodovat globální proměnná position, ve které bude při zobrazení další fotografie přičítat a při zobrazení předchozí fotografie odečítat jedničku. Takto snadno rozhodneme, zda můžeme přepnout na další fotografii či nikoli jednoduchou kontrolou této proměnné:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
next.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (position == (images.size() - 1)) return; try { show_next_image(directory + "/" + images.get(++position)); } catch (Exception e) { ; } } }); prew.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (position == 0) return; try { show_next_image(directory + "/" + images.get(--position)); } catch (Exception e) { ; } } }); begin.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { position = 0; try { show_next_image(directory + "/" + images.get(position)); } catch (Exception e) { ; } } }); end.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { position = images.size() - 1; try { show_next_image(directory + "/" + images.get(position)); } catch (Exception e) { ; } } }); th = new Thread(this); presentation.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { th.start(); } }); |
V poli images jsou uloženy všechny fotografie. Po kliknutí na tlačítko se nám upraví proměnná position, která je na začátku nastavena na hodnotu 0 a ověří se, zda může být fotograrie zobrazena, zda existuje.
Nyní si musíme vytvořit metodu pro zobrazení fotograie. Metoda musí nejprve nastavit status label, ve kterém zobrazujeme uživateli informaci čísle aktuálně prohlížené fotografie, dále zobrazí fotografii a upraví titulek okna, do kterého napíše název fotografie.
Pro vykreslení fotografie využijeme knihovnu Graphics, která bude volat metodu paint( Graphics graphics );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public void show_next_image(String imgname) { status.setText(" " + (position + 1) + "" + images.size() + " "); image = toolkit.getImage(imgname); mediaTracker.addImage(image, 0, 10, 10); try { mediaTracker.waitForID(0); } catch (InterruptedException ie) { System.err.println(ie); System.exit(1); } setSize(width + 1, height + 1); setSize(width, height); setTitle(imgname); } public void paint(Graphics graphics) { graphics.drawImage(image, 0, 0, this.getSize().width, this.getSize().height - 20, Color.white, this); } |
Nakonec nám zbývá pouze vyřešit automatickou presentaci. O to se nám stará Jbutton s názvem presentation, který vytváří nové vlákno a spouští metodu run:
1 2 3 |
public void run() { presentation_run(); } |
v této metodě pouze voláme metodu pro presentaci, ve které opět využijeme metodu show_next_image, jenom s tím rozdílem, že ji budeme volat automaticky po určité době:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public void presentation_run() { for (int i = position; i < images.size(); i++) { position = i; show_next_image(directory + "/" + images.get(position)); try { Thread.sleep(2000); } catch (InterruptedException e1) { ; e1.printStackTrace(); } } this.dispose(); } |
Tím je hotový opravdu jednoduchý prohlížeč obrázků, který umožňuje výběr adresáře s fotografiemi a jejich následnou presentaci.
Na závěr si můžete prohlídnout celý zdrojový kód této třídy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Panel; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.io.File; import java.util.LinkedList; import java.util.List; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; public class PicturesViewer extends JFrame implements ActionListener, Runnable { public int pos; public int op = 1; JButton opendialog; public JLabel statusbar; public String directory; public int position = 0; JFileChooser chooser; public Toolkit toolkit; public MediaTracker mediaTracker; List<string> images = new LinkedList<string>(); String choosertitle; private Image image; public int width = 640; public int height = 480; public JLabel status; public Thread th; public PicturesViewer( final String directory ) { this.directory = directory; selectimages(directory); setSize(width, height); setTitle("Image Viewer"); BorderLayout bl = new BorderLayout(); this.setLayout(bl); Container cont = getContentPane(); cont.setBackground(Color.red); setContentPane(cont); BorderLayout layout = new BorderLayout(); cont.setLayout(layout); Panel panel = new Panel(); panel.setBackground(Color.white); cont.add(panel, BorderLayout.SOUTH); status = new JLabel(""); JButton begin = new JButton("<<"); JButton prew = new JButton("<"); JButton next = new JButton(">"); JButton end = new JButton(">>"); JButton presentation = new JButton("Presentace"); panel.add(begin); panel.add(prew); panel.add(status); panel.add(next); panel.add(end); panel.add(presentation); toolkit = Toolkit.getDefaultToolkit(); mediaTracker = new MediaTracker(cont); try { show_next_image(directory + "/" + images.get(position)); } catch (Exception e) { System.out.println("konec"); } show(); next.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (position == (images.size() - 1)) return; try { show_next_image(directory + "/" + images.get(++position)); } catch (Exception e) { ; } } }); prew.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (position == 0) return; try { show_next_image(directory + "/" + images.get(--position)); } catch (Exception e) { ; } } }); begin.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { position = 0; try { show_next_image(directory + "/" + images.get(position)); } catch (Exception e) { ; } } }); end.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { position = images.size() - 1; try { show_next_image(directory + "/" + images.get(position)); } catch (Exception e) { ; } } }); th = new Thread(this); presentation.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { th.start(); } }); } public void presentation_run() { for (int i = position; i < images.size(); i++) { position = i; show_next_image(directory + "/" + images.get(position)); try { Thread.sleep(2000); } catch (InterruptedException e1) { ; e1.printStackTrace(); } } this.dispose(); } public void show_next_image(String imgname) { status.setText(" " + (position + 1) + "" + images.size() + " "); image = toolkit.getImage(imgname); mediaTracker.addImage(image, 0, 10, 10); try { mediaTracker.waitForID(0); } catch (InterruptedException ie) { System.err.println(ie); System.exit(1); } setSize(width + 1, height + 1); setSize(width, height); setTitle(imgname); } public void paint(Graphics graphics) { graphics.drawImage(image, 0, 0, this.getSize().width, this.getSize().height - 20, Color.white, this); } public void selectimages(String label_text) { // statusbar.setText("Obrázky: " + label_text ); this.directory = label_text; File dir = new File(label_text); String[] files; files = dir.list(); for (int i = 0; i < files.length; i++) { File f; f = new File(dir, files[i]); if (f.isDirectory()) { ; } else { if (files[i].toLowerCase().endsWith(".jpg") || files[i].toLowerCase().endsWith(".png")) images.add(files[i]); } } } public void run() { presentation_run(); } public void actionPerformed(ActionEvent arg0) { } } |
Metoda show() ze třídy java.awt.Window, kterou používáte pro zobrazení okna je od JDK verze 1.5 označena jako Deprecated. Místo ní je doporučeno používat metodu setVisible(true) ze stejné třídy.
Ale jinak velmi poučné. Díky za článek
K cemu slouzi tyto dva radky v metode show_next_image?
setSize(width + 1, height + 1);
setSize(width, height);
Vsiml jsem si, ze po jejich zakomentovani nedochazi k zobrazovani dalsich obrazku po stisku posunuvacich tlacitek.
Byl tam problem s tim, ze se obrazky neprekreslovaly, pokud se nezmenila velikost okna, nebo se s oknem nehnulo. Timto zpusobem je tato nechtena vlastnost velice jednoduse (spatne) potlacena
pro refresh obrazku je vhodne volat metodu repaint() a pokud to nejak jeste neni ono tak pak bych volal metodu validate().
Obě dvě varianty, co pisete jsem tusim vyzkousel, mozna to bylo starsi verzi javy, nevim, ale nefungovali tak, jak jsem potreboval.