@TOC
容器
默认布局管理器会导致下面图片内容显示不正常
window
public static void main(String[] args) {
//创建一个窗口
Frame frame=new Frame("这里测试window窗口");
//指定窗口的位置和大小
frame.setLocation(100,100);
frame.setSize(500,500);
//设置窗口对象可见
frame.setVisible(true);
}
Panel
panel不能单独存在需在window基础上
public static void main(String[] args) {
//创建一个window对象
Frame frame=new Frame("这里测试Panel窗口");
//创建Panel
Panel p=new Panel();
//创建一个文本和按钮,将其放入容器中
p.add(new TextField("这里是一个测试文本"));
p.add(new Button("这里是一个测试按钮"));
//把Panel放入Frame中
frame.add(p);
//指定窗口的位置和大小
frame.setLocation(100,100);
frame.setSize(500,500);
//设置窗口对象可见
frame.setVisible(true);
}
编码问题自己解决
Scrollpane(滚动条)
//创建一个window对象
Frame frame=new Frame("这里测试Scrollpane窗口");
//创建Scrollpane对象
ScrollPane s=new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
//添加内容
s.add(new TextField("这里是一个测试文本"));
s.add(new Button("这里是一个测试按钮"));
//把ScrollPane放入Frame中
frame.add(s);
//指定窗口的位置和大小
frame.setLocation(100,100);
frame.setSize(500,500);
//设置窗口对象可见
frame.setVisible(true);
布局管理器 layoutmanager
FlowLayOut(流式布局)
在FlowLayout布局管理器中,组件像水流一样向某方向流动(排列),遇到障碍(边界)就折回,重头开始排列。在默认情况下,FlowLayout布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。
构造方法 | 方法功能 |
---|---|
FlowLayout() | 使用默认的对齐方式及默认的垂直间距、水平间距创建FlowLayout布局管理器。 |
FlowLayout(int align) | 使用指定的对齐方式及默认的垂直间距、水平间距创建FlowLayout布局管理器。 |
FlowLayout(int align,int hgap,intvgap) | 使用指定的对齐方式及指定的垂直问距、水平间距创建FlowLayout布局管理器。 |
//创建一个window对象
Frame frame = new Frame("这里测试Flowlayout");
//通过setLayout方法设置容器的布局管理器
frame.setLayout(new FlowLayout(FlowLayout.LEFT,20,20));
//添加多个按钮到frame
for(int i=0;i<100;i++){
frame.add(new Button("按钮"+i));
}
//设置最佳大小
frame.pack();
frame.setVisible(true);
BorderLayout
BorderLayout将容器分为EAST、SOUTH、WEST、NORTH、CENTER五个区域,普通组件可以被放置在这5个区域的任意一个中。BorderLayout布局管理器的布局示意图如图所示。
当改变使用BorderLayaut的容器大小时,NORTH、SOUTH和CENTER区域水平调整,而EAST、WEST和CENTER区域垂直调整。使用BorderLayout有如下两个注意点:
1.当向使用BorderLayaut布局管理器的容器中添加组件时,需要指定要添加到哪个区域中。如果没有指定添加到哪个区域中,则默认添加到中间区域中;
2.如果向同一个区域中添加多个组件时,后放入的组件会覆盖先放入的组件;
构造方法 | 方法功能 |
---|---|
BorderLayout() | 使用默认的水平间距、垂直间距创建BorderLayout布局管理器。 |
BorderLayout(int hgap,int vgap) | 使用指定的水平间距、垂直间距创建 BorderLayout布局管理器。 |
//创建一个window对象
Frame frame = new Frame("这里测试Borderlayout");
//通过setLayout方法设置容器的布局管理器
frame.setLayout(new BorderLayout(30,10));
//在指定区域添加组件
frame.add(new Button("北侧按钮"),BorderLayout.NORTH);
frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);
frame.add(new Button("西侧按钮"),BorderLayout.WEST);
frame.add(new Button("东侧按钮"),BorderLayout.EAST);
frame.add(new Button("中间按钮"),BorderLayout.CENTER);
//设置最佳大小
frame.pack();
frame.setVisible(true);
如果不往某个区域中放入组件,那么该区域不会空白出来,而是会被其他区域占用
frame.add(new Button("北侧按钮"),BorderLayout.NORTH);
frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);
frame.add(new Button("中间按钮"),BorderLayout.CENTER);
frame.add(new TextField("ssssss"));
连一开始的组件都被覆盖了,将后面的组件添加到panel即可
frame.add(new Button("北侧按钮"),BorderLayout.NORTH);
frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);
Panel p=new Panel();
p.add(new Button("中间按钮"));
p.add(new TextField("ssssss"));
frame.add(p);
GridLayout
GridLayout布局管理器将容器分割成纵横线分隔的网格,每个网格所占的区域大小相同。当向使用GridLayout布局管理器的容器中添加组件时,默认从左向右、从上向下依次添加到每个网格中。与FlawLayout不同的是,放置在 GridLayout布局管理器中的各组件的大小由组件所处的区域决定(每个组件将自动占满整个区域)。
构造方法 | 方法功能 |
---|---|
GridLayout(int rows,in t cols) | 采用指定的行数、列数,以及默认的横向间距、纵向间距将容器分割成多个网格。 |
GridLayout(int rows,int cols,int | 采用指定的行数、列数,以及指定的横向间距、纵向间距将容器分割成多个网格。 |
计算器案例
//创建一个window对象
Frame frame = new Frame("计算器");
//添加一个Panel对象
Panel p = new Panel();
p.add(new TextField(30));
//将panel对象放到frame的北侧
frame.add(p,BorderLayout.NORTH);
//创建一个panel对象,并设置他的布局管理器为gridlayout
Panel pp = new Panel();
pp.setLayout(new GridLayout(3,5,4,4));
//往panel中添加内容
for (int i = 0; i < 10; i++) {
pp.add(new Button(String.valueOf(i)));
}
pp.add(new Button("+"));
pp.add(new Button("-"));
pp.add(new Button("*"));
pp.add(new Button("/"));
//把当前panel添加到frame中
frame.add(pp);
//设置最佳大小
frame.pack();
frame.setVisible(true);
GridBagLayout(了解就好)
GridBagLayout布局管理器的功能最强大,但也最复杂,与GridLayout布局管理器不同的是,在
GridBagLayout布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同,从而增加了布局的灵活性。当窗口的大小发生变化时,GridBagLayout布局管理器也可以准确地控制窗口各部分的拉伸。
由于在GridBagLayout布局中,每个组件可以占用多个网格,此时,我们往容器中添加组件的时候,就需要具体的控制每个组件占用多少个网格,java提供的GridBagConstaints类,与特定的组件绑定,可以完成具体大小和跨越性的设置。
CardLayout
CardLayout布局管理器以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片(每个卡片其实就是一个组件),每次只有最上面的那个Component 才可见。就好像一副扑克牌,它们叠在一起,每次只有最上面的一张扑克牌才可见.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window {
public static void main(String[] args) {
//创建一个window对象
Frame frame = new Frame("这里测试CardLayout");
//创建panel和布局管理器
Panel p=new Panel();
CardLayout c=new CardLayout();
p.setLayout(c);
//往panel里存储多个组件
String[] names={"第一张","第2张","第3张","第4张","第5张"};
for (int i = 0; i < names.length; i++) {
p.add(names[i],new Button(names[i]));
}
//放入中间区域
frame.add(p);
//创建pp存储按钮
Panel pp = new Panel();
//创建五个按钮组件
Button b1 = new Button("上一张");
Button b2 = new Button("下一张");
Button b3 = new Button("第一张");
Button b4 = new Button("最后一张");
Button b5 = new Button("第三张");
//创建一个事件监听器,监听按钮的点击动作
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();//获取按钮上的文字
switch (actionCommand){
case "上一张":
c.previous(p);
break;
case "下一张":
c.next(p);
break;
case "第一张":
c.first(p);
break;
case "最后一张":
c.last(p);
break;
case "第三张":
c.show(p,"第三张");
break;
}
}
};
//把事件监听器和按钮联系到一起
b1.addActionListener(actionListener);
b2.addActionListener(actionListener);
b3.addActionListener(actionListener);
b4.addActionListener(actionListener);
b5.addActionListener(actionListener);
pp.add(b1);
pp.add(b2);
pp.add(b3);
pp.add(b4);
pp.add(b5);
//把pp放到南边
frame.add(pp,BorderLayout.SOUTH);
//设置最佳大小
frame.pack();
frame.setVisible(true);
}
}
Boxlayout
为了简化开发,Swing引入了一个新的布局管理器:BoxLayout。BoxLayout 可以在垂直和水平两个方向上摆放GUI组件,BoxLayout提供了如下一个简单的构造器:
//创建一个window对象
Frame frame = new Frame("这里测试BoxLayout");
//基于Frame创建一个Boxlayout对象,并且组件垂直存放
BoxLayout boxLayout = new BoxLayout(frame,BoxLayout.Y_AXIS);
//对象给frame
frame.setLayout(boxLayout);
//添加两个组件
frame.add(new Button("1"));
frame.add(new Button("2"));
//设置最佳大小
frame.pack();
frame.setVisible(true);
在java.swing包中,提供了一个新的容器Box,该容器的默认布局管理器就是BoxLayout,大多数情况下,使用Box容器去容纳多个GUI组件,然后再把Box容器作为一个组件,添加到其他的容器中,从而形成整体窗口布局。
//创建一个window对象
Frame frame = new Frame("这里测试BoxLayout");
//创建一个水平排列组件的Box容器
Box hbox=Box.createHorizontalBox();
//往当前容器中添加两个按钮
hbox.add(new Button("1"));
hbox.add(new Button("2"));
//创建一个垂直排列组件的Box容器
Box vbox = Box.createVerticalBox();
vbox.add(new Button("3"));
vbox.add(new Button("4"));
frame.add(hbox,BorderLayout.SOUTH);
frame.add(vbox,BorderLayout.CENTER);
//设置最佳大小
frame.pack();
frame.setVisible(true);
通过之前的两个BoxLayout演示,我们会发现,被它管理的容器中的组件之间是没有间隔的,不是特别的美观,但之前学习的几种布局,组件之间都会有一些间距,那使用BoxLayout如何给组件设置间距呢?
其实很简单,我们只需要在原有的组件需要间隔的地方,添加间隔即可,而每个间隔可以是一个组件,只不过该组件没有内容,仅仅起到一种分隔的作用。
//创建一个window对象
Frame frame = new Frame("这里测试BoxLayout");
//创建一个水平排列组件的Box容器
Box hbox=Box.createHorizontalBox();
//往当前容器中添加三个按钮并分割
hbox.add(new Button("1"));
hbox.add(Box.createHorizontalGlue());
hbox.add(new Button("2"));
hbox.add(Box.createHorizontalStrut(30));
hbox.add(new Button("3"));
//创建一个垂直排列组件的Box容器
Box vbox = Box.createVerticalBox();
vbox.add(new Button("4"));
vbox.add(Box.createVerticalGlue());
vbox.add(new Button("5"));
vbox.add(Box.createVerticalStrut(30));
vbox.add(new Button("6"));
frame.add(hbox,BorderLayout.SOUTH);
frame.add(vbox,BorderLayout.CENTER);
//设置最佳大小
frame.pack();
frame.setVisible(true);
}
基本组件
案例:
代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window {
//创建一个window对象
Frame frame = new Frame("这里测试组件");
TextArea a=new TextArea(5,20);
Choice c=new Choice();
CheckboxGroup cbg=new CheckboxGroup();
Checkbox male=new Checkbox("男",cbg,true);
Checkbox female=new Checkbox("女",cbg,false);
Checkbox isMarried=new Checkbox("是否已婚",false);
TextField tx=new TextField(20);
Button ok=new Button("确认");
//true表示多选
List colorlist=new List(6,true);
public void init(){
//组装界面
//组装底部
Box bbox=Box.createHorizontalBox();
bbox.add(tx);
bbox.add(ok);
frame.add(bbox,BorderLayout.SOUTH);
//组装左侧
Box lbbox=Box.createHorizontalBox();
c.add("蓝色");
c.add("绿色");
c.add("红色");
lbbox.add(c);
lbbox.add(male);
lbbox.add(female);
lbbox.add(isMarried);
Box lbox=Box.createVerticalBox();
lbox.add(a);
lbox.add(lbbox);
//组装上边
Box nb=Box.createHorizontalBox();
nb.add(lbox);
nb.add(colorlist);
frame.add(nb);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
对话框dialog
Dialog 是 Window类的子类,是一个容器类,属于特殊组件。对话框是可以独立存在的顶级窗口,因此用法与普通窗口的用法几乎完全一样,但是使用对话框需要注意下面两点:
- ·对话框通常依赖于其他窗口,就是通常需要有一个父窗口;
- ·对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开后,该模式对话框总是位于它的父窗口之上,在模式对话框被关闭之前,父窗口无法获得焦点。
方法名称 | 方法功能 |
---|---|
Dialog(Frame owner, String title, boolean modal) | 创建一个对话框对象: owner:当前对话框的父窗口 title:当前对话框的标题 modal:当前对话框是否是模式对话框,true/false |
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window {
public static void main(String[] args) {
//创建一个window对象
Frame frame = new Frame("这里测试Dialog");
//创建对话框dialog,一个模式一个非模式
Dialog d1=new Dialog(frame,"moshi",true);
Dialog d2=new Dialog(frame,"feimoshi",false);
//通过setBounds设置对话框位置大小
d1.setBounds(20,30,200,300);
d2.setBounds(20,30,200,300);
//创建两个按钮并添加点击后行为
Button b1=new Button("打开模式对话框");
Button b2=new Button("打开非模式对话框");
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d1.setVisible(true);
}
});
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
d2.setVisible(true);
}
});
//把按钮添加到frame
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
通过add往dialog里添加内容。
Filedialog
Dialog类还有一个子类:FileDialog,它代表一个文件对话框,用于打开或者保存文件需要注意的是FileDialo:无法指定模态或者非模态,这是因为FileDialog依赖于运行平台的实现,如果运行平台的文件对话框是模态的,那么FileDialog也是模态的;否则就是非模态的。
案例:
代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window {
public static void main(String[] args) {
//创建一个window对象
Frame frame = new Frame("这里测试fileDialog");
//创建对话框
FileDialog f1=new FileDialog(frame,"选择要打开的文件",FileDialog.LOAD);
FileDialog f2=new FileDialog(frame,"选择要保存的文件",FileDialog.SAVE);
//创建两个按钮并添加点击后行为
Button b1=new Button("打开");
Button b2=new Button("保存");
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
f1.setVisible(true);
System.out.println("打开的文件名为"+f1.getFile());
System.out.println("打开的文件地址为"+f1.getDirectory());
}
});
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
f2.setVisible(true);
System.out.println("保存的文件名为"+f2.getFile());
System.out.println("保存的文件地址为"+f2.getDirectory());
}
});
//把按钮添加到frame
frame.add(b1,BorderLayout.NORTH);
frame.add(b2,BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
GUI事件处理机制
在GUI事件处理机制中涉及到4个重要的概念需要理解∶
事件源(Event Source):操作发生的场所,通常指某个组件,例如按钮、窗口等;
**事件(Event )**∶在事件源上发生的操作可以叫做事件,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取。
事件监听器(Event Listener):当在某个事件源上发生了某个事件,事件监听器就可以对这个事件进行处理。
注册监听︰把某个事件监听器(A通过某个事件(B)绑定到某个事件源©上,当在事件源C上发生了事件B之后,那么事件监听器A的代码就会自动执行。
使用步骤︰
1.创建事件源组件对象;
2.自定义类,实现XxxListener接口,重写方法;
3.创建事件监听器对象(自定义类对象)
4.调用事件源组件对象的addXxxListener方法完成注册监听
案例:
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window {
//创建一个window对象
Frame frame = new Frame("这里测试事件处理");
TextField tf=new TextField(30);
//事件源
Button ok=new Button("确定");
public void init(){
//组装视图
//监听器
MyListener myListener=new MyListener();
//注册监听
ok.addActionListener(myListener);
frame.add(tf,BorderLayout.NORTH);
frame.add(ok);
frame.pack();
frame.setVisible(true);
}
private class MyListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
tf.setText("nihao");
}
}
public static void main(String[] args) {
new Window().init();
}
}
事件
AWT把事件分为了两大类:
1.低级事件︰这类事件是基于某个特定动作的事件。比如进入、点击、拖放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。
⒉高级事件:这类事件并不会基于某个特定动作,而是根据功能含义定义的事件。
事件监听器
案例:
一:
通过ContainerListener监听Frame容器添加组件;
通过TextListener监听TextFiled内容变化;
通过ltemListener监听Choice条目选中状态变化;
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window {
public static void main(String[] args) {
//创建一个window对象
Frame frame = new Frame("这里测试窗口监听");
TextField tf=new TextField(30);
Choice c=new Choice();
c.add("呵");
c.add("aaaa");
c.add("bbbb");
//给文本域添加TextListener,监听内容变化
tf.addTextListener(new TextListener() {
@Override
public void textValueChanged(TextEvent e) {
String text = tf.getText();
System.out.println("当前文本框的内容为:"+text);
}
});
//给下拉选择框添加ItemListener,监听条目选项的变化
c.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
Object item = e.getItem();
System.out.println("当前选中的条目为:"+item);
}
});
//给frame注册ContainerListener监听器,监听容器中组件的添加
frame.addContainerListener(new ContainerListener() {
@Override
public void componentAdded(ContainerEvent e) {
Component child = e.getChild();
System.out.println("添加了"+child);
}
@Override
public void componentRemoved(ContainerEvent e) {
}
});
//添加到frame中
Box hbox=Box.createHorizontalBox();
hbox.add(c);
hbox.add(tf);
frame.add(hbox);
frame.pack();
frame.setVisible(true);
}
}
二:
给Frame设置WindowListner,监听用户点击X的动作,如果用户点击×,则关闭当前窗口
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window {
public static void main(String[] args) {
//创建一个window对象
Frame frame = new Frame("这里测试windows listener");
frame.setBounds(200,200,500,300);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
//停止当前程序
System.exit(0);
}
});
frame.setVisible(true);
}
}
菜单组件
菜单相关组件使用:
1.准备菜单项组件,这些组件可以是Menultem及其子类对象
⒉.准备菜单组件Menu或者PopupMenu(右击弹出子菜单),把第一步中准备好的菜单项组件添加进来;
3.准备菜单条组件MenuBar,把第二步中准备好的菜单组件Menu添加进来;
4.把第三步中准备好的菜单条组件添加到窗口对象中显示。
小技巧:
1.如果要在某个菜单的菜单项之间添加分割线,那么只需要调用Menu的add ( new Menultem("-"))即可。⒉.如果要给某个菜单项关联快捷键功能,那么只需要在创建菜单项对象时设置即可,例如给菜单项关联ctrl+shift+Q快捷键,只需要: new Menultem(“菜单项名字” ,new MenuShortcut(KeyEvent.MVK_Q,true);
案例:
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window {
//创建一个window对象
Frame frame = new Frame("这里测试菜单相关组件");
//创建菜单条
MenuBar menuBar=new MenuBar();
//创建菜单组件
Menu filemenu=new Menu("文件");
Menu editmenu=new Menu("编辑");
Menu formatmenu=new Menu("格式");
//菜单项组件
MenuItem auto=new MenuItem("自动换行");
MenuItem copy=new MenuItem("复制");
MenuItem paste=new MenuItem("粘贴");
MenuItem comment=new MenuItem("注释 Crtl+Shift+Q",new MenuShortcut(KeyEvent.VK_Q,true));
MenuItem cancelcomment=new MenuItem("取消注释");
TextArea ta=new TextArea(6,10);
public void init(){
//组装试图
comment.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ta.append("注释");
}
});
formatmenu.add(comment);
formatmenu.add(cancelcomment);
editmenu.add(copy);
editmenu.add(paste);
editmenu.add(auto);
editmenu.add(new MenuItem("-"));
editmenu.add(formatmenu);
menuBar.add(filemenu);
menuBar.add(editmenu);
frame.setMenuBar(menuBar);
frame.add(ta);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
案例:
实现思路:
1.创建PopubMenu菜单组件;
⒉.创建多个Menultem菜单项,并添加到PopupMenu中;
3.将PopupMenu添加到目标组件中;
4.为需要右击出现PopubMenu菜单的组件,注册鼠标监听事件,当监听到用户释放右键时,弹出菜单。
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window {
//创建一个window对象
Frame frame = new Frame("这里测试菜单相关组件");
Panel p=new Panel();
PopupMenu popupMenu=new PopupMenu();
//菜单项组件
MenuItem auto=new MenuItem("自动换行");
MenuItem copy=new MenuItem("复制");
MenuItem paste=new MenuItem("粘贴");
TextArea ta=new TextArea(6,10);
public void init(){
//组装试图
popupMenu.add(copy);
popupMenu.add(paste);
popupMenu.add(auto);
p.add(popupMenu);
p.setPreferredSize(new Dimension(300,400));
p.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()){
popupMenu.show(p,e.getX(),e.getY());
}
}
});
frame.add(ta);
frame.add(p,BorderLayout.SOUTH);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
画图
画图的步骤:
1.自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;
2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔的颜色、字体等属性;
3.调用Graphics画笔的drawXxx()方法开始画图。
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window {
private final String RECT_SHAPE="rect";
private final String OVAL_SHAPE="oval";
private Frame frame=new Frame("这里测试绘图");
Button b1= new Button("绘制矩形");
Button b2= new Button("绘制椭圆");
//定义一个变量来确定当前绘制矩形还是椭圆
private String shape="";
//自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
//绘制不同图形
if(shape.equals(RECT_SHAPE)){
//绘制矩形
g.setColor(Color.BLACK);
g.drawRect(100,100,200,150);
}else if(shape.equals(OVAL_SHAPE)){
//绘制椭圆
g.setColor(Color.red);
g.drawOval(100,100,200,150);
}
}
}
//创建自定义绘图对象
MyCanvas drawArea=new MyCanvas();
public void init(){
//组装视图
b1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
shape=RECT_SHAPE;
drawArea.repaint();
}
});
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
shape=OVAL_SHAPE;
drawArea.repaint();
}
});
Panel p=new Panel();
p.add(b1);
p.add(b2);
frame.add(p,BorderLayout.SOUTH);
drawArea.setPreferredSize(new Dimension(500,500));
frame.add(drawArea);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
弹球小游戏
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.sql.Time;
public class Window {
//创建窗口对象
private Frame frame=new Frame("这里是弹球小游戏");
//桌面宽度和高度
private final int TABLE_WIDTH=300;
private final int TABLE_HEIGHT=400;
//球拍宽度和高度
private final int RACKET_WIDTH=60;
private final int RACKRT_HEIGHT=20;
//小球的大小
private final int BALL_SIZE=16;
//定义变量记录小球坐标
private int ballX=120;
private int ballY=20;
//定义变量记录小球移动速度
private int speedX=10;
private int speedY=5;
//定义变量记录球拍坐标
private int racketX=120;
private int racketY=340;
//定义变量判断是结束
private boolean isOver=false;
//声明一个定时器
private Timer timer;
//自定义一个类,继承canvas,充当画布
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
// 这里绘制内容
if(isOver){
//游戏结束
g.setColor(Color.BLUE);
g.setFont(new Font("Times",Font.BOLD,30));
g.drawString("游戏结束",100,200);
}
else{
//游戏中
//绘制小球
g.setColor(Color.red);
g.fillOval(ballX,ballY,BALL_SIZE,BALL_SIZE);
//绘制球拍
g.setColor(Color.red);
g.fillRect(racketX,racketY,RACKET_WIDTH,RACKRT_HEIGHT);
}
}
}
MyCanvas drawArea=new MyCanvas();
public void init() {
//组装视图
//完成球拍坐标的变化
KeyListener listener = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取当前按键
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
if (racketX > 0) {
racketX -= 10;
}
}
if (keyCode == KeyEvent.VK_RIGHT) {
if (racketX < TABLE_WIDTH - RACKET_WIDTH) {
racketX += 10;
}
}
}
};
frame.addKeyListener(listener);
drawArea.addKeyListener(listener);
//小球坐标的控制
ActionListener task=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//更新小球的坐标
if(ballX<=0 || ballX>=TABLE_WIDTH-RACKET_WIDTH){
speedX=-speedX;
}
if (ballY<=0||(ballY>=racketY-BALL_SIZE&& ballX>=(racketX-BALL_SIZE/2)&&(ballX<=racketX+RACKET_WIDTH-BALL_SIZE/2))){
speedY=-speedY;
}
if(ballY>racketY+RACKRT_HEIGHT){
timer.stop();
isOver=true;
drawArea.repaint();
}
ballX+=speedX;
ballY+=speedY;
drawArea.repaint();
}
};
timer = new Timer(100,task);
timer.start();
drawArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
frame.add(drawArea);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
位图
如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调。AMT也允许在组件上绘制位图,
Graphics提供了drawlmage(Image image)方法用于绘制位图,该方法需要一个Image参数——代表位图,通过该方法就可以绘制出指定的位图。
位图使用步骤:
1.创建lmage的子类对象Bufferedlmage(int width,int height,int lmageType),创建时需要指定位图的宽高及类型属性;此时相当于在内存中生成了一张图片;
⒉调用Bufferedlmage对象的getGraphics()方法获取画笔,此时就可以往内存中的这张图片上绘图了,绘图的方法和之前学习的一模一样;
3.调用组件paint方法中提供的Graphics对象的drawlmage()方法,一次性的内存中的图片Bufferedlmage绘制到特定的组件上。
使用位图绘制组件的好处:
使用位图来绘制组件,相当于实现了图的缓冲区,此时绘图时没有直接把图形绘制到组件上,而是先绘制到内存中的Bufferedlmage上,等全部绘制完毕,再一次性的图像显示到组件上即可,这样用户的体验会好一些。
案例:
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.sql.Time;
public class Window {
//创建窗口对象
private Frame frame=new Frame("简单手绘程序");
//定义画图区的宽高
private final int AREA_WIDTH=500;
private final int AREA_HEIGHT=400;
//定义变量,记录鼠标拖动过程中,上一次所处的坐标
private int preY=-1;
private int preX=-1;
//定义一个右键菜单,用于设置画笔的颜色
private PopupMenu colorMenu=new PopupMenu();
private MenuItem redItem=new MenuItem("红色");
private MenuItem blueItem=new MenuItem("蓝色");
private MenuItem greenItem=new MenuItem("绿色");
//定义一个变量,记录当前画笔的颜色
private Color forceColor=Color.black;
//创建一个BufferedImage位图对象
BufferedImage image=new BufferedImage(AREA_WIDTH,AREA_HEIGHT,BufferedImage.TYPE_INT_RGB);
//通过位图,获取关联的Graphics对象
Graphics g=image.getGraphics();
//自定义一个类,继承Canvas
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
g.drawImage(image,0,0,null);
}
}
MyCanvas myCanvas=new MyCanvas();
public void init() {
ActionListener listener=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
switch (actionCommand){
case "红色":
forceColor=Color.red;
break;
case "绿色":
forceColor=Color.green;
break;
case "蓝色":
forceColor=Color.blue;
break;
}
}
};
redItem.addActionListener(listener);
greenItem.addActionListener(listener);
blueItem.addActionListener(listener);
colorMenu.add(redItem);
colorMenu.add(greenItem);
colorMenu.add(blueItem);
myCanvas.add(colorMenu);
myCanvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
boolean popupTrigger = e.isPopupTrigger();
if (popupTrigger){
colorMenu.show(myCanvas,e.getX(),e.getY());
}
preY=-1;
preX=-1;
}
});
g.setColor(Color.white);
g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT);
myCanvas.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if(preX>0&&preY>0) {
g.setColor(forceColor);
g.drawLine(preX,preY,e.getX(),e.getY());
}
preY=e.getY();
preX=e.getX();
myCanvas.repaint();
}
});
myCanvas.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT));
frame.add(myCanvas);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Window().init();
}
}
ImageIO的使用
案例:
编写图片查看程序支持另存操作
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.Time;
public class Window {
//创建窗口对象
private Frame frame=new Frame("图片查看器");
MenuBar menuBar=new MenuBar();
Menu menu=new Menu("文件");
MenuItem open=new MenuItem("打开");
MenuItem save=new MenuItem("另存为");
BufferedImage Image;
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
g.drawImage(Image,0,0,null);
}
}
MyCanvas drawArea=new MyCanvas();
public void init() throws Exception{
open.addActionListener(e -> {
FileDialog fileDialog=new FileDialog(frame,"打开文件",FileDialog.LOAD);
fileDialog.setVisible(true);
String file = fileDialog.getFile();
String directory = fileDialog.getDirectory();
try {
Image = ImageIO.read(new File(directory, file));
drawArea.repaint();
} catch (IOException ioException) {
ioException.printStackTrace();
}
});
save.addActionListener(e -> {
FileDialog fileDialog=new FileDialog(frame,"保存文件",FileDialog.SAVE);
fileDialog.validate();
String file = fileDialog.getFile();
String directory = fileDialog.getDirectory();
try {
ImageIO.write(Image,"JPEG",new File(directory,file));
} catch (IOException ioException) {
ioException.printStackTrace();
}
});
menu.add(open);
menu.add(save);
menuBar.add(menu);
frame.setMenuBar(menuBar);
frame.add(drawArea);
frame.setBounds(200,200,700,800);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) throws Exception {
new Window().init();
}
}