Błąd: cannot refer to a non-final variable... :/

0

Nie mogę zrozumieć błędu jaki mi wyrzucił eclipse,
kod:

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


public class Okno {
	
	
	

	public static void main(String rgs[])
	{
		
		
		
		JFrame ramka = new JFrame("Okno testowe");
		ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		ramka.setLayout(new FlowLayout());
		ramka.setSize(300, 300);
		
		JButton p1 = new JButton("Przycisk 1");

		JLabel napis1 = new JLabel("Wybierz akcję: ");
		JLabel tekst;	
		
		p1.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent ae) 
			{
			 tekst.setText("Naciśnięto przycisk 1");
			}
		});
		
		
		ramka.add(napis1);
		ramka.add(p1);

		

		ramka.setVisible(true);
	}
	
}

W linii:

  • tekst.setText("Naciśnięto przycisk 1");**

wyskakuje błąd:

cannot refer to a non-final variable inside an inner class defined in a different method

sorry że zawracam wam głowę, ale google nie pomogło :/

0

Oprócz tego, że text wskazuje na null to jeszcze odwołujesz się do niego z wnętrza innej klasy, przez co musi być polem finalnym.

0

Tak, racja. Teraz się kompiluje.

Ale jeszcze jedno pytanie,

Poprawiony kod:

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
 
 
public class Okno {
 
 
 
 
        public static void main(String args[])
        {
 
 
 
                JFrame ramka = new JFrame("Okno testowe");
                ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                ramka.setLayout(new FlowLayout());
                ramka.setSize(300, 300);
                ramka.setLocation(100, 100);
 
                JButton p1 = new JButton("Przycisk 1");
                JLabel napis1 = new JLabel("Wybierz akcję: ");
                
                
                ramka.add(napis1);
                ramka.add(p1);
                
                  
 
                p1.addActionListener(new ActionListener()
                {
                        public void actionPerformed(ActionEvent ae) 
                        {                       	
                         JLabel tekst = new JLabel();
                         tekst.setText("Naciśnięto Przycisk 1");
                         
                 
                        }
                });
 
               
                ramka.setVisible(true);

 
 
 
               
        }
 
}

Jak sprawić by
Naciśnięto Przycisk 1

Pojawiło się w aplikacji po naciśnięciu przycisku?
dodaję do alikacji:

ramka.add(tekst);

ale błędy wyskakują.

Czy konieczne jest zatem aby zrobić to na zasadzie wątków?

0

Nie jest konieczne. Zrób to porządnie, zmienna tekst powinna być polem w klasie - chcesz mieć do niej dostęp z różnych funkcji. Twórz ją raz, a nie po każdym kliknięciu.

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
 
 
public class Okno2 {
  
        private JLabel tekst;
        public static void main(String args[])
        {
            new Okno2();
        }
        public Okno2(){
 
 
 
                JFrame ramka = new JFrame("Okno testowe");
                ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                ramka.setLayout(new FlowLayout());
                ramka.setSize(300, 300);
                ramka.setLocation(100, 100);
 
                JButton p1 = new JButton("Przycisk 1");
                JLabel napis1 = new JLabel("Wybierz akcję: ");
 
 
                ramka.add(napis1);
                ramka.add(p1);
                tekst = new JLabel();
                ramka.add(tekst);
 
 
 
                p1.addActionListener(new ActionListener()
                {
                        public void actionPerformed(ActionEvent ae) 
                        {                               
                            tekst.setText("Naciśnięto Przycisk 1");
                        }
                });
 
 
                ramka.setVisible(true);
 
        }
}
0

Napiszę jeszcze o co chodzi z tymi finalami.

Otóż metody w Javie nie są obiektami, więc nie mają pól, a przynajmniej takich dostępnych z zewnątrz. Dlatego generalnie nie da się dostać do zmiennych lokalnych z jednej metody w innej metodzie. Wyjątkiem są stałe, czyli pola z modyfikatorem 'final'. Przed utworzeniem klasy wewnętrznej zawierającej metodę, która odwołuje się do pól finalnych z otaczającej metody Java tworzy sobie dodatkowy obiekt zawierający stałe (czyli zmienne lokalne z modyfikatorem final) z metody otaczającej. Dlaczego Java nie tworzy obiektu ze zmiennych, tzn takich bez modyfikatora final? Ponieważ te pola mogłyby być dalej zmieniane w metodzie otaczającej i nie miałoby to odzwierciedlenia w tym nowo stworzonym obiekcie zawierającym kopie zmiennych lokalnych metody otaczającej. Takie zachowanie mogłoby prowadzić do trudnych do wyłapania błędów.

0

Dzięki za pomoc. Przyswajam.

0

Co by nie zaczynać nowego tematu, podepnę jeszcze tu jedno pytanie,

otóż w zapisie:

   p1.addActionListener(new ActionListener()
                {
                        public void actionPerformed(ActionEvent ae) 
                        {                               
                            tekst.setText("Naciśnięto Przycisk 1");
                        }
                });

dodałem tekst.setLocation(100, 100);

                p1.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent ae) 
                    {     
                    	tekst.setLocation(100, 100);
                    	tekst.setText("Naciśnięto przycisk 1");   
                    	
                    }
                });

Napis przy pierwszym zainicjowaniu programu wyświetla się na domyślnej lokalizacji a dopiero po kliknięciu weń, obniża się o 100 punktów w dół.
Jak zrobić by pojawił się od razu w obniżonej pozycji?

Czy przypadkiem nie trzeba zrobić jakiejś drugiej zagnieżdżonej ramki która była by ustawiona poniżej i wyświetlała te napisy?

0

Omg, Przenieś to

tekst.setLocation(100, 100);

do konstruktora. Przecież metoda actionPerformed wykonuje się dopiero po kliknięciu.

0

Wiem wiem, że wykonuje się po kliknięciu. To oczywiste, próbowałem przenieść

tekst.setLocation(100, 100);

do konstruktora, zaraz po:

ramka.add(tekst);

ale bez efektu :/ dlatego pytam.

0
  1. Po to używa się menadżerów rozkładu (setLayout(new FlowLayout());), żeby nie rozmieszczać elementów ręcznie. Zdecyduj się: menadżer rozkładu czy rozmieszczanie ręczne. Nie mieszaj.
  2. Jaki napis się wyświetla po uruchomieniu programu skoro jest taki kod tekst = new Jlabel()? Weź pod uwagę, że dodanie tekstu do obiektu tekst zmienia jego rozmiar.
0

Fakt, jest rozmieszczanie ręcznie. Próbuję różnych prostych tutoriali, przerabiam je testując przeczytany fragment książki - muszę więcej czytać zanim się wezmę za pisanie.
Ok, dzięki za fatygę.

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