我的Java绘图程序存在一些问题。
我有JComboBox
我可以选择绘制矩形或徒手绘制。对象将添加到ArrayList
。我希望能够在绘制矩形和空手之间切换,然后再绘制一个矩形,然后用空手......等等。
如果我这样做,因为代码看起来像现在,它首先绘制矩形很好,然后当我切换到空闲手时它绘制线条很好,但是当我切换回矩形时它仍然绘制线条(或者有时与线条一起绘制线条)怪异的长方形)。我越切换它所得到的怪物。
任何人都可以看到代码有什么问题,因为我不能
public abstract class Draw {
public int startX, startY, endX, endY, width, height, w, h;
public String color = "Black";
public Draw(int startX, int startY, int width, int height) {
this.startX = startX;
this.startY = startY;
this.width = width;
this.height = height;
}
public abstract void draw(Graphics2D g);
public int getX() {
return startX;
}
public void setX(int startX) {
this.startX = startX;
}
public int getY() {
return startY;
}
public void setY(int startY) {
this.startY = startY;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void setColor(String color) {
this.color = color;
}
}
public class Rectangle extends Draw {
public Rectangle(int x, int y, int width, int height) {
super(x, y, width, height);
}
@Override
public void draw(Graphics2D g2) {
g2.drawRect(getX(), getY(), getWidth(), getHeight());
}
}
public class FreeHand extends Draw {
public FreeHand(int x, int y, int width, int height) {
super(x, y, width, height);
}
@Override
public void draw(Graphics2D g2) {
g2.drawLine(getX(), getY(), getWidth(), getHeight());
}
}
public class PaintProgram extends JFrame implements ActionListener {
public ArrayList<Draw> shapeList = new ArrayList<>();
int startX, startY, endX, endY, w, h;
private JPanel topPanel;
private JPanel bottomPanel;
private JPanel leftPanel;
private JPanel rightPanel;
private JComboBox comboBox;
private final String[] boxOptions = new String[] {"Rectangle", "Freehand"};
Container cp = getContentPane();
private int count = 0;
public JavaApplication30(String title) {
super(title);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(840, 500);
this.initComponents();
this.setVisible(true);
}
private void initComponents() {
cp.setBackground(Color.WHITE);
comboBox = new JComboBox(boxOptions);
topPanel = new JPanel();
bottomPanel = new JPanel(new GridLayout(1,2));
rightPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
leftPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
comboBox.setSelectedIndex(0);
comboBox.addActionListener(this);
topPanel.setPreferredSize(new Dimension(0,40));
bottomPanel.setPreferredSize(new Dimension(0,30));
bottomPanel.setBackground(Color.LIGHT_GRAY);
topPanel.add(comboBox);
bottomPanel.add(leftPanel);
bottomPanel.add(rightPanel);
this.add(topPanel, BorderLayout.PAGE_START);
this.add(bottomPanel, BorderLayout.PAGE_END);
}
@Override
public void paint(Graphics g) {
if(count == 0) {
cp.repaint();
}
Graphics2D g2 = (Graphics2D) g;
for (Draw d : shapeList) {
d.draw(g2);
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));
if (startX != 0 && startY != 0 && endX != 0 && endY != 0) {
int width = Math.abs(startX - endX);
int height = Math.abs(startY - endY);
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
Rectangle r = new Rectangle(minX, minY, width, height);
g2.setPaint(Color.WHITE);
g2.fillRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
r.setColor(pickedColor);
r.draw(g2);
}
}
@Override
public void actionPerformed(ActionEvent e) {
count++;
if (e.getSource().equals(comboBox)) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rectangle")) {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
endX = startX;
endY = startY;
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = Math.abs(startX - endX);
int height = Math.abs(startY - endY);
int minX = Math.min(startX, endX);
int minY = Math.min(startY, endY);
Rectangle r = new Rectangle(minX, minY, width, height);
shapeList.add(r);
r.setColor(pickedColor);
startX = 0;
startY = 0;
endX = 0;
endY = 0;
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
endX = e.getX();
endY = e.getY();
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Freehand")) {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
addCoordinate(startX, startY);
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g;
FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY());
shapeList.add(fh);
fh.setColor(pickedColor);
fh.draw(g2);
startX = e.getX();
startY = e.getY();
}
});
}
}
}
public static void main(String args[]) {
new PaintProgram("Paint");
}
}
答案 0 :(得分:2)
您添加MouseListeners但不删除它们。每次在组合框中选择一些东西时,都会添加一个新的监听器。因此,当你绘制一些东西时,每个听众都会被应用,并且会发生奇怪的事情。
您应该在添加新的MouseListener之前删除它。您可能必须在实例变量中记住它。
或者,您可以在开始时添加所有侦听器,但检查侦听器内组合框的值。如果该值与侦听器的值不对应,则它应该不执行任何操作。
编辑:以下是删除所有侦听器的方法
for (MouseListener listener : this.getMouseListeners()) {
this.removeMouseListener(listener);
}
for (MouseMotionListener listener : this.getMouseMotionListeners()) {
this.removeMouseMotionListener(listener);
}
在actionPerformed()方法
中添加新侦听器之前,请输入此代码答案 1 :(得分:2)
如前所述here和here,请勿在{{1}}中添加MouseListener
,而是创建一个ActionListener
并确定您的身份想要根据当前选择的项目进行。
基本上,每次调用MosueListener
时都会不断添加新的MouseListener
......他们正在累积...
解决方案是使用单个actionPerformed
和某种工厂......
首先定义工厂界面......
MouseListener
为您要绘制的每种类型的形状创建工厂实现...
public interface DrawFactory {
public Draw createDrawing(int x, int y, int width, int height, Color color);
public void addPoint(Draw draw, int x, int y);
}
接下来,创建一个从public class RectangleFactory implements DrawFactory {
@Override
public Draw createDrawing(int x, int y, int width, int height, Color color) {
return new Rectangle(x, y, width, height);
}
@Override
public void addPoint(Draw draw, int x, int y) {
// Does nothing...
}
@Override
public boolean isMutable() {
return false;
}
@Override
public String getName() {
return "Rectangle";
}
@Override
public String toString() {
return getName();
}
}
public class FreeHandFactory implements DrawFactory {
@Override
public Draw createDrawing(int x, int y, int width, int height, Color color) {
return new FreeHand(x, y, width, height);
}
@Override
public void addPoint(Draw draw, int x, int y) {
if (draw instanceof FreeHand) {
FreeHand fh = (FreeHand)draw;
//fh.addPoint(x, y);
}
}
@Override
public boolean isMutable() {
return true;
}
@Override
public String getName() {
return "Free Hand";
}
@Override
public String toString() {
return getName();
}
}
扩展的自定义组件,它将作为主要绘图表面,这将是可以监视JPanel
和绘制MouseLstener
实例的代表,就像提到here
Draw
接下来,将您的public class DrawSurface extends JPanel {
private DrawFactory factory;
private Draw currentDraw;
private List<Draw> shapeList = new ArrayList<>();
private Color drawColor;
public DrawSurface() {
shapeList = new ArrayList<>(25);
MouseAdapter ma = new MouseAdapter() {
private Point pressPoint;
@Override
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e) {
DrawFactory factory = getDrawFactory();
if (factory != null) {
Point p = e.getPoint();
if (factory.isMutable() && currentDraw != null) {
factory.addPoint(currentDraw, p.x, p.y);
} else {
int x = Math.min(p.x, pressPoint.x);
int y = Math.min(p.y, pressPoint.y);
int width = Math.abs(p.x - pressPoint.x);
int height = Math.abs(p.y - pressPoint.y);
Draw draw = factory.createDrawing(x, y, width, height, getDrawColor());
shapeList.add(draw);
if (factory.isMutable()) {
currentDraw = draw;
}
}
}
}
};
}
public DrawFactory getDrawFactory() {
return factory;
}
public void setDrawFactory(DrawFactory factory) {
this.factory = factory;
currentDraw = null;
}
public Color getDrawColor() {
return drawColor;
}
public void setDrawColor(Color drawColor) {
this.drawColor = drawColor;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Draw draw : shapeList) {
draw.draw(g2d);
}
g2d.dispose();
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
从boxOptions
更改为String
,这样可以更轻松地确定您应该使用哪个工厂。不要忘记添加对DrawFactory
DrawSurface
在private final DrawFactory[] boxOptions = new DrawFactory[]{new RectangleFactory(), new FreeHandFactory()};
private DrawSurface drawSurface;
创建initComponents
的新实例并将其添加到您的框架中...
DrawSurface
将您的private void initComponents() {
//...
drawSurface = new DrawSurface();
this.add(drawSurface);
}
方法更改为......
actionPerformed
由于示例代码不完整,不确定如何确定当前颜色,但基本上,您希望同样设置@Override
public void actionPerformed(ActionEvent e) {
count++;
drawSurface.setDrawFactory((DrawFactory)comboBox.getSelectedItem());
}
的{{1}}。
摆脱drawColor
中的DrawSurface
方法,因为您不应该覆盖顶级容器的paint
方法,至少一次被告知,如果不是两次。
所有这一切都很简单,当你想添加一个新的“绘图形状”时,你为它创建一个PaintProgram
和paint
并将工厂添加到组合框中......完成工作......