如何在调用paint()方法时避免重新初始化一维数组

时间:2015-02-11 03:25:43

标签: java swing user-interface graphics polygon

我正在创建一个绘制多边形并填充它的程序。然后显示按钮,以便用户可以向上,向下,向左或向右移动多边形。现在,当我调用repaint()方法时,我遇到了问题。

在paint()方法中,我创建了一个包含绘制和填充多边形的方法的类的新实例。这就是我的问题的原因。每次调用paint()时都会创建一个新的类实例,因此我所拥有的包含多边形点坐标的数组将重置为其初始值。

我的问题是攻击此问题的最佳方法是什么?如何在不创建新实例的情况下从paint()方法访问这些方法?我知道每个人都会说我可以使用像“NameOfClass.neededMethod();”这样的东西。这要求我把很多事情做成静态的,并且不会像希望的那样有效。

我感谢任何指针。

以下是我的类的代码,其中包含我需要访问的方法:

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

这是我的paint()方法,需要访问FillPolygon类中的方法才能实际绘制到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

2 个答案:

答案 0 :(得分:6)

  

在paint()方法中,我创建了一个包含绘制和填充多边形的方法的类的新实例。这就是我的问题的原因。每次调用paint()时都会创建一个新的类实例,因此我所拥有的包含多边形点坐标的数组将重置为其初始值。

不要这样做。 paint方法(或者更好的是JPanel的paintComponent方法覆盖)应仅用于绘画和绘画。你不应该在那里创建这样的实例,也不应该在那里改变类状态。只是画画,这就是它。请注意1)绘画可能由系统启动,并且不在您完​​全控制之下,2)每次调用repaint()时都不能保证绘画,因此如果您的程序逻辑依赖于绘画方法,它有失败的风险。

  

我知道每个人都会说我可以使用&#34; NameOfClass.neededMethod();&#34;这要求我把很多事情做成静态的,并且不会像希望的那样有效。

没有人完全了解你的问题(而且我还不知道我害怕)以及了解OOP的人会建议这一点,相信我。

如需更具体的帮助,请显示更多代码,并详细说明问题。


修改

您不应该更改绘画中按钮的可见性。你不应该在paint中创建FillPolygon,而应该在类构造函数中执行一次。你也应该总是调用超级绘画方法,并且应该避免覆盖绘画,更喜欢paintComponent。例如:

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;
   }
}

请注意,我的绘图组件上方的示例代码扩展了JPanel,绘图方法是paintComponent方法,其内部的第一个方法调用是超级paintComponent方法。在其中,它所做的只是绘制多边形或用于创建多边形的点和别的

答案 1 :(得分:0)

paint()中的所有代码都应该移动到组件的构造函数中。

只有paint()或更好的图纸才能在专为覆盖而设计的paintComponent()中完成(而paint()有一些内部功能,而BTW则因为没有调用而干扰了{ {1}})。