zoukankan      html  css  js  c++  java
  • 02.制作一个自己的 Java 编辑器

    难度中等,适合 Java 基础扎实,对 Java 核心 API 有所熟悉的同学学习

    No1、制作GUI界面

    一、实验介绍

    1.1 实验内容

    本节课程的主要内容是准备开发环境,建立项目并完成 GUI 界面的编程实现。

    1.2 实验知识点

    Java Swing 编程

    1.3 实验环境

    本实验环境采用带桌面的 Ubuntu Linux 环境,实验中会用到的环境或软件:

    JDK1.7

    Eclipse。

    1.4 适合人群

    本节课程难度较低,属于初级课程,适合要想学习Java Swing 编程的同学学习。

    1.5 代码获取

    你可以在Xfce终端下通过下面命令将实验的完整工程项目下载到实验楼环境中,作为参照对比进行学习。

    $ wget http://labfile.oss.aliyuncs.com/courses/287/MyEdit.tar.gz

    二、项目文件结构 

    三、实验步骤

    这一节我们将开发GUI界面。

     3.1 新建项目

    首先请双击打开桌面上的 Eclipse ,等待它启动完成后,在菜单 File 中点击 New -> Java Project选项。 此处输入图片的描述 

    在弹出的窗口里填写项目的名称 MyEdit,然后点击 Finish 按钮。

     

     3.2 创建包和类

    项目创建完成后,我们需要按照之前的项目结构来创建各个类。本项目一共有两个类:

    FileWindow:主要方法类,用作GUI界面以及逻辑功能的实现

    Main:测试类

    因此我们首先需要创建一个名为 com.hijackykun.myedit 的包。

     请在创建好的项目目录 src 文件夹上右键点击,然后选择 New -> Package。 

    在弹出的 New Java Package 对话框中填写包名com.shiyanlou.myedit,并点击 Finish 按钮。 

    最后,在新建好的包下新建FileWindow和Main类。

     3.3 GUI 界面的实现

    GUI界面的效果图如下:

     

    界面的设计采用卡片布局(CardLayout),白色文本域为程序输入区,粉红色文本域为编译结果显示区,浅蓝色文本域为程序运行结果区。点击上方不同的功能按钮显示对应的文本域。

     在FileWindow类中编写实现 GUI 的代码,相关的代码如下,代码的讲解将会以注释的形式进行,请在编写代码的同时留意相关的注释。

     注:以下代码均未导入相关的包

      public class FileWindow extends JFrame implements ActionListener, Runnable {

         /*注意:因为实现了ActionListener 和Runnable接口,所以必须要实现这两个接口的方法。这里我们先把这两个方法简单实现以下。下节课将彻底完成这两个方法。*/

         Thread compiler = null;

        Thread run_prom = null;

        boolean bn = true;

        CardLayout mycard;  //声明布局,以后会用到

        File file_saved = null;

        JButton button_input_txt,   //按钮的定义

                button_compiler_text,

                button_compiler,

                button_run_prom,

                button_see_doswin;

         JPanel p = new JPanel();

        JTextArea input_text = new JTextArea(); // 程序输入区

        JTextArea compiler_text = new JTextArea();// 编译错误显示区

        JTextArea dos_out_text = new JTextArea();// 程序的输出信息

         JTextField input_file_name_text = new JTextField();

        JTextField run_file_name_text = new JTextField();

         public FileWindow() {

            // TODO Auto-generated constructor stub

            super("Java语言编译器");

            mycard = new CardLayout();

            compiler=new Thread(this);

            run_prom=new Thread(this);

            button_input_txt=new JButton("程序输入区(白色)");

            button_compiler_text=new JButton("编译结果区(粉红色)");

            button_see_doswin=new JButton("程序运行结果(浅蓝色)");

            button_compiler=new JButton("编译程序");

            button_run_prom=new JButton("运行程序");

             p.setLayout(mycard);//设置卡片布局

            p.add("input",input_text);//定义卡片名称

            p.add("compiler", compiler_text);

            p.add("dos",dos_out_text);

            add(p,"Center");

             compiler_text.setBackground(Color.pink); //设置颜色

            dos_out_text.setBackground(Color.cyan);

            JPanel p1=new JPanel();

             p1.setLayout(new GridLayout(3, 3)); //设置表格布局

            //添加组件

            p1.add(button_input_txt);

            p1.add(button_compiler_text);

            p1.add(button_see_doswin);

            p1.add(new JLabel("输入编译文件名(.java):"));

            p1.add(input_file_name_text);

            p1.add(button_compiler);

            p1.add(new JLabel("输入应用程序主类名"));

            p1.add(run_file_name_text);

            p1.add(button_run_prom);

            add(p1,"North");

             //定义事件

            button_input_txt.addActionListener(this);

            button_compiler.addActionListener(this);

            button_compiler_text.addActionListener(this);

            button_run_prom.addActionListener(this);

            button_see_doswin.addActionListener(this);

        }

         public void actionPerformed(ActionEvent e)

        {

             //实现方法

        }

         @Override

        public void run() {

            //实现方法

        }

        }

     到此,我们的 GUI 界面就算做好了!

       3.4 测试类的实现

    下面,我们赶紧做个测试类,测试一下我们的界面。

    Main.java:

        import java.awt.event.WindowAdapter;

        import java.awt.event.WindowEvent;

        public class Main {

             public static void main(String[] args) {

                // TODO Auto-generated method stub

                FileWindow win=new FileWindow();

                win.pack();

                win.addWindowListener(new WindowAdapter() {

                    public void windowClosing(WindowEvent e)

                    {

                        System.exit(0);

                    }

                });

                win.setBounds(200, 180,550,360);

                win.setVisible(true);

            }

         }

    界面和测试类就完成了。

     四、实验总结

    在本节实验中,我们完成了项目的创建以及 GUI 界面,下节实验我们将完善本节的遗留问题,实现界面组件事件响应逻辑和Java文件的编辑、编译及运行。主要包括两个方法:

    public void actionPerformed(ActionEvent e)

    public void run()

     No2、实现功能

    一、实验介绍

    1.1 实验内容

    在上节实验中我们完成了编辑器的界面,可是按钮的响应功能并未完成,在本节实验中我们将实现界面组件事件响应逻辑和Java文件的编辑、编译及运行。主要包括两个方法:

     public void actionPerformed(ActionEvent e)

    public void run()

    1.2 实验知识点

    Java Swing 编程

    IO 流操作

    Runtime 类

    Thread 的使用

    1.3 实验环境

    本实验环境采用带桌面的 Ubuntu Linux 环境,实验中会用到的环境或软件:

     JDK1.7

    Eclipse。

    1.4 适合人群

    本节课程难度较难,属于中级课程,适合对 Java 核心 API 有较深入理解的同学学习。

     1.5 代码获取

    你可以在Xfce终端下通过下面命令将实验的完整工程项目下载到实验楼环境中,作为参照对比进行学习。

     $ wget http://labfile.oss.aliyuncs.com/courses/287/MyEdit.tar.gz

    二、项目文件结构

    三、实验步骤

     3.1 actionPerformed 方法的实现

    首先咱们实现 public void actionPerformed(ActionEvent e) 这个方法。代码中的注释进行了详细的讲解。

         public void actionPerformed(ActionEvent e)

            {

                if(e.getSource()==button_input_txt)

                {    //显示程序输入区

                    mycard.show(p,"input");

                }

                else if(e.getSource()==button_compiler_text)

                {    //显示编译结果显示区

                    mycard.show(p,"compiler");

                }

                else if(e.getSource()==button_see_doswin)

                {    //显示程序运行结果区

                    mycard.show(p,"dos");

                }

                else if(e.getSource()==button_compiler)

                {    //如果是编译按钮,执行编译文件的方法

                    if(!(compiler.isAlive()))

                    {

                        compiler=new Thread(this);

                    }

                    try {

                        compiler.start();

                    } catch (Exception e2) {

                        // TODO: handle exception

                        e2.printStackTrace();

                    }

                    mycard.show(p,"compiler");

                }

                else if(e.getSource()==button_run_prom)

                {    //如果是运行按钮,执行运行文件的方法

                    if(!(run_prom.isAlive()))

                    {

                        run_prom=new Thread(this);

                    }

                    try {

                        run_prom.start();

                    } catch (Exception e2) {

                        // TODO: handle exception

                        e2.printStackTrace();

                    }

                    mycard.show(p,"dos");

                }

             }

    以上的代码就是通过比较来判断需要处理哪些事件。

     3.2 run 方法的实现

    然后就剩一个 run() 方法,也是最重要的一个方法。在这个方法里会判断是编译还是运行:

     如果当前Thread是编译,那么会将程序输入区中的代码以.java文件的形式保存到项目的当前目录下,并通过javac命令执行刚才保存的.java文件生成.class文件,编译后的信息会输出到编译结果显示区。

     如果当前Thread是运行,那么会通过java命令执行编译生成的.class文件,并将程序结果显示到程序运行结果区中。

         public void run() {

                 //TODO Auto-generated method stub

                if(Thread.currentThread()==compiler)

                {

                compiler_text.setText(null);

                String temp=input_text.getText().trim();

                byte [] buffer=temp.getBytes();

                int b=buffer.length;

                String file_name=null;

           file_name=input_file_name_text.getText().trim();

          try {

        file_saved=new File(file_name);

        FileOutputStream writefile=null;

        writefile=new FileOutputStream(file_saved);

        writefile.write(buffer, 0, b);

        writefile.close();

                } catch (Exception e) {

                        // TODO: handle exception

                        System.out.println("ERROR");

                    }

        try {

         //获得该进程的错误流,才可以知道运行结果到底是失败了还是成功。

         Runtime rt=Runtime.getRuntime();

           InputStream in=rt.exec("javac "+file_name).getErrorStream(); //通过Runtime调用javac命令。注意:“javac ”这个字符串是有一个空格的!!

             BufferedInputStream bufIn=new BufferedInputStream(in);

             byte[] shuzu=new byte[100];

            int n=0;

            boolean flag=true;

             //输入错误信息       

        while((n=bufIn.read(shuzu, 0,shuzu.length))!=-1)

            {

                String s=null;

                  s=new String(shuzu,0,n);

                compiler_text.append(s);

                if(s!=null)

                            {

                                flag=false;

                            }

                }

                        //判断是否编译成功

                        if(flag)

                        {

                            compiler_text.append("Compile Succeed!");

                        }

                    } catch (Exception e) {

                        // TODO: handle exception

                    }

                }

        else if(Thread.currentThread()==run_prom)

            {

                //运行文件,并将结果输出到dos_out_text

            dos_out_text.setText(null);

            try {

                  Runtime rt=Runtime.getRuntime();

        String path=run_file_name_text.getText().trim();

        Process stream=rt.exec("java "+path);//调用java命令

        InputStream in=stream.getInputStream();

                        BufferedInputStream bisErr=new BufferedInputStream(stream.getErrorStream());

                        BufferedInputStream bisIn=new BufferedInputStream(in);

        byte[] buf=new byte[150];

        byte[] err_buf=new byte[150];

        @SuppressWarnings("unused")

        int m=0;

        @SuppressWarnings("unused")

        int i=0;

        String s=null;

        String err=null;

        //打印编译信息及错误信息

        while((m=bisIn.read(buf, 0, 150))!=-1)

                        {

                            s=new String(buf,0,150);

                            dos_out_text.append(s);

                        }

                                      while((i=bisErr.read(err_buf))!=-1)

                        {

                        err=new String(err_buf,0,150);

                        dos_out_text.append(err);

                        }

            }

             catch (Exception e) {

                        // TODO: handle exception

                        }

            }

         }

     3.3 进行简单测试

    点击编译按钮会出现错误信息,证明距离成功不远了。

     运行按钮错误:

     点击按钮在程序输入区(白色),写一个简单的测试小程序吧!代码如下:

         class a

        {

            public static void main(String [] args)

            {

                System.out.println("Hello ShiYanLou");

            }

        }

     接着在输入编译文件名(.java)后面的文本框里填入与类名相同的.java文件,如a.java,点击编译程序。

    如果程序没有出错,那么编译结果显示如下:

     在输入应用程序主类名后面的文本框里填入类名,如a,点击运行程序。

     程序的运行结果将会显示在浅蓝色的文本域中。

     重新编辑的时候需要点击按钮在程序输入区(白色),在白色文本域进行输入。

    三、实验总结

    至此,我们终于完成了整个程序,实现了编辑Java代码、编译和运行Java文件的功能。本次课程涉及的知识点比较复杂,特别是 Runtime 类和 Thread 的使用,希望同学们下来能够对这些知识点进行巩固。

    五、课后习题

    同学们下来考虑如何丰富其功能,例如 “代码高亮”、“代码自动补全” 等等。这些功能有的比较难,不一定要实现,但要勤于思考。

    具体代码:

    FileWindow.java

    package com.hijackykun.myedit;
    import java.awt.CardLayout;
    import java.awt.Color;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    @SuppressWarnings("serial")
    //压制信息,不会的同学可以不理会。
    public class FileWindow extends JFrame implements ActionListener,Runnable{
         /*注意:因为实现了ActionListener 和Runnable接口,所以必须要实现这两个接口的方法。
          * 这里我们先把这两个方法简单实现以下。下节课将彻底完成这两个方法。*/
        Thread compiler = null;
        Thread run_prom = null;
        boolean bn = true;
        CardLayout mycard;  //声明布局,以后会用到
        File file_saved = null;
        JButton button_input_txt,   //按钮的定义
                button_compiler_text,
                button_compiler,
                button_run_prom,
                button_see_doswin;
        JPanel p = new JPanel();
        JTextArea input_text = new JTextArea(); // 程序输入区
        JTextArea compiler_text = new JTextArea();// 编译错误显示区
        JTextArea dos_out_text = new JTextArea();// 程序的输出信息
        JTextField input_file_name_text = new JTextField();
        JTextField run_file_name_text = new JTextField();
        public FileWindow() {
            // TODO Auto-generated constructor stub
            super("Java语言编译器");
            mycard = new CardLayout();
            compiler=new Thread(this);
            run_prom=new Thread(this);
            button_input_txt=new JButton("程序输入区(白色)");
            button_compiler_text=new JButton("编译结果区(粉红色)");
            button_see_doswin=new JButton("程序运行结果(浅蓝色)");
            button_compiler=new JButton("编译程序");
            button_run_prom=new JButton("运行程序");
            p.setLayout(mycard);//设置卡片布局
            p.add("input",input_text);//定义卡片名称
            p.add("compiler", compiler_text);
            p.add("dos",dos_out_text);
            add(p,"Center");
    
            compiler_text.setBackground(Color.pink); //设置颜色
            dos_out_text.setBackground(Color.cyan);
            JPanel p1=new JPanel();
    
            p1.setLayout(new GridLayout(3, 3)); //设置表格布局
            //添加组件
            p1.add(button_input_txt);
            p1.add(button_compiler_text);
            p1.add(button_see_doswin);
            p1.add(new JLabel("输入编译文件名(.java):"));
            p1.add(input_file_name_text);
            p1.add(button_compiler);
            p1.add(new JLabel("输入应用程序主类名"));
            p1.add(run_file_name_text);
            p1.add(button_run_prom);
            add(p1,"North");
    
            //定义事件
            button_input_txt.addActionListener(this);
            button_compiler.addActionListener(this);
            button_compiler_text.addActionListener(this);
            button_run_prom.addActionListener(this);
            button_see_doswin.addActionListener(this);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
             if(e.getSource()==button_input_txt)
             {    //显示程序输入区
                 mycard.show(p,"input");
             }
             else if(e.getSource()==button_compiler_text)
             {    //显示编译结果显示区
                 mycard.show(p,"compiler");
             }
             else if(e.getSource()==button_see_doswin)
             {    //显示程序运行结果区
                 mycard.show(p,"dos");
             }
             else if(e.getSource()==button_compiler)
             {    //如果是编译按钮,执行编译文件的方法
                 if(!(compiler.isAlive()))
                 {
                     compiler=new Thread(this);
                 }
                 try {
                     compiler.start();
    
                 } catch (Exception e2) {
                     // TODO: handle exception
                     e2.printStackTrace();
                 }
    
                 mycard.show(p,"compiler");
    
             }
             else if(e.getSource()==button_run_prom)
             {    //如果是运行按钮,执行运行文件的方法
                 if(!(run_prom.isAlive()))
                 {
                     run_prom=new Thread(this);
                 }
                 try {
                     run_prom.start();
                 } catch (Exception e2) {
                     // TODO: handle exception
                     e2.printStackTrace();
                 }
                 mycard.show(p,"dos");
             }
    
        }
        
        @Override
        public void run() {
            // TODO Auto-generated method stub
            if (Thread.currentThread() == compiler) {
                compiler_text.setText(null);
                String temp = input_text.getText().trim();
                byte[] buffer = temp.getBytes();
                int b = buffer.length;
                String file_name = null;
                file_name = input_file_name_text.getText().trim();
    
                try {
                    file_saved = new File(file_name);
                    FileOutputStream writefile = null;
                    writefile = new FileOutputStream(file_saved);
                    writefile.write(buffer, 0, b);
                    writefile.close();
                } catch (Exception e) {
                    // TODO: handle exception
                    System.out.println("ERROR");
                }
                try {
                    // 获得该进程的错误流,才可以知道运行结果到底是失败了还是成功。
                    Runtime rt = Runtime.getRuntime();
                    InputStream in = rt.exec("javac " + file_name).getErrorStream(); 
                    // 通过Runtime调用javac命令。注意:“javac ”这个字符串是有一个空格的!!
                    BufferedInputStream bufIn = new BufferedInputStream(in);
                    byte[] shuzu = new byte[100];
                    int n = 0;
                    boolean flag = true;
                    // 输入错误信息
                    while ((n = bufIn.read(shuzu, 0, shuzu.length)) != -1) {
                        String s = null;
                        s = new String(shuzu, 0, n);
                        compiler_text.append(s);
                        if (s != null) {
                            flag = false;
                        }
                    }
                    // 判断是否编译成功
                    if (flag) {
                        compiler_text.append("Compile Succeed!");
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
            } else if (Thread.currentThread() == run_prom) {
                // 运行文件,并将结果输出到dos_out_text
                dos_out_text.setText(null);
                try {
                    Runtime rt = Runtime.getRuntime();
                    String path = run_file_name_text.getText().trim();
                    Process stream = rt.exec("java " + path);// 调用java命令
                    InputStream in = stream.getInputStream();
                    BufferedInputStream bisErr = new BufferedInputStream(
                            stream.getErrorStream());
                    BufferedInputStream bisIn = new BufferedInputStream(in);
                    byte[] buf = new byte[150];
                    byte[] err_buf = new byte[150];
                    @SuppressWarnings("unused")
                    int m = 0;
                    @SuppressWarnings("unused")
                    int i = 0;
                    String s = null;
                    String err = null;
                    // 打印编译信息及错误信息
                    while ((m = bisIn.read(buf, 0, 150)) != -1) {
                        s = new String(buf, 0, 150);
                        dos_out_text.append(s);
                    }
                    while ((i = bisErr.read(err_buf)) != -1) {
                        err = new String(err_buf, 0, 150);
                        dos_out_text.append(err);
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    }
    View Code

    Main.java

    package com.hijackykun.myedit;
    
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    public class Main {
    
        public static void main(String[] args) {
            FileWindow win =new FileWindow();
            win.pack();//根据窗口里面的布局及组件的preferredSize来确定frame的最佳大小
            win.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
            });
            //setBounds(x,y,width,height); 
            //x:组件在容器X轴上的起点 y:组件在容器Y轴上的起点 组件的长度 height:组件的高度
            win.setBounds(200, 180, 550, 360);
            win.setVisible(true);
        }
    
    }
    View Code

    参考来源:https://www.shiyanlou.com/courses/287

  • 相关阅读:
    解释 ASP.NET中的Web页面与其隐藏类之间的关系
    B/S与C/S的联系与区别
    三层架构
    列举 ASP.NET页面之间传递值的几种方式
    什么是SQL注入式攻击?如何防范?
    post、get的区别
    Session,ViewState,Application,cookie的区别?
    Vue 09.前后端交互
    Vue 08.webpack中使用.vue组件
    Vue 07.webpack
  • 原文地址:https://www.cnblogs.com/HiJackykun/p/10390929.html
Copyright © 2011-2022 走看看