Java基础_GUI

来源:互联网 发布:马勒 交响曲 知乎 编辑:程序博客网 时间:2024/05/18 00:53

概述

两种交互界面

GUI:Graphical User Interface(图形用户接口)
用图形的方式,来显示计算机操作的界面,这样更方便更直观
CLI:Command Line User Interface(命令行用户接口)
两种和用户进行交互的界面:图形化界面和命令行

java.Awt和javax.Swing

Java为GUI提供的对象都存在java.Awt和javax.Swing两个包中,除了导入以上两个包,还需要导入java.awt.event子包
java.Awt:Abstract Window ToolKit (抽象窗口工具包),需要调用本地系统方法实现功能。属重量级控件。平台依赖度高,跨平台性不是特别好,界面会变化
javax.Swing:在AWT的基础上,建立的一套图形界面系统,其中提供了更多的组件,而且完全 由Java实现。增强了移植性,属轻量级控件。
还有Swt外观包,在Eclipse网站下载。Eclipse所使用

继承关系图


Label:为标签,作用是封装文字
TextArea:文本框,显示单行文本
TextField:文本区域,显示多行文本
Container:为容器,是一个特殊的组件,该组件中可以通过add 方法添加其他组件进来。
FileDialog:负责文件的选取和保存

布局

容器中组件的排放方式,就是布局Layout
常见的布局管理器:
FlowLayout(流式布局管理器)
  • 从左到右的顺序排列(自动)。
  • Panel默认的布局管理器。
BorderLayout(边界布局管理器)
  • 东,南,西,北,中。默认居中。如果不指定组件的方位,组件会以整个最大面积填充窗体
  • Frame、Dialog默认的布局管理器。
GridLayout(网格布局管理器)
  • 规则的矩阵,应用计算器
CardLayout(卡片布局管理器)
  • 选项卡。例子:右键-->属性
GridBagLayout(网格包布局管理器)
  • 非规则的矩阵,一个组件占多个格子
图形化界面做之前需要打草稿
利用高级的编辑器:JBuilder,Eclipse图形化界面插件等
如果一个窗体有多个布局,首先在窗体中布置多个面板Panel,然后设置面板的布局

Frame

Container常用子类:Window Panel(面板, 不能单独存在。)
Window常用子类:Frame Dialog
图形化界面是由另外的线程来控制的,只要开启图形化界面就会多一个线程
创建图形化界面:
  1. 创建frame窗体
  2. 对窗体进行基本设置。比如大小,位置,布局
  3. 定义组件
  4. 将组建通过窗体的add方法添加到窗体中
  5. 让窗体显示,通过setVisible(true)方法
package GUITest;import java.awt.*;public class FrameDemo {public static void main(String[] args) {Frame f = new Frame("my awt");//创建一个窗体实例,默认不可见,参数是窗体标题。默认的布局管理器是边界式布局f.setSize(500,400);//设置窗体大小,参数是横坐标和纵坐标f.setLocation(300,200);//设置窗体位置,参数是左上角与屏幕左边和右边的距离f.setLayout(new FlowLayout());//设置窗体的布局为流式布局Button b = new Button("按钮");//创建一个按钮实例f.add(b);//将按钮添加到窗体f.setVisible(true);//设置窗体可见}}

事件监听机制

事件监听机制的组成

事件源(组件)
事件(Event):每一个事件源都有自己特有的事件和共性事件(比如鼠标键盘事件)
监听器(Listener):将可以触发某一事件(比如窗口事件)的动作(不止一个动作,比如杀人事件,可以有很多种动作)都已经封装到了监听器中。这样可以完全由监听器负责事件的处理
以上三者在java中都已经定义好了,直接获取其对象来使用即可。我们要做的就是对产生的动作进行处理
事件处理(引发事件后处理方式)

事件监听机制流程图


砸锁的例子:

窗体事件

WindowListener是一个接口,里面有7个方法,直接自定义一个类实现该接口来创建监听器对象需要覆盖所有方法,有可能只用到一个方法比如关闭,所以太麻烦。
WindowAdapter类实现了WindowListener接口,并覆盖了所有方法。使用时只要继承WindowAdapter类并覆盖需要的方法即可。
WindowAdapter类是接受窗口事件的抽象适配器类,因为该类的方法都是空,创建对象没有意义,所以定义为抽象类。而此适配器类存在的目的是方便创建监听器对象。
package GUITest;import java.awt.*;import java.awt.event.*;//需要单独导入event包public class FrameDemo {public static void main(String[] args) {Frame f = new Frame("my awt");f.setSize(500,400);f.setLocation(300,200);f.setLayout(new FlowLayout());Button b = new Button("按钮");f.add(b);//f.addWindowListener(new MyWin());//将监听器注册到事件源//匿名内部类实现方式f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}//窗体前置动作public void windowActivated(WindowEvent e){System.out.println("我活了");;}//窗体打开动作public void windowOpened(WindowEvent e){System.out.println("我被打开了");;}});f.setVisible(true);}}class MyWin extends WindowAdapter{//覆盖父类中的方法,此动作一执行就会产生一个窗体事件,所以这里接受了一个窗体事件对象public void windowClosing(WindowEvent e){//WindowAdapter类和WindowEvent类在awt包的event子包中,所以需要单独导入。//System.out.println("window closing!"+e.toString());//打印事件信息。frame0代表当前Frame的编号System.exit(0);//动作执行,事件触发,程序退出}}

Action事件

代码示例(已经优化了,将事件与组件进行了分离)
package GUITest;import java.awt.*;import java.awt.event.*;public class FrameDemo {//定义该图形界面中所需组件的引用。这样引用可以作用于整个类。private Frame f;private Button but;FrameDemo(){//加载init函数,对象一初始化就有了图形界面并具备了基本事件init();}//init方法专门对图形界面初始化,不加事件,将事件与图形化组件分离public void init(){f = new Frame("my frame");//对frame进行基本设置f.setBounds(300,100,500,400);//移动组件并调整其大小,统一设置Size和Location。f.setLayout(new FlowLayout());but = new Button("my button");//将组件添加到frame中f.add(but);//加载一下窗体上的事件myEvent();//显示窗体f.setVisible(true);}private void myEvent(){f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});//让按钮具备退出程序的功能/* * 按钮就是事件源 * 那么选择哪个监听器呢? * 通过关闭窗体事例了解到,想要知道该组件具备什么样的特有监听器,就要查看该组件对象的功能。 * 通过查阅button描述,发现按钮支持添加一个特有监听addActionListener * ActionListener是一个少数没有适配器的接口 */but.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){//这里接受一个Action事件System.exit(0);}});}public static void main(String[] args){new FrameDemo();}}

鼠标事件

鼠标事件和键盘事件几乎所有的组件都具备,所以找Component类查阅添加相关监听器的方法
在上面的myEvent方法中给按钮添加鼠标监听器:
       private void myEvent(){f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});//在button上添加一个Action监听器,按钮只要被活动就能执行,鼠标键盘都能让按钮活动。但是click事件会先执行,因为点击动作更具体but.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){System.out.println("action ok");}});//在button上添加一个鼠标监听器but.addMouseListener(new MouseAdapter(){int count=0;//鼠标进入动作,触发鼠标事件public void mouseEntered(MouseEvent e){System.out.println("mouse entered the component"+count++);}});but.addMouseListener(new MouseAdapter(){//鼠标点击动作,触发鼠标事件public void mouseClicked(MouseEvent e){//鼠标双击。鼠标的点击次数,左右键等信息属于鼠标事件内的东西,所以要在MouseEvent类中找if(e.getClickCount()==2)System.out.println("mouse was double clicked");}});}

键盘事件

java.awt.event包中存放的是Listener类(含Adapter类)和Event类
package GUITest;import java.awt.*;import java.awt.event.*;public class MouseAndKeyEvent {private Frame f;private Button but;private TextField tf;MouseAndKeyEvent(){init();}public void init(){f = new Frame("my frame");f.setBounds(300,100,500,400);f.setLayout(new FlowLayout());//创建一个文本框对象,指定列数为20列tf = new TextField(20);but = new Button("my button");//在窗体中添加文本框f.add(tf);f.add(but);myEvent();f.setVisible(true);}private void myEvent(){f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});//给button添加一个键盘监听器,当该按钮是当前事件源(有虚线标识)的时候,键盘按键会触发键盘事件but.addKeyListener(new KeyAdapter(){public void keyPressed(KeyEvent e){//获取键的字符和码//System.out.println(e.getKeyChar()+"..."+e.getKeyCode());//根据键盘码获取键的文本,getKeyText是一个静态方法//System.out.println(KeyEvent.getKeyText(e.getKeyCode()));//按下esc键,程序退出/* if(e.getKeyCode()==KeyEvent.VK_ESCAPE)//VK_ESCAPE是KeyEvent类的静态常量,不需要记住对应的码值System.exit(0);*///判断组合键:ctrol+enter,用到了KeyEvent的父类InputEvent的isControlDown方法if(e.isControlDown()&&e.getKeyCode()==KeyEvent.VK_ENTER)System.out.println("control+enter is run");}});//给文本框添加一个键盘监听器,判断键盘的输入值,在0至9之间,为了不让非法文本进入文本框,需要取消事件tf.addKeyListener(new KeyAdapter(){public void keyPressed(KeyEvent e){int code = e.getKeyCode();if(!(code>=KeyEvent.VK_0&&code<=KeyEvent.VK_9)){System.out.println(code+"的值是非法的!");e.consume();//对键进行屏蔽,consume方法是InputEvent类,该方法使用此事件,以便不会按照默认的方式由产生此事件的源代码来处理此事件。}}});}public static void main(String[] args){new MouseAndKeyEvent();}}

列出指定目录内容

先做界面,再加事件。
明确事件源:按钮
按钮操作对象:文本框、文本区域

对话框Dialog

用于提示用户的误操作
通常情况下,对话框不单独存在,一般依赖于一个窗体
对话框含有两个组件,label和button,label用于封装文本
默认布局是边界布局
全部代码:
package GUITest;import java.awt.*;import java.awt.event.*;import java.io.*;//实现类除了在类中建立窗体引用,创建对象外,也可以直接继承Frame,然后直接创建窗体子类对象public class MyWindowDemo {private Frame f;private Button but;private TextField tf;private TextArea ta;//窗体对象引用,这里是为了方便阅读,但是为了优化内存,不需要窗体一产生Dialog对象就存在,没有意义,不该先有的对象先不创建。private Dialog d;//封装文字的Label对象引用private Label lab;//对话框按钮对象引用private Button okBut;MyWindowDemo(){init();}public void init(){f = new Frame("my frame");f.setBounds(300,100,600,500);f.setLayout(new FlowLayout()); but = new Button("switch to");tf = new TextField(60);ta = new TextArea(25,70);//参数顺序:行,列//初始化对话框对象及其组件d = new Dialog(f,"information:self",true);//参数:依赖的窗体,模式为true:不操作对话框,所属窗体操作不了。d.setBounds(300,100,240,150);d.setLayout(new FlowLayout());lab = new Label();//label此时没有传入信息,因为初始化时还不知道显示什么信息okBut = new Button("ok");//在对话框中添加组件d.add(lab);d.add(okBut);f.add(tf);f.add(but);f.add(ta);myEvent();f.setVisible(true);}private void myEvent() {f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});//给按钮添加action监听,而不是鼠标监听,这样键盘也能监听到but.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {showDir(); }});//给对话框添加监听器d.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){d.setVisible(false);//关闭对话框,就将其设为不显示}});//给对话框的按钮添加监听器okBut.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){d.setVisible(false);//关闭对话框,就将其设为不显示}});//给文本框添加监听器,输入文本之后按回车就能输出内容tf.addKeyListener(new KeyAdapter(){public void keyPressed(KeyEvent e){if(e.getKeyCode()==KeyEvent.VK_ENTER)showDir();}});}//将功能进行封装,优化代码复用性private void showDir() {/*String text = tf.getText();//获取文本框文本,getText方法在父类TextComponent类中ta.setText(text);//往文本区域填充数据tf.setText("");//清空文本框*///获取目录String dirPath = tf.getText();//将目录封装为文件对象File dir = new File(dirPath);//做健壮性判断,如果文件存在并且是一个目录if(dir.exists()&&dir.isDirectory()){ta.setText("");//清空文本区域,这样区域中只显示该目录的内容String[] names = dir.list(); //只需要名字,所以用list方法就行了,不需要listFiles方法for(String name:names)//ta.setText(name+"\r\n");//加入回车符,但是这样会覆盖最终只显示一个文件ta.append(name+"\r\n");//追加文本}else{String info = "Your infor:"+dirPath+" is wrong,please enter again!";lab.setText(info);//设置对话框中的信息d.setVisible(true);//显示对话框,对话框大小应根据文本大小显示,应先获取组件大小,超出长度边框自动延长}}public static void main(String[] args) {new MyWindowDemo();}}

菜单

java.awt包中的MenuBar类
向Frame框架中添加菜单栏是调用setMenuBar方法而不是使用add方法
菜单结构:MenuBar包含Menu,Menu包含MenuItem,但是MenuItem是Menu的父类
添加子菜单:在Menu中再添加一个Menu
所以Menu既可以添加MenuItem,也可以添加它本身
代码示例:
package GUITest;import java.awt.*;import java.awt.event.*;public class MyMenuDemo {private Frame f;private MenuBar mb;private Menu m,subMenu;private MenuItem closeItem,subItem;MyMenuDemo(){init();}public void init() {f = new Frame("my frame");f.setBounds(300,100,500,600);f.setLayout(new FlowLayout()); //初始化菜单条mb = new MenuBar();//初始化菜单,设置名称为Filem = new Menu("File");//初始化子菜单subMenu = new Menu("Sub Menu");//初始化退出菜单项,设置名称为exitcloseItem = new MenuItem("Exit");//初始化子菜单项subItem = new MenuItem("Sub Item");//在子菜单中添加子菜单项subMenu.add(subItem);//在菜单中添加子菜单m.add(subMenu);//在菜单中添加退出菜单项m.add(closeItem);//菜单条添加菜单mb.add(m);f.setMenuBar(mb);myEvent();f.setVisible(true);}private void myEvent(){f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});//给菜单项添加活动监听器closeItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {System.exit(0);}});}public static void main(String[] args) {new MyMenuDemo();}}

打开文件

需要使用FileDialog类,它是Dialog的子类
FileDialog(Frame parent, String title, int mode)  创建一个具有指定标题的文件对话框窗口,用于加载或保存文件
  • parent - 对话框的所有者
  • title - 对话框的标题;接受 null 值时不会抛出 NullPointerException
  • mode - 对话框的模式,FileDialog.LOAD 或 FileDialog.SAVE,分别对应打开或保存模式,不传入该参数时,默认是打开模式
通过它的getDirectory和getFile方法获取所选择的目录或者文件字符串

保存文件

数据所在文件存在,点保存不弹出对话框,反之,弹出对话框
另存为是无论文件是否存在都要弹出
整体代码:
package GUITest;import java.awt.*;import java.awt.event.*;import java.io.*;public class MyMenuTest {private Frame f;private TextArea ta;private MenuBar bar;private Menu fileMenu;private MenuItem openItem,saveItem,closeItem;private FileDialog openDia,saveDia;private File file;//用于FileDialog监听器中MyMenuTest(){init();}public void init() {f = new Frame("my frame");f.setBounds(300,100,650,600);//f.setLayout(new FlowLayout());//默认边界布局,这样文本框会随着窗体填充,效果更好ta =new TextArea();bar = new MenuBar();fileMenu = new Menu("File");openItem = new MenuItem("Open");saveItem = new MenuItem("Save");closeItem = new MenuItem("Exit");fileMenu.add(openItem);fileMenu.add(saveItem);fileMenu.add(closeItem);bar.add(fileMenu);f.setMenuBar(bar);//创建文件对话框实例openDia = new FileDialog(f,"my open",FileDialog.LOAD);saveDia = new FileDialog(f,"my save",FileDialog.SAVE);f.add(ta);myEvent();f.setVisible(true);}private void myEvent(){f.addWindowListener(new WindowAdapter(){public void windowClosing(WindowEvent e){System.exit(0);}});closeItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e) {System.exit(0);}});//给打开菜单项添加活动监听,用于打开文件对话框openItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){openDia.setVisible(true);//获取选择的目录和文件名,并封装成文件对象String dirPath = openDia.getDirectory();String fileName = openDia.getFile();if(dirPath==null||fileName==null)return;//如果两者任意一个为null,直接返回不做任何事情。不作判断会发生异常ta.setText("");//当选择的是有效文件的时候,就清空文本区域file = new File(dirPath,fileName);try{BufferedReader bufr = new BufferedReader(new FileReader(file));String line = null;while((line=bufr.readLine())!=null){ta.append(line+"\r\n");//注意加回车符}bufr.close();}catch(IOException ex){//因为此方法内有e,这里不能命名重复throw new RuntimeException("读取失败!");}}});saveItem.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){//文件不存在,当用户点击保存菜单项时,则显示文件对话框,创建文件对象if(file==null){saveDia.setVisible(true);String dirPath = saveDia.getDirectory();String fileName = saveDia.getFile();if(dirPath==null||fileName==null)return;file = new File(dirPath,fileName);//这里创建的file对象会直接使用于下面的代码中}//文件存在,直接进行输出操作,源就是文本区域中的数据try{BufferedWriter bufr = new BufferedWriter(new FileWriter(file));String text = ta.getText();bufr.write(text);//bufr.flush();//不写flush也可以bufr.close();}catch(IOException ex){throw new RuntimeException("保存错误!");}}});}public static void main(String[] args) {new MyMenuTest();}}

双击执行的jar包

用于图形化界面应用程序,因为有显示界面

DOS命令行生成JAR包

首先在可执行类中指定包名:package XXX;
在dos命令行中带着包进行编译:

javac -d c:\myclass MyMenuTest.java,这样会在myclass目录下生成一个名为包名XXX的文件夹,里面包含了所有的class文件

然后将XXX文件夹打成jar包,在命令行中切换到文件夹所在目录,然后输入:

jar -cvf my.jar XXX就生成了指定名称的jar包:XXX.jar(但是此时双击该jar包不能执行,还需将主函数所在类的类名告诉jar包)

jar包中META-INF文件夹含有的配置信息文件:MANIFEST.MF,但是里面不能写入Main-Class属性信息

需要创建一个指定清单:

新建一个text文件,随便命名(例:1.txt),然后写入:Main-Class: 包名.主类名(别掉空格,空格用于区分键和值,否则会出现IO异常),再加上回车(注意这是固定格式,代表此行结束,否则数据不会写入),保存

在Dos中操作:

jar -cvfm my.jar 1.txt XXX

jar包必须在本地注册才能使用:

工具-->文件夹选项-->文件类型-->选择JAR-->高级-->添加“open”操作-->在用于执行操作的应用程序中选择命令路径并加上-jar(C:\Programming\Java\jdk1.7.0_10\bin\javaw.exe-jar

没有Jar就新建一个,并选择图标

Eclipse生成JAR包

第一:普通类导出jar包,我说的普通类就是指此类包含main方法,并且没有用到别的jar包。 
1.在eclipse中选择你要导出的类或者package,右击,选择Export子选项; 
2.在弹出的对话框中,选择java文件---选择JAR file,单击next; 
3.在JAR file后面的文本框中选择你要生成的jar包的位置以及名字,注意在Export generated class files and resources和Export java source files and resources前面打上勾,单击next; 
4.单击两次next按钮,到达JAR Manifest Specification。注意在最底下的Main class后面的文本框中选择你的jar包的入口类。单击Finish,完成。 
你可以在dos环境下,进入你的jar所在的目录,运行 java -jar 名字.jar,检测运行是否正确。 
第二、你所要导出的类里边用到了别的jar包。比如说你写的类连接了数据库,用到数据库驱动包oracl.jar.。 
1.先把你要导出的类按照上面的步骤导出形成jar包,比如叫test.jar 
2.新建一个文件夹main,比如在D盘根目录下; 
3.把test.jar和oracl.jar拷贝到main文件下,右击test.jar,解压到当前文件夹。把META-INF\MANIFEST.MF剪切到另外一个地方 (比如是桌面!) ; 
4.右击oracl.jar,解压到当前文件夹。 
5.在dos环境下,进入到D盘的main文件夹下,执行 jar cvfm new.jar meta-inf/manifest.mf .,不要忘了最后面的点。 
6.用压缩工具打开你新生成的new.jar,用你放在桌面的META-INF\MANIFEST.MF覆盖new.jar原有。 
你可以在dos环境下,进入你的jar所在的目录,运行 java -jar 名字.jar,检测运行是否正确。

0 0
原创粉丝点击