Dziedziczenie po JFrame i implementacja Runnable a tworzenie nowych wątków jako obiekty klasy.

0

Hi,

chciałem napisać program, który po utworzeniu nowego obiektu klasy ThreadFrame będzie tworzył nowy wątek rysujący ovale na formie.
Problem pojawia się gdy Tworzę nowy obiekt klasy ThreadFrame - tworzę za pewne nowe okno. Chciałbym jakoś
rozwiązać ten problem jednak nic potrafię wymyślić jak.

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
 
class ThreadFrame extends JFrame implements Runnable {
 
     public void run() {
         while(true) {
              Random r = new Random();
              x = r.nextInt(200);
              y = r.nextInt(200);
               try {
                    Thread.sleep(180);
                    repaint();
               } catch (InterruptedException ex) {}
         }
     }
 
     public void paint(Graphics g) {
          if (c == "RED")
               g.setColor(Color.RED);
          if (c == "GREEN")
               g.setColor(Color.GREEN);
          g.fillOval(x, y, 15, 15);
     }
 
     public ThreadFrame(String color) {
          setSize(300, 250);
          setTitle("Threadowo :D");
          c = color;
     }
     private int x;
     private int y;
     public String c;
}
public class Main {
 
    public static void main(String[] args) {
        ThreadFrame x = new ThreadFrame("RED");
        x.setVisible(true);
        x.run();
        ThreadFrame y = new ThreadFrame("GREEN");
        y.setVisible(true);
        y.run();
    }
}

Próbowałem rozbić tworzenie klasę na dwie w jeden tworzyć ramkę a w drugiej nań rysować jednak nie potrafię połączyć tych dwu klas aby obiekt klasy powiedzmy Ball rysował na ramce pochodzącej z innego obiektu.

Oto efekt moich prób:

package javaapplication29;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Ball extends JPanel {
     public Ball(int arg) {
          flag = arg;
          setVisible(true);
          repaint();
     }
     public void paint(Graphics g) {
          Random r = new Random();
          x = r.nextInt(280);
          y = r.nextInt(280);

         if(flag == 1)
              g.setColor(Color.RED);
         if(flag == 2)
              g.setColor(Color.GREEN);
         g.fillOval(x, y, 15, 15);
     }
     private int flag;
     private int x;
     private int y;
}
class ThreadFrame extends JFrame implements Runnable{
     public ThreadFrame() {
          setSize(300, 300);
          setTitle("Cos");
     }
     public void createThread(int ar) {
          arg = ar;
          x = new Ball(arg);
     }
     public void run() {
        while(true) {
               try {
                    Thread.sleep(250);
                    createThread(arg);  
               } catch (InterruptedException ex) {}
        }
     }
     public Ball x;
     public int arg;
}
public class Main {
    public static void main(String[] args) {
       ThreadFrame x = new ThreadFrame();
       x.setVisible(true);
       x.createThread(1);
       x.createThread(2);
    }
}

Niestety próby się nie powiodły.
Będę wdzięczny za pomoc!

Pozdrawiam!

0

Po co okno ma implementować Runnable? Co gorsza, w swoim kodzie nie tworzysz żadnego wątku.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Frame;
import javax.swing.Timer;

public class Main {

    public static void main(String[] args) {
        final ThreadFrame x = new ThreadFrame("RED");
        x.setVisible(true);
        
        new Timer(180, new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                x.doSth();
            }
        }).start();
    }

}

class ThreadFrame extends JFrame {

    private int x;
    private int y;
    public String c;
    private Random r;
    
    public ThreadFrame(String color) {
        setSize(300, 250);
        setTitle("Threadowo :D");
        c = color;
        r = new Random();
    }
    
    public void doSth() {
        x = r.nextInt(200);
        y = r.nextInt(200);
        repaint();
    }
    
    public void paint(Graphics g) {
        if ("RED".equals(c))
            g.setColor(Color.RED);
        if ("GREEN".equals(c))
            g.setColor(Color.GREEN);
        g.fillOval(x, y, 15, 15);
    }

}

Timery są w sposób bezpieczny dla Swinga odpalane z jego wątku.

0

Hi, dziękuję za odpowiedzi i porady.
Problem w tym, że chciałem osiągnąć coś nieco innego: chciałbym mieć możliwość utworzenie dwu wątków rysujących jeden na czerwono drugi na zielono.
Masz może jakieś pomysły ?

Pozdrawiam!

0
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Frame;
import javax.swing.Timer;
 
public class Main {
 
    public static void main(String[] args) {
        final ThreadFrame x = new ThreadFrame("RED");
        x.setVisible(true);
 
        new Timer(180, new Rysujacy(x, "GREEN")).start();
        new Timer(180, new Rysujacy(x, "RED")).start();
    }
 
}

class Rysujacy implements ActionListener {

    private ThreadFrame frame;
    private String color;

    public Rysujacy(ThreadFrame frame, String color) {
        this.frame = frame;
        this.color = color;
    }

    public void actionPerformed(ActionEvent evt) {
        frame.setColor(color);
        frame.doSth();
    }

}
 
class ThreadFrame extends JFrame {

    private String c;
    // ...
 
    public ThreadFrame(String color) // ...
 
    public void doSth() // ...

    public void setColor(String color) {
        c = color;
    }
 
    public void paint(Graphics g) // ...
 
}
0

Hi, dziękuję wszystko śmiga jak należy. Chciałem jednak przerobić ten program na kształt tego jak robimy to na zajęciach.


import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;

class ThreadFrame extends JFrame {
     public ThreadFrame() {
          setSize(300, 300);
          setTitle("Thread!");
     }
     public void setColor(int c) {
          color = c;
     }
     public void paint(Graphics g) {
          if (color == 1)
               g.setColor(Color.RED);
          else if (color == 2)
               g.setColor(Color.GREEN);
          else
               g.setColor(Color.BLUE);
          g.fillOval(x, y, 15, 15);
     }
     public void newThread() {
          Random r = new Random();
          x = r.nextInt(280);
          y = r.nextInt(280);
          repaint();
     }

     private int color;
     private int x;
     private int y;
}
class Draw implements Runnable {
     public Draw(ThreadFrame f, int color) {
          frame = f;
          frame.setColor(color);
     }
     private ThreadFrame frame;

     public void run() {
          while(true) {
               try {
                    Thread.sleep(180);
               } catch (InterruptedException ex) {}
              frame.newThread(); 
          }
     }
}
public class Main {
    public static void main(String[] args) {
         ThreadFrame x = new ThreadFrame();
         x.setVisible(true);
        Draw p1 = new Draw(x, 1);
        Draw p2 = new Draw(x, 2);
        p1.run();
        p2.run();   
    }
}

Masz może pomysł dlaczego ten kod uruchamia tylko jeden wątek?
Pozdrawiam!

0

Nie uruchamia żadnego wątku. Implementujesz tylko Runnable i wołasz run(), żadnej magii w tym nie ma. W najprostszy sposób wątek uruchamiasz tak:

new Thread(p1).start();
new Thread(p2).start();
0

Hi, dziękuję za pomoc.
Problem w tym, że uruchamia mi tylko wątek dla p2.

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;

class ThreadFrame extends JFrame {
     public ThreadFrame() {
          setSize(300, 300);
          setTitle("Thread!");
     }
     public void setColor(int c) {
          color = c;
     }
     public void paint(Graphics g) {
           System.out.println(color);
          if (color == 1)
               g.setColor(Color.RED);
          else
               g.setColor(Color.BLUE);
          g.fillOval(x, y, 15, 15);
     }
     public void newThread() {
          Random r = new Random();
          x = r.nextInt(280);
          y = r.nextInt(280);
          repaint();
     }

     private int color;
     private int x;
     private int y;
}
class Draw implements Runnable {
     public Draw(ThreadFrame f, int color) {
          frame = f;
          frame.setColor(color);
     }
     private ThreadFrame frame;

     public void run() {
          while(true) {
               try {
                    Thread.sleep(180);
               } catch (InterruptedException ex) {}
              frame.newThread(); 
          }
     }
}

public class Main {
    public static void main(String[] args) {
         ThreadFrame x = new ThreadFrame();
         x.setVisible(true);
        Draw p1 = new Draw(x, 1);
        Draw p2 = new Draw(x, 2);

        new Thread(p1).start();
        new Thread(p2).start();
    }
}

Masz może pomysł co zrobiłem zle?

Pozdrawiam!

0

Nie tylko dla p2. Działania nie sprawdziłem, ale zapewne pomyślałeś tak dlatego, że kolor cały czas jest niebieski. W konstruktorze Draw wywołujesz frame.setColor, a potem nigdzie już tego nie zmieniasz, więc w momencie utworzenia p2, x.color cały czas równy jest 2. Przenieś linijkę frame.setColor(color); z konstruktora nad frame.newThread(); w run().
No i pamiętaj, że Swing nie jest bezpieczny wątkowo, więc taki kod może się posypać, tym bardziej, że nie synchronizujesz nawet swoich wątków. Bez względu na to, jak robicie to na zajęciach, normalnie powinieneś jednak zrobić użytek z Timera / SwingUtilities.invoke...()

0

Hi, dziękuję za odpowiedzi - działa.
Co do SwingUtilities.invoke...() :
na wykładach o tym nie mieliśmy, wszystko wstawiamy w maina.
Jako, że masz dużo większą wiedzę ode mnie zastosuję się do Twojej rady.
Dziękuję raz jeszcze za poświęcony czas i pozdrawiam!

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