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

标签 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

最佳答案

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.

不要这样做。 Paint 方法(或者更好的是 JPanel 的 paintComponent 方法重写)应该仅用于绘画。您不应该在那里创建此类实例,也不应该在那里更改类状态。只要画画就可以了。请注意,1) 绘制可能由系统发起,并且不完全由您控制,并且 2) 不保证每次调用 repaint() 时都会发生绘制,因此如果您的程序逻辑取决于绘画方法,有失败的风险。

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.

没有人完全理解你的问题(恐怕我还不是)并且理解 OOP 会提出这个建议,相信我。

要获得更具体的帮助,请显示更多代码,并解释您的问题的更多详细信息。

<小时/>

编辑

您不应该更改绘制中按钮的可见性。您不应该在绘制中创建 FillPolygon,而应该在类构造函数中执行一次。另外,您应该始终调用 super 绘画方法,并且应该避免覆盖绘画,而更喜欢使用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方法,它内部的第一个方法调用是对superpaintComponent方法的调用。在它内部,它所做的只是绘制多边形或用于创建多边形的点,没有其他

关于java - 如何避免调用paint()方法时重新初始化一维数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28446065/

相关文章:

performance - matlab中获取控件底层java组件的快速方法

javascript - 与 jQuery 一起使用的最佳 UI 库

java - RxJava : if/else operation in flatMap

java - 错误 : Could not find or load main class?

java - 复制云存储文件(创建文件的副本)

java - 如何在JFrame中显示图像

Java JList 仅在最小化或最大化后刷新

java - 使用java根据xml标签将xml拆分为多个xml

Java - textField for 循环未完成

java - 尝试将 Jpanel 添加到 JFrame,但在调整 JPanel 窗口大小后将显示 Jpanel 的内容