【问题标题】:Java panel interfaceJava面板界面
【发布时间】:2013-10-29 18:30:19
【问题描述】:

我正在尝试制作一个线描程序。当我尝试重绘所有线条时(在创建新线条之后),只有最后一条被绘制出来。问题可能出在重绘中。

谁能看出我做错了什么?

代码在这里:

public class Kimp extends JFrame {

private ArrayList<Point[]> pointsArray = new ArrayList<>();
private Point points[] = new Point[10000];
private int pointCounter = 0;

public Kimp () {

     panel paintArea = new panel();
     add(paintArea, BorderLayout.CENTER);
}

private class panel  extends JPanel {

    public panel () {
        HandlerClass handler = new HandlerClass();
        this.addMouseListener(handler);
        this.addMouseMotionListener(handler);
    }

    @Override
     void paintComponent(Graphics g) {
        super.paintComponent(g);
        try {


            for (Point[] p : pointsArray) {
                for(int i = 0; i < p.length; i++) {                         
                    if (p[i].x == 0) {
                       continue;
                    } else {
                        if (p[i + 1].x == 0) {
                            g.setColor(Color.BLUE);
                            g.drawLine(p[i].x, p[i].y, p[i].x, p[i].y);
                        } else {
                            g.setColor(Color.BLUE);
                            g.drawLine(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y);
                        }
                    } 
                } 
            }
            points = preFill(points);
        } catch (NullPointerException e) {

        }                  
    }
}

private class HandlerClass implements MouseListener , MouseMotionListener {

    @Override
    public void mouseDragged(MouseEvent e) {
        points[pointCounter++] = e.getPoint();
    }

    @Override
    public void mousePressed(MouseEvent e) {
        points[pointCounter] = e.getPoint();
    }

    @Override
    public void mouseMoved(MouseEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

}

public static Point[] preFill (Point[] points) {
    for (int i = 0; i < points.length; i++) {
        points[i] = new Point(-999,-999);
    }
    return points;
}

}

【问题讨论】:

  • private Point points[] = new Point[10000]; - 只是不要。为此使用 ArrayList!因为加载这么多内存的目的是什么,当你不知道你会用多少的时候?其次,不要抓NullPointerException
  • 加上一条线可能使用超过 10000 点的方式,所以不要随意限制数量(或者只有在一定数量的点之后通过反复试验看到明显的性能问题) .

标签: java swing user-interface jpanel paintcomponent


【解决方案1】:

我很快重写了您的代码以尽可能简化它。你也许能更好地理解它背后的概念。

import java.awt.Graphics;
import java.awt.Point;
import java.awt.Color;
import java.awt.event.*;

import java.util.*;
import javax.swing.*;

public class Kimp {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Kimp!");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setLocationRelativeTo(null);
        frame.add(new CanvasPanel());
        frame.setVisible(true);
    }
}

class CanvasPanel extends JPanel {
    private final List<List<Point>> lines = new LinkedList<List<Point>>();
    private List<Point> points = new LinkedList<Point>();

    public CanvasPanel() {
        addMouseListener(mouseAdapter);
        addMouseMotionListener(mouseAdapter);
    }

    @Override
    public void paintComponent(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());

        for (List<Point> line : lines)
            drawLine(line, g);
        drawLine(points, g);
    }

    private void drawLine(List<Point> points, Graphics g) {
        if (points.size() < 2) return;

        Point p1 = points.get(0);

        for (int i=1, n=points.size(); i<n; i++) {
            Point p2 = points.get(i);

            g.setColor(Color.BLUE);
            g.drawLine(p1.x, p1.y, p2.x, p2.y);

            p1 = p2;
        }
    }

    private MouseAdapter mouseAdapter = new MouseAdapter() {
        @Override
        public void mousePressed(MouseEvent e) {
            points.add(e.getPoint());
            repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            points.add(e.getPoint());
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (points.size() > 1) {
                lines.add(points);
                points = new LinkedList<Point>();
            }
        }
    };
}

【讨论】:

  • @fusi0n 我刚刚想通了,抱歉 :) 我添加了缺失的行为,现在查看代码。如果包含超过 1 个点,则会在鼠标释放时将一条线添加到列表中。
  • 另一种打印所有行同时尽可能减少所需内存的方法是不使用“fillRect()”调用清除画布。您可以随心所欲地绘制,因为以前的行永远不会被删除。您只需在 mouseDragged() 中的最后一个点和新点之间画一条线,仅此而已。对最后一点的简单引用就足够了。
  • 如果我需要撤消刚刚创建的行...那我该怎么做呢?
  • 你不能使用后一个选项。如果你想这样做,你需要像我给你的代码一样存储这些行,然后删除最后一项并调用 repaint()。
  • 只需实现一个 KeyListener 即可知道给定的键是否已被按下/释放。在 mousePressed 和 mouseDragged 中添加一个 if-branch,如果要移动一条线,只需为该线的每个点坐标添加一些值即可。
【解决方案2】:
private ArrayList<Point[]> pointsArray = new ArrayList<>();

这是一个 Point[] 列表。这里只分配了一个private Point points[] = new Point[10000];。这意味着每次将points 添加到pointArray 中时,都会添加points 的相同实例。

当您更改points 的元素时,pointArray 中所有现有的Point[] 都会更新。因为所有元素都指向同一个points

绘制新线时分配新点[]。

【讨论】:

    【解决方案3】:

    每次绘制时都会重置点数组(preFillPoints() 在paint() 中调用)。您的 pointsArray (看在上帝的份上应该称为 pointsList )完全没有意义,每次释放鼠标时都添加相同的 points[] 数组。

    代码没有意义。您只需要列表 数组。不是都。声明一个 List(不是 Point[]),每次鼠标移动时添加一个新的 Point。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 2011-01-27
      • 1970-01-01
      相关资源
      最近更新 更多