图形化界面(Graphics User Interface,GUI)
是指采用图形方式显示的计算机操作用户界面。
通过图形化界面,用户和程序之间可以方便地进行交互。Java的抽象窗口工具包(Abstract Window Toolkit,AWT)
提供许多用来设计GUI的组件类。
java.awt
和javax.swing
包中一部分类的层次关系UML类图。
GUI组件按其作用可分为基本组件(Component)
和容器(Container)
两大类:GUI基本组件,其上不能容纳其他组件,如按钮、文本框等图形界面元素。容器是一种特殊的组件,可以用来容纳其他的组件,如窗口、对话框等。
如果我们要在一个窗口中显示按钮、文本框等,需要将这些组件放到一个容器中。在java.awt中主要有两个容器类Window类、Panel类和Applet类。但是Panel类必须放到Frame顶级容器中,一般不独立使用。同样我们也可以把Panel类和它的子类理解为一种中间容器,组件可以放到这个中间容器中,也可以放到顶级容器中。
容器和组件的概念与Android中的UI组件非常相似,View组件一定要依附在ViewGroup这个容器之下,此外,因为ViewGroup继承自View,ViewGroup也可以当做View组件使用。
一个基于GUI的应用程序应当提供一个能直接和操作系统直接交互的容器,该容器可以被直接显示、绘制在操作系统所控制的平台上,如显示器上,这样的容器被称作GUI设计中的底层容器。
JFrame类的实例就是一个底层容器,即通常称的窗口。其他容器必须被添加到底层容器中,以便借助这个底层容器和操作系统进行信息交互。
JFrame() 创建一个无标题的窗口
JFrame(String s) 创建标题为s的窗口
public void setVisible(boolean b) 设置窗口是否可见,窗口默认不可见
public void dispose() 撤销当前的窗口,并释放当前窗口所使用的资源
public void setDefaultCloseOperation(int operation) 设置单击窗体右上角关闭图标后,程序会做出怎样的处理
WindowConstants.DISPOSE_ON_CLOSE 隐藏当前的窗口,并释放窗体占有的其他资源
WindowConstants.DO_NOTHING_ON_CLOSE 什么也不做
WindowConstants.HIDE_ON_CLOSE 隐藏当前窗口
WindowConstants.EXIT_ON_CLOSE 结束窗口所在的应用程序
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class Windows {
public static void main(String[] args) {
JFrame window1 = new JFrame("撤销窗口"); //创建标题名
JFrame window2 = new JFrame("退出程序");
window1.setBounds(0,0,400,200);// 显示X轴位置,显示Y轴位置 ,宽,长
window2.setBounds(400,0,400,200);
window1.setVisible(true); // 窗口默认是不可见的
window1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
//设置单击窗体右上角关闭图标后,程序会做出怎样的处理。
window2.setVisible(true);
window2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
窗口中的菜单条、菜单、菜单项是我们所熟悉的组件,菜单放在菜单条里,菜单项放在菜单中。
菜单条
JComponent
类的子类 JMenubar
负责创建菜单条,即JMenubar
的一个实例就是一个菜单条,JFrame
类用一个把菜单条放到窗口的方法:
setJMenuBar( JMenuBar bar);
该方法将菜单条添加到窗口的顶端,需要注意的是,只能向窗口添加一个菜单条。
菜单
JComponent
类的子类JMenu
负责创建菜单,即JMenu
的一个实例就是一个菜单。
JComponent
类的子类JMenuItem
负责创建菜单项,即JMenuItem
的一个实例就是一个菜单项 JMenuItem(String text, Icon icon)
嵌入子菜单
JMenu
是JMenuItem
的子类,因此菜单本身也是一个菜单项,当把一个菜单看作菜单项添加到摸个菜单中时,称这个菜单为子菜单。
菜单上的图标
可以用 图标类Icon
声明一个图标,使用ImageIcon
类创建一个图标。
Icon icon = new ImageIcon("a.png");
然后菜单项调用setIcon(Icon icon)
设置图标
图片资源a.png、b.png、c.png、d.png存放到项目目录下
Main.java
public class Main {
public static void main(String[] args) {
WindowMenu win = new WindowMenu("带窗口的菜单", 20, 30, 400, 500);
}
}
WindowMenu.java
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
/**
* 自定义窗口WindowMenu
* @author Peng
*/
public class WindowMenu extends JFrame {
JMenuBar menubar;
JMenu menu, subMenu;
JMenuItem item1, item2;
public WindowMenu() {
}
public WindowMenu(String s, int x, int y, int w, int h) {
init(s);
setLocation(x, y);
setSize(w, h);
setVisible(true);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
void init(String s) {
setTitle(s);
menubar = new JMenuBar();
menu = new JMenu("菜单"); // JMnud的实例就是一个菜单
/**
* 一级菜单项
*/
subMenu = new JMenu("软件项目"); // 子菜单
item1 = new JMenuItem("Java话题"); // 创建菜单项
//为菜单项设置图标
ImageIcon icon = new ImageIcon("a.png");
item1.setIcon(icon);
//使用JMenuItem的构造方法设置图标
item2 = new JMenuItem("动画话题", new ImageIcon("b.png"));
item1.setAccelerator(KeyStroke.getKeyStroke('A'));
item2.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
menu.add(item1);
menu.addSeparator();
menu.add(item2);
menu.add(subMenu);
/**
* 添加二级菜单项
*/
subMenu.add(new JMenuItem("汽车销售系统", new ImageIcon("c.png")));
subMenu.add(new JMenuItem("农场信息系统", new ImageIcon("d.png")));
menubar.add(menu); // 菜单条中加入菜单
setJMenuBar(menubar); // 添加一个菜单条
}
}
文本框
使用JComponent
的子类JTextField
创建文本框。文本框的允许用户输入单行文本。
文本区
使用JComponent
的子类JButton
类创建按钮,允许用户单击按钮。
标签
使用JComponent
的子类JLabel
类创建标签,标签为用户提供信息提示。
选择框
使用JComponent
的子类JCheckBox
类来创建选择框,为用户提供多项悬着。选择框提供两种状态,选中和未选中,用户通过单击该组件切换状态。
单选按钮
使用JComponent
的子类的JRadioButton
类创建单项选择框,为用户提供单项选择。
下拉列表
使用JComponent
的子类的JComboBox
类来创建下拉列表,为用户提供下拉列表。
密码框
使用JComponent
的子类的子类JPasswordField
创建密码框,允许输入单行密码,密码框默认回显字符是“*”,也可以通过setEchoChar(char c)
来重新设置回显字符。密码框调用char[] getPassword()
方法可以返回实际的密码。
效果图:
Main.java
public class Main {
public static void main(String[] args) {
ComponentInWindow win = new ComponentInWindow();
win.setBounds(100, 100, 320, 310);
win.setTitle("常用组件");
}
}
ComponentInWindow.java
import java.awt.FlowLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ComponentInWindow extends JFrame {
JTextField text;
JButton button;
JCheckBox checkBox1, checkBox2, checkBox3;
JRadioButton radio1, radio2;
ButtonGroup group;
JComboBox
JComponent 是 Comtainer的 子类,因此 JComponent 的子类创建的组件也都是容器,但我们很少将 JButton、JTextField、JCheckBox 等组件当容器来使用。JComponent 专门提供了一些经常用来添加组建的容器。相对于底层容器 JFrame ,下面提到的容器被习惯地称为中间容器,中间容器必须被添加到底层容器中才能发挥作用。
Jpanel面板
我们会经常使用 JPanel 创建一个面板,再向这个面板添加组件,然后把这个面板添加到其他容器中。JPanel 面板的默认布局是 FlowLayout 布局。
滚动窗格 JScrollPane
拆分窗格 JSpitPane
分层窗格 JLayeredPane
当把组件添加到容器中时,希望控制组件在容器中的位置,这就需要用到布局设计。
容器可以使用方法设置自己的布局。
setLayout(布局对象);
设置自己的布局。
FlowLayout flow = new FlowLayout(); // 居中对齐
容器.setLayout(flow);
or
setLayout(new FlowLayout());
通过add 方法将组件按先后顺序,从左到右,默认水平和垂直间隙是 5 个像素的方式排列。组件的大小为默认的最佳大小,例如,控件的大小刚好能保证显示其上面的名字。
处理组件的点击或者选择事件。
事件源
能够产生处理了事件的对象都可以成为事件源,如文本框,按钮,下拉式列表等。也就是说,事件源必须是一个对象,而且这个对象必须是Java认为能够发生事件的对象。
监视器
我们需要一个对象对事件源进行监视,以便对发生的事件作出处理。事件源通过调用相应的方法将某个对象注册为自己的监视器。例如,对于文本框,这个方法是:
addActionListener(监视器);
对于注册监视器的文本框,在文本框获得焦点后,当用户对文本框进行操作,如按下回车键,Java 运行环境就会自动用 ActionEvent 类创建一个对象,触发 ActionEvent 事件 。对文本框进行相应的操作就会导致相应的事件发生,并通知监视器,监视器就会做出相应的处理。
ActionEvent 事件源
文本框、按钮、菜单项、密码框、和单选按钮都可以触发事件,都可以成为事件源。
注册监视器
能触发 ActionEvent 事件的组件,使用 addActionListener(ActionListener listen)
,将实现 ActionListener 接口的类的实例注册为事件源的监视器。
ActionListener 接口
ActionListener 接口位于 java.awt.event包中,该接口只有一个方法
public void actionPerformed(ActionEvent e)
在这里执行想要的操作
public Object getSourcee() 获取事件源对象的引用,返回向上转型为Object对象的应用
publi String getActionCommand() 获取和事件发生的一个命令字符串,例,文本框引发事件,文本框内的文本字符串就是和该事件相关的一个命令字符串。
在文本框内输入文件名(默认目录下要有文件),回车后,通过BufferReader流读出内容。
Main.java
public class Main {
public static void main(String[] args) {
WindowActionEvent win = new WindowActionEvent();
win.setBounds(100,100,310,260);
win.setTitle("处理ActionEvent事件");
}
}
WindowActionEvent.java
import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class WindowActionEvent extends JFrame {
JTextField text;
ReaderListen listener;
public WindowActionEvent() throws HeadlessException {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
setLayout(new FlowLayout());
text = new JTextField(10);
listener = new ReaderListen();
text.addActionListener(listener);
add(text);
}
}
class ReaderListen implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String fileName = e.getActionCommand();
System.out.println(fileName + "内容如下:");
try {
File file = new File(fileName);
FileReader inOne = new FileReader(file);// 在项目目录下 自己把Main.java复制一份到项目目录下
BufferedReader inTwo = new BufferedReader(inOne);
String s = null;
while ((s = inTwo.readLine()) != null) {
System.out.println(s);
}
inOne.close();
inTwo.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
效果图:
Main.java
public class Main {
public static void main(String[] args) {
WindowActionEvent win = new WindowActionEvent();
win.setBounds(100,100,360,300);
win.setTitle("处理ActionEvent事件");
}
}
WindowActionEvent.java
import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class WindowActionEvent extends JFrame {
JTextField text;
JTextArea textShow;
JButton button;
ReaderListen listener;
public WindowActionEvent() throws HeadlessException {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
setLayout(new FlowLayout());
text = new JTextField(10);
button = new JButton("读取");
textShow = new JTextArea(9,30);
listener = new ReaderListen();
listener.setJTextField(text);
listener.setJTextArea(textShow);
text.addActionListener(listener);
button.addActionListener(listener);
add(text);
add(button);
add(new JScrollPane(textShow));
}
}
class ReaderListen implements ActionListener {
JTextField text;
JTextArea textShow;
public void setJTextField(JTextField text) {
this.text = text;
}
public void setJTextArea(JTextArea textShow) {
this.textShow = textShow;
}
@Override
public void actionPerformed(ActionEvent e) {
try {
File file = new File(text.getText()); //getDocument()
FileReader inOne = new FileReader(file);
BufferedReader inTwo = new BufferedReader(inOne);
String s = null;
while ((s = inTwo.readLine()) != null) {
textShow.append(s+"\n");
}
inOne.close();
inTwo.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
Item事件源
选择框和下拉列表都可以触发 ItemEvent 事件。选择框提供两种状态,一种是未选中,另一种是选中,用户点击切换了状态,就会触发 ItemEvent 事件。对于下拉列表,用户选中了下拉列表中某个选项,就会触发 ItemEvent 事件。
注册监视器
选择框和下拉列表组件使用addItemListener(ItemListener listen)
,注册为事件源的监视器。
ItemListener 接口
class MyListener implements ItemListener{
@Override
public void itemStateChanged(ItemEvent e) {
// 触发事件后,你想要的操作
}
}
ItemEvent 事件对象使用 getSource() 方法返回 ItemEvent 事件源,使用 getItemSelectable 方法返回发生 ItemEvent 事件的事件源。
@Override
public void itemStateChanged(ItemEvent e) {
...
e.getSource();
e.getItemSelectable();
.
..
}
下拉列表的选项是当前目录下Java文件的名字,用户选择下拉列表的选项后,监视器负责在文本区显示文件的内容。
效果图:
Main.java
public class Main {
public static void main(String[] args) {
WindowActionEvent win = new WindowActionEvent();
win.setBounds(100, 100, 400, 300);
win.setTitle("处理ItemEvent事件");
}
}
WindowActionEvent.java
import java.awt.FlowLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FilenameFilter;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class WindowActionEvent extends JFrame {
JComboBox choice;
JTextArea textShow;
ReaderListen listener;
public WindowActionEvent() throws HeadlessException {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
setLayout(new FlowLayout());
choice = new JComboBox<>();
choice.addItem("请选择文件:");
File dir = new File(".");
FileAccept fileAccept = new FileAccept("java"); // 设置后缀名
String[] fileName = dir.list(fileAccept);// 把.java后缀的文件名返回,并存到数组中
for (String name : fileName) { // 遍历返回的.java文件名
choice.addItem(name); // 把文件名添加到下拉列表中
}
textShow = new JTextArea(9, 30);
listener = new ReaderListen();
/**
* 在ItemListener中自定义这个方法
* 主要是要用到下拉列表框和文本区的变量,进行相应的操作
*/
listener.setJComboBox(choice);
listener.setJTextArea(textShow);
choice.addItemListener(listener);
add(choice);
add(new JScrollPane(textShow)); //滚动窗格 常用容器
}
class FileAccept implements FilenameFilter { // 文件名过滤器
private String type;
FileAccept(String type) {
this.type = type;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(type);
}
}
}
class ReaderListen implements ItemListener {
JComboBox choice;
JTextArea textShow;
public void setJComboBox(JComboBox choice) {
this.choice = choice;
}
public void setJTextArea(JTextArea textShow) {
this.textShow = textShow;
}
@Override
public void itemStateChanged(ItemEvent e) {
textShow.setText(null);
try {
String fileName = choice.getSelectedItem().toString(); // 获取下拉列表名称
File file = new File(fileName);
FileReader inOne = new FileReader(file);
BufferedReader inTwo = new BufferedReader(inOne); // 专门用来逐行读取
String s = null;
while ((s = inTwo.readLine()) != null) { //逐行读出
textShow.append(s + "\n"); // 依次添加到textShow中
}
inOne.close();
inTwo.close();
} catch (Exception e2) {
textShow.append(e2.toString());
}
}
}
DocumentEvent 事件源
文本区 (JTextArea)含有一个实现 Document 接口的示例,该实例被称作文本区所维护的文档,文本区调用 getDocument 方法返回所维护的文档。文本区的文档能触发 DocumentEvent 事件。
注册监视器
事件源使用 addDocumentListener (DocumentListener listen),将实现 DocumentListener 接口的类的实例注册为事件源的监视器。
DocumentListener 接口
在 java.swing.event 包中,该接口有三个方法:
public void removeUpdate(DocumentEvent e)
public void insertUpdate(DocumentEvent e)
public void changedUpdate(DocumentEvent e)
有两个文本区。当用户在一个文本区输入若干字符串时(用逗号、空格或回车符作为单词间的分隔符),另一个文本区同时对用户输入的英文单词按字典集排序。
效果图:
Main.java
public class {
public static void main(String args[]) {
WindowDocument win=new WindowDocument();
win.setBounds(10,10,360,260);
win.setTitle("处理DocumentEvent事件");
}
}
WindowDocument.java
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class WindowDocument extends JFrame {
JTextArea inputText,showText; //一个用于输入,一个用于输出
PoliceListen listen;
WindowDocument() {
init();
setLayout(new FlowLayout());
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
inputText = new JTextArea(9,10);
showText = new JTextArea(9,10);
add(new JScrollPane(inputText));
add(new JScrollPane(showText));
listen = new PoliceListen();
listen.setInputText(inputText);
listen.setShowText(showText);
(inputText.getDocument()).addDocumentListener(listen);//向文档注册监视器
}
}
PoliceListenjava
import javax.swing.event.*;
import javax.swing.*;
import java.util.*;
public class PoliceListen implements DocumentListener {
JTextArea inputText, showText;
public void setInputText(JTextArea text) {
inputText = text;
}
public void setShowText(JTextArea text) {
showText = text;
}
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void changedUpdate(DocumentEvent e) {
String str = inputText.getText();
// 空格、数字和符号(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)组成的正则表达式:
String regex = "[\\s\\d\\p{Punct}]+";
String words[] = str.split(regex);
Arrays.sort(words); // 按字典序从小到大排序
showText.setText(null);
for (String s : words)
showText.append(s + ",");
}
}
任何组价上都可以发生鼠标事件,如鼠标进入组件,退出组件,在组件上方单击按钮,拖到按钮等都会触发鼠标事件,即导致 MouseEvent 类自动创建一个事件对象。
鼠标事件
MouseListener 接口可以处理的5种鼠标事件
MouseEvent 方法
int getX() 获取鼠标指针在事件源坐标系中的 X-坐标
int getY() 获取鼠标指针在事件源坐标系中的 Y-坐标
int getButton() 返回更改了状态的鼠标按键(如果有)。
int getClickCount() 返回与此事件关联的鼠标单击次数。
Point getPoint() 返回事件相对于源组件的 x, y 坐标。
Object getSource() 获取发生鼠标事件的事件源
String getMouseModifiersText(int modifiers) 返回一个描述事件期间所按下的修改键和鼠标按键(如“Shift”或“Ctrl+Shift”)的 String。
注册 MouseEvent 事件源
public void mousePressed(MouseEvent e) 处理组件上按下鼠标按钮事件
public void mouseReleased(MouseEvent e) 处理释放组件上的鼠标按钮事件
public void mouseEntered(MouseEvent e) 处理鼠标进入组件的事件
public void mouseExited(MouseEvent e) 处理在鼠标退出组件被调用事件
public void mouseClicked(MouseEvent e) 处理在源组件上点击鼠标按钮事件
分别监视按钮 、文本框、和窗口上的按钮事件,当发生鼠标事件时,获取鼠标指针的坐标值,注意,事件源的坐标系上的左上角是原点。
软件效果:
Main.java
public class Main {
public static void main(String args[]) {
WindowMouse win=new WindowMouse();
win.setTitle("处理鼠标事件");
win.setBounds(100,100,460,360);
}
}
WindowMouse.java
import java.awt.*;
import javax.swing.*;
public class WindowMouse extends JFrame {
JTextField text;
JButton button;
JTextArea textArea;
MousePolice police;
WindowMouse() {
init();
setBounds(100,100,420,220);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
setLayout(new FlowLayout());
text=new JTextField(8);
textArea=new JTextArea(10,28);
police=new MousePolice();
police.setJTextArea(textArea);
text.addMouseListener(police);
button=new JButton("按钮");
button.addMouseListener(police);
addMouseListener(police);
add(button);
add(text);
add(new JScrollPane(textArea));
}
}
MousePolice.java
import java.awt.event.*;
import javax.swing.*;
public class MousePolice implements MouseListener {
JTextArea area;
public void setJTextArea(JTextArea area) {
this.area=area;
}
public void mousePressed(MouseEvent e) {
area.append("\n鼠标按下,位置:"+"("+e.getX()+","+e.getY()+")");
}
public void mouseReleased(MouseEvent e) {
area.append("\n鼠标释放,位置:"+"("+e.getX()+","+e.getY()+")");
}
public void mouseEntered(MouseEvent e) {
if(e.getSource() instanceof JButton) // 得到的事件源是JButton的对象时,返回true
area.append("\n鼠标进入按纽,位置:"+"("+e.getX()+","+e.getY()+")");
if(e.getSource() instanceof JTextField)
area.append("\n鼠标进入文本框,位置:"+"("+e.getX()+","+e.getY()+")");
if(e.getSource() instanceof JFrame)
area.append("\n鼠标进入窗口,位置:"+"("+e.getX()+","+e.getY()+")");
}
public void mouseExited(MouseEvent e) {
area.append("\n鼠标退出,位置:"+"("+e.getX()+","+e.getY()+")");
}
public void mouseClicked(MouseEvent e) {
if(e.getClickCount()>=2)
area.setText("鼠标连击,位置:"+"("+e.getX()+","+e.getY()+")");
}
}
使用 MouseMotionListener 接口可以处理以下两种操作触发的鼠标事件。
事件源注册监视器的方法 addMouseMotionListener (MotionListener listen)
MouseMotionListener 接口的方法:
mouseDragged ( MouseEvent ) 处理了负责拖动鼠标触发的事件。即当拖动鼠标是(不必再事件源上),监视器调用接口中的这个方法对事件作出处理。
mouseMoved ( MouseEvent ) 负责处理移动鼠标触发的事件。即当事件源上移动鼠标时,监视器调用接口中的这个方法对事件作出处理。
可以使用坐标变换来实现组件的拖动。当鼠标拖动组件时,可以先获取鼠标指针在组件坐标系中的实时坐标x,y,以及组件的左上角在容器坐标系中的坐标a,b;如果在拖动组件时,想让鼠标指针相对于拖动的组件保持静止,那么组件左上角在容器作弊作息中的位置应当是a+x-x0, b+y-y0,其中x0,y0是最初在组件上按下鼠标时,鼠标指针在组建坐标系中的初始位置。
当鼠标移动或拖动时,给出提示并显示鼠标所在位置的坐标。
MyMouseMotionListener.java
import java.awt.BorderLayout;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MyMouseMotionListener {
JFrame myframe; // JFrame通常默认使用BorderLayout布局管理器的
TextArea tf; // 文本区
MousePolice mousepolice; // 实现监视器接口的类
JButton exitButton; // 按钮
public MyMouseMotionListener() {
Label label = new Label("点击或拖动鼠标"); // 初始化标签
myframe = new JFrame("MyMouseMotionListener"); // 创建标题为MyMouseMotionListener的窗口
tf = new TextArea(); // 初始化文本区
exitButton = new JButton("退出"); // 初始化退出按钮
mousepolice = new MousePolice(tf); // 利用构造方法把 TextArea传递到监视器
tf.addMouseMotionListener(mousepolice); // 注册监视器
exitButton.addActionListener(new ActionListener() { // 按钮的监听事件 匿名内部类方式
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0); // 正常退出
}
});
myframe.add(label, BorderLayout.NORTH); // 添加标签 位置为北
myframe.add(tf, BorderLayout.CENTER); // 添加文本 在中部
myframe.add(exitButton, BorderLayout.SOUTH); // 设置退出按钮 在南
myframe.setSize(400, 300); // 设置窗口大小
// myframe.setBounds(x, y, 400, 300); 这个方法可以设置窗口在显示屏幕的位置 x,y
myframe.setVisible(true); // 窗口可视
}
public static void main(String[] args) {
new MyMouseMotionListener();
}
}
MousePolice.java
import java.awt.TextArea;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class MousePolice implements MouseMotionListener {
int number = 1;
TextArea tf;
MousePolice(TextArea tf) {
this.tf = tf;
}
@Override
public void mouseDragged(MouseEvent e) {
// getX(),getY():获取鼠标的坐标位置
String s = number++ + "" + "鼠标拖动:x=" + e.getX() + "y=" + e.getY() + "\n";
tf.append(s);
}
@Override
public void mouseMoved(MouseEvent e) {
String s = number++ + "" + "鼠标移动:x=" + e.getX() + "y=" + e.getY() + "\n";
tf.append(s);
}
}
组件可以触发焦点事件。使用 addFocusListener( FocusListener listen)
注册焦点事件。
创建监视器的类必须要实现 FocusListener 接口,该接口有两个方法:
public void focusGained(FocusEvent e) 组件从无输入焦点变成有输入的的焦点时调用
public void focusLost (FocusEvent e) 组件从有输入焦点变成无输入的的焦点时调用
一个组件可以调用:
public boolean requestFocusInWindow()
获得输入焦点
当按下、释放和敲击键盘上一个键时就触发了键盘事件。当一个组件处于激活状态时,敲击键盘上一个键就导致这个组件触发键盘事件。
使用 KeyListener 接口处理键盘事件,该接口的三个方法:
void keyPressed(KeyEvent e) 按下某个键时调用此方法。
void keyReleased(KeyEvent e) 释放某个键时调用此方法。
void keyTyped(KeyEvent e) 键入某个键时调用此方法。
当一个组件使用 addKeyListener 方法注册监视器后,当该组件处于激活状态时,按下这个键,就会触发 KeyEvent 事件。
用 KeyEvent 类的 public int getKeyCode()
,可以判断哪个键被按下、敲击或释放,getKeyCode()
返回一个键码表。也可以用 public char getKeyChar
判断哪个键被按下、敲击和释放,返回的是键上的字符。
键码表
键码 | 键 |
---|---|
VK_F1-VK_F12 | 功能键 F1-F12 |
VK_0-VK_9 | 0~9 数字键 |
VK_A-VK_Z | a~z 键 |
VK_KP_DOWN | 用于数字键盘向下方向键的常量 |
VK_KP_LEFT | 用于数字键盘向左方向键的常量 |
VK_KP_RIGHT | 用于数字键盘向右方向键的常量 |
VK_KP_UP | 用于数字键盘向上方向键的常量 |
更多键码
在文本框输入序列号,当数字达到设定个数时,光标移动到下个文本框。
Winows.java
import java.awt.*;
import javax.swing.*;
class Winows extends JFrame {
JTextField text[] = new JTextField[3]; // 3个文本框
Police police;
JButton b;
Winows() {
setLayout(new FlowLayout());
police = new Police(); // 初始化监视器
for (int i = 0; i < 3; i++) {
text[i] = new JTextField(7); // 文本框显示的长度
text[i].addKeyListener(police); // 监视键盘事件
text[i].addFocusListener(police);
add(text[i]);
}
b = new JButton("确定");
add(b);
text[0].requestFocusInWindow(); // 第一个文本框获得焦点,光标处于第一个文本框
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
public class Win {
public static void main(String args[]) {
Winows win = new Winows();
win.setTitle("输入序列号");
win.setBounds(10, 10, 460, 160);
}
}
Police.java
import java.awt.event.*;
import javax.swing.*;
public class Police implements KeyListener, FocusListener {
public void keyPressed(KeyEvent e) {
JTextField t = (JTextField) e.getSource(); // 获取事件源
if (t.getCaretPosition() >= 5) // 光标的位置(>0)大于5则焦点移动到下一个文本框(可以输入6个数字)
t.transferFocus(); //失去当前焦点 transferFocus(false);
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void focusGained(FocusEvent e) {
JTextField text = (JTextField) e.getSource();
text.setText(null);
}
public void focusLost(FocusEvent e) {
}
}
匿名类的使用比较容易操作事件源所在的外部类的成员,不必把监视器需要处理的对象的引用传递给监视器。但是处理比较复杂的时,使用内部类或匿名类会让系统缺乏弹性,以为每次修改内部类的代码都会导致整个外部类同时被编译,反之也是。
窗口有两个文本框: text1 和 text2,当前窗口作为text1 的监视器,用户在 text1输入一个整数,当前窗口的 text2 中显示该数的平方根(没有作超出范围的异常处理),另外,一个匿名类的实例也注册为了 text1 的监视器,当在text1中输入 Exit 时,程序立即退出。
效果图:
Main.java
public class Main {
public static void main(String args[]) {
WindowPolice win = new WindowPolice();
win.setTitle("匿名内部类 或窗口做监视器");
win.setBounds(100, 100, 350, 150);
}
}
WindowPolice.java
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class WindowPolice extends JFrame implements ActionListener {
JTextField text1, text2; // 两个文本框
public WindowPolice() {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
setLayout(new FlowLayout());
text1 = new JTextField(10);
text2 = new JTextField(10);
text1.addActionListener(this); // WindowPolice类的实例(当前窗口)做监视器
add(text1);
add(text2);
text1.addActionListener(new ActionListener() { // 匿名类实例做监视器
public void actionPerformed(ActionEvent e) {
String str = text1.getText();
if (str.equalsIgnoreCase("Exit"))
System.exit(0);
}
});
}
public void actionPerformed(ActionEvent e) { // 重写接口中的方法
String str = text1.getText();
int n = 0, m = 0;
try {
n = Integer.parseInt(str); // 转化为 int 型数据
m = n * n * n;
text2.setText("" + m);
} catch (Exception ee) {
text2.setText("请输入数字字符");
text1.setText(null);
}
}
}
Java事件处理是基于授权模式,即事件源调用方法将某个对象注册为自己的监视器。在安卓中的一个按钮的监听事件,也要 button.setOnClickListener(OnClickListener listener)
设置一个监听。
Java语言使用接口回调技术来实现处理事件的过程。
addXXXListener(XXXListener listener)
方法中的参数是一个接口,listener 可以引用任何实现了该接口的类所创建的对象,当事件发生时,接口 listener 立刻回调被类实现的接口中的方法。
从方法绑定的角度看,Java将某种事件的处理绑定到对应的接口,即绑定到接口中的方法,也就是说,当事件源触发事件发生后,监视器准确知道去调用哪个方法。
监视器和事件源应当保持一种松耦合关系,也就是说尽量让事件所在的类和监视器是组合关系,尽量不要让事件源所在类的实例以及它的子类的实例或内部类、匿名类的实例做监视器。
也就是说,当事件源触发事件发生后,系统知道某个方法会被执行,但无需关心到底是哪个对象去调用这个方法,因为任何实现接口的类的实例(作为监视器)都可以调用这个方法来处理事件。
其实这就是为了降低耦合度,使代码结构更清晰 更容易维护。
软件工程中对象之间的耦合度就是对象之间的依赖性。指导使用和维护对象的主要问题是对象之间的多重依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。
内聚与耦合
内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。[2]
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
MVC是一种通过3个不同部分构造个软件或组件的理想方法。
从面向对象的角度看,MVC结构可以使程序更具有对象化特性,也更容易维护。在设计程序时,可以将某个对象看作“模型”,然后为“模型”提供恰当的显示组件,即“视图”。为了对用户的操作做出响应,可以使用某个组件做“控制器”,当发生组件事件时,通过“视图”修改或得到“模型”中维护着的数据,并让“视图”更新显示。
编写一个封装三角形的类,然后编写一个窗口。要求窗口使用 3个文本框和一个文本区为三角形对象中的数据提供视图,其中3个文本框用来显示和更新三角形对象的3个边的长度;文本区对象用来显示三角形的面积,计算面积按钮就像一个控制器,点击出结果。
效果图:
Main.java
public class Main {
public static void main(String args[]){
WindowTriangle win=new WindowTriangle();
win.setTitle("使用MVC结构");
win.setBounds(100,100,420,260);
}
}
Triangle.java
public class Triangle {
double sideA, sideB, sideC, area;
boolean isTriange = false;
public String getArea() {
if (isTriange) {
double p = (sideA + sideB + sideC) / 2.0;
area = Math.sqrt(p * (p - sideA) * (p - sideB) * (p - sideC)); // 海伦公式
return String.valueOf(area); // Double.toString(area)
} else {
return "无法计算面积";
}
}
public void setA(double a) {
sideA = a;
if (sideA + sideB > sideC && sideA + sideC > sideB && sideC + sideB > sideA)
// 两边之和大于第三边 或 两边只差小于第三边 来判断是否是三角形
isTriange = true;
else
isTriange = false;
}
public void setB(double b) {
sideB = b;
if (sideA + sideB > sideC && sideA + sideC > sideB && sideC + sideB > sideA)
isTriange = true;
else
isTriange = false;
}
public void setC(double c) {
sideC = c;
if (sideA + sideB > sideC && sideA + sideC > sideB && sideC + sideB > sideA)
isTriange = true;
else
isTriange = false;
}
}
WindowTriangle.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class WindowTriangle extends JFrame implements ActionListener {
Triangle triangle; // 数据对象
JTextField textA, textB, textC; // 数据对象的视图
JTextArea showArea; // 数据对象的视图
JButton controlButton; // 控制器对象
WindowTriangle() {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
triangle = new Triangle();
textA = new JTextField(5);
textB = new JTextField(5);
textC = new JTextField(5);
showArea = new JTextArea();
controlButton = new JButton("计算面积");
JPanel pNorth = new JPanel();
pNorth.add(new JLabel("边A:"));
pNorth.add(textA);
pNorth.add(new JLabel("边B:"));
pNorth.add(textB);
pNorth.add(new JLabel("边C"));
pNorth.add(textC);
pNorth.add(controlButton);
controlButton.addActionListener(this); // 宽口作为监视器
add(pNorth, BorderLayout.NORTH);
add(new JScrollPane(showArea), BorderLayout.CENTER);
}
public void actionPerformed(ActionEvent e) {
try {
double a = Double.parseDouble(textA.getText().trim()); //
double b = Double.parseDouble(textB.getText().trim());
double c = Double.parseDouble(textC.getText().trim());
triangle.setA(a); // 更新数据
triangle.setB(b);
triangle.setC(c);
String area = triangle.getArea();
showArea.append("三角形" + a + "," + b + "," + c + "的面积:");
showArea.append(area + "\n"); // 更新视图
} catch (Exception ex) {
showArea.append("\n" + ex + "\n");
}
}
}
JDialog类和JFrame 都是 Window 的子类,二者的实例都是底层容器,但二者有相似之处也有不同的地方,主要区别是,JDialog 类创建的对话框必须依赖于某个窗口。
对话框分为无模式和有模式两种。当弹出有模式的对话框是时,只让程序响应对话框内部的事件,而且将堵塞其他线程的执行,用户不能再激活所在程序的其他窗口,直到该对话框消失。无模式对话框处于激活状态时,能再激活其他窗口但不堵塞其他线程的执行。
进行一个重要的操作之前,通过弹出一个有模式的对话框来表明操作的重要性。
消息对话框是有模式的对话框。创建一个消息对话框,可以使用 javax.swing 包中的方法 JOptionPane 类的静态方法:
public static void showMessageDialog(Component parentComponent,
Object message, String title, int messageType)
parentComponent 指定对话框可见时的位置,输入组件,会在该组件的正前方显示出来如果为null,对话框会在屏幕的正前方显示出来
message 对话框显示的信息
title 对话框显示的标题
messageType 指定对话框的外观
messageType 的取值:
JOptionPane.ERROR_MESSAGE
JOptionPane.INFORMATION_MESSAGE
JOptionPane.WARNING_MESSAGE 显示一个 !号
JOptionPane.QUESTION_MESSAGE
JOptionPane.PLAIN_MESSAGE
要求用户在文本框中只能输入英文字母,当用户输入非英文字母时,弹出对话框。
效果图:
Main.java
public class Main {
public static void main(String args[]) {
WindowMess win=new WindowMess();
win.setTitle("带消息对话框的窗口");
win.setBounds(80,90,300,300);
}
}
WindowMess.java
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class WindowMess extends JFrame implements ActionListener {
JTextField inputEnglish;
JTextArea show;
String regex = "[a-zZ-Z]+";
WindowMess() {
inputEnglish = new JTextField(22);
inputEnglish.addActionListener(this);
show = new JTextArea();
add(inputEnglish, BorderLayout.NORTH);
add(show, BorderLayout.CENTER);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == inputEnglish) {
String str = inputEnglish.getText();
if (str.matches(regex)) {
show.append(str + ",");
} else { // 弹出“警告”消息对话框。
JOptionPane.showMessageDialog(this, "您输入了非法字符", "消息对话框", JOptionPane.WARNING_MESSAGE);
inputEnglish.setText(null);
}
}
}
}
输入对话框含有供用户输入文本的文本框、一个确认按钮和一个取消按钮,是有模式的对话框。
public static String showInputDialog(Component parentComponent,
Object message, String title, int messageType)throws HeadlessException
parentComponent 指定对话框可见时的位置,输入组件,会在该组件的正前方显示出来如果为null,对话框会在屏幕的正前方显示出来
message 对话框显示的信息
title 对话框显示的标题
messageType 指定对话框的外观
messageType 的取值:
JOptionPane.ERROR_MESSAGE
JOptionPane.INFORMATION_MESSAGE
JOptionPane.WARNING_MESSAGE 显示一个 !号
JOptionPane.QUESTION_MESSAGE
JOptionPane.PLAIN_MESSAGE
HeadlessException 当使用对显示设备,键盘,鼠标等的系统调用时,而本地的显示设备,键盘,鼠标等不支持调用就会出现该异常.
用户单击按钮弹出输入对话框,用户输入若干个数字后,按对话框上的确定按钮,程序将计算这些数字的和。
效果图:
Main.java
//package com.对话框.输入对话框;
public class Main {
public static void main(String args[]) {
WindowInput win=new WindowInput();
win.setTitle("带输入对话框的窗口");
win.setBounds(80,90,300,300);
}
}
WindowInput.java
//package com.对话框.输入对话框;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.InputMismatchException;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class WindowInput extends JFrame implements ActionListener {
JTextArea showResult; // 文本区
JButton openInput; // 按钮
WindowInput() {
openInput = new JButton("弹出输入对话框");
showResult = new JTextArea();
add(openInput, BorderLayout.NORTH); // 按钮位置在上放
add(new JScrollPane(showResult), BorderLayout.CENTER); // 滚动窗格 文本显示居中
openInput.addActionListener(this); // 注册窗口为监视器
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
String str = JOptionPane.showInputDialog(this, "输入数字,用空格分隔", "输入对话框", JOptionPane.PLAIN_MESSAGE);
if (str != null) {
Scanner scanner = new Scanner(str); // 利用空格分割字符
double sum = 0;
int k = 0;
while (scanner.hasNext()) {
try {
double number = scanner.nextDouble();
if (k == 0)
showResult.append("" + number);
else
showResult.append("+" + number);
sum = sum + number;
k++;
} catch (InputMismatchException exp) {
String t = scanner.next();
}
}
showResult.append("=" + sum + "\n");
}
}
}
确认对话框是有模式对话框。可以使用 javax.swing 包中的方法 JOptionPane 类的静态方法创建。
public static int showConfirmDialog(Component parentComponent,
Object message, String title, int optionType)
throws HeadlessException
optionType的取值
JOptionPane.DEFAULT_OPTION //“确定”按钮
JOptionPane.YES_NO_OPTION // “是”、“否”按钮
JOptionPane.YES_NO_CANCEL_OPTION //“是”、“否”、“取消”按钮
JOptionPane.OK_CANCEL_OPTION //“确定”、“取消”按钮
当确认对话框消失后,showConfirmDialog 会返回下列整数之一:
JOptionPane.YES_OPTION 点击 “是”
JOptionPane.NO_OPTION 点击 “否”
JOptionPane.CANCEL_OPTION 点击 “取消”
JOptionPane.OK_OPTION 点击 “确认”
JOptionPane.CLOSED_OPTION 点击对话框上的关闭按钮
用户在文本框中输入内容,确认后显示在文本区中,不确认不显示。
效果图:
Main.java
//package com.对话框.确认对话框;
public class Main {
public static void main(String args[]) {
WindowEnter win=new WindowEnter();
win.setTitle("带确认对话框的窗口");
win.setBounds(80,90,300,200);
}
}
WindowEnter.java
//package com.对话框.确认对话框;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class WindowEnter extends JFrame implements ActionListener {
JTextField inputName;
JTextArea save;
WindowEnter() {
inputName = new JTextField(22);
inputName.addActionListener(this);
save = new JTextArea();
add(inputName, BorderLayout.NORTH);
add(new JScrollPane(save), BorderLayout.CENTER);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
String s = inputName.getText();
int n = JOptionPane.showConfirmDialog(this, "确认是否正确", "确认对话框", JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION) {
save.append("\n" + s);
} else if (n == JOptionPane.NO_OPTION) {
inputName.setText(null);
}
}
}
颜色对话框是有模式的对话框。可以使用 javax.swing 包中的方法 JColorChooser 类的静态方法创建。
public static Color showDialog(Component component,
String title, Color initialColor) throws HeadlessException
parentComponent 指定对话框可见时的位置,输入组件,会在该组件的正前方显示出来如果为null,对话框会在屏幕的正前方显示出来
title 指定对话框的标题
initialColor 指定颜色对话框返回的初始颜色
用户通过颜色对话框选择颜色后,如果单击“确定”按钮,那么颜色对话框消失,showDialog() 方法返回颜色对话框所选择的颜色,点击“取消”按钮,则返回null。
用户单击按钮时,弹出颜色对话框,然后根据用户选中的颜色来改变窗口的颜色。
效果图:
Main.java
//package com.对话框.颜色对话框;
public class Main {
public static void main(String args[]) {
WindowColor win=new WindowColor();
win.setTitle("带颜色对话框的窗口");
win.setBounds(80,90,300,200);
}
}
WindowColor.java
//package com.对话框.颜色对话框;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
public class WindowColor extends JFrame implements ActionListener {
JButton button;
WindowColor() {
button = new JButton("打开颜色对话框");
button.addActionListener(this);
setLayout(new FlowLayout());
add(button);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
Color newColor = JColorChooser.showDialog(this, "调色板", getContentPane().getBackground());
if (newColor != null) {
getContentPane().setBackground(newColor);
}
}
}
文件对话框是一个从文件中选择文件的界面,是一个有模式的对话框。使用 javax.swing 包中的 JFileChooser 类创建文件对话框。
showSaveDialog (Component a) 保存文件界面
showSaveDialog (Component a) 打开文件界面
参数 a 指定对话框可见的位,当 a 为null时,文件对话框的出现在屏幕的中央;如果组件 a 不为空,文件对话框在 a 的正前方居中显示。
用户单击文件对话框上的“确定”,“取消”,文件对话框消失, showSaveDialog ()方法 和showSaveDialog()方法返回下列常量之一:
JFileChooser.APPROVE_OPTION
JFileChooser.CANCEL_OPTION
使用文本对话框打开或保存文件。
效果图:
Main.jva
//package com.对话框.文本对话框;
public class Main {
public static void main(String args[]) {
WindowReader win = new WindowReader();
win.setTitle("使用文件对话框读写文件");
win.setBounds(80, 90, 300, 300);
}
}
WindowReader.java
//package com.对话框.文本对话框;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class WindowReader extends JFrame implements ActionListener {
JFileChooser fileDialog; // 文件对话框
JMenuBar menubar; // 菜单条
JMenu menu; // 菜单
JMenuItem itemSave, itemOpen; // 菜单项
JTextArea text; // 文本区
BufferedReader in; // 缓冲读取流
FileReader fileReader; // 文件读取流
BufferedWriter out; // 缓冲写入流
FileWriter fileWriter; // 文件写入流
WindowReader() {
init();
setSize(300, 400);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
text = new JTextArea(10, 10);
text.setFont(new Font("楷体_gb2312", Font.PLAIN, 28));
add(new JScrollPane(text), BorderLayout.CENTER);
menubar = new JMenuBar();
menu = new JMenu("文件");
itemSave = new JMenuItem("保存文件");// 初始化菜单项
itemOpen = new JMenuItem("打开文件");
itemSave.addActionListener(this); // 注册监视器
itemOpen.addActionListener(this);
menu.add(itemSave);// 菜单中加入菜单项
menu.add(itemOpen);
menubar.add(menu); // 菜单条中加入菜单
setJMenuBar(menubar);
fileDialog = new JFileChooser();
}
// 监听事件
public void actionPerformed(ActionEvent e) {
if (e.getSource() == itemSave) {
int state = fileDialog.showSaveDialog(this);
if (state == JFileChooser.APPROVE_OPTION) {
try {
// 保存文件
File dir = fileDialog.getCurrentDirectory();
String name = fileDialog.getSelectedFile().getName();
File file = new File(dir, name);
fileWriter = new FileWriter(file);
out = new BufferedWriter(fileWriter);
out.write(text.getText());
out.close();
fileWriter.close();
} catch (IOException exp) {
}
}
} else if (e.getSource() == itemOpen) {
int state = fileDialog.showOpenDialog(this);
if (state == JFileChooser.APPROVE_OPTION) {
text.setText(null);
try {
// 打开文件
File dir = fileDialog.getCurrentDirectory();
String name = fileDialog.getSelectedFile().getName();
File file = new File(dir, name);
fileReader = new FileReader(file);
in = new BufferedReader(fileReader);
String s = null;
while ((s = in.readLine()) != null) {
text.append(s + "\n");
}
in.close();
fileReader.close();
} catch (IOException exp) {
}
}
}
}
}
创建对话框和创建窗口类似,通过建立 JDialog 的子类来建立一个对话框类。JDialog 对象也是一种容器,因此也可以给 JDialog 对话框指派布局管理器,对话框的默认布局为 BoarderLayout 布局。但组件不能直接加到对话框中,对话框也包含一个内容面板,应当把组件加到 JDialog 对象的内容面板中。由于对话框依赖窗口,因此要建立对话框,必须先要创建一个窗口。
JDialog类常用的构造方法有3个:
JDialog() 构造一个初始化不可见的非强制型对话框。
JDialog(JFramef,String s) 构造一个初始化不可见的非强制型对话框,参数f设置对话框所依赖的窗口,参数s用于设置标题。通常先声明一个JDialog类的子类,然后创建这个子类的一个对象,就建立了一个对话框。
JDialog(JFrame f,String s,boolean b) 构造一个标题为s,初始化不可见的对话框。参数f设置对话框所依赖的窗口,参数b决定对话框是否强制或非强制型。
JDialog 类的其他常用方法有以下几个:
getTitle() 获取对话框的标题。
setTitle(String s) 设置对话框的标题。
setModal(boolean b) 设置对话框的模式。
setSize() 设置框的大小。
setVisible(boolean b) 显示或隐藏对话框
使用自定义对话框改变窗口的标题。
效果图:
Main.java
//package com.对话框.自定义对话框;
public class Main {
public static void main(String args[]) {
MyWindow win=new MyWindow();
win.setTitle("带自定义对话框的窗口");
win.setSize(300,300);
}
}
MyDialog.java
//package com.对话框.自定义对话框;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class MyDialog extends JDialog implements ActionListener { // 对话框类
JTextField inputTitle;
String title;
MyDialog(JFrame f, String s) { // 构造方法
super(f, s);
inputTitle = new JTextField(10);
inputTitle.addActionListener(this);
setLayout(new FlowLayout());
add(new JLabel("输入窗口的新标题"));
add(inputTitle);
setBounds(60, 60, 100, 100);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
title = inputTitle.getText();
setVisible(false);
}
public String getTitle() {
return title;
}
}
MyWindow.java
//package com.对话框.自定义对话框;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MyWindow extends JFrame implements ActionListener {
JButton button;
MyDialog dialog;
MyWindow() {
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init() {
button = new JButton("打开对话框");
button.addActionListener(this);
add(button, BorderLayout.NORTH);
dialog = new MyDialog(this, "我是对话框"); // 对话框依赖于MyWindow创建的窗口
dialog.setModal(true); // 有模式对话框
}
public void actionPerformed(ActionEvent e) {
dialog.setVisible(true);
String str = dialog.getTitle();
setTitle(str);
}
}
可以使用 jar.exe 把一些文件压缩成一个 JAR 文件,来发布我们的应用程序。我们可以把 java 应用程序中涉及的类压缩成一个 JAR 文件,如 Hello.jar ,然后使用 java 解释器 (使用参数-jar)执行这个压缩文件,或用鼠标双击文件,执行这个压缩文件。
java -jar Hello.jar
假设 D:\test 目录中的应用程序有两个类 A、B,其中A是主类。生成一个 JAR 文件的步骤如下:
Mylist.mf:
注意蓝色处间隔一个空格,存放到D:\test下。
在cmd命令行中输入下面的名利,生成Hello.jar
D:\test> jar cfm Hello.jar Mylist.mf A.class B.class
or
D:\test> jar cfm Hello.jar Mylist.mf *.class
其中的 cfm,c 代表要生成一个新的 JAR 文件,f 表示文件名,m 代表文件清单的名字。
1.耿祥义、张跃平的《Java程序设计实用教程》