Mam JPanel, do którego chciałbym dodać obrazy JPEG i PNG, które generuję na bieżąco.
Wszystkie przykłady, które widziałem do tej pory w Swing Tutorials , szczególnie w przykładach Swing, używają ImageIcon
s.
Generuję te obrazy jako tablice bajtów i zwykle są one większe niż zwykła ikona, której używają w przykładach, w rozdzielczości 640x480.
- Czy jest jakiś (wydajność lub inny) problem z użyciem klasy ImageIcon do wyświetlenia obrazu o takim rozmiarze w JPanel?
- Jak to zwykle robi?
- Jak dodać obraz do JPanel bez użycia klasy ImageIcon?
Edycja : Dokładniejsze sprawdzenie samouczków i interfejsu API pokazuje, że nie można dodać ImageIcon bezpośrednio do JPanel. Zamiast tego osiągają ten sam efekt, ustawiając obraz jako ikonę JLabel. To po prostu nie wydaje się właściwe ...
MemoryImageSource
niż konwertowanie ich do formatu JPEG lub PNG, a następnie czytanie,ImageIO
jak sugeruje większość odpowiedzi. Można dostaćImage
z punktu AMemoryImageSource
zbudowane z danych obrazu za pomocącreateImage
, a wyświetlacz jak zasugerował w jednym z odpowiedziami.Odpowiedzi:
Oto jak to zrobić (z odrobiną więcej informacji na temat ładowania obrazu):
źródło
Principle of Encapsulation
metod podczas Nadrzędnym Super klasy, dostęp Specyfikator tegopaintComponent(...)
sposobu jestprotected
i niepublic
:-)Principle of Encapsulation
. Pamiętaj tylko, że podczas programowania to, co powinno być ukryte przed resztą kodu, musi być utrzymane w ten sposób, zamiast być widoczne dla wszystkich w kodzie. Wydaje się, że jest to jedna z takich rzeczy, które pojawiają się wraz z doświadczeniem, ponieważ uczy się każdego dnia. Każda książka może dać podstawowe wyobrażenie o tym, czym jest enkapsulacja, ale to w jaki sposób wdrażamy nasz kod, decyduje o tym, jak bardzo trzymamy się tej koncepcji.Jeśli używasz JPanels, prawdopodobnie pracujesz z Swing. Spróbuj tego:
Obraz jest teraz elementem składowym. Staje się przedmiotem warunków układu, jak każdy inny komponent.
źródło
Sposób Freda Haslama działa dobrze. Miałem jednak problem z ścieżką pliku, ponieważ chcę odwoływać się do obrazu w moim słoiku. Aby to zrobić, użyłem:
Ponieważ mam tylko skończoną liczbę (około 10) obrazów, które muszę załadować za pomocą tej metody, działa całkiem dobrze. Pobiera plik bez konieczności posiadania poprawnej względnej ścieżki pliku.
źródło
BufferedImage previewImage = ImageIO.read(new URL(imageURL));
aby pobrać moje zdjęcia z serwera.Myślę, że nie trzeba niczego podklasować. Po prostu użyj Jlabela. Możesz ustawić obraz w Jlabel. Zmień rozmiar Jlabela, a następnie wypełnij go obrazem. W porządku. Tak właśnie robię.
źródło
Możesz całkowicie uniknąć zwijania własnej podklasy składników, używając klasy JXImagePanel z bezpłatnych bibliotek SwingX .
Pobieranie
źródło
źródło
Możesz podklasować JPanel - oto fragment z mojego ImagePanel, który umieszcza obraz w jednym z 5 miejsc: u góry / po lewej, u góry / po prawej, w środku / w środku, u dołu / po lewej lub u dołu / po prawej:
źródło
ImageIcon
s. W przypadku pojedynczego obrazu pomyślałbym o stworzeniu niestandardowej podklasyJPanel
i zastąpieniu jejpaintComponent
metody rysowania obrazu.źródło
JPanel
prawie zawsze jest złą klasą do podklasy. Dlaczego nie podklasujeszJComponent
?Istnieje niewielki problem
ImageIcon
polegający na tym, że konstruktor blokuje czytanie obrazu. Naprawdę nie jest to problem podczas ładowania ze słoika aplikacji, ale może, jeśli potencjalnie czytasz przez połączenie sieciowe. Jest mnóstwo przykładów AWT-era użyciuMediaTracker
,ImageObserver
i przyjaciół, nawet w demo JDK.źródło
Robię coś bardzo podobnego w prywatnym projekcie, nad którym pracuję. Do tej pory wygenerowałem obrazy do 1024x1024 bez żadnych problemów (oprócz pamięci) i mogę je wyświetlać bardzo szybko i bez problemów z wydajnością.
Przesłonięcie metody malowania w podklasie JPanel jest przesadą i wymaga więcej pracy niż trzeba.
Tak to robię:
LUB
Kod użyty do wygenerowania obrazu będzie w tej klasie. Korzystam z BufferedImage, aby rysować, kiedy wywoływana jest funkcja paintIcon (), używam g.drawImvge (bufferedImage); Zmniejsza to ilość flashowania wykonanego podczas generowania obrazów i można go wątkować.
Następnie rozszerzam JLabel:
Wynika to z tego, że chcę umieścić obraz w okienku przewijania, tzn. Wyświetlić część obrazu i pozwolić użytkownikowi przewijać w razie potrzeby.
Więc używam JScrollPane do przechowywania MapLabel, który zawiera tylko MapIcon.
Ale dla twojego scenariusza (po prostu pokazuj cały obraz za każdym razem). Musisz dodać MapLabel do najwyższego JPanel i upewnić się, że wszystkie one mają rozmiar do pełnego rozmiaru obrazu (przez przesłonięcie GetPreferredSize ()).
źródło
Utwórz folder źródłowy w katalogu projektu, w tym przypadku nazwałem go Obrazy.
źródło
Możesz uniknąć korzystania z własnej
Component
biblioteki iImageIO
klasy SwingX oraz klasy:źródło
Ta odpowiedź jest uzupełnieniem odpowiedzi @ shawalli ...
Chciałem również odwołać się do obrazu w moim słoiku, ale zamiast mieć buforowany obraz, po prostu zrobiłem to:
źródło
Widzę wiele odpowiedzi, w rzeczywistości nie odnosząc się do trzech pytań PO.
1) Słowo o wydajności: tablice bajtów są prawdopodobnie niewystarczające, chyba że można użyć dokładnej kolejności bajtów pikseli, która pasuje do bieżącej rozdzielczości i głębi kolorów kart graficznych.
Aby osiągnąć najlepszą wydajność rysowania, wystarczy przekonwertować obraz na buforowany obraz, który jest generowany z typem odpowiadającym bieżącej konfiguracji grafiki. Zobacz createCompatibleImage na https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
Te obrazy będą automatycznie buforowane w pamięci karty graficznej po rysowaniu kilka razy bez żadnego wysiłku programistycznego (jest to standard w Swing od Java 6), a zatem faktyczny rysunek zajmie znikomą ilość czasu - jeśli nie zmieniłeś obrazu .
Zmiana obrazu nastąpi z dodatkowym transferem pamięci między pamięcią główną a pamięcią GPU - co jest wolne. Dlatego unikaj „przerysowywania” obrazu do BufferedImage, dlatego unikaj wykonywania getPixel i setPixel za wszelką cenę.
Na przykład, jeśli tworzysz grę, zamiast przyciągać wszystkich aktorów do BufferedImage, a następnie do JPanel, ładowanie wszystkich aktorów jako mniejsze BufferedImages jest znacznie szybsze i rysowanie ich jeden po drugim w kodzie JPanel na stronie ich właściwe położenie - w ten sposób nie zachodzi dodatkowy transfer danych między pamięcią główną a pamięcią GPU, z wyjątkiem początkowego transferu obrazów do buforowania.
ImageIcon użyje BufferedImage pod maską - ale w zasadzie kluczem jest przydzielenie BufferedImage z odpowiednim trybem graficznym i nie ma wysiłku, aby zrobić to dobrze.
2) Zwykłym sposobem na zrobienie tego jest narysowanie BufferedImage w przesłoniętej metodzie paintComponent JPanel. Chociaż Java obsługuje wiele dodatkowych dodatków, takich jak łańcuchy buforów kontrolujące VolatileImages buforowane w pamięci GPU, nie ma potrzeby korzystania z żadnego z nich, ponieważ Java 6 wykonuje dość dobrą pracę bez ujawniania wszystkich tych szczegółów przyspieszenia GPU.
Pamiętaj, że przyspieszenie GPU może nie działać w przypadku niektórych operacji, takich jak rozciąganie półprzezroczystych obrazów.
3) Nie dodawaj. Po prostu pomaluj jak wspomniano powyżej:
„Dodawanie” ma sens, jeśli obraz jest częścią układu. Jeśli potrzebujesz tego jako obrazu tła lub pierwszego planu wypełniającego JPanel, po prostu narysuj paintComponent. Jeśli wolisz zaparzyć ogólny komponent Swing, który może wyświetlać twój obraz, to jest to ta sama historia (możesz użyć JComponent i zastąpić jego metodę paintComponent) - a następnie dodać to do układu komponentów GUI.
4) Jak przekonwertować tablicę na obraz buforowany
Konwersja tablic bajtów do formatu PNG, a następnie ich załadowanie wymaga dużych zasobów. Lepszym sposobem jest konwersja istniejącej tablicy bajtów na BufferedImage.
W tym celu: nie należy używać do pętli i kopiowania pikseli. To jest bardzo, bardzo wolne. Zamiast:
źródło