首先了解一下java中有哪些可以用来实现用户交互的
1. 窗口
Java提供的JFrame类的实例就是一个底层容器,即通常所讲的窗口
JFrame()创建一个无标题的窗口,它的构造函数有

当需要一个窗口时,可使用JFrame或其子类创建一个对象。
需要注意的是,窗口默认被系统添加到显示器屏幕上,因此不允许将一个窗口添加到另一个容器中。
举一个例子
import javax.swing.*;
import java.awt.*;
class myJFrame extends JFrame
{
myJFrame(String s)
{
super(s);
setBounds(100,100,320,240);
setResizable(true);
setVisible(true);
//setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
public class test_JFrame {
public static void main(String args[])
{
myJFrame frm1 = new myJFrame("第一个窗口");
//frm1.setBackground(Color.blue);
myJFrame frm2 = new myJFrame("第二个窗口");
//frm2.setBackground(Color.BLACK);
Container con1 = frm1.getContentPane();
con1.setBackground(Color.BLUE);
Container con2 = frm2.getContentPane();
con2.setBackground(Color.CYAN);
frm1.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//释放当前窗口
frm2.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
}
我在这里利用了JFrame写了一个自己的窗口类。
然后在主类里面创建了两个myJFrame的对象frm1与frm2
接下来比较重要的是设置这两个窗口的背景颜色
首先我们可以看到我先利用的frm1和frm2自己的setBackground()方法,结果发现是这样的:
窗口的背景颜色并没有改变,但这是为什么呢?
从这篇文章中我们可以找到答案
查阅了一下博客我们发现,原来我们设置的JFrame的背景色会被JFrame的面板给盖住,那么不如直接设置面板的颜色。通过这篇文章我们可知,JFrame的内容面板可以通过.getContentPane()方法给提取出来,所以我们可以通过新建一个Container对象con1来提取出frm1的内容面板,然后调用setBackground()方法进行设置背景颜色,比如
Container con1 = frm1.getContentPane();
con1.setBackground(Color.BLUE);
也可以通过直接调取的方法改变窗口的背景色,比如
frm1.getContentPane().setBackground(Color.BLUE);
结果发现这两种方法的实现都是可行的。
再讲下public void setDefaultCloseOperation(int operation),该方法用来设置单击窗体右上角的“关闭图标”后,程序会作出怎样的处理。其中形参operation取JFrame类中的下列int型static常量,程序根据参数operation取值做出不同的处理:
- DO_NOTHING_ON_CLOSE(什么都不做)
- HIDE_ON_CLOSE(隐藏当前窗口)
- DISPOSE_ON_CLOSE(隐藏当前窗口,并释放窗体占有的其他资源)
- EXIT_ON_CLOSE(结束窗口所在的应用程序)
其次是pubilc void setExtendedState(int state),这是设置窗口的扩展状态,其中参数state取JFrame类中的下列类常量:
- MAXIMIZED_HORIZ(水平方向最大化)
- MAXIMIZED_VERT(竖直方向最大化)
- MAXIMIZED_BOTH(水平,垂直方向都最大化)
菜单
菜单条/菜单/菜单项作是窗口常用的组件,菜单放在菜单条里,菜单项放在菜单里。
举个例子:
这是一个带有菜单的窗口
“菜单”右边的
的这个图形就是菜单条,也就是菜单放置的位置
JComponent类的子类JMenubar负责创建菜单条。
JFrame类里有一个将菜单条放置到窗口中的方法:
setJMenuBar(JMenuBar bar);
然后
和
就是“菜单”,JComponent类的子类JMenu负责创建菜单。
再接着就是“菜单项”
也就是
和
菜单项可以用JComponent类的子类JMenuItem创建。
**需要注意的是JMenu是JMenuItem的子类,也就是说“菜单”也是“菜单项”的一种
然后我们举个例子:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import static javax.swing.JFrame.*;
class ButtonEvent implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String str = e.getActionCommand();
System.out.println(str+":"+str.length());
}
}
class WindowMenu extends JFrame{
//创建菜单条
JMenuBar menubar;
//创建菜单
JMenu menu,subMenu;
//创建菜单项
JMenuItem item1,item2;
ButtonEvent listener = new ButtonEvent();
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(DISPOSE_ON_CLOSE);
}
void init(String s)
{
setTitle(s);
menubar = new JMenuBar();
menu = new JMenu("菜单");
subMenu = new JMenu("软件项目");
//为使菜单项有一个图标,可以用图标类Icon声明一个图标,然后使用其子类ImageIcon类创建一个图标
item1 = new JMenuItem("Java话题",new ImageIcon("a.gif"));
item2 = new JMenuItem("动画话题",new ImageIcon("b.gif"));
//setAccelerator()的作用:
//设置组合键,它能直接调用菜单项的操作侦听器而不必显示菜单的层次结构。
//所以用这个方法就能制作我们所要的快捷键了。
item1.addActionListener(listener);
item1.setAccelerator(KeyStroke.getKeyStroke('A'));//这里的意思就是‘A’作为打开item1的快捷键
item2.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.CTRL_DOWN_MASK));
//而item2需要CTRL+S键才能打开
menu.add(item1);
//在菜单末尾附加一个新的分隔符。
menu.addSeparator();
menu.add(item2);
menu.add(subMenu);
subMenu.add(new JMenuItem("汽车销售系统",new ImageIcon("c.gif")));
subMenu.add(new JMenuItem("农场信息系统",new ImageIcon("d.gif")));
menubar.add(menu);
setJMenuBar(menubar);
}
}
public class test_Menu {
public static void main(String args[])
{
WindowMenu win = new WindowMenu("带菜单的窗口",20,30,200,190);
}
}
在这里因为我们没给item1的点击实现”监听器注册“,所以为了达到成果,我们加入了一个ButtonEvent的类的监视器,让其呈现出快捷键的实现与鼠标单击的实现。
而快捷键
item1.setAccelerator(KeyStroke.getKeyStroke('A'));
item2.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,InputEvent.CTRL_DOWN_MASK));
则是由这两条语句实现的,具体的操作可在后续的”键盘事件中查找“。
下面我们看一下快捷键的实现与鼠标的实现:
我们发现结果是完全一致的,所以可以表明:快捷键的设置是成功的。
但是注意一点,因为快捷键的设置为’A’,所以只有大写字母A才能触发快捷键的操作。
2.事件
在学习处理事件时,必须很好地掌握事件源、监视器、处理事件的接口这三个概念。




这是基本的概念,然后对于监听器而言,需要一个对象对“事件源”进行监视,以便对发生的事件做出处理。事件源通过调用相应的方法将某个对象***注册***为自己的监听器,例如
事件源.addActionListener(监视器);
对于注册了监视器的文本框,在文本框获得输入焦点后,如果用户按回车键,Java运行环境就自动用ActionEvent类创建了一个对象,也就是发生了ActionEvent事件。也就是说,事件源注册监听器后,相应的操作就会导致相应的事件的发生,并通知监视器,监听器就会做出相应的处理。

对于一系列的操作而言,我个人的理解是:
①首先先确立“事件源”
②然后给事件源注册一个监听器,也就是
事件源.addActionListener(监视器);
③在外面实现自己的监视器,通过implements实现监听器接口,将其抽象方法具体化,最后在需要的方法内完成想要得到的操作即可。
举个ActionEvent的例子:
import javax.swing.plaf.basic.BasicOptionPaneUI;
import java.awt.*;
import java.awt.event.*;
class myButtonFrame extends Frame
{
Button btn;
myButtonFrame(String s)
{
super(s);
setSize(400,300);
btn = new Button("Click");
add(btn);
//创建事件监听器
ButtonListener bl = new ButtonListener();
ButtonListener2 bl2 = new ButtonListener2();
//创建事件监听器注册
btn.addActionListener(bl);
btn.addActionListener(bl2);
//显示窗体
setVisible(true);
}
//事件监听器1
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("click-respond_1");
}
}
//事件监听器2
private class ButtonListener2 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("click-respond_2");
System.exit(1);
}
}
}
public class test_ActionEvent {
public static void main(String args[])
{
myButtonFrame frm = new myButtonFrame("ActionEventTest");
}
}
注意这里的一个细节:
//创建事件监听器注册
btn.addActionListener(bl);
btn.addActionListener(bl2);
在这里我在一个按钮上面添加了两个监听器,也可以理解为,现在有A和B两个***独立的***壮汉在监视着C这个囚徒,一旦C这个囚徒发生了任何动作,A和B都会做出相应的动作。
所以说,A和B的动作都是独立的,也是会一起发生的(但是由于bl的操作写在之前,所以会率先发生)。
然后是关于监视器的实现
//事件监听器1
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("click-respond_1");
}
}
//事件监听器2
private class ButtonListener2 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("click-respond_2");
System.exit(1);
}
}
这是对于不同的监视器的实现,我们可以看到基本写法都是
class ButtonListener implements ActionListener {
public void actionPerformed( ) {
/* 按钮事件所进行的具体工作 */
}
}
3.绘制基本图形
Component类中有一个方法public void paint(Graphics g),程序可以在其子类中重写这个方法,当程序运行时,Java运行环境会用Graphics2D将参数g实例化,对象g就可以在重写paint方法的组件上绘制图形、图像等。
基本的绘制操作为
在一个自定义继承JPanel的类里重写paint方法:
public void paint(Graphics g)
{
Graphics2D g_2d = (Graphics2D) g;
g_2d.setColor(Color.xxx);
//实例化
基本图形 a = new 基本图形类的构造函数;
g_2d.draw(a); //是指描边
g_2d.fill(a); //是指填充
}
但由于有时无法实现重写类,也就是说重写paint()的形参Graphics g无法获取,所以可以进行以下操作
Graphics g = getGraphics()
来获取画布,具体操作如下。
public void paint()
{
Graphics g = getGraphics()
Graphics2D g_2d = (Graphics2D) g;
g_2d.setColor(Color.xxx);
//实例化
基本图形 a = new 基本图形类的构造函数;
g_2d.draw(a); //是指描边
g_2d.fill(a); //是指填充
}
然后在getGraphics()里面有一个函数
通过使用当前绘图表面的背景色进行填充来清除指定的矩形。
但是在实现绘画的时候一定一定要记住,要把画布添加到窗口中。
因为如果没有添加到窗口中,事件虽然会触发,但是在我们人为看来是没有响应的。
4.鼠标事件
再写一个关于MouseEvent的触发事件
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
//这里是事件和监听器注册
class WindowMouse extends JFrame
{
JTextField text;
JButton button;
//设置一个多行文本框
JTextArea textArea;
//设置监听器
MousePolice police;
WindowMouse(){
init();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
void init()
{
setLayout(new FlowLayout());
text = new JTextField(8);
textArea = new JTextArea(5,28);
police = new MousePolice();
police.setJTextArea(textArea);
button = new JButton("按钮");
//监听器注册
button.addMouseListener(police);
addMouseListener(police);
add(button);
add(text);
//JScrollPane()是创建一个滚动窗格
add(new JScrollPane(textArea));
}
}
//这里是监听器
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.getX()+")");
}
public void mouseEntered(MouseEvent e)
{
//.getSource()返回的是个对象
if(e.getSource() instanceof JButton)
{
area.append("\n鼠标进入按钮,位置:"+"("+e.getX()+","+e.getX()+")");
}
if(e.getSource() instanceof JTextField)
{
area.append("\n鼠标进入文本框,位置:"+"("+e.getX()+","+e.getX()+")");
}
if(e.getSource() instanceof JFrame)
{
area.append("\n鼠标进入窗口,位置:"+"("+e.getX()+","+e.getX()+")");
}
}
public void mouseExited(MouseEvent e)
{
area.append("\n鼠标退出,位置:"+"("+e.getX()+","+e.getX()+")");
}
public void mouseClicked(MouseEvent e)
{
if(e.getClickCount() >= 2)
area.append("\n鼠标连击,位置:"+"("+e.getX()+","+e.getX()+")");
}
}
public class test_MouseEvent {
public static void main(String args[])
{
WindowMouse win = new WindowMouse();
win.setTitle("处理鼠标事件");
win.setBounds(10,10,460,360);
}
}
这个事件主要为:显示鼠标在执行操作x时所在的位置。
个人认为重要的代码块为:
①
void init()
{
police.setJTextArea(textArea);
/
button.addMouseListener(police);
addMouseListener(police);
}
这里是实行了监听器注册
②
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.getX()+")");
}
public void mouseEntered(MouseEvent e)
{
//.getSource()返回的是个对象
if(e.getSource() instanceof JButton)
{
area.append("\n鼠标进入按钮,位置:"+"("+e.getX()+","+e.getX()+")");
}
if(e.getSource() instanceof JTextField)
{
area.append("\n鼠标进入文本框,位置:"+"("+e.getX()+","+e.getX()+")");
}
if(e.getSource() instanceof JFrame)
{
area.append("\n鼠标进入窗口,位置:"+"("+e.getX()+","+e.getX()+")");
}
}
public void mouseExited(MouseEvent e)
{
area.append("\n鼠标退出,位置:"+"("+e.getX()+","+e.getX()+")");
}
public void mouseClicked(MouseEvent e)
{
if(e.getClickCount() >= 2)
area.append("\n鼠标连击,位置:"+"("+e.getX()+","+e.getX()+")");
}
}
其实这一部分也可以设置为WindowMouse的内部类,稍微需要的改动则为:删去成员变量JTextArea area; 删去成员函数public void setJTextArea(JTextArea area);
然后把抽象的方法中的对象area改为textArea即可。、
注意一点,MouseEvent类中有下列几个重要的方法:
getX():获取鼠标指针在事件源坐标系中的x坐标。
getY():获取鼠标指针在事件源坐标系中的y坐标。
getButton():获取鼠标的左键或右键。鼠标左键和右键分别用.Button1和.Button2来表示。
getClickCount():获取鼠标点击次数。
getSource():获取发生鼠标事件的事件源。(可在此次的 public void mouseEntered(MouseEvent e) 方法中找到。)