Java GUI
1、简介
核心技术:
Swing、AWT
缺点:
- 界面不美观
- 运行需要jre
作用:
-
自己写需要的小工具
-
工作时可能需要维护到Swing界面
-
了解MVC架构,了解监听器
2、AWT
2.1、AWT介绍
- (抽象窗口工具) 包含很多类和接口
- 元素:窗口、按钮、文本框
- 导入java.awt包
2.2、组件和容器
2.2.1、Frame
//新建窗口
Frame frame=new Frame("my first java gui window");
//需要设置可见性
frame.setVisible(true);
//设置窗口大小、颜色、初始位置、不可改变大小
frame.setSize(400,400);
frame.setBackground(Color.gray);
frame.setLocation(200,200);
frame.setResizable(false);
2.2.2、Pannel
可以看作一个空间,但不能单独存在,在Frame内部
//新建面板
Panel panel=new Panel();
//pannel设置,相对于frame
panel.setBounds(50,50,200,200);
panel.setBackground(Color.yellow);
//pannel加入frame
frame.add(panel);
//监听窗口关闭
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
//1指的是异常退出
}
});
2.3、布局管理器
- 流式布局(所有布局从左到右)
- 边框布局(相对)
- 表格布局
//流式布局
frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
frame.setVisible(true);
frame.add(button1);
frame.add(button2);
frame.add(button3);
//边框布局
frame.add(button1,BorderLayout.CENTER);
frame.add(button2,BorderLayout.EAST);
frame.add(button3,BorderLayout.NORTH);
frame.setVisible(true);
//设置为表格布局
frame.setLayout(new GridLayout(1,3));
frame.add(button1);
frame.add(button2);
frame.add(button3);
frame.setVisible(true);
frame.pack();//自动适应大小
三者嵌套:
//定义窗口
Frame frame=new Frame();
//定义四个面板,上、下、上中、下中
Panel panelup,paneldown,panelcu,panelcd;
panelup=new Panel(new BorderLayout());//边框布局
paneldown=new Panel(new BorderLayout());
panelcu=new Panel(new GridLayout(2,1));//表格布局
panelcd=new Panel(new GridLayout(2,2));
frame.setLayout(new GridLayout(2,1));
frame.setVisible(true);
frame.setBounds(400,300,300,300);
//上下两个面板添加模块
panelup.add(new Button("Buttonu-1"),BorderLayout.WEST);
panelup.add(panelcu,BorderLayout.CENTER);
panelup.add(new Button("Buttonu-2"),BorderLayout.EAST);
paneldown.add(new Button("Buttond-1"),BorderLayout.WEST);
paneldown.add(panelcd,BorderLayout.CENTER);
paneldown.add(new Button("Buttond-2"),BorderLayout.EAST);
//上中、下中两个面板添加模块
panelcu.add(new Button("Buttoncu-1"));
panelcu.add(new Button("Buttoncu-2"));
for(int i=1;i<=4;i++){
panelcd.add(new Button("Buttoncd-"+i));
}
frame.add(panelup);
frame.add(paneldown);
2.4、事件监听
基础与安卓类似,不赘述。
多个按钮使用同一个监听器以更加便利:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TestActionEvent {
public static void main(String[] args) {
//按下按钮触发事件
Frame frame=new Frame("开始-结束");
frame.setBounds(400,400,400,300);
frame.setVisible(true);
//设置开始、结束两个按钮
Button button1=new Button("start");
Button button2=new Button("end");
//定义为边框布局
frame.setLayout(new BorderLayout());
frame.add(button1,BorderLayout.NORTH);
frame.add(button2,BorderLayout.SOUTH);
//定义点击事件
MyActionMonitor monitor=new MyActionMonitor();
button1.addActionListener(monitor);
button2.addActionListener(monitor);
//监听关闭窗口
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
//重写点击监听器,多个按钮使用同一个监听器,更加方便
class MyActionMonitor implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("按钮被点击!点击了:"+e.getActionCommand());
}
}
2.5、输入框TextField
在监听器内实现获取输入框内容:
TextField field=(TextField)e.getSource();
String string=field.getText();
设置编码,如密码不可见:
textField.setEchoChar('*');
键入回车时清空文本框:
field.setText("");
2.6、简易计算器的实现
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TestCal {
public static void main(String[] args) {
Calculator calculator=new Calculator();
}
}
class Calculator extends Frame{
public Calculator(){
//定义元素
Frame frame=new Frame("加法计算器");
TextField text1=new TextField(10);
TextField text2=new TextField(10);
TextField text3=new TextField(20);
Label label=new Label("+");
Button button=new Button("=");
//流式加入窗口
frame.setLayout(new FlowLayout());
frame.add(text1);
frame.add(label);
frame.add(text2);
frame.add(button);
frame.add(text3);
frame.pack();
frame.setVisible(true);
//给按钮添加监听
MyCalculatorListener monitor=new MyCalculatorListener(text1,text2,text3);
button.addActionListener(monitor);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MyCalculatorListener implements ActionListener{
private TextField t1,t2,t3;
public MyCalculatorListener(TextField t1,TextField t2,TextField t3){
this.t1=t1;
this.t2=t2;
this.t3=t3;
}
@Override
public void actionPerformed(ActionEvent e) {
int a=Integer.parseInt(t1.getText());
int b=Integer.parseInt(t2.getText());
t3.setText(String.valueOf(a+b));
t1.setText("");
t2.setText("");
}
}
运行截图:
2.7、画笔Graphics
@Override
public void paint(Graphics g){
g.setColor(Color.red);
//g.drawOval(100,100,100,100)//画空心圆
g.fillOval(100,100,100,100)//画实心圆
g.setColor(Color.green);
g.fillRect(150,200,200,200);//画矩形
//画笔用完后需还原到最初颜色(黑色)
}
2.8、鼠标监听
鼠标点击画笔模拟:
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
public class TestPaint {
public static void main(String[] args) {
//新建窗口,MyPaint继承自Frame
new MyPaint("画图");
}
}
class MyPaint extends Frame{
//存储所有点击的点集
private ArrayList<Point> points;
//构造函数,注册关闭窗口的点击监听和画图鼠标点击监听
public MyPaint(String title){
super(title);
points=new ArrayList<>();
setBounds(400,300,600,400);
setVisible(true);
//监听鼠标点击,MyMouseMonitor继承自MouseAdapter
this.addMouseListener(new MyMouseMonitor());
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
//绘图,使用迭代器
@Override
public void paint(Graphics g){
Iterator iterator=points.iterator();
while (iterator.hasNext()){
Point point=(Point) iterator.next();
g.setColor(Color.BLACK);
g.fillOval(point.x,point.y,10,10);
}
}
//新加点
public void addPaint(Point point){
points.add(point);
}
//鼠标点击监听
private class MyMouseMonitor extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
//获取窗口
MyPaint mypaint=(MyPaint) e.getSource();
mypaint.addPaint(new Point(e.getX(),e.getY()));
//刷新,重新绘图
mypaint.repaint();
}
}
}
窗口监听、键盘监听类似。
3、Swing
AWT——底层
Swing——封装,更高级
3.1、窗口与面板
import javax.swing.*;
import java.awt.*;
public class TestJFrame {
//初始化
public void init(){
//JFrame是顶级窗口
JFrame jFrame=new JFrame("JFrame");
jFrame.setVisible(true);
jFrame.setBounds(100,100,200,200);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JLabel jLabel=new JLabel("My first JFrame demo");
//设置label居中
jLabel.setHorizontalAlignment(SwingConstants.CENTER);
jFrame.add(jLabel);
//容器实例化,获得一个容器
Container container=jFrame.getContentPane();
//无法直接设置JFrame颜色
container.setBackground(Color.YELLOW);
}
public static void main(String[] args) {
new TestJFrame().init();
}
}
3.2、弹窗
JDialog类,监听器弹出,默认有关闭方法。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestDialog extends JFrame {
public TestDialog(){
super("TestDialogDemo");
setVisible(true);
setSize(700,500);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container container=this.getContentPane();
//绝对定位,全部写死
container.setLayout(null);
//按钮
JButton jButton=new JButton("点击弹出对话框");
jButton.setBounds(30,30,200,50);
container.add(jButton);
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new MyDialogDemo();
}
});
}
public static void main(String[] args) {
new TestDialog();
}
}
class MyDialogDemo extends JDialog{
public MyDialogDemo(){
setVisible(true);
setBounds(100,100,500,500);
Container container=this.getContentPane();
container.setLayout(null);
container.add(new Label("这是一个弹窗"));
}
}
3.4、Icon与ImageIcon
Icon是一个接口,ImageIcon继承自Icon。
package TestIcon;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
public class IconDemo extends JFrame {
public IconDemo() {
JLabel label = new JLabel("icon_test");
URL url = IconDemo.class.getResource("pierce.jpg");
ImageIcon imageIcon = new ImageIcon(url);
//图标可以放在按钮、标签等元素上
label.setIcon(imageIcon);
label.setHorizontalAlignment(SwingConstants.CENTER);
Container container = getContentPane();
container.add(label);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBounds(300, 300, 400, 300);
}
public static void main(String[] args) {
new IconDemo();
}
}
3.5、JScroll
指侧边滚动条。
import javax.swing.*;
import java.awt.*;
public class TestJScroll extends JFrame {
public TestJScroll(){
Container container=this.getContentPane();
JTextArea jTextArea=new JTextArea(20,50);
jTextArea.setText("");
//container面板套jScrollPane面板,后者再套文本域
JScrollPane jScrollPane=new JScrollPane(jTextArea);
container.add(jScrollPane);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBounds(100,100,300,350);
}
public static void main(String[] args) {
new TestJScroll();
}
}
3.6、Button
- 按钮——Button
- 图片按钮——Button加入图片标签
- 单选框——RadioButton
- 复选框——CheckBox
皆与安卓类似。
3.7、列表框、下拉框、文本框
- 下拉框:JComboBox
- 列表框:JList(展示信息,动态扩容)
- 文本框:JTextField,前述
- 密码框:JPasswordField
- 文本域:JTextArea
4、应用:贪吃蛇
启动类:
package Snake;
import javax.swing.*;
public class StartGame {
//主启动类
public static void main(String[] args) {
JFrame jFrame=new JFrame();
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setBounds(100,100,1000,800);
jFrame.setResizable(false);
jFrame.add(new GamePanel());
jFrame.setVisible(true);
}
}
面板类:
package Snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
//游戏面板,所有元素均由此画出
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
int length;//长度小于54
int[] snakeX=new int[60];//蛇的X坐标
int[] snakeY=new int[60];//蛇的Y坐标
String fx;//方向
boolean isStart=false;//是否开始
Timer timer=new Timer(100,this);//100ms执行一次,监听本类
//食物的坐标
int foodx,foody;
Random random=new Random();
//游戏是否失败
boolean isFail=false;
//成绩
int score;
public GamePanel(){
init();
//获得焦点和键盘事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start();//游戏开始,定时器启动
}
//初始化
public void init(){
length=3;
snakeX[0]=350;snakeY[0]=310;
snakeX[1]=250;snakeY[1]=310;
snakeX[2]=150;snakeY[2]=310;
fx="R";
//随机食物坐标
foodx=50+100*random.nextInt(9);
foody=210+100*random.nextInt(6);
//初始化积分
score=0;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏
//绘制静态面板
this.setBackground(Color.black);
Data.header.paintIcon(this,g,50,5);
g.setColor(Color.white);
g.fillRect(50,210,900,600);
//画小蛇
switch (fx){
case "R":Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);break;
case "L":Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);break;
case "U":Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);break;
case "D":Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);break;
}
for(int i=1;i<length;i++){
Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//画食物
Data.food.paintIcon(this,g,foodx,foody);
//画积分
g.setColor(Color.BLACK);
g.setFont(new Font("微软雅黑",Font.BOLD,18));
g.drawString("长度:"+length,880,80);
g.drawString("分数:"+score,880,120);
if(!isStart){
g.setColor(Color.BLACK);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏",350,500);
}
if(isFail){
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("失败!按下空格开始游戏",350,500);
}
}
//键盘监听器
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_SPACE){
if(isFail){
isFail=false;
init();
}else{
isStart=!isStart;
repaint();
}
}
if(keyCode==KeyEvent.VK_UP){
fx="U";
}else if(keyCode==KeyEvent.VK_DOWN){
fx="D";
}else if(keyCode==KeyEvent.VK_LEFT){
fx="L";
}else if(keyCode==KeyEvent.VK_RIGHT){
fx="R";
}
}
@Override
public void keyReleased(KeyEvent e) {}
//事件监听(定时器,1s十次)
@Override
public void actionPerformed(ActionEvent e) {
if(isStart&&!isFail){
//吃食物
if(snakeX[0]==foodx&&snakeY[0]==foody){
length++;
//再次随机食物坐标
foodx=50+100*random.nextInt(9);
foody=210+100*random.nextInt(6);
score+=10;
}
//身子移动
for(int i=length-1;i>0;i--){
snakeX[i]=snakeX[i-1];
snakeY[i]=snakeY[i-1];
}
//走向
if(fx.equals("R")){
snakeX[0]=snakeX[0]+100;
//边界判断
if(snakeX[0]>900){
snakeX[0]=50;
}
}else if(fx.equals("L")){
snakeX[0]=snakeX[0]-100;
if(snakeX[0]<50){
snakeX[0]=950;
}
}else if(fx.equals("U")){
snakeY[0]=snakeY[0]-100;
if(snakeY[0]<210){
snakeY[0]=810;
}
}else if(fx.equals("D")){
snakeY[0]=snakeY[0]+100;
if(snakeY[0]>760){
snakeY[0]=210;
}
}
//失败判定(撞到自己)
for(int i=1;i<length;i++){
if(snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){
isFail=true;
}
}
repaint();
}
timer.start();
}
}
数据类:
package Snake;
import javax.swing.*;
import java.net.URL;
//数据中心
public class Data {
public static URL headerURL=Data.class.getResource("static/header.png");
public static ImageIcon header=new ImageIcon(headerURL);
public static URL bodyURL=Data.class.getResource("static/body.png");
public static ImageIcon body=new ImageIcon(bodyURL);
public static URL foodURL=Data.class.getResource("static/food.png");
public static ImageIcon food=new ImageIcon(foodURL);
public static URL upURL=Data.class.getResource("static/up.png");
public static ImageIcon up=new ImageIcon(upURL);
public static URL downURL=Data.class.getResource("static/down.png");
public static ImageIcon down=new ImageIcon(downURL);
public static URL leftURL=Data.class.getResource("static/left.png");
public static ImageIcon left=new ImageIcon(leftURL);
public static URL rightURL=Data.class.getResource("static/right.png");
public static ImageIcon right=new ImageIcon(rightURL);
}
运行效果: