Okienko JFRAME i zmienianie jego zawartosci

0

Witam,
Potrzebuje wyświetlić zmieniający się tekst w standardowym okienku. Można w jakikolwiek sposób wysłać do metody paintComponent, obiekt typu String, który ma zostać narysowany? Nie mogę tworzyć tego obiektu w klasie "Panel" ponieważ jest on tworzony co jedna sekundę w klasie, która implementuje ActionListener (Timer). A z kolei do funkcji paintComponent nie wiem jak przekazać obiekt z zewnątrz. Jest to możliwe? Prosze o pomoc

class Panel extends JPanel
 {  
    public void paintComponent(Graphics g)
    {  
     
       super.paintComponent(g);
 
       g.drawString(tekst, 
          WIADOMOSC_X, WIADOMOSC_Y);
    }
 
    public static final int WIADOMOSC_X = 75;
    public static final int WIADOMOSC_Y = 100;
 }
0

Można np. tak:

class Panel extends JPanel
 {
    private JakasKlasa parent; 
    Panel(JakasKlasa parent)
    {
        this.parent=parent;
    }
    public void paintComponent(Graphics g)
    { 
     
       super.paintComponent(g);
 
       g.drawString(parent.getKomunikat(),
          WIADOMOSC_X, WIADOMOSC_Y);
    }
 
    public static final int WIADOMOSC_X = 75;
    public static final int WIADOMOSC_Y = 100;
 }
0
bogdans napisał(a)

Można np. tak:

class Panel extends JPanel
 {
    private JakasKlasa parent; 
    Panel(JakasKlasa parent)
    {
        this.parent=parent;
    }
    public void paintComponent(Graphics g)
    { 
     
       super.paintComponent(g);
 
       g.drawString(parent.getKomunikat(),
          WIADOMOSC_X, WIADOMOSC_Y);
    }
 
    public static final int WIADOMOSC_X = 75;
    public static final int WIADOMOSC_Y = 100;
 }

Dzięki, ale kod:

 g.drawString( ObrazWyspy.calosc,
          WIADOMOSC_X, WIADOMOSC_Y);

Zwraca błąd:

 non-static variable calosc cannot be referenced from a static context

Czyli w ogóle chyba nie jest możliwe to co chce zrobić przy użyciu JPanel.
Mozecie zasugerować jakieś klasy które nie będą bardzo trudne do wykorzystania dla początkującego, a które pozwolą mi wyświetlać w równych odstępach czasy kwadratowa tablice typu String na ekranie? Proszę o pomoc.

0
class Panel extends JPanel {  
	private String text = null;
	public void paintComponent(Graphics g) {  
		super.paintComponent(g);
		if(text != null)
		 	g.drawString(text,  WIADOMOSC_X, WIADOMOSC_Y);
	}
 
	public static final int WIADOMOSC_X = 75;
	public static final int WIADOMOSC_Y = 100;
	
	public String setText(String text) {
		this.text = text;
	}
}

W swoim listenerze po prostu wywołujesz metode setText, i repaint. Na obiekcie klasy Panel.

0

Co to jest ObrazWyspy nazwa klasy, czy nazwa zmiennej obiektowej ? Wielka litera na początku sugeruje że nazwa klasy, jeśli tak, to kod jest błędny. W moim przykładzie parent było nazwą zmiennej.

0

Błąd jest bo pole calosc w klasie ObrazWyspy nie jest statyczne. Ale jak zrozumiałem, intancja obiektu ObrazWyspy nie może się znajdować w klasie Panel.

Proponowałbym zatem by w mistycznej klasie ObrazWyspy zawrzeć metodę:

public String getCalosc() {
	return calosc;
}

I jeżeli owe obiekty klasy ObrazWyspy, tworzone są każdorazowo w ramach działania ActionListener'a, proponowałbym by rozwiązać to w następujący sposób:

...
private Panel panel;
...

public void actionPerformed(ActionEvent e) {
	//obsługa zdarzenia
	ObrazWyspy ow= //costam
	panel.setText(ow.getCalos());
	panel.repaint();	
}

Dodatkowo chciałbym zauważyć, że istnieje już klasa o nazwie Panel (java.awt.Panel) ;/

0

Dziekuje Panowie za odpowiedzi.

Jacobus2k, skorzystałem z Twoich porad ale dalej mam pewien problem. Nie wiem czy do końca rozumiem błąd

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at ObrazWyspy.actionPerformed(Wyspa.java:322)

w lini
panel.setText(calosc);
i później masa wyjątków. Ale po rożnych testach doszedłem ze String text w metodzie rysowania ma zawsze wartość zero. Nie wiem dlaczego, poznieważa drukuje zmienna całość w Listenerze i sie drukuje elegancko, wiec coś musi być nie tak z tym przekazaniem tego Stringa, tylko co?
Mój kod wyglada tak:

class ObrazWyspy implements ActionListener
{
  public void actionPerformed(ActionEvent zdarzenie)
  {

if (first_time){
//ustawienia początkowe
first_time = false; 
}

  //obsługa zdarzenia
calosc=wys1.pobierzWyspe();
panel.setText(calosc);
panel.repaint(); 
wys1.zmienPolozenie();

}
private Panel panel;
private  String calosc;
private Wysepka wys1;
private boolean first_time = true; 
}


class Panel extends JPanel { 
    
    public void paintComponent(Graphics g) { 
               
            super.paintComponent(g);
                if(text !=null){
                g.drawString(text,  WIADOMOSC_X, WIADOMOSC_Y);
                }
        }
 
        public void setText(String text) {
                this.text = text;
        }
public static final int WIADOMOSC_X = 75;
public static final int WIADOMOSC_Y = 100;
private String text = null;    
}
0

To co chce drukować wygląda np tak (jest generowane losowo ustawienie początkowe):

  Kk   KmSk                                          
   Sk               Sm      Sk            Sk            
Kk                                                         
   SkKm   Sm                        KkSm               
                                                      Km   
                                                            
   SkSm                                                   
                                 Km                        
                                             Km   Sm      
                        Sk            Km                  
   Sk                        Km                        Km
Sm      KkKm                                          Km
                           Km                              
         Km            Sk               Km      Kk      
                                                            
      Kk                                                   
                                                            
                              Sk                        Sm
Sk                              Sk      Sk               
               Kk                                          

Moze cos jest nie tak dlatego ze jest spacja zazwyczaj na pcozatku i traktuje to jako null. Juz nic nie wiem :(

0

A masz gdzieś (w tym opuszczonym) wiersz

panel=new Panel();

?

0
bogdans napisał(a)

A masz gdzieś (w tym opuszczonym) wiersz

panel=new Panel();

?

Ehh, cały czas zapominam o najpotrzebniejszych rzeczach. Dzieki bardzo, już sie kompiluje ale w okienku dalej mam pusty, szary ekran.
Gdy w actionPerformed zrobię:

System.out.println(calosc);

to wyswietla mi sie w konsoli cyklicznie ta moja "wyspa"
gdy natomiast wstawie do public void paintComponent

System.out.println(text);

Pojawia sie w konsoli "null" i to tylko jeden raz. Więc obawiam się, że

panel.setText(calosc);
panel.repaint();

nie działają tak jak powinny.
panel.repaint();- nie powinno to odpalać metody paintComponent? Skoro tak to dlaczego okno jest cały czas puste a w konsoli "null" pojawia sie tylko raz? Calosc jak chce wydrukowac w actionPerformed działa prawidłowo.

0

Panel jest pierwszy raz rysowany przed wykonaniem funkcji actionPerformed().
Zmień

private String text = null;

na

private String text = "Jeszcze nikt nie klikał"; // i zobacz efekt
0
bogdans napisał(a)

Panel jest pierwszy raz rysowany przed wykonaniem funkcji actionPerformed().
Zmień

private String text = null;

na

private String text = "Jeszcze nikt nie klikał"; // i zobacz efekt

Teraz wysietla sie w panelu tekst:
Jeszcze nikt nie klikał
I nic sie więcej nie pojawia. Tak jakby

panel.setText(calosc);
panel.repaint(); 

w ogóle nie działały. "Jeszcze nikt nie klikał" jest widoczny przez cały czas wyświetlania okna, nie zmienia się co sekundę tak jak jest to zdefiniowane w ActionListener.

0

To co u Ciebie wywołuje metodę actionPerformed() ? Klikający użytkownik czy jakiś timer ? Jeśli timer, to może brak wywołania timer.start() ?

0
bogdans napisał(a)

To co u Ciebie wywołuje metodę actionPerformed() ? Klikający użytkownik czy jakiś timer ? Jeśli timer, to może brak wywołania timer.start() ?

Mam w main cos takiego:

ActionListener sluchacz = new ObrazWyspy();
Timer t = new Timer(1000, sluchacz);
t.start();

Wiec wszystko wywołuje sie automatycznie co sekundę.

0

Widzę tylko kawałek kodu zatem spekuluję.
Są dwa obiekty klasy ObrazWyspy, jeden wyświetla, w drugim działa timer.
Spróbuj tak:

Timer t = new Timer(1000, this);
0
bogdans napisał(a)

Widzę tylko kawałek kodu zatem spekuluję.
Są dwa obiekty klasy ObrazWyspy, jeden wyświetla, w drugim działa timer.
Spróbuj tak:

Timer t = new Timer(1000, this);

Timer wywołuje w równych odstępach czasu (pierwszy argument) obiekt który jest podany jako drugi argument (słuchacz).
ActionListener sluchacz = new ObrazWyspy();
Timer t = new Timer(1000, sluchacz);
t.start();
Słuchacz jest obiektem klasy obraz wyspy. Z tej klasy wywoływana jest metoda actionPerformed. ObrazWyspy musi implementowac ActionListener. Caly interesujacy nas kod wyglada wiec tak:

//zdefiniowanie i wlaczenie Timera
ActionListener sluchacz = new ObrazWyspy();
Timer t = new Timer(1000, sluchacz);
t.start();    



//klasa ktorej metoda actionPerformed jest wywolywana
class ObrazWyspy implements ActionListener
{
  public void actionPerformed(ActionEvent zdarzenie)
  {
//ustawienia początkowe
if (first_time){
//to co sie wykonuje przy pierwszy uruchomieniu
panel= new Panel();
first_time = false; 

}

  //obsługa zdarzenia

calosc=wys1.pobierzWyspe();
panel.setText(calosc);
panel.repaint(); 
wys1.zmienPolozenie();

}

//klasa odpowiedzialna za wyswietlanie
class Panel extends JPanel { 
       
    public void paintComponent(Graphics g) { 
               
            super.paintComponent(g);
                 System.out.println(text);
            
            if(text !=null){   
                g.drawString(text,  WIADOMOSC_X, WIADOMOSC_Y);
                }
        }
 
        public void setText(String t) {
                this.text = t;
        }
public static final int WIADOMOSC_X = 75;
public static final int WIADOMOSC_Y = 100;
private static String text = "Jeszcze nikt nie klikał"; 
        
}

Tak jak pislalem, program działa tak ze jakbym jakis println wstawił do actionPerformed to bedzie sie wyswietlal co sekunde. Ale w Panaelu wysietla sie tekst:
Jeszcze nikt nie klikał
I nic sie więcej nie pojawia. Tak jakby
panel.setText(calosc);
panel.repaint();

w ogóle nie działały. "Jeszcze nikt nie klikał" jest widoczny przez cały czas wyświetlania okna, nie zmienia się co sekundę tak jak jest to zdefiniowane w ActionListener.

0

Na oko są dwa obiekty klasy ObrazWyspy - w jednym działa timer, a drugi zajmuje się wyświetlaniem (dlatego na konsoli widać działanie timera a na panelu nie).
Zrób tak jak Ci radziłem.Zrezygnuj z ObrazWyspy sluchacz=new OrazWyspy();, zamiast tego wpisz

Timer t = new Timer(1000, this);
0
bogdans napisał(a)

Na oko są dwa obiekty klasy ObrazWyspy - w jednym działa timer, a drugi zajmuje się wyświetlaniem (dlatego na konsoli widać działanie timera a na panelu nie).
Zrób tak jak Ci radziłem.Zrezygnuj z ObrazWyspy sluchacz=new OrazWyspy();, zamiast tego wpisz

Timer t = new Timer(1000, this);

Dzieki wielkie za kazda kolejna odpowiedz :) Jestem poczatkujacym programista Javy dlatego ciezko to idzie.

ActionListener sluchacz = new ObrazWyspy();
Timer t = new Timer(1000, sluchacz);
t.start();  

Jest w klasie głównej i jest wykonywane tylko raz. Później już sie cały czas wykonuje kod który jest w metodzie actionPerformed. To co sugerujesz nie działa. chodzi Ci o to aby te początkowe wywołanie wyglądało tak?

Timer t = new Timer(1000, this);
t.start();  

Tak sie nie da, to powoduje blad. Do Timera musi byc przekazany obiekt typu ActionListener. Wiem gdzie jest blad tylko nie wiem dlaczego. Odnosnie klasy Panel. Jak wstawie linie:

System.out.println(text);

Do setText(String t) to wyswietla sie w konsoli ta wyspa cyklicznie. Natomiast to samo wywołanie:

System.out.println(text);

W metodzie rysujacej
paintComponent(Graphics g)
Nie wyswietla nic, oprocz tesktu tego poczatkowego. Dlatego:

 public void paintComponent(Graphics g) { 
               
            super.paintComponent(g);
                 System.out.println(text);
            
            if(text !=null){   
                g.drawString(text,  WIADOMOSC_X, WIADOMOSC_Y);
            }
        }
 
        public void setText(String t) {
              text = t;
             
        }

Jest na pewno wykonywane tylko raz i metoda panel.repaint(); po prostu nie działa. Tylko dlaczego?

0

Umieść ten fragment

Timer t = new Timer(1000, this);
t.start(); 

w konstruktorze klasy ObrazWyspy

0
bogdans napisał(a)

Umieść ten fragment

Timer t = new Timer(1000, this);
t.start(); 

w konstruktorze klasy ObrazWyspy

Zrobiłem tak jak radziłeś, wstawiłem podany przez Ciebie kod do konstruktora klasy ObrazWyspy. Tylko nie wiem do czego zmierzasz więc nie wiem co ma być w klasie głównej (main), jak zostawię:

ActionListener sluchacz = new ObrazWyspy();
Timer t = new Timer(1000, sluchacz);
t.start();   

To jest efekt taki sam jak wcześniej.

0

Moze to ma cos wspólnego z taka uwaga kompilatora NetBeans:
add @Override annotation
Gdy najadę na metodę:

public void paintComponent(Graphics g) 
0

W ilu miejscach programu występuje kod

new ObrazWyspy();

?

0
bogdans napisał(a)

W ilu miejscach programu występuje kod

new ObrazWyspy();

?

Przeszukuje cały dokument i z pewnością występuje tylko w jednym miejscu, w main. A konstruktor tej klasy wyglada tak:

public ObrazWyspy(){

Timer t = new Timer(1000, (ActionListener)this);
t.start(); 
    }

Rzutowanie na obiekt ActionListener nie ma wpływu na działanie programu, ale zrobiłem je ponieważ wyczytałem ze Timer powinien otrzymywać obiekt tego typu.

0
  
public void actionPerformed(ActionEvent zdarzenie)
{
   //ustawienia początkowe
   if (first_time)
   {
      //to co sie wykonuje przy pierwszy uruchomieniu
      panel= new Panel(); // tu tworzysz panel (nazwa klasy jak wcześniej zauważył @Jacobus jest 
                                    // nieszczęśliwa - łatwo o pomyłkę z klasą java.awt.Panel)
                                    // ale ten panel trzeba gdzieś umieścić - wygląda, że rysujesz na niewidocznym      
                                    // panelu
      first_time = false;
   }

  //obsługa zdarzenia

   calosc=wys1.pobierzWyspe();
   panel.setText(calosc);
   panel.repaint();
   wys1.zmienPolozenie();

}
0
bogdans napisał(a)
  
public void actionPerformed(ActionEvent zdarzenie)
{
   //ustawienia początkowe
   if (first_time)
   {
      //to co sie wykonuje przy pierwszy uruchomieniu
      panel= new Panel(); // tu tworzysz panel (nazwa klasy jak wcześniej zauważył @Jacobus jest 
                                    // nieszczęśliwa - łatwo o pomyłkę z klasą java.awt.Panel)
                                    // ale ten panel trzeba gdzieś umieścić - wygląda, że rysujesz na niewidocznym      
                                    // panelu
      first_time = false;
   }

  //obsługa zdarzenia

   calosc=wys1.pobierzWyspe();
   panel.setText(calosc);
   panel.repaint();
   wys1.zmienPolozenie();

}

Zgadza się, dokadnie tak to wygląda.
Mam klasy Ramka i Panel dziedziczące odpowiednio po JFrame i JPanel, więc dlaczego sądzisz, że rysuję na niewidocznym panelu? Panel się pokazuje i jest w nim przez cały czas wykonywania programy ten sam początkowy tekst("Za sekunde powinna tu byc wyspa"):

class Ramka extends JFrame
 {
    public Ramka()
    {
       setTitle("Wyspa");
       setSize(SZEROKOSC, WYSOKOSC);
       // dołącz panel do ramki
       Panel panel = new Panel();
       Container powZawartosci = getContentPane();
       powZawartosci.add(panel);
    }
    public static final int SZEROKOSC = 800;
    public static final int WYSOKOSC = 800;
 }


class Panel extends JPanel { 
    
         public void setText(String t) {
              text = t;
          
        }
         
    public void paintComponent(Graphics g) { 
               
            super.paintComponent(g);
             if(text !=null){  
                g.drawString(text,  WIADOMOSC_X, WIADOMOSC_Y);
             }
        }

      
public static final int WIADOMOSC_X = 75;
public static final int WIADOMOSC_Y = 100;
private static String text = "Za sekunde powinna tu byc wyspa";
        
}
0

Ręce opadają.

class Ramka extends JFrame
 {
    public Ramka()
    {
       setTitle("Wyspa");
       setSize(SZEROKOSC, WYSOKOSC);
       // dołącz panel do ramki
       Panel panel = new Panel(); // tu tworzysz panel
       Container powZawartosci = getContentPane();
       powZawartosci.add(panel); // tu go dodajesz do ramki i ten panel jest widoczny
    }
    public static final int SZEROKOSC = 800;
    public static final int WYSOKOSC = 800;
 }
 if (first_time)
   {
      //to co sie wykonuje przy pierwszy uruchomieniu
      panel= new Panel(); //  tu tworzysz nowy panel, który jest niewidoczny
                                    //  i na rzecz tego panelu wywołujesz metody
                                    //  panel.setText(calosc); oraz
                                    // panel.repaint();
 
                                    
      first_time = false;
   }

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