Java Can';无法将我的面板另存为图像
我做了一个简单的绘画程序,但似乎有一些问题。首先,当我运行程序时,直到我将鼠标拖动到每个组件上,组件才会显示。其次,我创建的drawPanel图像只保存面板的背景,而不保存在上面绘制的内容。另一个小问题是,当我通过下拉菜单改变点的大小时,它下面画的任何东西都会被擦除。任何关于清理我的代码或解决我的问题的建议都会很好Java Can';无法将我的面板另存为图像,java,swing,jframe,jpanel,bufferedimage,Java,Swing,Jframe,Jpanel,Bufferedimage,我做了一个简单的绘画程序,但似乎有一些问题。首先,当我运行程序时,直到我将鼠标拖动到每个组件上,组件才会显示。其次,我创建的drawPanel图像只保存面板的背景,而不保存在上面绘制的内容。另一个小问题是,当我通过下拉菜单改变点的大小时,它下面画的任何东西都会被擦除。任何关于清理我的代码或解决我的问题的建议都会很好 import javax.imageio.ImageIO; import javax.swing.*; import java.awt.*; import java.awt.even
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);
}
}
编辑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);
}
}
解决了一个问题:
您没有在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等等。。。你真的不想冒险弄乱这些子组件的图纸
接下来,要保存图形中的图像,请绘制到BuffereImage,然后将该BuffereImage显示在图形JPanel的(连接了鼠标侦听器的)paintComponent中,如:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
g.drawImage(myImage, 0, 0, null);
}
}
因此,在鼠标侦听器中,您可以使用通过调用图像上的getGraphics()
或createGraphics()
从图像中获取的图形来绘制此图像。前者获取图形对象,而后者获取Graphics2D对象。请注意,这与对不推荐的组件调用getGraphics()
不同(根据我的评论)。还请注意,以这种方式获得的任何图形对象都应该在使用完毕后进行处理,以免浪费资源
我创建了一个BuffereImage,但如何将其添加到drawPanel/JFrame中 图形JPanel可以将BuffereImage作为字段保存。当您需要在它上面绘制时,您可以获得上面提到的图形上下文——请注意,我更喜欢使用
createGraphics()
来获得Graphics2D对象,这样我就可以使用它的所有优点,例如笔划。将BuffereImage的大小调整为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);
}
}
}
欢迎来到StackOverflow。请理解,如果您提出一个具体且可回答的问题,而不是一个含糊不清的要求“帮助我清理”,我们将能够更好地提供帮助。请查看,并找出如何改进此问题并提高获得正确答案的几率。请注意,您不希望直接在JFrame中绘制,而是希望在JPanel的paintComponent方法中绘制,并且您希望在重写中首先调用super的方法。请阅读绘画教程。您可以在此处找到指向Swing教程和其他Swing资源的链接:@HovercraftFullOfEels那么您的意思是每个JPanel都有其特定的绘制组件?我是否仍然需要JPanel边界的if语句,这样我就不会在其他组件上绘制了?我看到您直接调用了paint--永远不要这样做。您还可以通过
getGraphics()
获取组件的图形对象,如果这样做,您将得到一个短暂的对象,它可能导致NullPointerException或图像消失,因此您也不想这样做。你看过Swing图形教程了吗?如果没有,您真的希望尽快完成此操作。请检查:1)、Swing graphics入门教程和2)、Swing graphics高级教程。我创建了BuffereImage,但如何将其添加到drawPanel/JFrame中。我也不确定如何在缓冲图像上绘制;然后重新绘制();直接在mouseClicked中什么也看不到。@Alexarkenzon:最好的办法是,如果你有问题,创建一个小的可编译和可运行的程序,向我们演示你的问题。我添加了一个较小的版本top@AlexMarkenzon当前位置您没有按照我的建议进行操作,似乎您仍然直接在JFrame中进行绘制,一个甚至没有要重写的paintComponent方法的类(这就是为什么编译器不允许您调用超级方法,而是调用完全不相关的paintComponents方法)。请重新阅读我的建议,请重新阅读我的代码示例。你可以解决这个问题,但这需要一些努力。
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);
}
}
}