Prośba o wyjaśnienie- osobne klasy

0
public class NewJFrame extends javax.swing.JFrame {

    public NewJFrame() {
        initComponents();
    }

                              
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        Osobna_klasa odeslij_mnie = new Osobna_klasa();
 
        jButton1.addActionListener(odeslij_mnie);
        jButton1.setText("Napis");

        jLabel1.setBackground(new java.awt.Color(0, 0, 0));
                         
    public javax.swing.JLabel jLabel1;
    public javax.swing.JButton jButton1;
    
}
public class Osobna_klasa implements ActionListener
{
   
    public void actionPerformed(ActionEvent zdarzenie)
    {
        tu wykorzystanie jButton1 i jLabel1 z klasy NewJFrame
    }
    
    public static javax.swing.JLabel jLabel1_naprowadzajacy;
    public javax.swing.JButton jButton1_naprowadzajacy;

}

Witam, mam kilka pytań, ogólnie celem jest zawarcie actionPerformed wraz z obsługą dla jButton1 z klasy NewJFrame w innej klasie w tym wypadku w Osobna_klasa
pytania:

1.Sprawdzalem to i mogę tak zrobić z jButton1 np jFileChooser mi sie otwiera gdy go zaimplementowalem w actionPerformed
ale nie wiem na jakiej zasadzie to działa? Dodatkowo dlaczego nazwy buttonow mogą być różne w obu klasach a i tak kompilator wie że chodzi o button z NewJFrame(wykonując kod z actionPerformed)?

2.jButton1 jeszcze jakąś regułę można zauważyć i przyjąć ze ok, ale teraz pytanie jak po wczytaniu np zdjecia wyslac je na ten label ktory jest zadeklarowany w klasie NewJFrame ? Wystarczy ze go zadeklaruję tak jak to jest teraz i mogę na nim operować czy w jakiś inny sposób mogę do niego sie dostać? Prosilbym o przykładowy kod wykorzystujący jLabel1 z NewJFrame napisany oczywiście w actionPerformed.

0
  1. Otwieranie JFileChosera czy inne operacje powiązane z actionPerformed() oraz ich wyzwalanie wynika ze sposobu obsługi zdarzenia naciśnięcia przycisku. Jak naciśniesz przycisk to informacja o tym przekazywana jest do kolejki z której wybierane jest to zdarzenie po czym sprawdzane są powiązania czyli czy do zdarzenia przypisana jest jakaś operacja i jeżeli tak to operacja jest wykonywana.
    Co do nazw zmiennych to są tylko dla programistów. Kompilator i tak sobie je zamienia na odpowiednie adresy w pamięci i na tej podstawie wiąże zmienne.
  2. Poczytaj tutorial Suna:
    http://java.sun.com/docs/books/tutorial/uiswing/
0

Ok, dzięki za odpowiedź

0

Chociaż jeśli możesz naprowadź mnie dokładniej na to gdzie mogę przeczytać o tym bo w sumie w Netbeans wiem, że można w jednej klasie to zrobić (wydaje mi się, że o to chodziło Tobie z tym linkiem) cały sęk jak to zrobić w innej klasie tj to wcześniej pisałem, no chyba, że się mylę co do Twoich intencji to jak to nie kłopot podaj linka gdzie to jest na stronie sun a opisane. Dzieki jeszcze raz. Pozdr.

0

To ja spróbuję najprościej jak się da (co nie znaczy najkrócej).

Za pomocą jButton1.addActionListener(odeslij_mnie); zarejestrowałeś dla jButton1 obsługę zdarzenia wciśnięcia przycisku.
Jego odpalenie (tego zdarzenia) spowoduje wywołanie przez jakiś obiekt Swinga (nie jest to ważne tutaj) metody: odeslij_mnie.actionPerformed().
odeslij_mnie musi mieć taką metodę ponieważ implementuje interfejs ActionListener, a ten właśnie taką metodę posiada (i to jest jedyna jego metoda). Zresztą nie może nie posiadać ponieważ addActionListener przyjmie jako argument wyłącznie referencję typu ActionListener (inaczej będzie błąd kompilacji).
Działa to dlatego, że każdą klasę, która implementuje jakiś interfejs można rzutować w górę na referencję do tego interfejsu. Traktuj interfejs jako klasę bazową z abstrakcyjnymi metodami do przeciążenia - łatwiej to rozumieć.

Co do przycisku i etykiety z Osobna_klasa, to Swing nie ma nawet o nich pojęcia, że istnieją. Dla Swinga i jego obsługi zdarzeń istnieją wyłącznie te rzeczy, które zostały zarejestrowane przez jakiś addXXXListener.
Jest jeszcze jeden myk z dostępem do źródła zdarzenia. Z wnętrza metody ActionListener można się dostać do referencji JButton1 bezpośrednio przez pole lub jakąś metodę NewJFrame, ale to bardzo zła i niebezpieczna technika powodująca masę błędów.
Znacznie lepszym sposobem jest użycie zmiennej zdarzenie typu ActionEvent, które jest argumentem ActionPerformed (i ogólniej do każdej metody obsługi zdarzeń dochodzi jako argument jakiś obiekt samego zdarzenia). W zmiennej tej zapisane są niemal wszystkie potrzebne informacje lub odnośniki do tych informacji - szczególnie takie jak dla jakiego obiektu zdarzenie zostało wygenerowane, jaki był jego czas, i co było jego przyczyną. Aby dostać się do jButton1 trzeba użyć (JButton)(zdarzenie.getSource()).

Oczywiście zawsze warto sprawdzić czy wynik getSource da się zrzutować ponieważ pamiętaj, że actionPerformed może być wywoływane nie tylko dla JButtona, a ta ten sam obiekt implementujący ActionListener (czyli tutaj odeslij_mnie) może być zarejestrowany (przez addActionListener) do uruchomienia dla wielu różnych przycisków (więcej niż jednego). Po udanym zrzutowaniu dostajesz referencję do konkretnego przycisku JButton, który został przyciśnięty. Z ActionEvent nie dowiesz się nic więcej niż tylko o tym przycisku. Natomiast z obiektu przycisku możesz dowiedzieć się coś o jego rodzicu za pomocą metody JButton.getParent(). Dostaniesz z niej referencję do obiektu NewJFrame, który zawiera naciśnięty przycisk - ALE - wynikiem jest referencja do klasy Container, z której NewJFrame po łańcuszku rodziców Windows, Frame i JFrame dziedziczy. Dlatego trzeba tę referencję znowu przekonwertować na referencję do klasy NewJFrame upewniając się, że to możliwe. Dopiero wtedy jest możliwe dostanie się do pola jLabel1 w obiekcie tej klasy. W (działającym) uproszczeniu może wyglądać to tak:

JButton źródło = (JButton)(zdarzenie.getSource());
NewJFrame ramka = (NewJFrame)(źródło.getParent());
ramka.jLabel1.setIcon(jakiśObrazek);
ramka.jLabel1.setText("Wciśnięto przycisk");

Można również inaczej. Trzeba w Osobna_klasa stworzyć pole typu JLabel i za pomocą np. konstruktora wypełnić je referencją pobraną z NewJFrame.jLabel1 tego obiektu, który naprawdę zawiera przycisk, który Ciebie interesuje.

Pamiętaj, że aplikacja zawsze może stworzyć nieskończoną ilość obiektów NewJFrame z identycznie wyglądającymi obiektami, których referencje będą przechowywać ich własne pola jButton1. Tyle, że każdy z nich będzie innym egzemplarzem. W razie wyświetlania wszystkich tych okienek, Twój program musi wiedzieć o którego buttona w którym okienku chodzi. Pamiętaj, że w takim wypadku wszystkie obiekty NewJFrame zarejestrują obsługę przyciśnięcia swoich przycisków jButton1 przez różne obiekty, których referencję posiadać będzie lokalna zmienna odeslij_mnie (każdy nowy egzemplarz Osobna_klasa() jest tworzony w initComponents()). Założenie, że jest tylko jedno okienko dziedziczące po JFrame, to tylko przypadek szczególny. Jednak obsługa zdarzeń musi sobie poradzić ze wszystkimi możliwymi przypadkami.

Wracając do tego innego sposobu - jest on dużo mniej bezpieczny ponieważ musisz wiedzieć na pewno (a łatwo się pomylić), który obiekt jest źródłem i który egzemplarz obiektu będzie jego odbiornikiem. Można w tym celu porównywać referencję pobraną jButton1 z referencją (JButton)(zdarzenie.getSource()). Jeżeli będą równe (==), to pomyłki nie ma.

Z powodów, które napisałem najbezpieczniejszą obsługą zdarzeń jest przekazywanie do addXXXListener klasy wewnętrznej tego obiektu, który posiada obiekt wywołujący zdarzenie. Wtedy jest pewność, że zdarzenie jest obsługiwane przez właściwy odbiornik dla właściwego źródła.
Obsługa zdarzeń obiektów jednej klasy przez metody zupełnie innej klasy (szczególnie publicznej), to proszenie się o naprawdę duże kłopoty. Trzeba mieć naprawdę bardzo mocne powody (ja takich nigdy nie miałem), żeby w taki sposób zakodować obsługę zdarzeń.
Tutaj wersja z odbiornikiem zdzarzeń, który jest klasą wewnętrzną. Można to jeszcze uprościć przez zamianę jawnej klasy wewnętrznej na klasę anonimową, ale to może przy innej okazji.

import javax.swing.*;

public class NewJFrame extends JFrame {

    public NewJFrame() {
        initComponents();
    }

                             
    private void initComponents() {
        jButton1 = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        Wewnetrzna_klasa odeslij_mnie = new Wewnetrzna_klasa();
 
        jButton1.addActionListener(odeslij_mnie);
        jButton1.setText("Napis");
        jLabel1.setBackground(new java.awt.Color(0, 0, 0));
    }

    private class Wewnetrzna_klasa implements ActionListener {
        public void actionPerformed(ActionEvent zdarzenie)
        {   //można wykorzystać jLabel1 i jButton1 bezpośrednio bez używania obiektu zdarzenie
             //można użyć dostępu jawnego NewJFrame.this. lub niejawnego jak poniżej
            jLabel1.setIcon(jakiśObrazek);
            jLabel1.setText("Wciśnięto przycisk");
        }
    }        
    private JLabel jLabel1;     //prywatne, zawsze możesz zrobić metodę
    private JButton jButton1; //public getMójLabel() { return jLabel1; }
}

I jeszcze jedno. 99% pól wszelkich obiektów powinno być typu private. Użycie pola z modyfikatorem public to na 99% bardzo poważny błąd, który srogo się kiedyś zemści. Nie rób tak.
Przy okazji używaj konsekwentnie formatowania kodu ponieważ jeżeli tego nie zrobisz, to cały czas będziesz mieć wielkie problemy z brakującymi lub nadmiarowymi nawiasami klamrowymi (i nie tylko). Takie błędy czasem piekielnie trudno wykryć, szczególnie jak się pechowi pomaga.

Się rozpisałem... :d

0

Dzieki za wyjaśnienie jeszcze nie wszystko zrozumiełem co napisałeś ale przeczytam to jeszcze z kilka razy i zrozumiem. Powodem takiej sytuacji jest to ze pisze program w Netbeans i nie chcialem całego kodu mieć w jednej klasie. Ale po Twojej wypowiedzi zamierzam zmienić postępowanie z tym programem, tylko jeśli możesz to powiedz jak Ty byś napisał taki program żeby wszystko nie znajdowało się w jednej klasie (dziedziczącej po JFrame) ale też nie zamulało. A coś więcej o programie : Jlabel Otwieranie Zapisywanie Zdjęcie-Negatyw + kilka innych efektów tego typu(obsługiwanych przez przyciski button1,2,3,4...) takie będą możliwości programu. W jaki sposób można to napisać żeby nie było to wszystko w jednej klasie ale też żeby nie było tak jak ja chciałem zrobić ? Pozdrawiam i jeszcze raz Wielkie Dzieki za poświęcenie czasu i wyjaśnienie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1