Вот пример того, как go об этом:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
public class Main {
private static void drawPoint(final Graphics g, final Point p) {
g.drawLine(p.x - 10, p.y, p.x + 10, p.y);
g.drawLine(p.x, p.y - 10, p.x, p.y + 10);
}
private static void drawLine(final Graphics g, final Point p1, final Point p2) {
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
public static interface ShapeByPoints {
int getPointCount();
void draw(final Graphics g, final Point... points);
}
public static class DrawPanel extends JPanel {
private final ArrayList<Point> points;
private ShapeByPoints s;
public DrawPanel() {
points = new ArrayList<>();
s = null;
}
public void setShape(final ShapeByPoints s) {
this.s = s;
points.clear();
repaint();
}
public void modifyLastPoint(final Point p) {
points.get(points.size() - 1).setLocation(p);
repaint();
}
public void addPoint(final Point p) {
if (s != null && points.size() == s.getPointCount())
points.clear();
points.add(p);
repaint();
}
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (s != null && s.getPointCount() == points.size())
s.draw(g, points.toArray(new Point[s.getPointCount()]));
else {
points.forEach(p -> drawPoint(g, p));
for (int i = 1; i < points.size(); ++i)
drawLine(g, points.get(i - 1), points.get(i));
}
}
}
public static class EllipseByPoints implements ShapeByPoints {
@Override
public int getPointCount() {
return 2;
}
@Override
public void draw(final Graphics g, final Point... points) {
g.drawOval(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
public static class PolygonByPoints implements ShapeByPoints {
private final int points;
public PolygonByPoints(final int points) {
this.points = points;
}
@Override
public int getPointCount() {
return points;
}
@Override
public void draw(final Graphics g, final Point... points) {
for (int i = 1; i < this.points; ++i)
drawLine(g, points[i - 1], points[i]);
drawLine(g, points[this.points - 1], points[0]);
}
}
public static class LineByPoints extends PolygonByPoints {
public LineByPoints() {
super(2);
}
}
public static class RectangleByPoints implements ShapeByPoints {
@Override
public int getPointCount() {
return 2;
}
@Override
public void draw(final Graphics g, final Point... points) {
g.drawRect(Math.min(points[0].x, points[1].x), Math.min(points[0].y, points[1].y), Math.abs(points[1].x - points[0].x), Math.abs(points[1].y - points[0].y));
}
}
private static JRadioButton createButton(final String buttonText, final ButtonGroup bg, final DrawPanel dp, final ShapeByPoints s) {
final JRadioButton btn = new JRadioButton(buttonText);
btn.addActionListener(e -> dp.setShape(s));
bg.add(btn);
return btn;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final DrawPanel dp = new DrawPanel();
final MouseAdapter ma = new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent mevt) {
dp.addPoint(mevt.getPoint());
}
@Override
public void mouseDragged(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
@Override
public void mouseReleased(final MouseEvent mevt) {
dp.modifyLastPoint(mevt.getPoint());
}
};
dp.setPreferredSize(new Dimension(500, 350));
dp.addMouseListener(ma);
dp.addMouseMotionListener(ma);
final ButtonGroup bg = new ButtonGroup();
final JPanel buttons = new JPanel();
buttons.add(createButton("Line", bg, dp, new LineByPoints()));
buttons.add(createButton("Ellipse", bg, dp, new EllipseByPoints()));
buttons.add(createButton("Rectangle", bg, dp, new RectangleByPoints()));
buttons.add(createButton("Triangle", bg, dp, new PolygonByPoints(3)));
buttons.add(createButton("Pentagon", bg, dp, new PolygonByPoints(5)));
//... keep creating buttons here ...
final JPanel contents = new JPanel(new BorderLayout());
contents.add(dp, BorderLayout.CENTER);
contents.add(buttons, BorderLayout.PAGE_START);
final JFrame frame = new JFrame("Clicking shapes.");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Примечания:
- Не используйте
paint
, если нет веской причины, которая обычно нет. В большинстве случаев вы хотите нарисовать панель, в этом случае paintComponent
должно быть достаточно. - Не забудьте сначала вызвать
super.paintComponent
внутри paintComponent
override. Это должен быть первый вызов, поскольку он очистит панель для вас от предыдущих рисунков. - Решите, хотите ли вы добавить
JComponent
s, которые будут рисовать фигуры, или нарисовать фигуры самостоятельно в подпункте. Классифицированная панель. В этом случае кажется, что вы пробуете оба (потому что Line extends JPanel
и вы также переопределяете paint
). На мой взгляд, в этом случае использование абстракции фигуры, нарисованной между некоторыми точками, подойдет. Вот почему я создал интерфейс ShapeByPoints
. - Swing не является потокобезопасным, что означает, что могут быть условия между конкурирующими доступами к одной и той же переменной. Чтобы избежать такого сценария ios, вы можете запускать каждую связанную с Swing операцию в Потоке рассылки событий (или EDT для краткости). Чтобы явно выполнить вызов в EDT, вызовите метод, подобный
SwingUtilities.invokeLater
, SwingUtilities.invokeAndWait
, EventQueue.invokeLater
и т. Д. ... В Inte rnet достаточно материалов об этой топике c. Например, здесь . - В моем подходе практически все с нуля переработано (ie Я не модифицировал ваш пример кода, потому что предположил, что это займет немного больше времени, но это всего лишь предположение).
Я только что создал интерфейс ShapeByPoints
, который определяет способ рисования фигуры (ie количество нужных ей точек и метод draw
для выполнения рисунок).
Затем я создал DrawPanel extends JPanel
, который содержит состояние каждой операции. Например, если пользователь выбирает пятиугольник для рисования, ему нужно 5 очков, но что произойдет, если он нажал только дважды? ... DrawPanel
отвечает за такой сценарий ios, а также за рисование заданного форма, когда все точки завершены / нажаты.
Я добавил экземпляр DrawPanel
в кадре, MouseAdapter
для взаимодействия с пользователем и пару кнопок, чтобы продемонстрировать эту логику c.
Все, что вам нужно сделать сейчас, это реализовать ShapeByPoints
, как вам нравится, и передать его экземпляр в DrawPanel
в зависимости от нажатой кнопки. Я уже сделал несколько примеров того, как сделать это в коде (например, EllipseByPoints
, LineByPoints
, RectangleByPoints
и PolygonByPoints
).
Наконец, в качестве бонуса, я добавил возможность перетащите точки щелчка (ie не только , нажмите их, но щелкните и перетащите их).
Надеюсь, это поможет.