2012-11-16 25 views
9

Jakiś czas temu napisałem mały program do przeglądania/przetwarzania obrazów z Javą, mini-Photoshopem, jeśli zechcesz.Używanie Java klasy wewnętrznej i tworzenie instancji

Chciałem mieć rozwijane menu, w którym mógłbym wybrać, które z obrazów, które otworzyłem, będą "na stole", tj. pokazano i zastosowane metody. Chciałem, aby nazwa obrazu była nazwą elementu JMenuItem wyświetlanego w menu. Chciałem też, aby pojawił się nowy przycisk, gdy dodam nowy obraz.

Zastanowiłem się przez pewien czas i ostatecznie opracowałem to rozwiązanie, nową klasę, która obsługuje tworzenie nowego przycisku po dodaniu obrazu. Kod jest następujący:

import java.awt.event.*; 
import javax.swing.*; 
import java.util.*; 


public class ImageList{ 

    private ArrayList<JMenuItem> list; 
    private ImageHandler main; 
    private ImageLevel img; 

    public ImageList() {} 

    public void setHandler(ImageHandler hand) { 
     main = hand; 
     img = main.getImg1(); 
    } 

    public void add(Buffer addi) { 
     final String added = addi.getName(); 
     JMenuItem uusi = new JMenuItem(added); 

     main.getMenu5().add(uusi); 
     uusi.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       img.setBuffer(added); 
       main.getScr().updateUI(); 
      } 
     }); 
    } 
} 

Działa to tak, jak powinno. Dla tej strony przetłumaczyłem oryginalne fińskie nazwy na angielski, zastanawiam się, dlaczego napisałem je po portugalsku ... Ssałem nazywanie rzeczy.

Metoda add ma być wielokrotnie wywoływana, gdy program jest uruchomiony.

To, czego nie rozumiem, to klasyczna implementacja interfejsu ActionListener, a mianowicie jego kompilacja i sposób działania.

Jeśli mam dwa przyciski na moim interfejsie i chcę, żeby robili różne rzeczy, potrzebuję dwóch klas wewnętrznych, po jednej dla każdego, z których każda ma własną wewnętrzną implementację interfejsu ActionListener. Ale w moim kodzie jest jedna klasa, która wydaje się wykonywać pracę wielu, jeden posłużył się do tego plikiem klasy, ale końcowy rezultat działa tak, jakby było ich wiele.

Czy ktoś może mnie uczyć w tej sprawie? Czy ten kod to jedna klasa, a nowe przyciski są jego instancjami? Czy to są nowe zajęcia? Czy powinien istnieć nowy plik .class dla każdego nowego przycisku? etc ...

+3

Re. nazywanie: 'new' jest zastrzeżonym słowem, więc powinieneś użyć czegoś innego dla tej zmiennej JMenuItem. – assylias

+0

@peter Naprawi to. – Valtteri

+0

Należy również rozważyć "Akcja", jak pokazano w tym ['FileMenu'] (http://stackoverflow.com/a/4039359/230513) – trashgod

Odpowiedz

5

Często wewnętrzna klasy jest tworzony w kodzie, który nazywa się tylko raz (na przykład w przypadku rozszerzania JPanel i dodać ActionListeners do JButton sw konstruktora). Tutaj tworzysz wewnętrzną klasę w metodzie, którą wywołujesz kilka razy (jeśli dobrze rozumiem twój opis). Za każdym razem, gdy wywołasz add(), zostanie utworzone nowe wystąpienie klasy wewnętrznej. Podobnie jak w przypadku nazwanych klas, istnieje tylko klasa jedna klasa, ale może istnieć wiele instancji.

+0

+1 za faktyczne udzielenie odpowiedzi na pytanie OP. – Perception

+0

@ Code-Guru: OK, więc są to nowe instancje. Nigdy nie widziałem, a przynajmniej nie zauważyłem, wewnętrznych klas z więcej niż jedną instancją. – Valtteri

+0

@Valtteri Dokładnie. Zobacz [odpowiedź Teda Hoppa] (http://stackoverflow.com/questions/13420151/java-inner-class-usage-andinstinstiation/13420335#13420335) dla wyjaśnienia na temat robienia tego samego z nazwaną klasą wewnętrzną. Oba są równoważne, jeśli chodzi o tworzenie instancji. –

0

Tworzysz nowe anonimowe klasy dla słuchaczy akcji menu.

Zasadniczo kod

menuItem.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
}); 

Definiuje nową implementację klasy dla ActionListener

+2

To nie jest poprawne .... anonimowe klasy są tworzone w czasie kompilacji, a nie w czasie wykonywania. – Renato

+1

Ten kod tworzy nowe * obiekty * z jednej * klasy *. –

0
  • main.getScr().updateUI(); nie jest właściwa metoda aktualizacji już widocznych Swing Objects, metoda ta jest Look and Feel wrażliwy

  • użyć JPanel (nie zapomnij zastąpić w przeciwnym razie zwraca Dimension (0, 0)) z paintComponent,

  • jeśli chcesz ot usunąć następnie dodać nowy pojemnik, przytrzymaj zdjęcie, a następnie trzeba zadzwonić revalidate() i repaint()


  • użytkowania JList obrazami zamiast JMenuItem

  • dodaj ListSelectionListener t O JList, wówczas można przełączyć obrazów pośredników


  • jeśli nie zostanie dodany dowolny inny JComponent (e) do Container posiada Image, a następnie użyć JLabel z Icon/ImageIcon
+1

-1 Nie odpowiada na pytanie OP. –

+0

Podstawowe rzeczy, tylko po to, by unikać strzałów w ciemność opisywanych tutaj – mKorbel

+0

@mKorbel Tak, wiem, że ktoś strzelałby do mnie z takimi radami: D W każdym razie dzięki. Wciąż nie bardzo rozumiem GUI i takie w zasadzie w ogóle, więc ten kod jest bardzo śliny i stalowego drutu i jest to cud, który trzyma razem ... W każdym razie będzie czytał twoje rady. – Valtteri

3

W tym kodzie:

public void add(Buffer addi) { 
    . . . 
    uusi.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      img.setBuffer(added); 
      main.getScr().updateUI(); 
     } 
    }); 
} 

Konstrukcja new ActionListener() {...} jest anonimową klasą wewnętrzną. Zachowuje się tak, jakby była zadeklarowana oddzielnie jako regularna klasa wewnętrzna. Główną różnicą jest to, że nazwa jest generowana automatycznie przez kompilator. Jest to odpowiednik:

private class Anonymous implements ActionListener { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
} 

public void add(Buffer addi) { 
    . . . 
    uusi.addActionListener(new Anonymous()); 
} 

Za każdym razem wykonywać swój kod addActionListener, tworzy nową instancję tej klasy.

Anonimowe klasy wewnętrzne mają kilka innych ograniczeń, które są konsekwencją bycia anonimowym. Na przykład, jeśli deklarują pola, pola są dostępne tylko (bez użycia odbicia) z poziomu klasy.

+0

+1 za wyjaśnienie równoważności z nazwana wewnętrzna klasa –

+0

Różnica między tymi dwoma polega na tym, że anonimowa klasa wewnętrzna ma dostęp do "końcowych" zmiennych lokalnych swojego kontekstu zawierającego (tj. 'dodany'), ale klasa' Anonimowa', jak ją napisałeś, nie robi (ponieważ jest poza metodą). Możesz przenieść 'prywatną klasę Anonymous' wewnątrz metody' add', aby była ona właściwie równoważna z kodem OP. –

+0

main.getScr(). UpdateUI(); proszę, co jest ważne w tej linii kodu ??? – mKorbel

0

To, co robisz, to tworzenie anonimowej implementacji interfejsu ActionListener. Każda anonimowa implementacja będzie miała swój własny plik klasy (o nazwie ImageList $ 1.class, ImageList $ 2.class i tak dalej).

Można też zrobić coś takiego, z podobnymi wynikami:

class MyActionListener implements ActionListener { 
    public void actionPerformed(ActionEvent e) { 
     img.setBuffer(added); 
     main.getScr().updateUI(); 
    } 
}; 

menuItem.addActionListener(new MyActionListener()); 
0

Wewnętrzna klasy wewnątrz klasy jest kompiluje do „rodzica” .class pliku. Możesz mieć wiele klas wewnętrznych w klasie 1. (w wyniku czego 1.pliki klas po kompilacji) Każde "wywołanie" do klasy wewnętrznej (środowisko uruchomieniowe) stworzy obiekt tej klasy wewnętrznej (tak samo jak "klasy norma"). Ale to nie zmienia twoich plików .class.

Po dodaniu 3 przycisków tego samego typu, za każdym razem tworzony jest nowy obiekt klasy wewnętrznej. Ta sama zasada co dla samego przycisku.

Powiązane problemy