[Java] Custom Shape maken

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Ik ben bezig om een simpel grafisch dominospel te maken en ik wil graag voor de dominostenen gebruik maken van een Shape. Een dominosteen is eigenlijk niks meer dan een rectangle2d met wat rondjes erin. Dus lijkt het me handig om een subclass van rectangle2d te gebruiken.

Om mijn vraag even zo simpel mogelijk te houden wil ik op dit moment graag het volgende bereiken:

Afbeeldingslocatie: http://img820.imageshack.us/img820/9005/shapel.png
Een rechthoek met een rondje erin zoals je ziet.

Ik maak gebruik van JPanel om in te tekenen, ik override de paintComponent methode, en dmv graphics2d.draw(shape) zijn alle standaard shapes makkelijk te tekenen, so far so good.

Waar ik echter niet uitkom is, hoe maak je een subclass van een bestaande shape als rectangle2d, zodat wanneer je graphics2d.draw(dominoSteen) aanroept, er een dominosteen getekend wordt?

Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Lijkt me dat je moet inheriten van Shape, en dan de juiste methods moet implementeren.

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Snake schreef op zondag 20 maart 2011 @ 20:05:
Lijkt me dat je moet inheriten van Shape, en dan de juiste methods moet implementeren.
Maar dan bouw je echt helemaal from scratch een nieuwe shape zeg maar, is er geen mogelijkheid om dit met een subclass van rectangle te doen?

Acties:
  • 0 Henk 'm!

  • Amras
  • Registratie: Januari 2003
  • Laatst online: 01-10 12:59
tabakje schreef op zondag 20 maart 2011 @ 20:33:
[...]


Maar dan bouw je echt helemaal from scratch een nieuwe shape zeg maar, is er geen mogelijkheid om dit met een subclass van rectangle te doen?
Dan moet je afleiden van Rectangle en in de OnPaint (o.i.d.) het tekenen van de Rectangle uitbreiden met een rondje. Ben niet meer zo thuis in Java, maar zou moeten lukken. Wel zorgen dat je dus de super methode aanroept, zodat je zelf geen Rectangle hoeft te tekenen.

Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14-10 16:44
Als je de Rectangle2D wil overriden, kun je het beste de getPathIterator functie implementeren. Je krijgt dan het volgende idee:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Domino extends Rectangle2D.Double {
    private final Ellipse2D.Double ellipse;

    public Domino(double x, double y, double width, double height) {
        super(x, y, width, height);

        double diameter = Math.min(width, height) * 0.5;
        ellipse = new Ellipse2D.Double(x + (0.5 * width) - (0.5 * diameter),
                                       y + (0.5 * height) - (0.5 * diameter),
                                       diameter, diameter);
    }

    public PathIterator getPathIterator(final AffineTransform at) {
        return new PathIterator() {
            private boolean usingRect = true;
            private final PathIterator rectIt = Domino.super.getPathIterator(at);
            private final PathIterator elliIt = ellipse.getPathIterator(at);

            public boolean isDone() {
                // Algoritme om te schakelen
            }

            public void next() {
                if (usingRect) {
                    rectIt.next();
                } else {
                    elliIt.next();
                }
            }

            // etc. voor de andere functie
        };
    }
}

Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Marcj schreef op zondag 20 maart 2011 @ 22:08:
Als je de Rectangle2D wil overriden, kun je het beste de getPathIterator functie implementeren. Je krijgt dan het volgende idee:
Ah kijk, daar zal ik me eens in gaan verdiepen, thnx.

Acties:
  • 0 Henk 'm!

  • bronce
  • Registratie: Januari 2011
  • Laatst online: 23:00
Je zou ook gewoon een leeg rechthoek kunnen tekenen en dan Points bij houden waar mogelijk een rondje moet komen. En dan kun je een functie maken die dan een rondje tekent op een aantal van de 6 Points van een zijde van een dominosteen.

Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Na lang nadenken heb ik er het volgende van gebakken, ik kon niet zo heel veel vinden over het implementeren van een PathIterator klasse, dus heb ik een beetje m'n eigen logica erop losgelaten, aangezien ik nog niet lang zo programmeer (1e jaars student) zal het mogelijk niet kloppen.

Ik krijg de volgende foutmelding wanneer ik de Domino shape probeer te tekenen:
Exception in thread "AWT-EventQueue-0" sun.dc.pr.PRError: appendLine: unexpected

zie ook deze screenshot:
Afbeeldingslocatie: http://img713.imageshack.us/img713/6613/schermafbeelding2011032j.png

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class Domino extends RoundRectangle2D.Double
{
    private static final double TILE_HEIGHT = 50;
    private static final double TILE_WIDTH = 25;
    private static final double TILE_CORNER = 10; // de grootte van de afronding van de hoeken van de rectangle
    private final Ellipse2D.Double ellipse; 
    private Value firstValue;
    private Value secondValue;
    
    public Domino(double x, double y, Value first, Value second) 
    {
        super(x, y, TILE_WIDTH, TILE_HEIGHT, TILE_CORNER, TILE_CORNER); 
        double diameter = Math.min(TILE_WIDTH, TILE_HEIGHT) * 0.25; 
        ellipse = new Ellipse2D.Double(x + (0.5 * TILE_WIDTH) - (0.5 * diameter), 
                                       y + (0.5 * TILE_HEIGHT) - (0.5 * diameter), 
                                       diameter, diameter);
        firstValue = first;
        secondValue = second;
    }
   
    
    public PathIterator getPathIterator(final AffineTransform at) { 
        return new PathIterator() { 
            private boolean usingRect = true; 
            private final PathIterator rectIt = Domino.super.getPathIterator(at);
            private final PathIterator elliIt = ellipse.getPathIterator(at); 

            public boolean isDone() { 
                if(rectIt.isDone() && elliIt.isDone()) {
                    return true;
                }
                if(!rectIt.isDone()) {
                    next();
                    return false;
                }
                else {
                    usingRect = false;
                    next();
                    return false;
                }
            } 

            public void next() { 
                if (usingRect) { 
                    rectIt.next(); 
                } else { 
                    elliIt.next(); 
                } 
            }

            public int getWindingRule() {
                if(usingRect)
                    return rectIt.getWindingRule();
                else
                    return elliIt.getWindingRule();
            }

            public int currentSegment(float[] coords) {
                if(usingRect)
                    return rectIt.currentSegment(coords);
                else
                    return elliIt.currentSegment(coords);
            }

            public int currentSegment(double[] coords) {
                if(usingRect)
                    return rectIt.currentSegment(coords);
                else
                    return elliIt.currentSegment(coords);
            }
        }; 
    } 

Acties:
  • 0 Henk 'm!

  • Mammon
  • Registratie: December 2006
  • Laatst online: 24-09 03:04
Volgens mij moeten die calls naar next() weg uit isDone().

Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Mammon schreef op woensdag 23 maart 2011 @ 16:54:
Volgens mij moeten die calls naar next() weg uit isDone().
Ja, klopt! ik had ze al gevonden, thx.

Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
Wanneer ik mijn nieuwe shape teken dmv

g2d.setColor(Color.black)
g2d.fill(Domino)

Afbeeldingslocatie: http://img156.imageshack.us/img156/4403/domino.png
dan is de rectangle zwart en circel is open, dus niet gefillt. is het mogelijk om in een shape klasse aan te geven dat ie altijd met een bepaalde kleur gefillt moet worden?
Zodat ik bijv. kan instellen dat de rectangle altijd zwart is, en de ellipsen geel oid.

[ Voor 13% gewijzigd door tabakje op 24-03-2011 09:29 ]


Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
schopje

Acties:
  • 0 Henk 'm!

  • MacWolf
  • Registratie: Januari 2004
  • Laatst online: 06-09-2024
Al heel wat jaren geen Java meer gedaan, maar volgende kom ik tegen op internet.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   public void paintComponent(Graphics g)
   {
      Graphics2D g2 = (Graphics2D) g;

      // draw a rectangle

      double leftX = 100;
      double topY = 100;
      double width = 200;
      double height = 150;

      Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
      g2.setPaint(Color.RED);
      g2.fill(rect);

      // draw the enclosed ellipse

      Ellipse2D ellipse = new Ellipse2D.Double();
      ellipse.setFrame(rect);
      g2.setPaint(new Color(0, 128, 128)); // a dull blue-green
      g2.fill(ellipse);
   }


Op basis daarvan zou ik het volgende doen:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Domino(double x, double y, double width, double height) { 
        Graphics2D g2 = (Graphics2D) g;

        super(x, y, width, height); 
        g2.setPaint(new Color(0, 0, 0)); // zwart        
        g2.fill(this); // of 'self', mijn Java is beetje verroest :P

        double diameter = Math.min(width, height) * 0.5; 
        ellipse = new Ellipse2D.Double(x + (0.5 * width) - (0.5 * diameter), 
                                       y + (0.5 * height) - (0.5 * diameter), 
                                       diameter, diameter); 

        g2.setPaint(new Color(255, 255, 255)); // wit
        g2.fill(ellipse);
    } 


Op deze manier handelt de Domino klasse zelf het inkleuren af en hoe je dat niet meer te regelen in de aanroep.

Microsoft Windows: A thirty-two bit extension and graphical shell to a sixteen-bit patch to an eight-bit operating system originally coded for a four-bit microprocessor which was written by a two-bit company that can't stand one bit of competition.


Acties:
  • 0 Henk 'm!

  • tabakje
  • Registratie: Maart 2005
  • Laatst online: 06-10 23:40
MacWolf schreef op zaterdag 26 maart 2011 @ 04:41:
Al heel wat jaren geen Java meer gedaan, maar volgende kom ik tegen op internet.

Java:
1
   ...


Op deze manier handelt de Domino klasse zelf het inkleuren af en hoe je dat niet meer te regelen in de aanroep.
Thnx man, ik heb nu een aparte draw() en fill() methode gemaakt in de Domino klasse, hiermee kan hij zichzelf tekenen, dus je roept nou Domino.fill(graphics2D) aan ipv graphics2D.fill(Domino). Op deze manier kan die worden getekend op het moment dat ik dat wil, ipv meteen wanneer die aangemaakt word.

Alleen wordt de overschreven getPathIterator methode nou niet meer gebruikt, maar dat lijkt me op zich geen probleem.

hier wat code (ps. Domino heet bij mij een Tile)

Mocht iemand nog op of aanmerkingen hebben dan hoor ik het graag :)

Tile:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Tile extends RoundRectangle2D.Double
{
    private static final double TILE_HEIGHT = 26;
    private static final double TILE_WIDTH = 52;
    private static final double TILE_CORNER = TILE_WIDTH/5; // de grootte van de afronding van de hoeken van de rectangle
    private ArrayList<Shape> shapes;
    private Value firstValue;
    private Value secondValue;
    
    /**
     * CONSTRUCTOR
     * @param x Coordinaat
     * @param y Coordinaat
     * @param first Eerste waarde
     * @param second Tweede waarde
     */
    
    public Tile(double x, double y, Value first, Value second) 
    {
        super(x, y, TILE_WIDTH, TILE_HEIGHT, TILE_CORNER, TILE_CORNER);         
        shapes = new ArrayList<Shape>();
        firstValue = first;
        secondValue = second;
        shapes.add(new Line2D.Double(x+(TILE_WIDTH/2), y+(TILE_HEIGHT/8), x+(TILE_WIDTH/2), y+(TILE_HEIGHT)-(TILE_HEIGHT/8)));
        shapes.addAll(createEllipses());          
    }

    /**
     * Tile gebruikt deze methode om zichzelf te drawen
     * @param g2d het Graphics2D object waarmee getekend moet worden
     */
    public void draw(Graphics2D g2d)
    {       
        g2d.setColor(Color.black);
        g2d.draw(this);       
        g2d.draw(shapes.get(0));  // dit is de verticale lijn in het midden
        for(Shape shape: shapes) {            
            g2d.draw(shape);
        }     
    }
    
    /**
     * Tile gebruikt deze methode om zichzelf te fillen
     * @param g2d het Graphics2D object waarmee getekend moet worden
     */
    public void fill(Graphics2D g2d)
    {        
        g2d.setColor(Color.black);
        g2d.fill(this);
        g2d.setColor(Color.red);
        g2d.draw(shapes.get(0)); // dit is de verticale lijn in het midden
        for(Shape shape: shapes) {            
            g2d.fill(shape);
        }     
    }


JPanel in GUI:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class TablePanel extends JPanel
    {
        private int width, height;
        private Graphics2D graphics;
        private Image panelImage;
        
        public TablePanel()
        {
            width = 1060;
            height = 600;
            setBorder(new LineBorder(Color.BLACK, 1));
            setBackground(backgroundColor);
        }
        
        public Dimension getPreferredSize()
        {
            return new Dimension(width, height);
        }
        
        
        
        public void paintComponent (Graphics g) 
        {
            super.paintComponent (g);
            
            if(graphics == null) {
                panelImage = createImage(width, height);  
                graphics = (Graphics2D)panelImage.getGraphics();
                graphics.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                graphics.setColor(backgroundColor);
                graphics.fillRect(0, 0, width, height);
            }           
            
            frame.pack();
                        
            g.drawImage(panelImage, 0, 0, null);
        }
        
                   
        public void draw()
        {
            
            Tile tile1 = new Tile(100, 100, Value.FOUR, Value.SIX);
            Tile tile2 = new Tile(100, 150, Value.THREE, Value.BLANK);
            Tile tile3 = new Tile(100, 200, Value.BLANK, Value.ONE);
            Tile tile4 = new Tile(100, 250, Value.ONE, Value.FIVE);
            Tile tile5 = new Tile(100, 300, Value.THREE, Value.TWO);
            Tile tile6 = new Tile(100, 350, Value.SIX, Value.BLANK);
            Tile tile7 = new Tile(100, 400, Value.FIVE, Value.ONE);
            Tile tile8 = new Tile(100, 450, Value.FOUR, Value.TWO);                     
            
            tile1.fill(graphics);
            tile2.fill(graphics);
            tile3.draw(graphics);
            tile4.draw(graphics);
            tile5.fill(graphics);
            tile6.fill(graphics);
            tile7.fill(graphics);
            tile8.fill(graphics);

        }
}


resultaat:
Afbeeldingslocatie: http://img834.imageshack.us/img834/7854/domino2.png
Pagina: 1