sabo
sabo

Reputation: 943

How to avoid one dimensional arrays from being reinitialized when paint() method is called

I am creating a program that draws a polygon and fills it. It then displays buttons so the user can move the polygon up, down, left, or right. Right now I am having an issue when I call the repaint() method.

In the paint() method I create a new instance of the class that contains the methods to draw and fill the polygon. Therein lies the reason for my problem. A new instance of the class is created every time that paint() is called so the arrays that I have that contain the coordinates of the points of the polygon are reset to their initial values.

My question is what is the best way to attack this problem? How do I access these methods from the paint() method without creating a new instance? I know everyone is going to say I can use something like "NameOfClass.neededMethod();" which requires me to make many things static and it does not work out as hoped.

I appreciate any pointers.

Here is the code for my class that has the methods that I need access to:

public class FillPolygon
{
    int left_most_edge, right_most_edge, scan = 0;
    double[] xcoord;
    double[][] table = new double[4][200];  //2d array containing: 
                                            //[0][-] -> ymax, [1][-] -> ymin, [2][-] -> dx, [3][-] -> x
    double[] px = {100, 150, 250, 300, 250, 150, 100}; //contains all x coord.
    double[] py = {125, 100, 200, 150, 100, 200, 200}; //contains all y coord.

    public void initializeTable()
    {
        int i, j;

        for (i = 0; i < 4; i++)
        {
            for (j = 0; j < 200; j++)
            {
                table[i][j] = 0;
            }//end for
        }//end for
    }//end initializeTable

    public void upPressed()
    {
        for (int i = 0; i < py.length; i++)
        {
            py[i] -= 5;
        }//end for
        repaint();
    }//end upPressed

    public void downPressed()
    {
        for (int i = 0; i < py.length; i++)
        {
            py[i] += 5;
        }//end for
        repaint();
    }//end upPressed

    public void leftPressed()
    {
        for (int i = 0; i < px.length; i++)
        {
            px[i] -= 5;
        }//end for
        repaint();
    }//end upPressed

    public void rightPressed()
    {
        for (int i = 0; i < px.length; i++)
        {
            px[i] += 5;
        }//end for
        repaint();
    }//end upPressed

    public double max (double x, double y)
    { //determines the greater of two values
        double max;
        if (x > y)
            max = x;
        else
            max = y;
        return max;
    }//end max

    public void edgeInsert(double xStart, double yStart, double xEnd, double yEnd, int number_entered_edges)
    { //inserting edges into the edge table
        int j = number_entered_edges; //removing the - 1 removes line on left side
        double x;

        if (yStart > yEnd)
        {
            table[0][j] = yStart;
            table[1][j] = yEnd;
        }//end if
        else
        {
            table[0][j] = yEnd;
            table[1][j] = yStart;
        }//end else

        if (table[1][j] == xStart)
            x = xStart;
        else
            x = xEnd;

        if (table[0][j] == yStart)
            table[2][j] = -(-(xEnd - xStart) / (yEnd - yStart));
        else
            table[2][j] = -(xEnd - xStart) / (yEnd - yStart);

        table[3][j] = x + table[2][j] / 2;

        help(j);
    }//end edgeInsert

    public void loadTable(int number_vertices, int number_entered_edges,
                    double[] px, double[] py)
    { //take the x and y coordinates and build an edge table based off of them
        int k;
        double xStart, yStart, xEnd, yEnd;

        xStart = px[number_vertices - 1];
        yStart = trunc(py[number_vertices - 1]) + 0.5;

        //start off with no edges in edge table
        number_entered_edges = 0;
        for (k = 0; k < number_vertices; k++)
        {
            xEnd = px[k];
            yEnd = trunc(py[k]) + 0.5;

            if (yStart == yEnd)
            {
                xStart = xEnd;
            }//end if
            else
            {
                //add edge to edge table
                number_entered_edges++;
                edgeInsert(xStart, yStart, xEnd, yEnd, number_entered_edges);

                yStart = yEnd;
                xStart = xEnd;
            }//end else
        }//end for
        scan = (int)trunc(table[1][0]); //start at the top of the polygon
    }//end loadTable

    public void include(int number_entered_edges)
    { //pushing the right most edge
        while ((right_most_edge + 1 < number_entered_edges) && (table[1][right_most_edge + 1] < scan))
        {
            right_most_edge++;
        }//end while
    }//end include

    public void exclude()
    { //excluding edges that we no longer care about
        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            if (table[0][i] < scan)
            {
                left_most_edge++;
                for (int j = i; j >= left_most_edge; j--)
                {
                    table[0][j] = table[0][j - 1];
                    table[2][j] = table[2][j - 1];
                    table[3][j] = table[3][j - 1];
                }//end for
            }//end if
        }//end for
    }//end exclude

    public void help(int i)
    {
        double helpX, helpDX, helpYMax, helpYMin;
        for (int j = i - 1; j >= 0; j--)
        {
            if ((table[1][j] == table[1][j + 1] && table[3][j] > table[3][j + 1]) || table[1][j] > table[1][j + 1])
            {
                helpYMax = table[0][j];
                table[0][j] = table[0][j + 1];
                table[0][j + 1] = helpYMax;

                helpYMin = table[1][j];
                table[1][j] = table[1][j + 1];
                table[1][j + 1] = helpYMin;

                helpDX = table[2][j];
                table[2][j] = table[2][j + 1];
                table[2][j + 1] = helpDX;

                helpX = table[3][j];
                table[3][j] = table[3][j + 1];
                table[3][j + 1] = helpX;
            }//end if
        }//end for
    }//end help

    public void updateX()
    { //increment x based on dx
        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            table[3][i] += table[2][i];
        }//end for
    }//end updateX

    public void sortOnX()
    { //sorting x values from least to greatest in edge table
        int l = 0;
        double t;
        xcoord = new double[right_most_edge - left_most_edge + 1];

        for (int i = left_most_edge; i <= right_most_edge; i++)
        {
            xcoord[l] = table[3][i];
            for(int j = l - 1; j >= 0; j--)
            {
                if (xcoord[j] > xcoord[j + 1])
                {
                    t = xcoord[j];
                    xcoord[j] = xcoord[j + 1];
                    xcoord[j + 1] = t;
                }//end if
            }//end for

            l++;
        }//end for
    }//end sortOnX

    public void fillScan(Graphics g)
    { //determines the line to be drawn for filling
        for (int i = 0; i < xcoord.length; i += 2)
        {
                drawMyHorizontalLine(g, (int)Math.round(xcoord[i]), scan, (int)Math.round(xcoord[i + 1]));
        }//end for
    }//end fillScan

    public double trunc(double num)
    { //trucates the number passed in to remove any decimal
        double rem;
        if ((num % 2) == 0)
            return num;
        else
        {
            rem = num % 2;
            return num - rem;
        }//end else
    }//end trunc

    public void drawMyPolygon(Graphics g)
    { //draws the polygon
        g.setColor(Color.RED);

        g.drawLine((int)px[0], (int)py[0], (int)px[1], (int)py[1]);
        g.drawLine((int)px[1], (int)py[1], (int)px[2], (int)py[2]);
        g.drawLine((int)px[2], (int)py[2], (int)px[3], (int)py[3]);
        g.drawLine((int)px[3], (int)py[3], (int)px[4], (int)py[4]);
        g.drawLine((int)px[4], (int)py[4], (int)px[5], (int)py[5]);
        g.drawLine((int)px[5], (int)py[5], (int)px[6], (int)py[6]);
        g.drawLine((int)px[6], (int)py[6], (int)px[0], (int)py[0]); 
    }//end drawMyPolygon

    public void drawMyHorizontalLine(Graphics g, int x1, int y, int x2)
    { //draws the line for filling
        g.setColor(Color.GREEN);
        g.drawLine(x1, y, x2, y);
    }//end drawMyHorizontalLine

    public void fillMyPolygon(Graphics g, int number_vertices, int number_entered_edges)
    { //calls methods to deal with edge table and fill the polygon
        if (number_entered_edges < 3 || number_entered_edges > 200)
        {
            System.out.println("Polygon size error");
        }//end if
        else
        {
            loadTable(number_vertices, number_entered_edges, px, py);
            while (left_most_edge < number_entered_edges)
            {
                scan++; //move down the screen
                exclude();
                updateX();
                include(number_entered_edges);
                sortOnX();
                fillScan(g);
            }//end while
        }//end else
    }//end fillMyPolygon
}//end FillPolygon

Here is my paint() method that needs access to the methods in the FillPolygon class in order to actually draw to the JFrame:

@Override
public void paint(Graphics g)
{
    FillPolygon f = new FillPolygon();

    jButton1.setVisible(true);
    jButton2.setVisible(true);
    jButton3.setVisible(true);
    jButton4.setVisible(true);
    jButton5.setVisible(true);
    jButton6.setVisible(true);

    //initialize the edge table to all zeroes
    f.initializeTable();

    //begin filling the polygon
    f.fillMyPolygon(g, 7, 7);

    //draw polygon with red outline
    f.drawMyPolygon(g); 
}//end paint

Upvotes: 2

Views: 84

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

In the paint() method I create a new instance of the class that contains the methods to draw and fill the polygon. Therein lies the reason for my problem. A new instance of the class is created every time that paint() is called so the arrays that I have that contain the coordinates of the points of the polygon are reset to their initial values.

Don't do this. The paint method (or better the paintComponent method override of a JPanel) should be for painting and painting only. You shouldn't be creating such instances there, nor should you be changing class state there. Just paint and that's it. Note that 1) painting may be initiated by the system and is not under your completely under your control, and 2) painting is not guaranteed to occur each time you call repaint(), and so if your program logic depends on a painting method, it risks failure.

I know everyone is going to say I can use something like "NameOfClass.neededMethod();" which requires me to make many things static and it does not work out as hoped.

No one who understands your problem fully (and that's not yet me I'm afraid) and who understands OOPs is going to suggest this, trust me.

For more specific help, please show more code, and explain more details of your problem.


Edit

You should not be changing the visibility of buttons in paint. You should not be creating FillPolygon in paint, but rather should do this once in perhaps the class constructor. Also you should always call the super painting method, and should avoid overriding paint, preferring paintComponent. For example:

enter image description here

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.*;

@SuppressWarnings("serial")
public class DrawMovePolygonMain extends JPanel {
   private DrawPolygonPanel drawPolygonPanel = new DrawPolygonPanel();
   private MyMouseListener myMouseListener = new MyMouseListener();

   public DrawMovePolygonMain() {
      drawPolygonPanel.addMouseListener(myMouseListener);

      JPanel buttonPanel = new JPanel();
      buttonPanel.add(createDrawToggleButton());
      for (PolyDirection dir : PolyDirection.values()) {
         buttonPanel.add(new JButton(new DirectionAction(dir)));
      }

      setLayout(new BorderLayout());
      add(drawPolygonPanel, BorderLayout.CENTER);
      add(buttonPanel, BorderLayout.PAGE_END);
   }

   private JComponent createDrawToggleButton() {
      JToggleButton toggleButton = new JToggleButton("Draw Poly Points");
      toggleButton.addItemListener(new ItemListener() {

         @Override
         public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
               drawPolygonPanel.clearPoly();
               drawPolygonPanel.resetPoints();
               myMouseListener.setEnabled(true);
            } else {
               myMouseListener.setEnabled(false);
               Path2D poly = new Path2D.Double();
               List<Point> points = drawPolygonPanel.getPoints();
               if (points == null || points.size() == 0) {
                  return;
               }
               poly.moveTo(points.get(0).getX(), points.get(0).getY());
               for (Point point : points) {
                  poly.lineTo(point.getX(), point.getY());
               }
               poly.closePath();
               drawPolygonPanel.clearPoints();
               drawPolygonPanel.setPoly(poly);
            }
         }
      });
      return toggleButton;
   }

   private class DirectionAction extends AbstractAction {
      private PolyDirection dir;

      public DirectionAction(PolyDirection dir) {
         super(dir.name());
         this.dir = dir;
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         drawPolygonPanel.move(dir);
      }
   }

   private class MyMouseListener extends MouseAdapter {

      private boolean enabled;

      public void setEnabled(boolean enabled) {
         this.enabled = enabled;
      }

      @Override
      public void mousePressed(MouseEvent e) {
         if (enabled) {
            drawPolygonPanel.addPoint(e.getPoint());
         }
      }
   }

   private static void createAndShowGui() {
      DrawMovePolygonMain mainPanel = new DrawMovePolygonMain();

      JFrame frame = new JFrame("DrawMovePolygonMain");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

@SuppressWarnings("serial")
class DrawPolygonPanel extends JPanel {
   private static final int PREF_W = 600;
   private static final int PREF_H = PREF_W;
   private static final Color POLY_COLOR = Color.red;
   private static final Color POLY_EDGE_COLOR = Color.blue;
   private static final Stroke EDGE_STROKE = new BasicStroke(3f,
         BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
   private static final double SCALE = 10.0;
   private static final int PT_RADIUS = 4;
   private Path2D poly;
   private List<Point> points = new ArrayList<>();

   public void move(PolyDirection direction) {

      double tx = direction.getTx() * SCALE;
      double ty = direction.getTy() * SCALE;
      AffineTransform transform = AffineTransform.getTranslateInstance(tx, ty);
      poly.transform(transform);
      repaint();
   }

   public void resetPoints() {
      points = new ArrayList<>();
   }

   public void setPoly(Path2D poly) {
      this.poly = poly;
      repaint();
   }

   public void clearPoly() {
      poly = null;
      repaint();
   }

   public void addPoint(Point p) {
      if (points != null) {
         points.add(p);
      }
      repaint();
   }

   public List<Point> getPoints() {
      return points;
   }

   public void clearPoints() {
      points = null;
      repaint();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (poly != null) {

         Graphics2D g2 = (Graphics2D) g;
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
         g2.setColor(POLY_COLOR);
         if (poly != null) {
            g2.fill(poly);
         }
         g2.setColor(POLY_EDGE_COLOR);
         Stroke oldStroke = g2.getStroke();
         g2.setStroke(EDGE_STROKE);
         g2.draw(poly);

         g2.setStroke(oldStroke);
      }

      if (points != null && points.size() > 0) {
         g.setColor(Color.black);
         Graphics2D g2 = (Graphics2D) g;
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
         for (Point pt : points) {
            int x = pt.x - PT_RADIUS;
            int y = pt.y - PT_RADIUS;
            int width = 2 * PT_RADIUS;
            int height = width;
            g.fillOval(x, y, width, height);
         }
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }   

}

enum PolyDirection {
   UP(0.0, -1.0), DOWN(0.0, 1.0), LEFT(-1.0, 0.0), RIGHT(1.0, 0.0);

   private double tx;
   private double ty;

   private PolyDirection(double tx, double ty) {
      this.tx = tx;
      this.ty = ty;
   }

   public double getTx() {
      return tx;
   }

   public double getTy() {
      return ty;
   }
}

Note that my example code above the drawing component extends JPanel, the drawing method is a paintComponent method, its first method call inside of it is to the super paintComponent method. And inside it, all it does is draw the polygon or the points used to create a polygon and nothing else.

Upvotes: 6

Mordechai
Mordechai

Reputation: 16234

All code in paint() should be moved to the component's constructor.

Only drawings should be done in paint(), or even better - in paintComponent() that is designed for override (while paint() has some internal functions, which BTW you interfered by not calling super.paint()).

Upvotes: 0

Related Questions