锁定老帖子 主题:Swing 实现截图小软件 (三)
精华帖 (0) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-02-24
前面两节完成了,截图软件的基本功能:全屏,区域截图 功能
本节实现:涂鸦
, 画线 ,
画圈 和
保存
第一步:实现涂鸦功能。 涂鸦也就是说:使用鼠标随意的拖动,去绘制随意的线条。那么就只需要在主程序的展示截图的JLabel中添加鼠标拖动监听。在鼠标每个移动点是绘制“一个点”,这样就可以按照鼠标的移动轨迹,来绘制任意的线条了。
按照上面的思路给出代码:SnapShoot.java import java.awt.AWTException; import java.awt.Color; import java.awt.Container; import java.awt.Graphics2D; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.GroupLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; /** * 屏幕截图小程序 * @author pengranxiang * */ public class SnapShoot extends JFrame { /** * */ private static final long serialVersionUID = 1L; private JButton snapButton; private JLabel imageLabel; private int x, y; //记录鼠标坐标 public SnapShoot() { initUI(); initLayout(); createAction(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(600, 400); this.setTitle("截图小工具"); this.setLocationRelativeTo(null); //居中 this.setVisible(true); } private void initUI() { snapButton = new JButton("开始截图(点右键退出)"); imageLabel = new JLabel(); } private void initLayout() { JPanel pane = new JPanel(); pane.add(imageLabel); JScrollPane imgScrollPane = new JScrollPane(pane); Container container = this.getContentPane(); GroupLayout layout = new GroupLayout(container); container.setLayout(layout); layout.setAutoCreateContainerGaps(true); layout.setAutoCreateGaps(true); GroupLayout.ParallelGroup hGroup = layout.createParallelGroup(); hGroup .addComponent(snapButton) .addComponent(imgScrollPane); layout.setHorizontalGroup(hGroup); GroupLayout.SequentialGroup vGroup = layout.createSequentialGroup(); vGroup .addComponent(snapButton) .addComponent(imgScrollPane); layout.setVerticalGroup(vGroup); } private void createAction() { snapButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { //开启模拟屏幕,将显示截图的目标组件传入 new ScreenWindow(imageLabel); } catch (AWTException e1) { e1.printStackTrace(); } catch (InterruptedException e1) { e1.printStackTrace(); } } }); imageLabel.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent e) { x = e.getX(); y = e.getY(); //鼠标移动时,在imageLabel展示的图像中,绘制点 //1. 取得imageLabel中的图像 Image img = ((ImageIcon)imageLabel.getIcon()).getImage(); //2. 创建一个缓冲图形对象 bi BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) bi.getGraphics(); //3. 将截图的原始图像画到 bi g2d.drawImage(img, 0, 0, null); //4. 在鼠标所在的点,画一个点 g2d.setColor(Color.RED); //设置画笔颜色为红色 g2d.drawLine(x, y, x, y); //Java中没有提供点的绘制,使用起点和终点为同一个点的画线代替 g2d.dispose(); //5. 为了保留每一个点,不能直接使用imageLabel.getGraphics()来画, //需要使用imageLabel.setIcon()来直接将画了点的图像,设置到imageLabel中, //这样,在第一步中,取得img时,就为已经划过上一个点的图像了。 imageLabel.setIcon(new ImageIcon(bi)); } public void mouseMoved(MouseEvent e) { } }); } public static void main(String[] args) { new SnapShoot(); } }
运行该代码,发现在涂鸦时,跟踪鼠标画的点,太过分散,不连续。鼠标移动越快,点就越不连续。如图: 可见,在监听鼠标移动时,画点的速度,跟不上鼠标移动的速度。又图想到,如果把上面的散点全部连接起来,则可以构成一条平滑的线了。
于是:改变思路,由画点,改为画线。将鼠标移动监听到的每一个点,都首尾连接的画线。 节约篇幅:展示修改的部分代码,在createActon()中 imageLabel.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { //鼠标按下的点,作为画线的最初的起点 x = e.getX(); y = e.getY(); } }); imageLabel.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent e) { xEnd = e.getX(); yEnd = e.getY(); //鼠标移动时,在imageLabel展示的图像中,绘制点 //1. 取得imageLabel中的图像 Image img = ((ImageIcon)imageLabel.getIcon()).getImage(); //2. 创建一个缓冲图形对象 bi BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) bi.getGraphics(); //3. 将截图的原始图像画到 bi g2d.drawImage(img, 0, 0, null); //4. 在鼠标所在的点,画一个点 g2d.setColor(Color.RED); //设置画笔颜色为红色 g2d.drawLine(x, y, xEnd, yEnd); //将画点,改为画线 g2d.dispose(); //5. 为了保留每一个点,不能直接使用imageLabel.getGraphics()来画, //需要使用imageLabel.setIcon()来直接将画了点的图像,设置到imageLabel中, //这样,在第一步中,取得img时,就为已经划过上一个点的图像了。 imageLabel.setIcon(new ImageIcon(bi)); //下次画线起点是设置为这次画线的终点 x = xEnd; y = yEnd; } public void mouseMoved(MouseEvent e) { } });
改变思路后,涂鸦的线条效果,就好多了。如图:
第二步:实现画线功能。 画线的话,与涂鸦有点不同。 涂鸦是根据鼠标移动实时画线。 而画线功能要求是:从鼠标按下, 到鼠标弹起的两点之间画一条线段。鼠标移动时,只是展示最后效果,并不直接画上去。 鼠标弹起后,才真的画上去。
同时因为,有了连个功能,我们给个功能开关,是要涂鸦,还是要画线。 代码片段:createAction() 中
imageLabel.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { //鼠标按下的点,作为画线的最初的起点 x = e.getX(); y = e.getY(); } public void mouseReleased(MouseEvent e) { if(isLine) { //该方法只用作画线时处理 //鼠标弹起时需要将最后定为的图像 bi,调用imageLabel.setIcon()方法,设置进去。 //这样就可以将线段真的画进去了。为了使用变量 bi 将其转为 该类的private变量 imageLabel.setIcon(new ImageIcon(bi)); } } }); imageLabel.addMouseMotionListener(new MouseMotionListener() { public void mouseDragged(MouseEvent e) { if(isDoodle) { //涂鸦开关 xEnd = e.getX(); yEnd = e.getY(); //鼠标移动时,在imageLabel展示的图像中,绘制点 //1. 取得imageLabel中的图像 Image img = ((ImageIcon)imageLabel.getIcon()).getImage(); //2. 创建一个缓冲图形对象 bi bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) bi.getGraphics(); //3. 将截图的原始图像画到 bi g2d.drawImage(img, 0, 0, null); //4. 在鼠标所在的点,画一个点 g2d.setColor(Color.RED); //设置画笔颜色为红色 g2d.drawLine(x, y, xEnd, yEnd); //Java中没有提供点的绘制,使用起点和终点为同一个点的画线代替 g2d.dispose(); //5. 为了保留每一个点,不能直接使用imageLabel.getGraphics()来画, //需要使用imageLabel.setIcon()来直接将画了点的图像,设置到imageLabel中, //这样,在第一步中,取得img时,就为已经划过上一个点的图像了。 imageLabel.setIcon(new ImageIcon(bi)); //下次画线起点是设置为这次画线的终点 x = xEnd; y = yEnd; } if(isLine) { //画线开关 xEnd = e.getX(); yEnd = e.getY(); //鼠标移动时,在imageLabel展示的图像中,绘制点 //1. 取得imageLabel中的图像 Image img = ((ImageIcon)imageLabel.getIcon()).getImage(); //2. 创建一个缓冲图形对象 bi bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) bi.getGraphics(); //3. 将截图的原始图像画到 bi g2d.drawImage(img, 0, 0, null); //4. 在鼠标所在的点,画一个点 g2d.setColor(Color.RED); //设置画笔颜色为红色 g2d.drawLine(x, y, xEnd, yEnd); //Java中没有提供点的绘制,使用起点和终点为同一个点的画线代替 g2d.dispose(); //5. 不需要保留在鼠标拖动过程中所画的线段,所以直接使用imageLabel.getGraphics()绘制 //这样imageLabel.getIcon()并没有被改变,所以每次都只到原始截图和多了一条线,即为最后效果的演示 Graphics g = imageLabel.getGraphics(); g.drawImage(bi, 0, 0, null); //将处理后的图片,画到imageLabel g.dispose(); } } 运行情况如图: 完整代码,见附件:SnapShoot1.jar 源码在 jar 包中。
第三步:实现画圈功能。 画圈的功能实现与画线就很想了, 只是修改一下,drawLine -- > drawOval
代码片段: if(isLine) { g2d.drawLine(x, y, xEnd, yEnd); //Java中没有提供点的绘制,使用起点和终点为同一个点的画线代替 } if(isCircle) { //因为如果鼠标向上,或向左移动时,xEnd > x, yEnd > y ,所以画圆的起点要取两者中的较小的, //而宽度和高度是不能 < 0 的,所以取绝对值 g2d.drawOval(Math.min(x, xEnd), Math.min(y, yEnd), Math.abs(xEnd - x), Math.abs(yEnd - y)); }
运行如图: 完成代码见附件:SnapShoot2.jar 源码在 jar 包中。
第四步: 为了然该小软件有点用处,光截图,涂鸦之类的,只能看不能用。所以现在就加入 保存 功能吧。
代码片段: chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & PNG Images", "jpg", "png"); chooser.setFileFilter(filter); saveButton = new JButton("保存"); saveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(imageLabel.getIcon() == null) { JOptionPane.showMessageDialog(SnapShoot.this, "没有图片信息,请先截图", "提示", JOptionPane.INFORMATION_MESSAGE); return; } File file = null; int returnVal = chooser.showOpenDialog(SnapShoot.this); if(returnVal == JFileChooser.APPROVE_OPTION) { file = chooser.getSelectedFile(); } //取得imageLabel中的图像 Image img = ((ImageIcon)imageLabel.getIcon()).getImage(); try { if(file != null) { ImageIO.write((BufferedImage)img, "png", file); JOptionPane.showMessageDialog(SnapShoot.this, "保存成功", "提示", JOptionPane.INFORMATION_MESSAGE); } } catch (IOException e1) { e1.printStackTrace(); } } }); 运行如图: 完成代码见附件:SnapShoot3.jar 源码在 jar 包中
最后,界面是丑了点啦。。。
想要稍微让界面好看点,可以修改 LookAndFeel 为本地皮肤,修改 main()方法 public static void main(String[] args) { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); JFrame.setDefaultLookAndFeelDecorated(true); } catch (Exception e) { System.out.println("Error setting native LAF: " + e); } new SnapShoot(); }
如图:
完成代码见附件:SnapShoot.jar 源码在 jar 包中
到此,该小软件还剩下,水印功能。 明天继续。。。O(∩_∩)O~ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-02-25
呵呵,下载了,有时间看一下。
|
|
返回顶楼 | |
发表时间:2011-02-25
恩,应该挺有趣的。。。。
|
|
返回顶楼 | |
发表时间:2011-03-08
很久没上javaeye swing,发现有这么多更新,可惜现在工作了,忙,没空研究
|
|
返回顶楼 | |
浏览 6037 次