搜尋
首頁Javajava教程使用Java製作簡易的畫板教學

使用Java製作簡易的畫板教學

Jul 18, 2017 pm 02:54 PM
java實現

Windows的畫圖板相信很多人都用過,這次我們就來講講Java版本的簡易畫板的實作。
基本的思路是這樣的:畫板實現大致分為三部分:一是畫板介面的實現,二是畫板的監聽以及畫圖的實現,三是畫板的重繪。 (文章較長,但是程式碼是逐步遞進的,可以按三部分分開來看,實現了當前部分再去看下一部分。)首先是畫板的介面實現,因為我沒有去找具體的圖標,介面上的所有元件都是Swing的自帶元件,所以介面略微有點簡陋,不過如果想要優化也簡單,把介面上的元件都改成自訂的圖示即可。介面實現後,就可以考慮為介面的元件加上監聽,不同的圖形依具體情況添加不同的監聽方法。然後編寫事件處理類別依據不同的圖形編寫畫圖的具體演算法。一個簡易版本的畫圖板基本上就差不多可以實現了。重繪這裡先不提放到後面再講。
先來看看畫圖介面的實作:
# #實作畫圖介面需要用的API類別主要有:FlowLayout,GridLayout,Color,Dimension,JButton,JFrame,JPanel。
定義Draw類,讓Draw類別繼承JFrame。設定它的大小,標題,可見性等。要注意的是這裡如果添加的按鈕如果比較多,建議使用數組來完成按鈕的添加,因為如果直接一個一個的加按鈕,不僅會使得代碼量增大,而且不利於查找、添加和代碼的維護。為了使得介面不至於顯得那麼簡陋,這裡使用了幾個Jpanel,和不同的佈局管理器。主窗體使用的是流式佈局管理器,然後使用三個面板,分別承裝圖形按鈕,顏色按鈕和畫布。承裝圖形按鈕和顏色按鈕的面板都使用表格佈局。然後介面的實作就基本完成了。
package Cbs;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.GridLayout;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;/**
 * Draw类,用于界面的初始化
 * @author CBS */@SuppressWarnings("serial")public class Draw extends JFrame {// 界面初始化方法public void showUI() {
        setTitle("画图");//窗体名称setSize(1200, 900);//窗体大小setDefaultCloseOperation(3);
        setLocationRelativeTo(null);//窗体居中//流式布局左对齐FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
        setLayout(layout);//窗体使用流式布局管理器this.setResizable(false);//窗体大小不变        //使用数组保存按钮名String buttonName[] = { "画直线", "画椭圆", "画曲线", "多边形", 
                  "橡皮擦", "拖动线","三角形", "画球形", "笔刷", "喷枪", 
                  "色子", "立体矩形", "立体圆", "立体三角","迭代分形",                   "现代分形", "枫叶", "画树", "mandelbrot集", "L-System",                  "迭代画线","迭代三角形", "谢尔宾斯基地毯", "画字符", "清空",                  "吸管" ,"矩形","五角星","多线","字符"};//用于保存图形按钮,使用网格布局JPanel jp1=new JPanel(new GridLayout(15, 2,10,10));
        jp1.setPreferredSize(new Dimension(200, 800));        //循环为按钮面板添加按钮for (int i = 0; i <div class="cnblogs_code_hide"></div>View Code<span class="cnblogs_code_collapse" style="font-size: 18px;"></span>
##這裡還要一點要注意的地方,Jpanel面板的添加先後順序不要改變,這是根據流式佈局算出來的面板大小,讀者可以自行更改調試。還有一個就是窗體的setSize方法只對窗體本身有效,如果要改變其他元件的大小要用setPreferredSize方法。這樣畫圖板的基本介面就實現。介面的按鈕和麵板可以根據自身需求更改。
這是介面的大概樣子:

使用Java製作簡易的畫板教學
 
監聽的實作:
###
当然我们空有个界面并没有什么用,我们需要的是点击不同的按钮能够实现不同的功能。这里就需要用到事件的监听机制了。实现监听的主要API类有: ActionListener,MouseListener,MouseMotionListener。添加事件监听的方法根以前的步骤是一样的:确定事件源对象,编写事件处理类,添加监听方法。画图板中的事件源对象有两种,一种是按钮,另一种就是画布的面板,按钮使用的是ActionListener,而画布面板因为负责的是绘图,所以使用的是MouseListener和MouseMotionListener。为了实现事件的监听,我们需要定义一个事件处理类DrawListener,该类实现了以上的三个事件接口。之后在重写的方法中实现不同图形的绘制。图形的绘制都可以通过Graphics对象的方法来实现。但是这里有一个问题,如何分辨在Draw类中按下的是哪个按钮呢?在定义Draw类的时候,我们使用了图形按钮和颜色按钮,图形类的按钮在实例化对象的时候是使用了带参数的构造方法的,也就是图形按钮都是有文字的,而颜色按钮则没有。依据这一点就可以很容易的区分不同的按钮了。
DrawListener类:
package Cbs;import java.awt.Color;import java.awt.Graphics;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import javax.swing.JButton;public class DrawListener implements ActionListener, MouseListener,
        MouseMotionListener {private Color color;//颜色属性private Graphics g;//画笔属性private String str;//保存按钮上的字符串,区分不同的按钮private int x1,y1,x2,y2;//(x1,y1),(x2,y2)分别为鼠标的按下和释放时的坐标private JButton nowColor;//当前颜色按钮    //获取Draw类的画笔对象public void setG(Graphics g) {this.g = g;
    }//获取当前颜色按钮public void setNowColor(JButton nowColor) {this.nowColor = nowColor;
    }


    @Override//鼠标拖动的方法public void mouseDragged(MouseEvent e) {//画曲线的方法if ("画曲线".equals(str)) {int x, y;
            x = e.getX();
            y = e.getY();
            g.drawLine(x, y, x1, y1);
            x1 = x;
            y1 = y;
        }
    }

    @Override//鼠标移动方法public void mouseMoved(MouseEvent e) {

    }

    @Override//鼠标单击方法public void mouseClicked(MouseEvent e) {

    }

    @Override//鼠标按下方法public void mousePressed(MouseEvent e) {
        
        g.setColor(color);//改变画笔的颜色        
        x1=e.getX();//获取按下时鼠标的x坐标y1=e.getY();//获取按下时鼠标的y坐标    }

    @Override//鼠标释放方法public void mouseReleased(MouseEvent e) {
        x2=e.getX();//获取释放时鼠标的x坐标y2=e.getY();//获取释放时鼠标的y坐标//画直线的方法if ("画直线".equals(str)) {
            g.drawLine(x1, y1, x2, y2);
        }
    }

    @Override//鼠标进入方法public void mouseEntered(MouseEvent e) {

    }

    @Override//鼠标退出方法public void mouseExited(MouseEvent e) {

    }

    @Override//处理按钮上的鼠标点击动作public void actionPerformed(ActionEvent e) {//判断是颜色按钮还是图形按钮if ("".equals(e.getActionCommand())) {
            JButton jb = (JButton) e.getSource();
            color = jb.getBackground();
            nowColor.setBackground(color);//处理当前颜色} else {
            str = e.getActionCommand();
        }
    }

}
View Code

Draw类也要做一些修改,为按钮和面板添加监听:

 1 package Cbs; 2  3 import java.awt.Color; 4 import java.awt.Dimension; 5 import java.awt.FlowLayout; 6 import java.awt.Graphics; 7 import java.awt.GridLayout; 8  9 import javax.swing.JButton;10 import javax.swing.JFrame;11 import javax.swing.JPanel;12 13 /**14  * Draw类,用于界面的初始化15  * @author CBS16  */17 @SuppressWarnings("serial")18 public class Draw extends JFrame {19     private DrawListener dl;20     private Graphics g;21     // 界面初始化方法22     public void showUI() {23         setTitle("画图");//窗体名称24         setSize(1200, 900);//窗体大小25         setDefaultCloseOperation(3);26         setLocationRelativeTo(null);//窗体居中27                 //流式布局左对齐28         FlowLayout layout = new FlowLayout(FlowLayout.LEFT);29         setLayout(layout);//窗体使用流式布局管理器30         this.setResizable(false);//窗体大小不变31         32         //使用数组保存按钮名33         String buttonName[] = { "画直线", "画椭圆", "画曲线", "多边形",34                       "橡皮擦", "拖动线","三角形", "画球形", "笔刷", "喷枪", 
35                       "色子", "立体矩形", "立体圆", "立体三角","迭代分形",36                        "现代分形", "枫叶", "画树", "mandelbrot集", "L-System", 
37                        "迭代画线","迭代三角形", "谢尔宾斯基地毯", "画字符", "清空",38                       "吸管" ,"矩形","五角星","多线","字符"};39                 //用于保存图形按钮,使用网格布局40         JPanel jp1=new JPanel(new GridLayout(15, 2,10,10));41         jp1.setPreferredSize(new Dimension(200, 800));42         43         //实例化DrawListener对象44         dl=new DrawListener();45         //循环为按钮面板添加按钮46         for (int i = 0; i 
View Code
drawDrawListener里面只写了画直线和曲线的方法,读者可以根据自己的需求添加,思路和方式都是一样的。Draw类里面有些需要注意的地方在这里提一下:一个是画笔g的获取一定要在窗体的可见之后采取获取,不然获取的画笔对象返回值会是null。二是要为图形按钮添加监听,DrawListener的实例化需要在setVisible方法之前,所以不建议使用构造方法直接传入g画笔参数,我使用的是set方法。最后是注意一下使用哪个添加方法,按钮使用的是addActionListener方法,画板面板使用的是addMouseListener和addMouseMotionListener方法。使用画板面板来获取画笔并给画面面板添加监听是为了让绘图的时候图形不会跑出面板外,这里的画笔和监听都由主窗体获得也是可以的,不过绘制时会出现线画出面板的问题。
画板的重绘:
到这里画板的制作已经基本实现了,我们已经可以在上面绘制各种各样的图形了。但是细心的人可能会发现一个问题,那就是如果把窗体最小化之后再次打开,画板上原本已经画好的东西会全部都消失了。这样子肯定是不行的,辛辛苦苦画的“大作”怎么能说说没就没了呢。那么为什么会出现这样的问题呢?要回答这个问题我们就需要先了解Java的绘图机制。做画图板我们使用的是Swing组件,这套组件是基于原先的AWT组件开发,在绘制的时候会调用系统的画图函数,这就是为什么我们可以从面板或者是窗体中获取画笔对象的原因。这也就是说Java中你所能够看到窗体,按钮或者其它的所有组件其实都是画出来。所以当我们点击窗体使它最小化或者改变大小的时候,原来的画的窗体就不能适应需要了,这时系统会调用JFrame的paint方法实现窗体的重绘,也就是再次画了一个新的窗体,而JFrame的paint方法只对窗体已经添加的组件有效,我们自己绘制的东西并没有写在paint方法里面,所以窗体重绘之后,我们原先绘制的图形也就消失了。要解决这个问题我们需要重写父类的paint方法。但是这样的话问题又来了,画图是在DrawListener类里面实现的,要怎么把它们弄到paint方法里面去呢?
当然方法可能有很多,这里我只介绍我所知道的:要把画出来的图形在paint方法中再次画出来,就需要有东西来保存画过的图形。保存可以使用数组或者集合,这里推荐使用集合,可以很方便的实现添加,而不需要去考虑大小的问题。数组的实现也大同小异,这里就不多做介绍。确定了使用集合,那么集合内保存什么类型的数据呢?毫无疑问应该保存的是图形的数据,但是集合使用泛型的话也只能保存同一种类型的数据,我们却有那么多种图形?这里就可以使用接口或者抽象类,我们只需要创建不同得图形类,让它继承抽象类或者是实现接口。然后每画一个图形就实例化一个图形的对象,存入集合中,最后在paint方法中遍历集合,重新绘制图形即可。
下面直接贴最终代码(仍然只写了直线和曲线),只是添加了几行代码,注意与前面比较。
//图形接口package Cbs;//图形集合public interface NetJavaShape {public abstract void draw();
}//直线类package Cbs;import java.awt.Color;import java.awt.Graphics;import Cbs.NetJavaShape;public class ImpLine implements NetJavaShape{
    Graphics g;int x1, y1,x2, y2;
    Color c;public ImpLine(Graphics g,int x1,int y1,int x2,int y2,Color c){this.g=g;this.c=c;this.x1=x1;this.y1=y1;this.x2=x2;this.y2=y2;
    }public void draw() {
        g.setColor(c);
        g.drawLine(x1, y1, x2, y2);
    }

}//DrawListener类package Cbs;import java.awt.Color;import java.awt.Graphics;import java.util.List;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import java.util.ArrayList;import Cbs.NetJavaShape;import javax.swing.JButton;public class DrawListener implements ActionListener, MouseListener,
        MouseMotionListener {private Color color=Color.BLACK;//颜色属性,初始值为黑色private Graphics g;//画笔属性private String str;//保存按钮上的字符串,区分不同的按钮private int x1,y1,x2,y2;//(x1,y1),(x2,y2)分别为鼠标的按下和释放时的坐标private JButton nowColor;//当前颜色按钮//保存图形对象的集合private List<netjavashape> shapesArray = new ArrayList<netjavashape>();//图形private NetJavaShape shape;//在draw类中获取集合public List<netjavashape> getShapesArray() {return shapesArray;
    }//获取Draw类的画笔对象public void setG(Graphics g) {this.g = g;
    }//获取当前颜色按钮public void setNowColor(JButton nowColor) {this.nowColor = nowColor;
    }


    @Override//鼠标拖动的方法public void mouseDragged(MouseEvent e) {//画曲线的方法if ("画曲线".equals(str)) {int x, y;
            x = e.getX();
            y = e.getY();//实例化对象,曲线也是直线画的所以不同新建一个曲线类了shape=new ImpLine(g,x,y,x1,y1,color);//调用画图方法            shape.draw();//将图形存入集合中            shapesArray.add(shape);//            g.drawLine(x, y, x1, y1);x1 = x;
            y1 = y;
        }
    }

    @Override//鼠标移动方法public void mouseMoved(MouseEvent e) {

    }

    @Override//鼠标单击方法public void mouseClicked(MouseEvent e) {

    }

    @Override//鼠标按下方法public void mousePressed(MouseEvent e) {
        
        g.setColor(color);//改变画笔的颜色        
        x1=e.getX();//获取按下时鼠标的x坐标y1=e.getY();//获取按下时鼠标的y坐标    }

    @Override//鼠标释放方法public void mouseReleased(MouseEvent e) {
        x2=e.getX();//获取释放时鼠标的x坐标y2=e.getY();//获取释放时鼠标的y坐标//画直线的方法if ("画直线".equals(str)) {//实例化对象,shape=new ImpLine(g,x1,y1,x2,y2,color);//调用画图方法            shape.draw();//将图形存入集合中            shapesArray.add(shape);//            g.drawLine(x1, y1, x2, y2);        }
    }

    @Override//鼠标进入方法public void mouseEntered(MouseEvent e) {

    }

    @Override//鼠标退出方法public void mouseExited(MouseEvent e) {

    }

    @Override//处理按钮上的鼠标点击动作public void actionPerformed(ActionEvent e) {        if ("".equals(e.getActionCommand())) {
            JButton jb = (JButton) e.getSource();
            color = jb.getBackground();
            nowColor.setBackground(color);//处理当前颜色} else {
            str = e.getActionCommand();
        }
    }

}//draw类package Cbs;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.Graphics;import java.awt.GridLayout;import java.util.ArrayList;import java.util.List;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;/**
 * Draw类,用于界面的初始化
 * @author CBS */@SuppressWarnings("serial")public class Draw extends JFrame {private DrawListener dl;private Graphics g;//保存图形对象的集合private List<netjavashape> shapesArray = new ArrayList<netjavashape>();// 界面初始化方法public void showUI() {
        setTitle("画图");//窗体名称setSize(1200, 900);//窗体大小setDefaultCloseOperation(3);
        setLocationRelativeTo(null);//窗体居中FlowLayout layout = new FlowLayout(FlowLayout.LEFT);//流式布局左对齐setLayout(layout);//窗体使用流式布局管理器this.setResizable(false);//窗体大小不变        //使用数组保存按钮名String buttonName[] = { "画直线", "画椭圆", "画曲线", "多边形",     "橡皮擦", "拖动线","三角形", "画球形", "笔刷", "喷枪", "色子", "立体矩形", "立体圆", "立体三角","迭代分形", "现代分形", "枫叶", "画树", "mandelbrot集", "L-System", "迭代画线","迭代三角形", "谢尔宾斯基地毯", "画字符", "清空","吸管" ,"矩形","五角星","多线","字符"};
        JPanel jp1=new JPanel(new GridLayout(15, 2,10,10));//用于保存图形按钮,使用网格布局jp1.setPreferredSize(new Dimension(200, 800));        //实例化DrawListener对象dl=new DrawListener();//循环为按钮面板添加按钮for (int i = 0; i </netjavashape></netjavashape></netjavashape></netjavashape></netjavashape>
View Code
这里使用集合添加图形实现画板的重绘时,我是每实现一个图形就会新建一个类来保存图形的信息,这样图形类就会有很多。如果不想创建那么多的图形类可以把它们都放到一个类里面,设置一个type的参数,赋上按钮的名称。然后在draw方法中依据这个值判断是什么图形实现不同的画图方法。这样画板的所有功能基本就实现了,画板的项目也就到这里。
总结:

畫圖板的製作重要用到了Swing的元件,事件監聽機制,Graphics繪圖和畫板的重繪以及集合的使用,抽象類別或是介面作為規範圖形類別的作用。


#監聽器類別


package com.baidu;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event. MouseListener;

public class MyMouseListener implements MouseListener{
 //顏色
 Panel p;
 //畫布
# Graphics g;
 //動作指令
# private SimpleDraw1 draw;
 //給出座標
 private int x1,y1,x2,y2;
 //建構方法
 
 
 public MyMouseListener(SimpleDraw draw){
  this## public MyMouseListener(SimpleDraw draw){
  this## public MyMouseListener(SimpleDraw draw){
  this## public MyMouseListener(SimpleDraw draw){
 .g=draw.getGraphics();//將傳過來的物件值賦給屬性g
  this.draw=draw;
  
 } 

 
 //滑鼠進入到元件上時呼叫
 @Override
 public void mouseClicked(MouseEvent e) { 
 }
 //滑鼠離開元件時呼叫
# @Override
  public void mouseEntered(MouseEvent e) {
 }
 @Override
 public void mouseExited(MouseEvent e) { 
 }
 @Override
 public void mousePressed(Mouse e) {
Event e) {
Event e) {
> ;
   y1=e.getY(); 
 }
 @Override
 public void mouseReleased(MouseEvent e) {   
   x2=e.getX();# getY();
   String command = draw.getCommand();
   g.setColor(Color.blue);
   
#   
   if(command.equals("直線##    g.drawLine(x1, y1, x2, y2);
    
   }else if(command.equals("矩形")){
    g.drawRect(x1, y1, x  y2-y1);
    
   }else if(command.equals("橢圓")){
    g.drawOval(x1, y1, x2-x1, y2-y1);

# ## }

}










#################### ######################################

以上是使用Java製作簡易的畫板教學的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Java平台獨立性:這對開發人員意味著什麼?Java平台獨立性:這對開發人員意味著什麼?May 08, 2025 am 12:27 AM

Java'splatFormIndependecemeansDeveloperScanWriteCeandeCeandOnanyDeviceWithouTrecompOlding.thisAcachivedThroughThroughTheroughThejavavirtualmachine(JVM),WhaterslatesbyTecodeDecodeOdeIntComenthendions,允許univerniverSaliversalComplatibilityAcrossplatss.allospplats.s.howevss.howev

如何為第一次使用設置JVM?如何為第一次使用設置JVM?May 08, 2025 am 12:21 AM

要設置JVM,需按以下步驟進行:1)下載並安裝JDK,2)設置環境變量,3)驗證安裝,4)設置IDE,5)測試運行程序。設置JVM不僅僅是讓其工作,還包括優化內存分配、垃圾收集、性能調優和錯誤處理,以確保最佳運行效果。

如何查看產品的Java平台獨立性?如何查看產品的Java平台獨立性?May 08, 2025 am 12:12 AM

toensurejavaplatFormIntence,lofterTheSeSteps:1)compileAndRunyOpplicationOnmultPlatFormSusiseDifferenToSandjvmversions.2)upureizeci/cdppipipelinelikeinkinslikejenkinsorgithikejenkinsorgithikejenkinsorgithikejenkinsorgithike forautomatecross-plateftestesteftestesting.3)

Java的現代發展功能:實用概述Java的現代發展功能:實用概述May 08, 2025 am 12:12 AM

javastandsoutsoutinmoderndevelopmentduetoitsrobustfeatureslikelambdaexpressions,streams,andenhanced concurrencysupport.1)lambdaexpressionssimplifyfunctional promprogientsmangional programmanging,makencodemoreconciseandable.2)

掌握Java:了解其核心功能掌握Java:了解其核心功能May 07, 2025 pm 06:49 PM

Java的核心特點包括平台獨立性、面向對象設計和豐富的標準庫。 1)面向對象設計通過多態等特性使得代碼更加靈活和可維護。 2)垃圾回收機制解放了開發者的內存管理負擔,但需要優化以避免性能問題。 3)標準庫提供了從集合到網絡的強大工具,但應謹慎選擇數據結構以保持代碼簡潔。

爪哇可以到處跑嗎?爪哇可以到處跑嗎?May 07, 2025 pm 06:41 PM

Yes,Javacanruneverywhereduetoits"WriteOnce,RunAnywhere"philosophy.1)Javacodeiscompiledintoplatform-independentbytecode.2)TheJavaVirtualMachine(JVM)interpretsorcompilesthisbytecodeintomachine-specificinstructionsatruntime,allowingthesameJava

JDK和JVM有什麼區別?JDK和JVM有什麼區別?May 07, 2025 pm 05:21 PM

jdkincludestoolsfordEveloping and compilingjavacode,whilejvmrunsthecompiledbytecode.1)jdkcontainsjre,編譯器,andutilities.2)

Java功能:快速指南Java功能:快速指南May 07, 2025 pm 05:17 PM

Java的關鍵特性包括:1)面向對象設計,2)平台獨立性,3)垃圾回收機制,4)豐富的庫和框架,5)並發支持,6)異常處理,7)持續演進。 Java的這些特性使其成為開發高效、可維護軟件的強大工具。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!