Swing Grafika

0

Czy w poniższym programie po stworzeniu obiektów klasy rysowanie możliwe jest narysowanie dwukrotnie tego samego obiektu ( tak zeby były widoczny dwa razy )? W poniższym przykładzie mamy dwa obiekty klasy rysowanie po dodaniu 1 obiektu następnie 2 i uzyciu funkcji reapint na 2 widoczny jest tylko jeden kwadrat ten ostatni po odświeżeniu . Nie rozumiem czemu tak się dzieje czy ktoś mógłby pomóc ? Działa to tak jak by po kazdym dodaniu panelu rysowania tło się odświeżało a chciałbym tego uniknąć .

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


class Solution   {
       int x,y;      

        
        public static void main (String[]args){
            Solution ala=new Solution();
            ala.start();
        }

        public void start(){
            JFrame ramka =new JFrame("Testowe");
            ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)  ;             
            
           x=1;y=1;
           rysowanie rys1=new rysowanie();  
                 
            ramka.add(rys1);

            x=51;y=1;
            rysowanie rys2=new rysowanie();
           
            ramka.add(rys2);   
         

            x=200;y=200;
            rys2.repaint();      
            
            ramka.setSize(500,500);            
            ramka.setVisible(true);                        
          
            }


    class rysowanie extends JPanel{

        public rysowanie (){
        }

        @Override
        public void paintComponent(Graphics g){
            g.setColor(Color.blue);
            g.drawRect(x,y,100, 100);
     }   
    }
}

2

Rysujesz 2 razy ale w tym samym miejscu :]
Zobacz sobie kiedy metoda paintComponent jest wołana.

0

Nie rozumiem współrzędne x i y mają zmienia wartości przy każdym tworzeniu obiektu rysowanie . Generalnie program rysuje 3 kwadraty a widoczny jest tylko ten 3 .Czy mógłbyś mi bardziej łopatologicznie wskazać błąd bo chyba nie do końca rozumiem jego istotę .

2

A sprawdziłeś kiedy jest wołana metoda paintComponent tak jak napisałem?
Nie tam gdzie dodajesz metodą add ale już po wyjściu z metody start. Bierzesz te same globale x i y za każdym razem, takie jak ustawiasz dla ostatniego kwadratu.

1
szweszwe napisał(a):

A sprawdziłeś kiedy jest wołana metoda paintComponent tak jak napisałem?
Nie tam gdzie dodajesz metodą add ale już po wyjściu z metody start. Bierzesz te same globale x i y za każdym razem, takie jak ustawiasz dla ostatniego kwadratu.

Kolego zaoszczędziłeś mi zapewne parę godzin ślepego patrzenia w ten kod i szukania odpowiedzi . Wiedz że jestem ci wdzięczny . Na początku liczba elementów które trzeba zrozumieć trochę przytłacza i taka pomoc jest nieoceniona i pozwala na szybsze zrozumienie .

0

A możesz mi podpowiedzieć jak wykonać 3 wywołania a nie jedno tak żeby były widoczne te 3 kwadraty . Czy da się jakoś wywołać paintComponent 3 razy z poziomu metody start . Jedyne co udało mi się stworzyć ale to jest rozwiązanie bez sensu i nie dokońca rozumiem jego działanie .

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


class Solution   {
       int x=30,y=40;
      
       

        
        public static void main (String[]args){
            Solution ala=new Solution();
            ala.start();
        }

        public void start(){
            JFrame ramka =new JFrame("Testowe");
            ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)  ;

            ramka.setSize(500,500);            
            ramka.setVisible(true);  
            
          
            rysowanie rys2=new rysowanie();
           
            ramka.add(rys2);   
         
           
         
               
            for(int i=0;i<3;i++){
                x=x+60;
                y=y+60;
    
                rys2.repaint();
    
                try{
                    Thread.sleep(50);
                }catch(Exception ex){}
            }                     
          
            }


    class rysowanie extends JPanel{

        public rysowanie (){
        }

        @Override
        public void paintComponent(Graphics g){
            g.setColor(Color.blue);
            g.fillRect(x,y,100, 100);
        }    
    
    }
}


Dlaczego repain() w połaczeniu Thread.sleep() zdaje egzamin . Ale już sam repaint() nic nie daje ???? Nie rozumiem jak działa ten painComponent zupełnie nie trzeba go wywołać nie ma się zupełnie nad tym kontroli w ksiązce napisali tylko ze uruchamia się automatycznie w trakcie wyświetlania okna (nic mi to nie mówi) . Gdyby działał jak normalna metoda było by to czytelniejsze prostsze i przede wszystkim przyjemne narzędzie a tak mamy bubla przez którego wyłysieje :) :) .

1

Powiedzmy, że metoda repaint jest wołana za każdym razem, gdy zmienisz rozmiar okienka (przeciąganiem).
Za każdym przeciągnietym "pikselem" widok komponentu byłby przeliczany - to mogą być stosunkowo ciężkie operacje, np. przeskalowywanie obrazka, cokolwiek.
Jeśli zrobisz z repaint operację blokującą (czekającą aż się wszystko przerysuje), czyli jak to napisałeś Gdyby działał jak normalna metoda, to użytkownik musiałby czekać aż wszystko się wyrenderuje i dopiero wtedy móc przesunąć o kolejny "pixel".
Żeby temu zapobiec repaint jest nieblokujący. Po wywołaniu przerysowanie nastąpi w bliżej nieokreślonym kiedyś.

Ponadto przeliczanie widoku przy każdym wywołaniu repaint, jeśli wywołujesz je n razy na sekundę,nie jest uzasadniowe. Jak przeciągasz okienko, to interesuje cię widok po zakończeniu przeciągania. Oczywiście fajnie jak w między czasie się coś pokazuje, ale generalnie chcesz, żeby po zakończeniu przeciągania pojawił się przeliczony widok w miarę szybko. Nie chcesz czekać aż powoli wszystkie możliwe widoki powstałe przy przeciąganiu powoli się wyrenderują. Dlatego repaint jest wykonywany co jakiś czas, jak mu się zachce.

Ty w twojej metodzie paint robisz bardzo podobnie: Wywołujesz metodę repaint trzy razy w przeciągu kilku milisekund. Swing nie ma szans tak szybko przeliczyć nowego widoku, a ponadto użytkownik nic by nie zobaczył, dlatego widzisz tylko ostatnie wywołanie repaint.

Żeby uzyskać to co chcesz, musisz "zablokować" repaint, poczekać aż się wykona, i dopiero wtedy wywołać następny repaint. Ty zrobiłeś to za pomocą Thread.sleepa.

0

Wielkie dzięki teraz jest jasne . Udało mi się też pokonać ten paintComponent (zmusić go do wywołania się dwa razy) ustawiłem Layout na null i wszystko recznie rozmieszczam za pomocą setBounds().

Dzieki temu dwa obiekty klasy rysowanie rysują dwa odzielne kwadraty a ich współrzędne sa dalej składowymi klasy głównej(i moge modyfikowac ich wartość) tyle że nie przekazywane bezpośrednio do podklasy rysowanie. Są umieszczane jako parametr setBounds().W sumie nie o to mi chodziło ale powiedzmy że ten półśrodek spełnia moje oczekiwania .

A teraz pytanie czy dało by się w prostszy sposób tego dokonać ( narysować dwa razy kwadrat klasy rysowanie ) tak zeby skladowe klasy głównej x i y odpowiadały za ich współrzędne? Tzn. g.fillRect(x,y,100, 100); ? Piszę prosty program bedący odpowiednikiem gry w statki i taka funkcjonalność jest mi potrzebna .

Ja niestety nie mam pomysłu i zmuszony jestem uzywac setBounds na setLayout(null) .


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


class Solution   {
       int x=30,y=40;
      
       

        
        public static void main (String[]args){
            Solution ala=new Solution();
            ala.start();

          
            
            
        }

        public void start(){
            JFrame ramka =new JFrame("Testowe");
            ramka.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)  ;

          
          
            rysowanie rys2=new rysowanie();
            rys2.setBounds(x,y,100,100);
           
            ramka.add(rys2);   

            x=100;y=100;

            rysowanie rys1=new rysowanie();
            rys1.setBounds(x,y,100,100);
            ramka.add(rys1);
            
         
           
         
           

            ramka.setLayout(null);
            ramka.setSize(500,500);            
            ramka.setVisible(true);    
                     
          
            }


   class rysowanie extends JPanel{

        public rysowanie (){
        }

        @Override
        public void paintComponent(Graphics g){
            g.setColor(Color.blue);
            g.fillRect(0,0,100, 100);
        }
    
    
    
    
    
    }
}










0

A nie możesz zrobić tak, że zamiast jakiejś dziwacznej klasy rysowanie zrobisz sobie klasę Kwadrat która będzie miała pola x i y.
Potem zamiast:
rysowanie rys2=new rysowanie();
Robisz sobie:
Kwadrat kwadrat = new Kwadrat(x , y);
gdzie przekazujesz odpowiednie wartości do konkretnego obiektu klasy a w metodzie paintComponent kwadrat używa swoich zmiennych x i y które przekazałeś w tym konstruktorze.

To, że GB wyszła z UE nie oznacza, że kod powinieneś pisać po polsku. Więc będzie Square czy tam Ship.

0

Ok posłuchałem twych rad. Teraz faktycznie to lepiej wygląda. Ale nie udało się przeskoczyć wywoływania painComonentu (tzn zmuszony jestem dalej uzywać setBounds() ). Nie mam pojęcia jak to napisać inaczej ale współrzędne podawane sa w konstruktorze tak jak radziłeś a setBound podaje ze stałymi parametrami ( " setBounds(0,0,200,200) " ) wszystko teraz ma ręce i nogi .

Przy czym nie rozumiem jednej rzeczy skoro wymiary kwadratu są 100 na 100 to czemu w setBounds zawsze trzeba podać wartość dwa razy większą niż ta w paintComponencie :)

Dzieki programowaniu mam o czym rozmyślać będąc w pracy :P


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


class Solution   {
        
        public static void main (String[]args){
            Solution ala=new Solution();
            ala.start();   
            
            
        }

        public void start(){
            JFrame frame =new JFrame("Test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)  ;          
          
            field f1=new field(90,30);   
            f1.setBounds(0,0,200,200);
            frame.add(f1) ;
         
            field f2=new field(90,132);  
            f2.setBounds(0,0,200,200);          
            frame.add(f2);   

          
            frame.setSize(500,500);            
            frame.setVisible(true);    
                     
          
            }


   class field extends JPanel{
    
       int x;
       int y;   


        public field (int x,int y){
            this.x=x;
            this.y=y;
            
        }

        @Override
        public void paintComponent(Graphics g){
            g.setColor(Color.blue);
            g.fillRect(x,y,100, 100);
            this.repaint();
        }   
    
    }
}

Osoba która narysuje dwa kwadraty bez uzycia setBounda(); stanie się moim osobistym Jezusem programowania .

0

Dzięki koledze szweszwe udało napisać się logikę do wyświetlania planszy i trafionych pól (dla mojego projektu gra w statki ). Działa to dość prosto rysuje planszę składającą się ze 100 pól planszy i na to nadrysowuje 100 pól pustych strzałów (puste kwadraty w tej samej barwie ). Gdy gracz odda strzał zmieniam parametr setVisible obiektu pełnego kwadraty na false i zostaje tylko ramka .


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


class TestBoard  {
    

    public static void main (String[]args)  {

        TestBoard start=new TestBoard();
        start.startTest();
       

    }

    public void startTest(){
        JFrame frame=new JFrame();
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
       //tablica do przechowywania wypełnionych kafli wody (przed strzałem) i po strzale
       //tablica zawiera  121 pol a potrzeba 100 ale pamietaj olewamy indexy 0 zeby uniknac przesuniec
       //łatwo bedzie sie odniesc do konkretnego obiektu gdyz jego idndex bedzie odpowiadał faktycznemu połozeniu 

       seaField[][]sea=new seaField[11][11];
       shootField[][]shoot=new shootField[11][11];

       int x,y;

       //parametr poczatkowy okresla połozenie planszy w ramce
       //w razie zmiany pamietaj zmień tez wartość w drugiej petli !!!!

       x=5;
       y=5;

        //wypełnienie tablicy 100 obiektami klasy seaField i shoot


       for(int i=1;i<11;i++){
           for(int j=1;j<11;j++){
               sea[i][j]=new seaField(x,y);
               shoot[i][j]=new shootField(x, y);
               sea[i][j].setBounds(0,0,500,500);
               shoot[i][j].setBounds(0,0,500,500);
               x+=32;
           }
                x=5;
                y+=32;
       }

       // wyświetlenie planszy 

       for(int i=1;i<11;i++){
           for(int j=1;j<11;j++){

                
                frame.add(sea[i][j]);
                frame.add(shoot[i][j]);     
                
                
          
        }        
    }
        //przykładowe umieszczenie statku logika rozmieszczania w budowie 
            ships s1=new ships(sea[5][2].x,sea[5][2].y);
            s1.setBounds(0,0,300,300);
            frame.add(s1);


    //PRZYKŁADOWE STRZAŁY !!! DZIAŁA !!!!!

            sea[3][1].setVisible(false);
            sea[5][2].setVisible(false);
            sea[10][10].setVisible(false);  

            
           
        
        frame.setLayout(null);
        frame.setSize(800,700);
        frame.setVisible(true);
    }

       
class seaField extends JPanel{    
        int x;
        int y; 
    public seaField (int x,int y){                 
        this.x=x;
        this.y=y;              
     }         
    public void paintComponent(Graphics g){
             g.setColor(Color.blue);
             g.fillRect(x,y,30, 30);            
     }         
}


class shootField extends JPanel{    
    int x;
    int y;
public shootField (int x,int y){                 
    this.x=x;
    this.y=y;              
 }     
public void paintComponent(Graphics g){
         g.setColor(Color.blue);
         g.drawRect(x,y,30, 30);            
 }    
 
}

class ships extends JPanel{
    
    int x;
    int y;

public ships (int x,int y){                 
    this.x=x;
    this.y=y;              
 } 
    
public void paintComponent(Graphics g){
         g.setColor(Color.black);
         g.fillRect(x,y,30, 30);            
 }    
 
}



 }





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