问题
I've read a lot of tutorials on drawing Graphics2D components and adding to JPanel/JFrame but I can't find how to add multiple these components into one JPanel simply. My code below adds only 1 component (line) and I can't find why it isn't possible to add more.
What am I doing wrong?
Desired behaviour: there should be 3 red lines.
My whole code:
package Examples;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example1 extends JFrame {
private final JPanel panel;
public Example1() {
// jpanel with graphics
panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 200));
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
panel.setBackground(Color.WHITE);
add(panel);
// adding lines to jpanel
AddMyLine(); // 1st: this works well
AddMyLine(); // 2nd: this doesn't work
AddMyLine(); // 3rd: this doesn't work
setLayout(new FlowLayout(FlowLayout.LEFT));
setSize(250, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLocationRelativeTo(null);
}
// add new line to jpanel
private void AddMyLine() {
MyLine c = new MyLine();
System.out.println(c);
panel.add(c);
}
// line component
private class MyLine extends JComponent {
public MyLine() {
setPreferredSize(new Dimension(200, 200));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.red);
g2d.setStroke(new BasicStroke(1));
int x1 = (int)Math.round(Math.random()*200);
int y1 = (int)Math.round(Math.random()*200);
int x2 = (int)Math.round(Math.random()*200);
int y2 = (int)Math.round(Math.random()*200);
g2d.drawLine(x1,y1,x2,y2);
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Example1();
}
});
}
}
回答1:
Your MyLine class should not be a Swing component and thus should not extend JComponent. Rather it should be a logical entity, and in fact can be something that implements Shape such as a Line2D, or could be your own complete class, but should know how to draw itself, i.e., if it does not implement Shape, then it should have some type of draw(Graphics2D g)
method that other classes can call. I think instead you should work on extending your panel's JPanel class, such that you override its paintComponent
method, give it a collection to hold any MyLine items added to it, and draw the MyLine items within the paintComponent.
Other options include drawing directly on to a BufferedImage, and then displaying that BufferedImage in your JPanel's paintComponent method. This is great for static images, but not good for images that need to change or move.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class DrawChit extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private List<Shape> shapes = new ArrayList<>();
public DrawChit() {
setBackground(Color.white);
}
public void addShape(Shape shape) {
shapes.add(shape);
repaint();
}
@Override // make it bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
private static void createAndShowGui() {
DrawChit drawChit = new DrawChit();
drawChit.addShape(new Line2D.Double(10, 10, 100, 100));
drawChit.addShape(new Ellipse2D.Double(120, 120, 200, 200));
JFrame frame = new JFrame("DrawChit");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(drawChit);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Or an example using my own MyDrawable class, which produces a GUI that looks like this:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
@SuppressWarnings("serial")
public class DrawChit extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private List<MyDrawable> drawables = new ArrayList<>();
public DrawChit() {
setBackground(Color.white);
}
public void addMyDrawable(MyDrawable myDrawable) {
drawables.add(myDrawable);
repaint();
}
@Override
// make it bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (MyDrawable myDrawable : drawables) {
myDrawable.draw(g2);
}
}
public void clearAll() {
drawables.clear();
repaint();
}
private static void createAndShowGui() {
final List<MyDrawable> myDrawables = new ArrayList<>();
myDrawables.add(new MyDrawable(new Line2D.Double(100, 40, 400, 400),
Color.red, new BasicStroke(40)));
myDrawables.add(new MyDrawable(new Ellipse2D.Double(50, 10, 400, 400),
Color.blue, new BasicStroke(18)));
myDrawables.add(new MyDrawable(new Rectangle2D.Double(40, 200, 300, 300),
Color.cyan, new BasicStroke(25)));
myDrawables.add(new MyDrawable(new RoundRectangle2D.Double(75, 75, 490, 450, 40, 40),
Color.green, new BasicStroke(12)));
final DrawChit drawChit = new DrawChit();
JFrame frame = new JFrame("DrawChit");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(drawChit);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener() {
private int drawCount = 0;
@Override
public void actionPerformed(ActionEvent e) {
if (drawCount >= myDrawables.size()) {
drawCount = 0;
drawChit.clearAll();
} else {
drawChit.addMyDrawable(myDrawables.get(drawCount));
drawCount++;
}
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyDrawable {
private Shape shape;
private Color color;
private Stroke stroke;
public MyDrawable(Shape shape, Color color, Stroke stroke) {
this.shape = shape;
this.color = color;
this.stroke = stroke;
}
public Shape getShape() {
return shape;
}
public Color getColor() {
return color;
}
public Stroke getStroke() {
return stroke;
}
public void draw(Graphics2D g2) {
Color oldColor = g2.getColor();
Stroke oldStroke = g2.getStroke();
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(shape);
g2.setColor(oldColor);
g2.setStroke(oldStroke);
}
public void fill(Graphics2D g2) {
Color oldColor = g2.getColor();
Stroke oldStroke = g2.getStroke();
g2.setColor(color);
g2.setStroke(stroke);
g2.fill(shape);
g2.setColor(oldColor);
g2.setStroke(oldStroke);
}
}
回答2:
You shouldn't be drawing lines by adding components. Components are things like panels, buttons etc.
See this tutorial on how to draw with Graphics2D: https://docs.oracle.com/javase/tutorial/2d/geometry/primitives.html
回答3:
Your code adds three components but the panel is not big enough to show the other two components
panel.setPreferredSize(new Dimension(200, 600));
setSize(250, 800);
来源:https://stackoverflow.com/questions/31033359/drawing-multiple-graphic2d-components-into-jpanel