Java基础_GUI

概述

两种交互界面

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();
		//初始化菜单,设置名称为File
		m = new Menu("File");
		//初始化子菜单
		subMenu = new Menu("Sub Menu");
		//初始化退出菜单项,设置名称为exit
		closeItem = 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值