我做了一个简单的绘画程序,但似乎有一些问题。首先,当我运行程序时,组件不会显示,直到我将鼠标拖到每一个上面。其次,我创建的drawPanel图像只保存面板的背景而不是绘制在其上的东西。另一个小问题是,当我通过下拉菜单更改点的大小时,在它下面绘制的任何内容都会被删除。任何建议清理我的代码或解决我的问题将是伟大的。
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class MyPaint extends JFrame implements MouseListener, MouseMotionListener, ActionListener {
//initialize coordinates somewhere offscreen
int myX = -100, myY = -100;
private JPanel bucket = new JPanel(new GridLayout(7, 2));
private JPanel northPanel = new JPanel(new GridBagLayout());
private JPanel drawPanel = new JPanel();
GridBagConstraints c = new GridBagConstraints();
private String[] pencilSize = {"1", "5", "10", "15", "20"};
private JComboBox sizeList = new JComboBox(pencilSize);
private JButton[] buttons = new JButton[11];
private Color[] colorList = {Color.RED, Color.BLUE, Color.ORANGE, Color.CYAN, Color.YELLOW, Color.GREEN,
Color.WHITE, Color.MAGENTA, Color.GRAY, Color.PINK, Color.BLACK};
private Color currentColor = Color.BLACK;
int radius = 5;
private JLabel thickness = new JLabel("Thickness");
private JButton clear = new JButton("Clear");
private JButton save = new JButton("Save");
private JButton open = new JButton("Open");
private JLabel image = new JLabel(" ");
JFileChooser fc = new JFileChooser();
// ******************* MyPaint **************
public MyPaint(){
super("MyPaint");
setSize(1000, 1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addMouseListener(this);
addMouseMotionListener(this);
setVisible(true);
setResizable(false);
sizeList.setEditable(true);
drawPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
for(int i = 0; i < buttons.length; i++){
buttons[i] = new JButton();
buttons[i].setBackground(colorList[i]);
buttons[i].addActionListener(this);
bucket.add(buttons[i]);
}
northPanel.add(clear);
clear.addActionListener(this);
northPanel.add(thickness);
northPanel.add(sizeList);
sizeList.addActionListener(this);
northPanel.add(open);
open.addActionListener(this);
northPanel.add(save);
save.addActionListener(this);
add(drawPanel, BorderLayout.CENTER);
add(bucket, BorderLayout.WEST);
add(northPanel, BorderLayout.NORTH);
}
// ******************* Override of paint **************
//paint the oval at the current location
public void paint(Graphics g){
g.setColor(currentColor);
if(myX > drawPanel.getX() + 10 && myY > drawPanel.getY() + 25)
g.fillOval(myX - radius, myY - radius, 2 * radius, 2 * radius);
}
// ******************* Mouse Events **************
public void mouseClicked(MouseEvent e){
myX = e.getX();
myY = e.getY();
repaint();
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseDragged(MouseEvent e){
myX = e.getX();
myY = e.getY();
repaint();
}
public void mouseMoved(MouseEvent e){
}
// ******************* Actions **************
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
for(int i = 0; i < buttons.length; i++)
if(source == buttons[i])
currentColor = colorList[i];
if(source == clear)
super.paint(getGraphics());
else if(source == sizeList)
radius = Integer.parseInt((String) sizeList.getSelectedItem());
//open a file
else if(source == open){
int returnValue = fc.showOpenDialog(null);
if (returnValue == fc.APPROVE_OPTION) {
File sf = fc.getSelectedFile();
try {
image.setIcon(new ImageIcon(ImageIO.read(sf)));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
super.paint(getGraphics());
drawPanel.add(image);
drawPanel.revalidate();
drawPanel.repaint();
}
}
//save a file
else if(source == save){
fc.setDialogTitle("Specify a file to save");
int userSelection = fc.showSaveDialog(drawPanel);
if (userSelection == JFileChooser.APPROVE_OPTION) {
File fileToSave = fc.getSelectedFile();
try{
BufferedImage image = new BufferedImage(drawPanel.getWidth(),
drawPanel.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = image.getGraphics();
drawPanel.printAll(g);
g.dispose();
ImageIO.write(image, "png", new File("pic.png"));
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
// ******************* Main **************
public static void main(String[] args){
MyPaint frame = new MyPaint();
frame.setVisible(true);
}
}
编辑:
我用paintComponent()替换了paint(),但我仍然不知道如何绘制它,因为g.fillOval ...()什么都不做
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(currentColor);
g.fillOval(myX - radius, myY - radius, 2 * radius, 2 * radius);
if(img != null)
g.drawImage(img, 0, 0, null);
}
编辑2:
小版本
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class MySmallPaint extends JPanel implements MouseListener, MouseMotionListener, ActionListener{
int myX = 0, myY = 0;
int radius = 5;
JPanel drawPanel = new JPanel();
Dimension d = drawPanel.getPreferredSize();
BufferedImage img = new BufferedImage(d.width,d.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
public MySmallPaint(){
super();
setSize(1000, 1000);
addMouseListener(this);
addMouseMotionListener(this);
//add(drawPanel, BorderLayout.CENTER);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.fillOval(myX - radius, myY - radius, 2 * radius, 2 * radius);
if(img != null)
g.drawImage(img, 0, 0, null);
}
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
myX = e.getX();
myY = e.getY();
repaint();
}
@Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent e) {
myX = e.getX();
myY = e.getY();
repaint();
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args){
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MySmallPaint());
f.pack();
f.setVisible(true);
}
}
答案 0 :(得分:3)
解决了一个问题:
你没有在paint方法覆盖中调用super的paint方法,这样做不允许GUI绘制自己的组件。换句话说,你不是这样做的:
public void paint(Graphics g) {
super.paint(g); // *************** missing ************
g.setColor(currentColor);
if (myX > drawPanel.getX() + 10 && myY > drawPanel.getY() + 25)
g.fillOval(myX - radius, myY - radius, 2 * radius, 2 * radius);
}
但是说过这个,我还强烈建议你不要像你正在做的那样绘制,而是覆盖JPanel的paintComponent方法并在那里绘制。通过直接在JFrame上绘图,你可能会弄清楚它是如何绘制自己,它的组件,边界......,正如你所发现的那样。 JFrames是复杂的组件,包含许多子组件,包括JRootPanes,contentPanes,JLayeredPanes,glasspanes ......,你真的不想冒这些子组件的绘图的风险。
接下来,要保存图形中的图像,请绘制到BufferedImage,然后在绘图JPanel(附带MouseListener的那个)paintComponent中显示BufferedImage,类似于:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
g.drawImage(myImage, 0, 0, null);
}
}
因此,在您的鼠标监听器中,您可以使用从图像中获取的图形来调用此图像,方法是调用getGraphics()
或createGraphics()
。前者获取Graphics对象,而后者获取Graphics2D对象。请注意,这与在不推荐的组件上调用getGraphics()
不同(根据我的评论)。另请注意,以这种方式获得的任何Graphics对象都应该在您使用它时进行处理,这样您就不会浪费资源。
我创建了一个BufferedImage,但是如何将它添加到我的drawPanel / JFrame中。
您的绘图JPanel可以将BufferedImage保存为字段。当你需要绘制它时,你会得到它的Graphics上下文,如上所述 - 请注意,我更喜欢使用createGraphics()
来获取Graphics2D对象,这样我就可以使用它的所有东西,比如Strokes。您将BufferedImage的大小调整为JPanel的首选大小,然后按照我上面的显示进行绘制。
我也不确定如何在缓冲图像上绘图。
如上所述。另请注意,如果您尝试创建连接的绘图,通常最好绘制线而不是椭圆或椭圆
举个简单的例子,没有你想要做的所有事情......
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class SimpleDrawMain extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private SimpleDrawPanel simpleDrawPanel = new SimpleDrawPanel(PREF_W, PREF_H);
private MyMouse myMouse = new MyMouse();
// drawStroke: thickness of lines drawn. Can change this as needed
private Stroke drawStroke = new BasicStroke(6f);
// drawColor -- change this as needed
private Color drawColor = Color.BLUE;
public SimpleDrawMain() {
simpleDrawPanel.addMouseListener(myMouse);
simpleDrawPanel.addMouseMotionListener(myMouse);
simpleDrawPanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
JPanel topPanel = new JPanel();
topPanel.add(new JButton(new SaveImageAction("Save", KeyEvent.VK_S)));
topPanel.add(new JButton(new ClearImageAction("Clear", KeyEvent.VK_C)));
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(simpleDrawPanel, BorderLayout.CENTER);
}
private class MyMouse extends MouseAdapter {
private Graphics2D g2;
private Point point; // point to draw a line with
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// get our Graphics object to draw with
g2 = simpleDrawPanel.getMyImage().createGraphics();
point = e.getPoint(); // get the first point
g2.setStroke(drawStroke); // set stroke and color
g2.setColor(drawColor);
}
@Override
public void mouseDragged(MouseEvent e) {
if (point == null) {
return;
}
drawOnImage(e);
}
@Override
public void mouseReleased(MouseEvent e) {
if (point == null) {
return;
}
drawOnImage(e);
// clean up things
g2.dispose();
g2 = null;
point = null;
}
private void drawOnImage(MouseEvent e) {
// better to draw a line between two points rather than an oval
// get 2nd point, and then using 2 points, create line to draw
Point p2 = e.getPoint();
int x1 = point.x;
int y1 = point.y;
int x2 = p2.x;
int y2 = p2.y;
g2.drawLine(x1, y1, x2, y2);
// reset the original point to the new point
point = p2;
simpleDrawPanel.repaint();
}
}
private class SaveImageAction extends AbstractAction {
public SaveImageAction(String name, int mnemonioc) {
super(name);
putValue(MNEMONIC_KEY, mnemonioc);
}
@Override
public void actionPerformed(ActionEvent e) {
BufferedImage img = simpleDrawPanel.getMyImage();
// TODO write code to save img to file
}
}
private class ClearImageAction extends AbstractAction {
public ClearImageAction(String name, int mnemonioc) {
super(name);
putValue(MNEMONIC_KEY, mnemonioc);
}
@Override
public void actionPerformed(ActionEvent e) {
simpleDrawPanel.clearImage();
}
}
private static void createAndShowGui() {
SimpleDrawMain mainPanel = new SimpleDrawMain();
JFrame frame = new JFrame("SimpleDraw");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setResizable(false);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class SimpleDrawPanel extends JPanel {
// preferred size dimensions for this JPanel
private int prefW;
private int prefH;
// image to draw on
private BufferedImage myImage;
public SimpleDrawPanel(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
myImage = new BufferedImage(prefW, prefH, BufferedImage.TYPE_INT_ARGB);
}
public BufferedImage getMyImage() {
return myImage;
}
public void clearImage() {
// simply create a new BufferedImage
myImage = new BufferedImage(prefW, prefH, BufferedImage.TYPE_INT_ARGB);
repaint();
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
g.drawImage(myImage, 0, 0, null);
}
}
}