如何在对象之间切换时摆脱矩形内的圆

我有一个combobox,我可以选择绘制矩形,圆形或手绘。 如果我选择绘制一个圆圈,它会完美地绘制它。 如果我然后切换到绘制一个矩形,它会在矩形内部绘制一个圆圈。 如果我先选择绘制一个矩形然后再绘制一个圆圈,也会发生同样的情况。 (见下图)

我的问题是:

  1. 如何在没有圆形出现在矩形内的情况下在绘制圆形和矩形之间切换?

  2. 在拖动鼠标时,如何显示矩形/圆圈。 我的意思是在我释放鼠标点击之前线条如何显示?

  3. 为什么不用手工绘图呢?

在此处输入图像描述

这是我的测试类:

import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; public class Lab6 extends JFrame implements ActionListener { int startX, startY, endX, endY, w, h; ArrayList shapeList = new ArrayList(); Container cp = getContentPane(); private JPanel topPanel; private JComboBox comboBox; private final String[] boxOptions = new String[] {"Rektangel", "Cirkel", "Frihand"}; public Lab6(String title) { super(title); this.setLayout(new BorderLayout()); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setLocationRelativeTo(null); this.setSize(840, 500); this.initComponents(); this.setVisible(true); } private void initComponents() { topPanel = new JPanel(new GridLayout(1,2)); topPanel.setPreferredSize(new Dimension(0,40)); comboBox = new JComboBox(boxOptions); comboBox.setSelectedIndex(0); comboBox.addActionListener(this); topPanel.add(comboBox); this.add(topPanel, BorderLayout.PAGE_START); } @Override public void paint(Graphics g) { for (Shape s : shapeList) { s.draw(g); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource().equals(comboBox)) { JComboBox cb = (JComboBox)e.getSource(); if (cb.getSelectedItem().equals("Rektangel")) { cp.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); } @Override public void mouseReleased(MouseEvent e) { endX = e.getX(); endY = e.getY(); int width = startX - endX; int height = startY - endY; w = Math.abs(width); h = Math.abs(height); Rectangle r = new Rectangle(startX, startY, w, h); shapeList.add(r); repaint(); } }); } else if (cb.getSelectedItem().equals("Cirkel")) { cp.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); } @Override public void mouseReleased(MouseEvent e) { endX = e.getX(); endY = e.getY(); int width = startX - endX; int height = startY - endY; w = Math.abs(width); h = Math.abs(height); Circle c = new Circle(startX, startY, w, h); shapeList.add(c); repaint(); } }); } else if (cb.getSelectedItem().equals("Frihand")) { //I need help with this part cp.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { startX = e.getX(); startY = e.getY(); } @Override public void mouseDragged(MouseEvent e) { FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY()); shapeList.add(fh); repaint(); } }); } } } public static void main(String args[]) { new Lab6("Drawing Program"); } } 

在类Rectangle中(类Circle看起来相同):

 import java.awt.*; public class Rectangle extends Shape { public Rectangle(int x, int y, int width, int height) { super(x, y, width, height); } public Rectangle() { super(); } @Override public void draw(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.RED); g2.setStroke(new BasicStroke(4)); g.drawRect(getX(), getY(), getWidth(), getHeight()); } } 

在FreeHand课程中(我需要这方面的帮助):

 import java.awt.*; public class FreeHand extends Shape { public FreeHand(int x, int y, int width, int height) { super(x, y, width, height); } public FreeHand() { super(); } @Override public void draw(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.BLUE); g2.setStroke(new BasicStroke(4)); g2.drawLine(getX(), getY(), getWidth(), getHeight()); } } 

在class级形状:

 import java.awt.Graphics; import javax.swing.JPanel; public abstract class Shape extends JPanel { private int startX, startY, width, height; public Shape() { this(0, 0, 1, 1); } public Shape(int startX, int startY, int width, int height) { this.startX = startX; this.startY = startY; this.width = width; this.height = height; } public abstract void draw(Graphics g); @Override public int getX() { return startX; } @Override public int getY() { return startY; } @Override public int getWidth() { return width; } @Override public int getHeight() { return height; } } 

有很多事情正在发生……

  1. 覆盖JFrame paint
  2. 在执行自定义绘画之前不调用super.paint
  3. MosueListener更改形状时添加新的MosueListener

相反,创建一个自定义组件,从JPanel扩展并覆盖它的paintComponent方法。 使用此组件具有基本绘图表面(您的控件应包含在另一个组件中)。

确保在执行任何自定义绘制之前调用super.paintComponent ,这样就不会破坏绘制链

有关详细信息,请参阅在AWT和Swing中 执行自定义绘画和绘画

创建一个SINGLE MouseListener并将其注册到面板。 当用户选择不同的形状时,在面板中更改状态变量(通过设置器),告诉MouseListener当用户开始绘制时它应该做什么。

更新…

创建一个从JPanel扩展的自定义类…

 public static class ShapePane extends JPanel { } 

覆盖类paintComponent方法…

 public static class ShapePane extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Custom Painting here... } } 

为布局管理器提供一些大小提示……

 public static class ShapePane extends JPanel { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Custom Painting here... } public Dimension getPreferredSize() { return new Dimension(200, 200); } } 

提供一种可以改变形状类型的方法……所以你知道要画什么…

 public static class ShapePane extends JPanel { public enum ShapeType { CIRCLE, RECTANGLE } private ShapeType currentShapeType; public void setCurrentShapeType(ShapeType currentShapeType) { this.currentShapeType = currentShapeType; } public ShapeType getCurrentShapeType() { return currentShapeType; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Custom Painting here... } } 

将SINGLE MouseListener添加到自定义类以创建所需类型的形状…

 public static class ShapePane extends JPanel { public enum ShapeType { CIRCLE, RECTANGLE } private ShapeType currentShapeType; public ShapePane() { addMouseListener(new MouseAdapter() { private Point clickPoint; @Override public void mousePressed(MouseEvent e) { clickPoint = e.getPoint(); } @Override public void mouseReleased(MouseEvent e) { Point releasePoint = e.getPoint(); int x = Math.min(releasePoint.x, clickPoint.x); int y = Math.min(releasePoint.y, clickPoint.y); int width = Math.abs(clickPoint.x - releasePoint.x); int height = Math.abs(clickPoint.y - releasePoint.y); switch (getCurrentShapeType()) { case CIRCLE: // Make a circle break; case RECTANGLE: // Make a rectangle... break; } repaint(); } }); } public void setCurrentShapeType(ShapeType currentShapeType) { this.currentShapeType = currentShapeType; } public ShapeType getCurrentShapeType() { return currentShapeType; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Custom Painting here... } } 

填空白……

创建另一个JPanel (这次你可以简单地创建一个实例),添加你的控件

创建一个JFrame的实例,向其添加自定义类和控件面板(确保它们正确布局,以便它们不会相互覆盖 – 请参阅在容器中布置组件以获取更多详细信息)

使用适当的控件侦听器来确定用户想要绘制的形状类型,并相应地设置currentShapeType属性…