JavaSE(6):java界面编程技术,javase编程技术
JavaSE(6):java界面编程技术,javase编程技术
六、java界面编程技术
1、图形用户界面概念:
GUI:Graphical User Interface,图形用户接口,图形方式直观显示操作。
CLI:Command Line User Interface,命令行用户接口,如常见的dos操作。
2、AWT与Swing;
java.Awt:Abstract Window Toolkit (抽象窗口工具包),需要调用本地的系统方法实现功能,是重量级控件。
javax.Swing:轻量级控件。组件的实现不包含任何本地代码,不受硬件平台的限制。
当组件区域有重叠时,重量级组件总是显示在上面,所以通常不同时使用。
3、设计和实现图形用户界面的内容:
①创建图形界面需要的元素,进行相应布局;
②定义界面元素对于用户事件的响应以及对事件的处理。
Awt组件继承图
4、常用容器类与容器布局管理
1、顶层容器 —— JFrame
容器:组件必须包含在某个容器中,处于嵌套层次最外层的是顶层容器,Swing提供了四种顶层容器:JFrame、JApplet、JDialog、JWindow。通常应用程序创建是以JFrame为顶层容器的。JFrame类创建的窗体期初不可见的,需要通过调用show方法或是setVisible(true)才能使其可见。
在定义窗口框架后,用add方法加入组件之前,需要获取内容窗格,类似windows编程中获取窗口设备上下文DC。然后将内容添加到内容窗格中,通常有两种方法:
一:先获取窗格,然后在窗格中加入内容,如
jframe.getContentPane().add(button,BorderLayout.CENTER);
二:创建一个窗格,在窗格上布置内容,再将窗格放到窗体中,类似windows程序中的双缓冲绘图的缓冲DC:
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
contentPane.add(button,BorderLayout.CENTER);
frame.setContentPane(contentPane);
但是在J2SE1.5之后可以直接用顶层容器add方法添加组件,等价于通过顶层容器的内容窗格添加组件,注意,JFrame才有contentPane,而Frame类没有。
2、中间容器 —— JPanel、JscorllPane
JPanel不能独立存在,必须添加到其他容器中,且本身可以嵌套,JPanel是无边框的,不能被移动、放大、缩小,自身支持双缓冲功能。通常先创建对象,再设置排列方式,然后加入依托面板中。
JscorllPane是一个滚动窗口容器,带滚动条,具体用法见api文档。
3、布局管理器
每个容器都有默认的布局管理器,同时可以通过setLayout方法人工设置需要的布置模式。
FlowLayout(流式布局,最常用的布局,Panel默认布局,Applet缺省布局,可自定义对齐方式如左对齐FlowLayout.LEFT)、BorderLayout(边界布局,分东西南北中五区,是顶层容器如JFrame的默认布局,若不指定位置,组件add默认添加到中间区域CENTER)、GridLayout(网格式布局,指定行列分布)、CardLayout(卡片布局管理)、GridBagLayout(网络包布局管理器)。
注:设计界面时也可以不使用布局管理器,setLayout(null),此时可通过组件的setBounds()方法精确设置组件在容器中的位置、大小。
创建界面过程:创建JFrame(frame)窗体 -> 设置窗口大小、布局、位置 -> 定义组件 -> add方法添加组件到窗体中 -> 显示窗体,setVisible(true)方法。
MyWindow.java(窗口的创建(两种方法,拥有Frame类属性,或继承Frame类)、contentPane的使用、及布局管理器的使用)
package blog6;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 窗口的创建(两种方法,拥有Frame类属性,或继承Frame类)、
* contentPane的使用(此属性是JFrame的,Frame类没有)、及布局管理器的使用
*/
public class MyWindow {
/*
//测试1、Frame作为属性的窗口
public static void main(String[] args) {
new Window1();
}
*/
/*
//测试2、类继承Frame类
public static void main(String[] args){
new Window2("我的第二个窗口");
}
*/
//测试3、JFrame及contentPane的用法
public static void main(String[] args) {
new Window3("我的第三个窗口");
}
}
class Window1{
private Frame f;
public Window1() {
f = new Frame("我的第一个窗口");
//自定义组件位置,不使用layout
f.setLayout(null);
Button bt = new Button("按钮");
bt.setBounds(100, 100, 50, 50); //bt出现在f窗口的100,100位置
f.add(bt);
f.setBounds(200, 200, 400, 400); //窗口大小,位置
f.setVisible(true); //此时窗口没有任何事件监听及处理
}
}
@SuppressWarnings("serial")
class Window2 extends Frame{
public Window2(String name) {
super(name);
setBounds(100, 100, 400, 300);
setWindow(); //插入布局设置自定义函数
setVisible(true);
}
//布局管理器的使用
public void setWindow(){
//Frame类的默认布局是BorderLayout,Panel类默认为FlowLayout
setLayout(new BorderLayout()); //此句无用,因为本身默认就是BorderLayout布局了
add(new Button("按钮A")); //不指定布局位置的话,默认置于CENTER位置
add(new Button("按钮B"),BorderLayout.EAST);
add(new Button("按钮C"),BorderLayout.SOUTH);
}
}
@SuppressWarnings("serial")
class Window3 extends JFrame{
public Window3(String name) {
super(name);
//法一
// getContentPane().add(new JButton(),BorderLayout.EAST);
//法二
JPanel contentPane = new JPanel(new BorderLayout()); //默认为流式布局,设为边界
contentPane.add(new Button("A按钮"));
contentPane.add(new Button("B按钮")); //此处AB按钮都会默认放到中央区域,会覆盖吗?会覆盖
contentPane.add(new Button("C按钮"),BorderLayout.NORTH);
setContentPane(contentPane);
//其实不用contentPane窗格内容也同样可以使用的
setBounds(new Rectangle(100,100,400,400));
setVisible(true);
}
}
5、事件处理机制
事件处理模型如下图所示:
事件处理中的几个关键元素:
1、确定事件源:组件或容器
2、通过事件源对象的addXXXXListener()方法将监听器注册到该事件源上,表示该事件源能够监听到这类事件的发生。
3、在监听器注册方法中,接收XXXListener的子类对象,做出相应的处理反应。一般以匿名内部类表示。
4、在覆盖方法时,方法的参数一般是XXXEvent类型的变量。事件触发后会将事件打包成对象传递给该变量(其中包括了事件源信息,通过getSource或者getCompopent获取)。
WindowEvent.java(三种事件监听实现,创建内部类实现ActionListener接口、窗口类本身实现ActionListener接口、匿名内部类)
package blog6;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
/**
* 三种事件监听实现 1 创建内部类实现ActionListener接口、 2 窗口类本身实现ActionListener接口、 3 匿名内部类
*/
public class MyWindowEvent {
/*
// 测试1、内部类 作为事件监听者
public static void main(String[] args) {
new EventOne();
}
*/
/*
// 测试2、组件类本身实现
public static void main(String[] args) {
new EventTwo();
}
*/
// 测试3、匿名内部类实现事件监听,最常用方法,但是需要为每个事件源都独立建立其对应的监听器
public static void main(String[] args) {
new EventThree();
}
}
// 测试一的类
@SuppressWarnings("serial")
class EventOne extends JFrame {
private JButton jbt;
public EventOne() {
super("the first window");
jbt = new JButton("按钮A");
add(jbt, BorderLayout.SOUTH);
jbt.addActionListener(new JbtActionListener()); // 为按钮注册监听器
setBounds(100, 100, 500, 500);
setVisible(true);
}
// 创建内部类,实现按钮的监听方法
class JbtActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// 重写接口提供的处理动作事件的方法
if (e.getSource() == jbt) { // 一个监听器可以为多个事件源服务,getSource可以获取事件源
JOptionPane.showMessageDialog(EventOne.this, "按钮A被按下");
// 弹出一个个信息提示对话框
}
}
}
}
// 测试二的类
@SuppressWarnings("serial")
class EventTwo extends JFrame implements ActionListener {
private JButton jbt;
public EventTwo() {
super("the second window");
jbt = new JButton("按钮B");
add(jbt, BorderLayout.NORTH);
jbt.addActionListener(this); // 为按钮注册监听器,以本类实例自身为监听器
setBounds(100, 100, 500, 500);
setVisible(true);
}
@Override
/* 在窗口类中实现监听接口,本类作为事件监听器 */
public void actionPerformed(ActionEvent e) {
if (e.getSource() == jbt) {
JOptionPane.showMessageDialog(EventTwo.this, "按钮B被按下");
}
}
}
// 测试三的类
@SuppressWarnings("serial")
class EventThree extends Frame {
private Button jbt;
public EventThree() {
super("the thrid window");
jbt = new Button("按钮C");
add(jbt, BorderLayout.WEST);
//此处可以将所有的事件监听处理集成一个方法在此处调用注册
jbt.addActionListener(new ActionListener(){
@Override /* 匿名内部类 */
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(EventThree.this, "按钮C被按下");
}} ); // 为按钮注册监听器,以本类实例自身为监听器
setBounds(100, 100, 500, 500);
setVisible(true);
}
}
事件适配器:为了进行事件处理需要创建实现对应接口的类,而在这些接口中往往声明了很多抽象方法,但是通常,我们只需要处理某几种指定的方法,此时对应两个以上方法的监听者接口会有一个XXXXAdapter类,提供了接口中每个方法的缺省实现,用户只需要重写需要处理的方法即可。适配器通常以匿名内部类实现。
KeyMouseEvent.java(键盘鼠标事件适配器实现的实例)
package blog6;
import java.awt.FlowLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
/**
* 本例任务,完成一个鼠标和键盘的动作采集。
* 对于鼠标、键盘事件的处理,采用事件适配器
*/
@SuppressWarnings("serial")
public class KeyMouseEvent extends JFrame{
private JLabel keyInfo,mouseX,mouseY,mouseClikCount;
private JTextField mouseXInfo,mouseYInfo;
private int clickCount = 0;
public KeyMouseEvent() {
this.setLayout(new FlowLayout()); //设置成流式布局
keyInfo = new JLabel("你按下的键盘键是: ");
mouseX = new JLabel("x坐标");
mouseY = new JLabel("y坐标");
mouseClikCount = new JLabel("点击鼠标 次");
mouseXInfo = new JTextField(10); //指定文本框长度
mouseYInfo = new JTextField(10);
mouseXInfo.setEditable(false);
mouseYInfo.setEditable(false); //因为是显示作用的, 所以设置成不可编辑
add(keyInfo);
add(mouseX);
add(mouseXInfo);
add(mouseY);
add(mouseYInfo);
add(mouseClikCount);
MyKeyMouseEvent();
setBounds(100, 100, 600, 400);
setVisible(true);
setTitle("键盘、鼠标捕捉程序");
this.requestFocus();//此句重要,若不设置焦点,默认焦点在TextField中,按键不会有反应的
setResizable(false); // 设置大小不可变 resizable is false
}
public void MyKeyMouseEvent(){
//确定事件源,本窗口,事件监视器,处理部分都是在各个文本框或是JLabel中
this.addKeyListener(new KeyAdapter() {
//键盘事件适配器,本程序只监听键盘按下事件,所以重写键盘按下事件
public void keyTyped(KeyEvent e){
char c = e.getKeyChar();
keyInfo.setText("你按下的键盘键是:" + c + "");
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==27){
System.exit(0);
}
}
});
//窗口事件监听、关闭窗口
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
//鼠标事件监听,点击
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
int x = e.getX();
int y = e.getY();
mouseXInfo.setText(String.valueOf(x));
mouseYInfo.setText(String.valueOf(y));
clickCount++;
mouseClikCount.setText("点击鼠标" + clickCount + "次");
}
});
//鼠标监听事件,移动
this.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e){
int x = e.getX();
int y = e.getY();
mouseXInfo.setText(String.valueOf(x));
mouseYInfo.setText(String.valueOf(y));
}
});
//窗口的焦点监听,使用原因在总结里说。
this.addFocusListener(new FocusAdapter(){
@Override
public void focusLost(FocusEvent e) {
KeyMouseEvent.this.requestFocus();
}
});
}
public static void main(String[] args) {
new KeyMouseEvent();
}
}
/**
* 程序问题:反应较慢,而且鼠标的移动并没有捕捉到,只监听到鼠标的点击
* 编写过程中的问题:
* 1、开始时我采用,两个子Panel分别放鼠标和键盘的信息显示,但是运行失败了;
* 2、后来测试发现是因为,程序一运行就把焦点定在了JTextField上,虽然我将文本框设置成了不可编辑,还是没用
* 3、于是我开始控制焦点,构造器中将焦点设置在窗口Frame上,然后添加一个焦点监控器,一旦Frame发生focusLost
* 就将焦点重新绑定到Frame中。
* 4、但是也许是焦点操作的问题,使得我的鼠标移动的事件没有能够监控到........
*
* 5、原来如此:找到了问题的根源,一开始我将所有鼠标的监控都写在了mouseAdapter中
* 事实上,鼠标的点击事件在MouseListener(或mouseAdapter)中,
* 其处理的是MouseEvent;
* 但是鼠标的移动应该在MouseMotionListener(对应MouseMotionAdapter)中,
* 其处理的是MouseMotionEvent
*/
6、 Dialog/JDialog:构造一个最初不可见,指定所有者Frame、标题和模式的对话框,模式参数选择True则为模式对话框,false为非模态对话框。
文件对话框:JFileChooser。通过showOpenDialog和showSaveDialog显示文件“打开”或文件“保存”对话框,提供几种有关文件的操作geSelectedFile。
7、 菜单
先创建菜单栏MenuBar,再创建菜单(文件、视图、编辑等菜单小项目)Menu,再在每一个菜单Menu中添加菜单项MenuItem,也可以将菜单添加到菜单中,作为子菜单。最后通过setMenuBar方法,将菜单栏添加到Frame中。
弹出式菜单:JPopupMenu,必须调用show才能显示。
菜单项和菜单的使用会产生AcitonEvent事件,需要addActionListener为菜单注册监听器,以便对事件进行处理。
AddMenu.java(添加菜单实例、并完成菜单项的响应事件、弹出菜单实例)
package blog6;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
/**
* 菜单的添加、弹出式菜单的实现
* 选中菜单项时发生ActionEvent事件,通过addActionListener添加监听器
*/
@SuppressWarnings("serial")
public class AddMenu extends JFrame{
private JMenuBar menuBar;
private JMenu menuFile,menuEdit,menuHelp,subFileMenu;
private JMenuItem fileOpen,fileSave,fileClose,editCopy,editPaste,helpAbout,helpUser;
private JMenuItem subFileMenu1,subFileMenu2;
private JPopupMenu popMenu;
public AddMenu() {
super("带菜单的窗口");
//初始化各菜单项
menuBar = new JMenuBar();
menuFile = new JMenu("文件");
fileOpen = new JMenuItem("打开");
fileSave = new JMenuItem("保存");
fileClose = new JMenuItem("关闭");
subFileMenu = new JMenu("文件子菜单");
subFileMenu1 = new JMenuItem("子菜单选项1");
subFileMenu2 = new JMenuItem("子菜单选项2");
subFileMenu.add(subFileMenu1);
subFileMenu.add(subFileMenu2);
menuFile.add(fileOpen);
menuFile.add(fileSave);
menuFile.add(subFileMenu);
menuFile.add(fileClose);
menuEdit = new JMenu("编辑");
editCopy = new JMenuItem("复制");
editPaste = new JMenuItem("粘贴");
menuEdit.add(editCopy);
menuEdit.add(editPaste);
menuHelp = new JMenu("帮助");
helpAbout = new JMenuItem("关于");
helpUser = new JMenuItem("使用帮助");
menuHelp.add(helpAbout);
menuHelp.add(helpUser);
menuBar.add(menuFile);
menuBar.add(menuEdit);
menuBar.add(menuHelp);
this.setJMenuBar(menuBar);
//弹出式菜单
popMenu = new JPopupMenu();
popMenu.add(new JMenuItem("弹出菜单1"));
popMenu.add(new JMenuItem("弹出菜单2"));
popMenu.addSeparator();//增加菜单分割线
popMenu.add(new JMenuItem("弹出菜单C"));
this.setBounds(100, 100, 600, 400);
this.setVisible(true);
theEvent(); //弹出菜单本身需要在鼠标事件响应中显示,本例不对弹出菜单项做事件监听
}
//事件处理
public void theEvent(){
//窗口的关闭事件WindowEvent
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
//菜单选项事件,每一个选项都写太麻烦,写一个共用的内部类(因为本例中没个菜单的功能都一样:弹出对话框)
OnMenu onMenu = new OnMenu(); //创建一个类对象为大家共用,不用匿名类那么浪费空间了
fileOpen.addActionListener(onMenu);
fileSave.addActionListener(onMenu);
subFileMenu1.addActionListener(onMenu);
subFileMenu2.addActionListener(onMenu);
editCopy.addActionListener(onMenu);
editPaste.addActionListener(onMenu);
helpAbout.addActionListener(onMenu);
helpUser.addActionListener(onMenu);
//单独为“关闭”菜单选项写一个监视器的匿名内部类,为之注册到选项上(事件源)
fileClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
if( e.getButton()== MouseEvent.BUTTON3){//判断是右键点击
popMenu.show(e.getComponent(),e.getX(),e.getY());
//让弹出式菜单在鼠标事件发生的容器面板的当前点击位置显示
}
}
});
}
//为菜单项写的公共的监听器,每个菜单项都可以用
class OnMenu implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem obj;
obj = (JMenuItem) e.getSource(); //强转定位到事件源
String str = obj.getText();
JOptionPane.showMessageDialog(AddMenu.this,("你点击的菜单是:" + str));
}
}
public static void main(String[] args) {
new AddMenu();
}
}
8、常用的Swing组件
①JLabel,标签,每一个标签可以显示一行静态文本和图标。
②JTextField(文本框,单行)、JTextArea(文本域,多行),JTextField类只引发ActionEvent事件,当用户在文本框中按回车时引发。JTextArea因为是多行,通常放置在滚动面板JScrollPane中,该组件事件相应位DocumentEvent和UndoableEvent事件,对文本的增删改等操作是,触发DocumentEvent;当用户撤销了之前所做的增删改操作时,触发UndoableEvent事件。
此外还有一个JPasswordField密码框供特殊情况使用。
TextFieldTest.java(文本框实例)
package blog6;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
/**
* 文本框的运用:第一个框中输入正整数,回车,把1到该数的总和输出在第二个文本上
*/
@SuppressWarnings("serial")
public class TextFieldTest extends JFrame implements ActionListener{
private JLabel lb1,lb2;
private JTextField t1,t2;
public TextFieldTest() {
this.setLayout(new FlowLayout());
lb1 = new JLabel("请输入第一个正整数");
lb2 = new JLabel("1到该数的和为");
t1 = new JTextField(10);
t2 = new JTextField(10);
t2.setEditable(false); //文本框2不可编辑
this.add(lb1);
this.add(t1);
this.add(lb2);
this.add(t2);
this.setBounds(100, 100, 200, 200);
this.setVisible(true);
this.setTitle("加法器");
this.setResizable(false);
//事件监听器
t1.addActionListener(this);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
@Override //本类实现监听器接口,事件源为t1文本框,在文本框中按下回车会触发ActionEvent!!!!
public void actionPerformed(ActionEvent e) {
int n = Integer.parseInt(t1.getText());
int sum = 0;
for(int i=0;i<n;i++){
sum +=i;
}
t2.setText(String.valueOf(sum));
}
public static void main(String[] args) {
new TextFieldTest();
}
}
③JButton(按钮),JCheckBox(复选框),JRadioButton(选项按钮),三种按钮式组件。JButton引发ActionEvent事件。JCheckBox触发ActionEvent和ItemEvent(addItemListener)事件,JRadioButton事件同JCheckBox。
④JComboBox(组合框),下拉列表框,选取下拉列表项时触发ItemEvent事件,当直接输入选项并回车选择时,触发ActionEvent事件。
⑤JList列表框,与JComboBox的区别是,一次可以选择多项或一项。双击列表框选项产生MouseEvent,打击某一选项选中时触发ListSelectionEvent事件。
⑥JTable(表格),十分复杂但对大规模数据处理较方便的组件。
本章综合练习:
MyNotpad.java(记事本文件,融入:窗口编写、菜单加入、事件监听、文件操作、文件对话框)。
package blog6;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
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.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* 一个简单的记事本,作为对java GUI综合运用总结
* 遇到的难题:通过网络学习解决如下:
* 1、textArea通过JScrollPane添加到JFrame中的方法,使用new JScrollPane(textArea)构造方法
* 2、剪贴板内容判断、textArea剪贴复制操作,textComponent都有cut、copy、paste方法
*
* 遗留问题:稍微复杂一点:就是撤销操作,undo,还未学习实现
*/
@SuppressWarnings("serial")
public class MyNotepad extends JFrame{
//本记事本包含资源:菜单(文件(打开dialog,保存dialog,关闭)、帮助)、弹出式菜单(粘贴、复制、剪贴)
//一个滚动面板,用于放置文本域
private JMenuBar menuBar;
private JPopupMenu popMenu;
private JMenu menuFile,menuHelp;
private JMenuItem fileOpen,fileSave,fileClose,helpAbout,helpUser,popCopy,popCut,popPaste;
private JScrollPane pane;
private JTextArea textArea;
public MyNotepad() {
super("MyNotepad");
//菜单栏
menuBar = new JMenuBar();
menuFile = new JMenu("文件");
menuHelp = new JMenu("帮助");
fileOpen = new JMenuItem("打开");
fileSave = new JMenuItem("保存");
fileClose = new JMenuItem("关闭");
helpUser = new JMenuItem("帮助");
helpAbout = new JMenuItem("关于");
menuFile.add(fileOpen);
menuFile.add(fileSave);
menuFile.add(fileClose);
menuHelp.add(helpUser);
menuHelp.add(helpAbout);
menuBar.add(menuFile);
menuBar.add(menuHelp);
this.setJMenuBar(menuBar);
//弹出菜单
popMenu = new JPopupMenu();
popCopy = new JMenuItem("复制");
popPaste = new JMenuItem("黏贴");
popCut = new JMenuItem("剪切");
popMenu.add(popCopy);
popMenu.add(popCut);
popMenu.add(popPaste);
//滚动面板、文字域,这里注意:使用JScrollPane的时候,不要用无参的构造器
//直接将要显示的textArea对象以参数形式传进JScrollPane的构造器中
textArea = new JTextArea();
textArea.setLineWrap(true);//激活自动换行功能
textArea.setWrapStyleWord(true);//激活断行不断字功能
textArea.setTabSize(4); //设置table为4个字符长度
/*下面这种表现形式很重要,否则用无参构造器再add添加textArea组件会不显示textArea*/
pane = new JScrollPane(textArea);
this.add(pane);
this.setBounds(100,100,800,600);
this.setVisible(true);
//添加事件监听器
MyEvent();
}
public void MyEvent(){
//窗体事件
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
//菜单事件,可以集成在一个Jmenu中处理,也可以分开到每一个JMenuItem事件中,本例采用后者
//打开
fileOpen.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//以当前目录建一个文件选择对话框,参数为获取的当前目录路径
JFileChooser fileDialog = new JFileChooser(System.getProperty("user.dir"));
//显示一个打开对话框,以当前JFrame为父窗口
int select = fileDialog.showOpenDialog(MyNotepad.this);
//判断当在代开对话框中选择了确定时
if(select == JFileChooser.APPROVE_OPTION){
//根据选择的文本创建文件对象
File f = fileDialog.getSelectedFile();
//将文件内容通过IO流输入到TextArea中
try{
BufferedReader bufr = new BufferedReader(new FileReader(f));
String line = null;
textArea.setText("");//加载文件内容前,先清空当前内容,使用setText方法
while((line=bufr.readLine())!=null)
{
textArea.append(line+"\r\n");
}
bufr.close();
}catch (IOException ex){
JOptionPane.showMessageDialog(MyNotepad.this, "打开失败...");
}
}
}
});
//保存
fileSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//以当前目录建一个文件选择对话框,参数为获取的当前目录路径
JFileChooser fileDialog = new JFileChooser(System.getProperty("user.dir"));
//显示一个保存对话框,以当前JFrame为父窗口
int select = fileDialog.showSaveDialog(MyNotepad.this);
//判断当在代开对话框中选择了确定时
if(select == JFileChooser.APPROVE_OPTION){
//根据选择的文本创建文件对象
File f = fileDialog.getSelectedFile();
//将文件内容通过IO流从TextArea输出到文件中
try{
BufferedWriter bufw = new BufferedWriter(new FileWriter(f));
String text = textArea.getText();//一次性全部保存,在大型文件的时候效率捉急
bufw.write(text);
bufw.flush(); //刷新缓冲
bufw.close();
}catch (IOException ex){
JOptionPane.showMessageDialog(MyNotepad.this, "保存失败...");
}
}
}
});
fileClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
helpAbout.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(MyNotepad.this, "关于本软件\n详情登陆本人博客...");
}
});
helpUser.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(MyNotepad.this, "这不科学...\n竟然没有使用帮助...");
}
});
//为文本域添加右键弹出菜单
textArea.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e){
if(e.getButton()== MouseEvent.BUTTON3){
//若是右键,弹出菜单,e.getComponet获取事件发生的组件
if(isClipboardString()){ //当前剪贴板有无内容,决定了弹出菜单的paste项能否可用
popPaste.setEnabled(true);
}else{
popPaste.setEnabled(false);
}
popMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
//弹出菜单选项事件,文本的编辑操作:粘贴复制....
popCopy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.copy();
}
});
popCut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.cut();
}
});
popPaste.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textArea.paste();
}
});
}
/**
* 自定义方法、判断当前剪贴板中有无String内容
* 使用到getSystemClipboard方法返回一个clipboard对象,访问其getContents方法获取内容。
*/
public boolean isClipboardString() {
boolean b = false;
Clipboard clipboard = this.getToolkit().getSystemClipboard();
Transferable content = clipboard.getContents(this);
try {
if (content.getTransferData(DataFlavor.stringFlavor) instanceof String) {
b = true;
}
} catch (Exception e) {
}
return b;
}
public static void main(String[] args) {
new MyNotepad();
}
}
相关文章
- 暂无相关文章
用户点评