绘图(二)五子棋小游戏

AWT编程 · 语雀

仓库Java图形化界面: Java图形化界面学习demo与资料 (gitee.com)

处理位图

如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调 。 AWT 也允许在组件上绘制位图, Graphics 提供了 drawlmage() 方法用于绘制位图,该方法需要一个Image参数一一代表位图,通过该方法就可 以绘制出指定的位图 。

位图使用步骤:

1.创建Image的子类对象BufferedImage(int width,int height,int ImageType),创建时需要指定位图的宽高及类型属性;此时相当于在内存中生成了一张图片;

2.调用BufferedImage对象的getGraphics()方法获取画笔,此时就可以往内存中的这张图片上绘图了,绘图的方法和之前学习的一模一样;

3.调用组件的drawImage()方法,一次性的内存中的图片BufferedImage绘制到特定的组件上。

使用位图绘制组件的好处:

使用位图来绘制组件,相当于实现了图的缓冲区,此时绘图时没有直接把图形绘制到组件上,而是先绘制到内存中的BufferedImage上,等全部绘制完毕,再一次性的图像显示到组件上即可,这样用户的体验会好一些。

案例:

通过BufferedImage实现一个简单的手绘程序:通过鼠标可以在窗口中画图。

演示代码:

java 复制代码
package awt_swimg.day04;

import awt_swimg.day01.Utils;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

public class HandDraw {

    //定义画图区的宽高
    private final int AREA_WIDTH = 500;
    private final int AREA_HEIGHT = 400;

    //定义变量,保存上一次鼠标拖动时,鼠标的坐标
    private int preX = -1;
    private int preY = -1;
    //定义一个右键菜单,用于设置画笔的颜色
    private PopupMenu popupMenu=new PopupMenu();
    private MenuItem redItem = new MenuItem("红色");
    private MenuItem greenItem = new MenuItem("绿色");
    private MenuItem buleItem = new MenuItem("蓝色");
    //定义一个BufferedImage对象
    private BufferedImage image = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_RGB);
    //获取BufferedImage对象关联的画笔
    private Graphics g=image.getGraphics();
    //定义窗口对象
    private JFrame frame = new JFrame("简单手绘程序");
    //定义画布对象
    private Canvas canvas=new Canvas(){
        @Override
        public void paint(Graphics g) {
            g.drawImage(image,0,0,null);
        }
    };
    //定义一个Color对象,用来保存用户设置的画笔颜色,默认为黑色
    private Color color = Color.BLACK;
    public void init(){

        redItem.addActionListener(e -> color = Color.red);
        greenItem.addActionListener(e -> color = Color.GREEN);
        buleItem.addActionListener(e -> color = Color.BLUE);
        canvas.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                if (e.isPopupTrigger()) {
                    popupMenu.show(canvas, e.getX(), e.getY());
                }
                preX = -1;
                preY = -1;
            }
        });
        canvas.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (preX > 0 && preY > 0) {
                    g.setColor(color);
                    g.drawLine(preX, preY, e.getX(), e.getY());
                }
                preX = e.getX();
                preY = e.getY();
                canvas.repaint();
            }
        });
        g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT);
        canvas.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT));
        canvas.add(popupMenu);
        popupMenu.add(redItem);
        popupMenu.add(greenItem);
        popupMenu.add(buleItem);

        frame.add(canvas);
        Utils.setJFrame(frame);
    }

    public static void main(String[] args) {
        new HandDraw().init();
    }



}

ImageIO的使用

在实际生活中,很多软件都支持打开本地磁盘已经存在的图片,然后进行编辑,编辑完毕后,再重新保存到本地磁盘。如果使用AWT要完成这样的功能,那么需要使用到ImageIO这个类,可以操作本地磁盘的图片文件。

|------------------------------------------------------------------------|--------------|
| 方法名称 | 方法功能 |
| static BufferedImage read(File input) | 读取本地磁盘图片文件 |
| static BufferedImage read(InputStream input) | 读取本地磁盘图片文件 |
| static boolean write(RenderedImage im, String formatName, File output) | 往本地磁盘中输出图片文件 |

案例:

编写图片查看程序,支持另存操作

演示代码:

java 复制代码
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

public class ReadAndSaveImage {

    private Frame frame = new Frame("图片查看器");

    private BufferedImage image;

    private class MyCanvas  extends Canvas{

        @Override
        public void paint(Graphics g) {
            if (image!=null){
                g.drawImage(image,0,0,image.getWidth(),image.getHeight(),null);
            }
        }
    }

    private MyCanvas imageComponent = new MyCanvas();

    public void init() throws Exception{

        //设置菜单项
        MenuBar mb = new MenuBar();
        Menu menu = new Menu("文件");
        MenuItem openItem = new MenuItem("打开");
        MenuItem saveItem = new MenuItem("另存为");

        openItem.addActionListener(e -> {
            //弹出对话框,选择本地图片
            FileDialog oDialog = new FileDialog(frame);
            oDialog.setVisible(true);
            //读取用户选择的图片
            String dir = oDialog.getDirectory();
            String file = oDialog.getFile();
            try {
                image = ImageIO.read(new File(dir,file));

                imageComponent.repaint();

            } catch (IOException e1) {
                e1.printStackTrace();
            }

        });


        saveItem.addActionListener(e -> {
            //弹出对话框,另存为
            FileDialog sDialog = new FileDialog(frame,"保存图片",FileDialog.SAVE);
            sDialog.setVisible(true);
            String dir = sDialog.getDirectory();
            String file = sDialog.getFile();

            try {
                ImageIO.write(image,"JPEG",new File(dir,file));
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        });

        mb.add(menu);
        menu.add(openItem);
        menu.add(saveItem);

        frame.setMenuBar(mb);
        frame.add(imageComponent);

        frame.setBounds(200,200,800,600);

        frame.setVisible(true);

        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }



    public static void main(String[] args) throws Exception {
        new ReadAndSaveImage().init();
    }
}

五子棋

接下来,我们使用之前学习的绘图技术,做一个五子棋的游戏。

演示代码:

java 复制代码
package awt_swimg.day04;

import awt_swimg.day01.Utils;

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 Gobang {
    //定义三个BufferedImage,分别代表棋盘图、黑子图、白子图
    private BufferedImage table;
    private BufferedImage black;
    private BufferedImage white;

    //定义一个BufferedImage,代表当鼠标移动时将要下子的选择框
    private BufferedImage selected;

    //定义棋盘的宽高,这里的定义尺寸和给定的board.jpg图片的尺寸一致因为棋盘背景是通过图片加载的
    private final int TABLE_WIDTH = 535;
    private final int TABLE_HEIGHT = 536;

    //定义棋盘中,每行和每列可下子的数目,这个数目跟给定的board.jpg中的数目是一致的,都为15
    private final int BOARD_SIZE = 15;

    //定义每个棋子所占棋盘总宽度的大小比率;每个棋子所占宽度 535/15=35
    private final int RATE = TABLE_WIDTH / BOARD_SIZE;

    //定义棋盘有效区域与背景图坐标之间的偏移值,x坐标右移5个像素,y坐标下移6个像素
    private final int X_OFFSET = 5;
    private final int Y_OFFSET = 6;
    /*

      定义一个二维数组充当棋盘上每个位置处的棋子;
      该数组的索引与该棋子在棋盘上的坐标需要有一个对应关系:
          例如: 索引[2][3]处的棋子,对一个的真实绘制坐标应该是:

              xpos = 2*RATE+X_OFFSET=75;
              ypos = 3*RATE+Y_OFFSET=111;

   */
    private int[][] board = new int[BOARD_SIZE][BOARD_SIZE];//如果存储0,代表没有棋子,如果存储1,代表黑棋,如果存储2,代表白棋

    //定义五子棋游戏窗口
    private JFrame frame = new JFrame("五子棋游戏");

    //定义变量,记录当前选中的坐标点对应的boad数组中对应的棋子索引;
    private int selectX = -1;
    private int selectY = -1;

    //定义一个变量,记录当前用户选择下的是白棋还是黑棋还是清除,清除:0,黑棋:1,白棋:2;
    private int chessCategory = 1;

    private JPanel canvas = new JPanel() {
        @Override
        public void paint(Graphics g) {
            g.drawImage(table, 0, 0, null);
            if (selectX > 0 && selectY > 0) {
                g.drawImage(selected, selectX * RATE + X_OFFSET, selectY * RATE + Y_OFFSET, null);
            }
            for (int i = 0; i < BOARD_SIZE; i++) {
                for (int j = 0; j < BOARD_SIZE; j++) {
                    if (board[i][j] == 2) {
                        g.drawImage(white, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null);
                    }
                    if (board[i][j] == 1) {
                        g.drawImage(black, i * RATE + X_OFFSET, j * RATE + Y_OFFSET, null);
                    }
                }
            }
        }
    };
    private Panel panel = new Panel();
    private Button whiteChess = new Button("白棋");
    private Button blackChess = new Button("黑棋");
    private Button delete = new Button("删除");


    public void init() throws IOException {
        //初始化数组,默认
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                board[i][j] = 0;
            }
        }
        canvas.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                selectX = (e.getX() - X_OFFSET) / RATE;
                selectY = (e.getY() - Y_OFFSET) / RATE;
                canvas.repaint();
            }

        });
        canvas.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                int xChess = (e.getX() - X_OFFSET) / RATE;
                int yChess = (e.getY() - Y_OFFSET) / RATE;
                board[xChess][yChess] = chessCategory;
                canvas.repaint();
            }

            @Override
            public void mouseExited(MouseEvent e) {
                selectX = -1;
                selectY = -1;
                canvas.repaint();
            }
        });
        whiteChess.addActionListener(e -> {
            chessCategory = 2;
            this.setButtonColor(Color.green,Color.white,Color.white);
        });
        blackChess.addActionListener(e -> {
            chessCategory = 1;
            this.setButtonColor(Color.white,Color.green,Color.white);
        });
        delete.addActionListener(e -> {
            chessCategory = 0;
            this.setButtonColor(Color.white,Color.white,Color.green);
        });


        table = ImageIO.read(new File("src/awt_swimg/img/board.jpg"));
        white = ImageIO.read(new File("src/awt_swimg/img/white.gif"));
        black = ImageIO.read(new File("src/awt_swimg/img/black.gif"));
        selected = ImageIO.read(new File("src/awt_swimg/img/selected.gif"));
        canvas.setPreferredSize(new Dimension(table.getWidth(), table.getHeight()));


        panel.add(whiteChess);
        panel.add(blackChess);
        panel.add(delete);
        frame.add(canvas);
        frame.add(panel, BorderLayout.SOUTH);
        Utils.setJFrame(frame);


    }

    public void setButtonColor(Color w,Color b ,Color d){
        whiteChess.setBackground(w);
        blackChess.setBackground(b);
        delete.setBackground(d);
    }

    public static void main(String[] args) throws IOException {
        new Gobang().init();
    }
}
相关推荐
学java的小菜鸟啊12 分钟前
第五章 网络编程 TCP/UDP/Socket
java·开发语言·网络·数据结构·网络协议·tcp/ip·udp
zheeez16 分钟前
微服务注册中⼼2
java·微服务·nacos·架构
程序员-珍20 分钟前
SpringBoot v2.6.13 整合 swagger
java·spring boot·后端
徐*红27 分钟前
springboot使用minio(8.5.11)
java·spring boot·spring
聆听HJ28 分钟前
java 解析excel
java·开发语言·excel
AntDreamer32 分钟前
在实际开发中,如何根据项目需求调整 RecyclerView 的缓存策略?
android·java·缓存·面试·性能优化·kotlin
java_heartLake36 分钟前
设计模式之建造者模式
java·设计模式·建造者模式
G皮T36 分钟前
【设计模式】创建型模式(四):建造者模式
java·设计模式·编程·建造者模式·builder·建造者
niceffking40 分钟前
JVM HotSpot 虚拟机: 对象的创建, 内存布局和访问定位
java·jvm
菜鸟求带飞_43 分钟前
算法打卡:第十一章 图论part01
java·数据结构·算法