Swing #1: Dwa obrazki obok siebie

Treść zadania

Stwórz na podstawie kodu z artykułu o polach tekstowych program, który wyświetli obok siebie dwa obrazy, jeden zapisany na Twoim dysku twardym, drugi pobrany z dowolnego adresu URL.

Rozwiązanie

Cóż zadanie nie powinno sprawiać wielkich trudności, wystarczy zastosować się do prostego schematu dołączonego na końcu lekcji i lekko zmodyfikować kod tam zamieszczony. Dla ułatwienia w rozwiązaniu zastosowano następujący schemat:

  • Pobranie obrazka z sieci - w przypadku braku połączenia z internetem, lub niepoprawnym adresie URL obrazka zostanie wyrzucony wyjątek i aplikacja się nie uruchomi, ponieważ nie uda się zainicjować panelu.
  • Zapisanie obrazka na dysku
  • Wyświetlenie obu obrazów bezpośrednio obok siebie

Aby zobaczyć, że obraz faktycznie został zapisany na dysku odśwież projekt w eclipse (przycisk F5), lub sprawdź po prostu na dysku.

Klasa panelu:

import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.net.URL;
 
 import javax.imageio.ImageIO;
 import javax.swing.JPanel;
 
 public class ObrazPanel extends JPanel {
 
 	private BufferedImage diskImage;
 	private BufferedImage netImage;
 
 	private int panelWidth;
 	private int panelHeight;
 
 	public ObrazPanel() {
 		super();
 
 		try {
 			//utworzenie obiektu URL ze ścieżką do obrazu
 			URL imageURL = new URL("http://hosaf.org/files/java-duke-guitar.png");
 			//odczytanie obrazu z adresu URL
 			netImage = ImageIO.read(imageURL);
 
 			//Utworzenie nowego pliku na dysku
 			File imageFile = new File("java.jpg");
 			//zapisanie obrazu do pliku
 			ImageIO.write(netImage, "png", imageFile);
 			//wczytanie obrazu z pliku
 			diskImage = ImageIO.read(imageFile);
 
 		} catch (IOException e) {
 			System.err.println("Blad odczytu obrazka");
 			e.printStackTrace();
 		}
 
 		panelWidth = diskImage.getWidth()*2; //*2 aby zmieścić ten sam obraz dwukrotnie
 		panelHeight = diskImage.getHeight(); //wysokość panelu == wysokość obrazu
 		Dimension dimension = new Dimension(panelWidth, panelHeight);
 		setPreferredSize(dimension);
 	}
 
 	@Override
 	public void paintComponent(Graphics g) {
 		Graphics2D g2d = (Graphics2D) g;
 		//narysowanie obrazu z dysku
 		g2d.drawImage(diskImage, 0, 0, this);
 		//narysowanie obrazu z sieci
 		g2d.drawImage(netImage, diskImage.getWidth(), 0, null);
 	}
 }

Klasa ramki:

import javax.swing.*;
 
 public class ObrazFrame extends JFrame {
 
 	public ObrazFrame() {
 		super("Program obrazkowy");
 
 		JPanel obrazPanel = new ObrazPanel();
 		add(obrazPanel);
 
 		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 		pack();
 		setVisible(true);
 	}
 }

Klasa testowa:

import java.awt.EventQueue;
 
 public class Test {
 	public static void main(String[] args) {
 		EventQueue.invokeLater(new Runnable() {
 			@Override
 			public void run() {
 				new ObrazFrame();
 			}
 		});
 	}
 }

a

Dyskusja i komentarze

Masz pytania do tego wpisu? Może chcesz się podzielić spostrzeżeniami? Zapraszamy dyskusji na naszej grupie na Facebooku.

Poniżej znajdziesz archiwalne wpisy z czasów, gdy strona była jeszcze hobbystycznym blogiem.

Tomek

Tylko jaki jest sens zapisywania tego obrazka na dysku? Chyba, że napisane zostało to tylko i wyłącznie w celu pokazania, że tak można...

Slawek

Zapisanie obrazka na dysku ma tylko i wyłącznie taki sens, żeby każdemu ten przykład działał bez żadnych zmian (nazw plików etc.). Jeśli ktoś wczyta obrazek, który już był na dysku to jest jak najbardziej ok.

piko

Jesli mają się wyświetlic 2 różne obrazki: z internetu i z dysku to nie można pod zmienną imageFile zapisywac pliku ściąniętego z internetu. Jest tam już plik lokalny i w konsekwencji wyświetla się 2 razy to samo.

Slawek

w zadaniu jest, aby wyświetlić dowolne obrazy - najprościej wyświetlić 2x to samo. Obrazki przechowujemy w obiektach BufferedImage, plik na dysku jest tylko pomocniczy.

piko

No cóżja to zrozumiałem tak: 4.1 Stwórz na podstawie powyższego schematu program, który wyświetli obok siebie dwa obrazy, jeden zapisany na Twoim dysku twardym, drugi pobrany z dowolnego adresu URL. Czytając polecenie wydaje się, że mają to byc dwa różne obrazy. Jeśli natomiast netImage zapisujemy do imageFile a potem do diskImage zaczytujemy obraz z imageFile to jest to trochę masło maślane.

piko

Ponadto jeszcze taki szczegół. Jeśli pod nazwę java.jpg (plik jpg) zapisujemy grafikę w innym formacie (png) to mamy na dysku plik java.jpg ale z zawartością w formacie png.

Slawek

Dokładnie - rozszerzenie pliku nie ma żadnego znaczenia, możemy sobie nawet zapisać jako .coś. Ma natomiast znaczenia to co wpiszemy w metodzie write() z ImageIO. Co do zadania to jeszcze raz - wczytaujemy dwa dowolne obrazy 1 z dysku, drugi z neta, czy będą takie same, czy nie kwestia tego, czy nam się chce ;) Twój sposób oczywiście jest ciekawszy, ten tutaj, jak to nazwałeś - masło maślane, ale każdy może zobaczyć o co chodzi.

piko

Dzięki za komentarze "on-line" nawet przy niedzieli :) Pozdrawiam

torgat

swietny poradnik! tak trzymac!

Paweł

A ja wpadłem na pomysł podania obrazków i niech system ustali który jest wyższy. Obrazy wprowadzam JOptionPane.showInputDialog(); if(image.getHeight()>image2.getHeight()) { Dimension dim = new Dimension(image.getWidth()+image2.getWidth(), image.getHeight()); setPreferredSize(dim); } else { Dimension dim = new Dimension(image.getWidth()+image2.getWidth(), image2.getHeight()); setPreferredSize(dim); }

mandragorn

nie czaje tego...

Witek

Witam Czy ktoś miał też błąd odczytu obrazka z adresu URL, bo mi wyskakuje taki komunikat, adres wpisałem to ten sam co podany jest w rozwiązaniu. Treść komunikatu to: „Blad odczytu obrazka javax.imageio.IIOException: Can't get input stream from URL!” oczywiście to nie cały komunikat. Sprawdziłem pod tym adresem nie widać obrazka. Może ktoś to również sprawdzić u siebie. Z góry dziękuję.

Slawek

Obrazek nie istnieje, więc po prostu znajdź inny i podmień URL :)

Witek

Wielkie dzięki, tak myślałem, że go tam nie ma, ale wolałem się upewnić. Pozdrawiam

Robert

Dlaczego jak w klasie ObrazFrame dodam linijkę setResizable(false); to po wyświetleniu ramka nie jest idealnie takich rozmiarów jak oba obrazki? U mnie jest ciut większa i wystaje poza obrazki z prawej strony i u dołu. Jak nie mam setResizable(false); to wszystko pięknie przylega. Pozdrawiam

Anka

U mnie obrazki z netu działają, ale nie mogę wgrać nic z dysku. Co może być nie tak z moimi obrazkami ?? Czy fakt że zdjęcie było robione telefonem ma tutaj jakieś znaczenie?

lolo

To, że były robione telefonem nie ma znaczenia (chyba, że zapisałaś je w jakims dziwnym formacie). Dobrze podałaś ścieżkę do tych plików?

Sławek Ludwiczak

Również stawiałbym na błędną ścieżkę do pliku :) Kod błędu wiele by powiedział

Verteks

Pochwalę się własnym rozwiązaniem, mam nadzieję, że komuś się przyda: Tak jak niektórzy powyżej sądziłem, iż mają to być dwa różne obrazki. Zastosowałem zasadę - jeden obraz, jedna klasa będąca rozszerzeniem JPanel jak i zarazem osobnym panelem mojego okna. Plusem takiego rozwiązania jest to, że nieistotna jest dysproporcja między obrazami - jeśli któryś jest większy, to program sam dostosowuje wielkość okna. Dodatkowo wywalenie któregoś obrazka z okna wiąże się tylko z zakomentowaniem dwóch linijek w klasie tworzącej okno - jednej z tworzeniem obiektu JPanel, drugiej związanej z dodawaniem panelu do okna poprzez metodę add().

snt.banzai

A ja zrobiłem osobną klasę pt. ObrazekZNeta i stworzyłem obiekt tej klasy w klasie rozszerzającej JFrame. Obrazek wyświetla mi się bez konieczności zapisywania na dysku.

Zabawa

Działa

Leon

Moje rozwiązanie ustawienie wielkości okna. Dimension dimentions = new Dimension(); dimentions.height = image.getHeight() > img2.getHeight() ? image.getHeight():img2.getHeight(); dimentions.width = image.getWidth()+img2.getWidth(); setPreferredSize(dimentions);

Stasiek

Nie bardzo rozumiem dlaczego w metodzie ObrazPanel() jest "super()" bez argumentów - jak to usuwam działa dalej ok. Co to znaczy?

Lolo

Oznacza to, że wywołujesz konstruktor nadklasy

Stasiek

No ok, ale po co? Jaki to ma wpływ na program?

Lolo

To zależy co znajduje się w konstruktorze nadklasy. Np. jeśli w konstruktorze nadklasy wykonywana jest jakaś inicjalizacja zmiennych to zostanie ona wykonana i dodatkowo zostaną wykonane instrukcje które zawrzesz w swojej klasie.