栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java中的GUI学习

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java中的GUI学习

目录

1.GUI简介

2.AWT

2.1frame框架

2.2panel面板

2.3布局管理器

2.3.1流式布局

2.3.2东西南北中

2.3.3表格布局

2.4画笔

2.5监听

2.5.1事件监听

2.5.2文本框监听

2.5.3鼠标监听

2.5.4窗口监听

2.5.5键盘监听

2.6实操案例

2.6.1面板使用布局管理器进行排版

2.6.2加法计算器编程实现

3.Swing

3.1窗口

3.2弹窗

3.3标签

3.3.1普通标签

3.3.2图片标签

3.4面板

3.5按钮

3.5.1图片按钮

 3.5.2单选按钮

3.5.3多选框

3.6列表

3.6.1下拉框

3.6.2列表框

3.7文本框

3.7.1文本框

3.7.2密码框

3.7.3文本域

4.贪吃蛇项目

4.1程序编写思路

4.1.1需要创建的类与其各自的作用

4.1.2GamePanel类的编写过程

4.2源码

4.2.1Data类

4.1.2StartGame类

4.1.3GamePanel类(核心)


1.GUI简介

用处:了解MVC架构,了解监听

弊端:    1.因为界面不美观                        2.需要 jre 环境

GUI:Graphical User Interface图形用户界面编程

主要内容:Swing以及 AWT(也就是主要涉及这两个javax.swing和java.awt这两个工具包)

2.AWT

主要内容:

  • frame框架
  • panel面板
  • 布局管理器(流式布局;东西南北中;表格布局)
  • 监听(事件、文本框、鼠标、窗口、键盘)
  • 画笔

2.1frame框架

frame中主要涉及new frame()创建一个新的框架,之后调用一下几个常用的方法,后续需要调用其他纺发可以到frame类中去找structure中去寻找即可。
        setSize(400,400);
        setBackground(Color.black);
        setBackground(new Color(37, 80, 167));
        setLocation(200,200)
        setResizable(false);

package com.shu.lesson;

import java.awt.*;


public class Testframe {
    public static void main(String[] args) {
        frame frame = new frame("我的第一个gui图形界面编程窗口");

        frame.setVisible(true);//设置窗口可见

        frame.setSize(400,400);//设置窗口大小

        frame.setBackground(new Color(94, 212, 217, 255));

        frame.setLocation(200,200);//弹出窗口的初始位置

        frame.setResizable(false);//设置大小固定

    }
}

优化后的代码如下:该部分提供了创建多个框架页面的方法

并且将框架封装在了Myframe类当中、并实现多个框架的调用。

import java.awt.*;
public class Testframe2 {
    public static void main(String[] args) {
        //可能需要多个窗口
        Myframe myframe1 = new Myframe(100, 100, 200, 200, Color.blue);
        Myframe myframe2 = new Myframe(150, 150, 200, 200, Color.yellow);
        Myframe myframe3 = new Myframe(200, 200, 200, 200, Color.red);
        Myframe myframe4 = new Myframe(250, 250, 200, 200, Color.green);
    }
}
class Myframe extends frame {
    static int id = 0;      //可能存在多个窗口,需要一个计数器
    public Myframe(int x,int y,int w,int h,Color color){
        super("Myframe+"+(++id));//继承
        setBounds(x, y, w, h);//坐标
        setBackground(color);//颜色
        setVisible(true);//可见性
    }
}

2.2panel面板

panel就是将一个部分与frame大框架独立开来,相当远在frame框架上在加上一层图层。

import java.awt.*;
//panel 可以看成是一个空间,但是不能单独存在
public class TestPanel {
    public static void main(String[] args){
        frame frame = new frame();  //new 窗口
        //布局的概念
        Panel panel = new Panel();  //new 面板
        Panel panel1 = new Panel();
        //设置布局,不设置面板会置顶
        frame.setLayout(null);
        //窗口坐标和颜色
        frame.setBounds(300,300,500,500);
        frame.setBackground(new Color(140, 208, 212));
        //panel 设置坐标,相对于frame
        panel.setBounds(50,50,400,100);
        panel.setBackground(new Color(181, 186, 54));
        panel1.setBounds(50,200,400,250);
        panel1.setBackground(new Color(165, 34, 101));
        //将panel添加进frame
        frame.add(panel1);
        frame.add(panel);
        frame.setVisible(true);

    }
}

2.3布局管理器

布局管理器主要是对frame类中的setLayout()方法的调用

2.3.1流式布局

frame.setLayout(new FlowLayout(FlowLayout.LEFT))向左对齐

frame.setLayout(new FlowLayout(FlowLayout.CENTER))向中对齐

frame.setLayout(new FlowLayout(FlowLayout.RIGHT))向右对齐

import java.awt.*;
public class TestFlowLayout  {
    public static void main(String[] args) {
        frame frame = new frame();
        //组件-按钮
        Button button1 = new Button("button1");
        Button button2 = new Button("button2");
        Button button3 = new Button("button3");
        //设置流式布局的位置
        //frame.setLayout(new FlowLayout(0));	0为左,1为中...
        frame.setLayout(new FlowLayout(FlowLayout.LEFT));//两种方式
        frame.setSize(200,200);
        //把按钮添加上去
        frame.add(button1);
        frame.add(button2);
        frame.add(button3);
        frame.setVisible(true);
    }
}

2.3.2东西南北中

frame对象.add(要加入的对象,该对象的方位)

举例子:       

         frame.add(east,BorderLayout.EAST);
         frame.add(west,BorderLayout.WEST);
        frame.add(south,BorderLayout.SOUTH);
        frame.add(north,BorderLayout.NORTH);
        frame.add(center,BorderLayout.CENTER);
其中EAST;WEST;SOUTH;CENTER表示回家入市该内容的方位

import java.awt.*;
public class TestBorderLayout {
    public static void main(String[] args) {
        frame frame = new frame("TestBorderLayout");
        Button east = new Button("East");
        Button west = new Button("West");
        Button south = new Button("South");
        Button north = new Button("North");
        Button center = new Button("Center");
        frame.setSize(400,400);
        //不同布局的方位
        frame.add(east,BorderLayout.EAST);
        frame.add(west,BorderLayout.WEST);
        frame.add(south,BorderLayout.SOUTH);
        frame.add(north,BorderLayout.NORTH);
        frame.add(center,BorderLayout.CENTER);
        frame.setVisible(true);
    }
}

2.3.3表格布局

该布局方式应用方式:

frame对象.setLayout(new GirdLayout(行数,列数));

frame对象.add(要加入框架中的对象);

要加入到框架中的对象逐行把表格填满

举例说明:frame.setLayout(new GridLayout(3,2));

frame.add(new button("butn1"));

创建了一个3行2列的表格面板其中第一行第一列是标有butn1的按钮。

import java.awt.*;
public class TestGridLayout {
    public static void main(String[] args) {
        frame frame = new frame("TestGridLayout");
        Button btn1 = new Button("btn1");
        Button btn2 = new Button("btn2");
        Button btn3 = new Button("btn3");
        Button btn4 = new Button("btn4");
        Button btn5 = new Button("btn5");
        Button btn6 = new Button("btn6");
        frame.setLayout(new GridLayout(3,2));
        frame.add(btn1);
        frame.add(btn2);
        frame.add(btn3);
        frame.add(btn4);
        frame.add(btn5);
        frame.add(btn6);
        frame.pack();//Java函数,用于优化大小;
        // frame.setSize(400,400);
        frame.setVisible(true);
    }
}

2.4画笔

通过重写public void paint(Graphics g)方法来实现相应图形的绘制,

其中g就表示一个画笔对象

这个public void paint(Graphics g)方法也是不需要显示调用的,在系统之会自动调用,并执行一次。

import java.awt.*;
public class TestPaint {
    public static void main(String[] args) {
        new MyPaint().loadframe();
    }
}
class MyPaint extends frame {
    public void loadframe(){
        setBounds(200,200,600,500);
        setVisible(true);
    }
    //画笔,颜色,可以画画
   @Override
    public void paint(Graphics g) {
       // super.paint(g);有些类里面有初始化操作,就无法删除
       g.setColor(Color.red);
       //g.drawOval(100,100,100,100);   //draw空心
       g.fillOval(100,100,100,100);   //fill实心、填充的
       g.setColor(Color.GREEN);
       g.fillRect(200,200,200,200);
       //养成习惯,画笔用完,将它还原到最初的颜色,不然你再化一个图会带上之前的颜色。
    }
}

2.5监听

监听的主要流程是创建一个监听类重写public void actionPerformed(ActionEvent e)方法,之后将监听类的对象使用

某个动作的对象.addActionListener(监听类的对象)

之后监听类中actionPerformed方法中的操作就会执行。(这个方法应该是addActionListene()方法中调用了,因此可以执行)

2.5.1事件监听

该部分主要以button.addActionListener(myActionListener)为例

监听类的作用即是button被按下之后需要执行的操作。

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 TesActionEvent {
    public static void main(String[] args) {
        //按下按钮,触发一些事件
        frame frame = new frame();
        Button button = new Button();
        
        
        //因为,addActionListener()需要一个ActionListener,所以我们需要构造一个ActionListener
        //接口就写实现类,父类就继承
        MyActionListener myActionListener = new MyActionListener();
        button.addActionListener(myActionListener);
        frame.add(button,BorderLayout.CENTER);
        windowClose(frame);
        frame.pack();
        frame.setVisible(true);
    }
    //关闭窗体的事件
    private static void windowClose(frame frame){
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
}
class MyActionListener implements ActionListener{
    //事件监听
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("666");
    }
}

当不同的事件公用一个监听类的时候,就需要获取事件的信息并进行判断后进行编写执行代码

关键代码:

button1.addActionListener(myMonitor);

button2.addActionListener(myMonitor);


if (e.getActionCommand().equals("start")){//equals 等号
            System.out.println(e.getActionCommand()+"按钮被点击");
        } if (e.getActionCommand().equals("stop")){
            System.out.println(e.getActionCommand()+"按钮被点击");
        }

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestActionTwo {
    public static void main(String[] args) {
        //两个按钮,实现同一个监听
        //开始--停止
        frame frame = new frame("开始-停止");
        Button button1 = new Button("start");
        Button button2 = new Button("stop");
      // button2.setActionCommand("button2-stop");
        MyMonitor myMonitor = new MyMonitor();
        button1.addActionListener(myMonitor);
        button2.addActionListener(myMonitor);
        frame.add(button1,BorderLayout.NORTH);
        frame.add(button2,BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
    }
}
class MyMonitor implements ActionListener{
    @Override
    public void actionPerformed(ActionEvent e) {
        
        //可以多个按钮只写一个监听类
        if (e.getActionCommand().equals("start")){//equals 等号
            System.out.println(e.getActionCommand()+"按钮被点击");
        } if (e.getActionCommand().equals("stop")){
            System.out.println(e.getActionCommand()+"按钮被点击");
        }
    }
}

2.5.2文本框监听

文本框监听主要是通过监听器获取到文本信息,并在控制台上面显示。

关键代码:

MyActionListener2 myActionListener2 = new MyActionListener2();
        textField.addActionListener(myActionListener2);


TextField field = (TextField)e.getSource();
        System.out.println(field.getText());

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TestText01 {
    public static void main(String[] args) {
        new Myframe();
    }
}
class Myframe extends frame{
    public Myframe(){
        TextField textField = new TextField();//文本 textarea文本域,可以写多行
        add(textField);
        //监听这个文本框输入的文字
        MyActionListener2 myActionListener2 = new MyActionListener2();
        //按下enter 就会触发这个输入框的事件
        textField.addActionListener(myActionListener2);
        //设置替换编码
        textField.setEchoChar('*');
        setVisible(true);
        pack();
    }
}
class MyActionListener2 implements ActionListener{//监听器
    @Override
    public void actionPerformed(ActionEvent e) {
        TextField field = (TextField)e.getSource();//获得一些资源,返回的一个对象
        System.out.println(field.getText());//获得输入框的文本
        field.setText("");//设置enter 后的状态
    }
}

2.5.3鼠标监听

实现的目标:当按下鼠标的时候frame框架上显示一个圆点

鼠标监听需要编写自己的监听器并使这个监听器继承MouseAdapter类而不是实现MouseListener接口,因为接口需要将所有有关鼠标动作的监听器的方法(关于鼠标点击、鼠标松开、鼠标移动等等)全部重写,然而MouseAdapter类可以对方法进行选择

主要思路:

1.鼠标的坐标位置用一个集合存起来

2.由于重写的画笔方法只能执行一次,因此需要在此处使用一个while循环。来实多次实现points中的点的位置进行画点

过程:1.监听器监听到鼠标的动作之后获得此时鼠标的位置并储存到points集合中,之后通过Iterator类不断的在frame上画点。

关键代码:

this.addMouseListener(new MyMouseListener());


while (iterator.hasNext()){                         //检查序列中是否还有元素
            Point point = (Point) iterator.next();
            g.setColor(Color.BLUE);
            g.fillOval(point.x,point.y,10,10);
 


frame.repaint();

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;

//鼠标监听事件
public class TestMouseListener {	//(1)
    public static void main(String[] args) {
    new Myframe("画图");
    }
}
//自己的类
class Myframe extends frame{		//(2)
    //画画需要画笔,需要监听鼠标当前的位置,需要集合来存储这个点
    ArrayList points;


    public Myframe(String title) {//--------框架
        super(title);       //名字                                           
        setBounds(200, 200, 400, 300);
        //存标点击的点
        points = new ArrayList<>();
        //鼠标监听器,针对这个窗口
        this.addMouseListener(new MyMouseListener());        //-监听鼠标

        setVisible(true);
    }
    @Override				//(3)
    public void paint(Graphics g) { //画画                  //--------------画笔存储实施
        //画画,需要监听鼠标的事件
        Iterator iterator = points.iterator();              //-迭代器
        while (iterator.hasNext()){                         //检查序列中是否还有元素
            Point point = (Point) iterator.next();
            g.setColor(Color.BLUE);
            g.fillOval(point.x,point.y,10,10);
        }
    }
    //添加一个点到界面上,点集合			//(4)
    public void addPaint(Point point){
        points.add(point);                  //将(点)传到迭代器里


    }


    //适配器模式,就是别人已经写好的端口,不用全部重写内部类,直接继承更加方便。
    private class MyMouseListener extends MouseAdapter{  //(5)    //----------监听器
            //鼠标,按下,弹起,按下不放。
            @Override
            public void mousePressed(MouseEvent e) {        //-鼠标按下
               Myframe frame = (Myframe) e.getSource();     //-鼠标按下的来源
                //这里我点击的时候,就会在界面上产生一个点
                //这个点就是鼠标的点
                frame.addPaint(new Point(e.getX(),e.getY()));//--将监控的(点的坐标)传到点集合
                //每次点击鼠标都需要重写画一遍
                frame.repaint();                             //再次刷漆
            }
        }
}            

2.5.4窗口监听

窗口监听

此处一般不会用监听器类去继承WindowAdapter类,而不是去实现WindowLisener接口,用来选择对窗口不同的操作进行监听。

关键代码:

this.addWindowListener(
                new WindowAdapter() {
                    @Override
                    public void windowOpened(WindowEvent e) {
                        System.out.println("窗口打开");
                    }
                    @Override
                    public void windowClosed(WindowEvent e) {
                        System.out.println("窗口关闭中");
                    }
                    @Override
                    public void windowActivated(WindowEvent e) {
                        System.out.println("窗口激活");
                        Windowframe source = (Windowframe) e.getSource();       //获取框架信息
                        source.setTitle("被激活了");
                    }
                    @Override
                    public void windowStateChanged(WindowEvent e) {
                        Windowframe source = (Windowframe) e.getSource();
                        source.setTitle("状态改变了");
                        System.out.println("窗口状态改变");
                    }
                    @Override
                    public void windowClosing(WindowEvent e) {
                        System.out.println("窗口关闭");
                        System.exit(0);

package com.ssxxz.lesson03;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class TestWindow {
    public static void main(String[] args) {
        new Windowframe("窗口监听");
    }
}
class Windowframe extends frame{
    public Windowframe(String kk) {
        super(kk);
        setBackground(Color.cyan);
        setBounds(100,100,200,200);
        setVisible(true);
        //匿名内部类
        this.addWindowListener(
                new WindowAdapter() {
                    @Override
                    public void windowOpened(WindowEvent e) {
                        System.out.println("窗口打开");
                    }
                    @Override
                    public void windowClosed(WindowEvent e) {
                        System.out.println("窗口关闭中");
                    }
                    @Override
                    public void windowActivated(WindowEvent e) {
                        System.out.println("窗口激活");
                        Windowframe source = (Windowframe) e.getSource();       //获取框架信息
                        source.setTitle("被激活了");
                    }
                    @Override
                    public void windowStateChanged(WindowEvent e) {
                        Windowframe source = (Windowframe) e.getSource();
                        source.setTitle("状态改变了");
                        System.out.println("窗口状态改变");
                    }
                    @Override
                    public void windowClosing(WindowEvent e) {
                        System.out.println("窗口关闭");
                        System.exit(0);
                    }
                }
        );
    }
   
}

2.5.5键盘监听

这里同样是使用继承KeyAdapter()类的方法来针对键盘的默写动作进行监听。

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
//键盘
public class TestKeyListener {
    public static void main(String[] args) {
        new Keyframe();
    }
}
class Keyframe extends frame{
    public Keyframe() {
        setBounds(10,10,300,400);
        setVisible(true);
        this.addKeyListener(new KeyAdapter() {
            //键盘按下
            @Override
            public void keyPressed(KeyEvent e) {
                //获得当前键盘的码
                int keyCode = e.getKeyCode();       //不需要去记录这个数值,直接使用静态属性VK_XXX
                System.out.println(keyCode);
                if (keyCode == KeyEvent.VK_UP){     //KeyEvent.VK 按键类
                    System.out.println("你按下了上键!");
                }
                //根据按下不同操作,产生不同结果。
            }
        });
    }
}

2.6实操案例

2.6.1面板使用布局管理器进行排版

使用frame中嵌套进Panel面板,并使用东西南北中布局方式进行排版

源码及最后实现的面板情况如下:

import java.awt.*;
public class ExDemo01 {
    public static void main(String[] args) {
        frame frame = new frame();
        frame.setSize(400,300);
        frame.setLocation(300,400);
        frame.setVisible(true);
        frame.setLayout(new GridLayout(2,1));
        //4个面板
        Panel south = new Panel(new BorderLayout());
        Panel south2 = new Panel(new GridLayout(2,1));
        Panel north = new Panel(new BorderLayout());
        Panel north2 = new Panel(new GridLayout(2,2));
        //上面
        south.add(new Button("East-1"),BorderLayout.EAST);
        south.add(new Button("West-1"),BorderLayout.WEST);
        south2.add(new Button("south-1"));
        south2.add(new Button("south-2"));
        south.add(south2,BorderLayout.CENTER);
        //下面
        north.add(new Button("East-2"),BorderLayout.EAST);
        north.add(new Button("West-2"),BorderLayout.WEST);
        //中间4个
        for (int i = 1; i <= 4; i++) {
            north2.add(new Button("north-"+i));
        }
        north.add(north2);
        frame.add(south);
        frame.add(north);
    }
}
import java.awt.*;
public class ExDemo01 {
    public static void main(String[] args) {
        frame frame = new frame();
        frame.setSize(400,300);
        frame.setLocation(300,400);
        frame.setVisible(true);
        frame.setLayout(new GridLayout(2,1));
        //4个面板
        Panel south = new Panel(new BorderLayout());
        Panel south2 = new Panel(new GridLayout(2,1));
        Panel north = new Panel(new BorderLayout());
        Panel north2 = new Panel(new GridLayout(2,2));
        //上面
        south.add(new Button("East-1"),BorderLayout.EAST);
        south.add(new Button("West-1"),BorderLayout.WEST);
        south2.add(new Button("south-1"));
        south2.add(new Button("south-2"));
        south.add(south2,BorderLayout.CENTER);
        //下面
        north.add(new Button("East-2"),BorderLayout.EAST);
        north.add(new Button("West-2"),BorderLayout.WEST);
        //中间4个
        for (int i = 1; i <= 4; i++) {
            north2.add(new Button("north-"+i));
        }
        north.add(north2);
        frame.add(south);
        frame.add(north);
    }
}

2.6.2加法计算器编程实现

将监听类封装到Calculator类当中,直接可以调用Calculator类中的一些属性,能够更好的实现编程过程中的封装性以及更加便于多人进行协同编程。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TesCalc {
    public static void main(String[] args) {
        new Calculator().loadframe();
    }
}
    //计算器类
    class Calculator extends frame{
    //属性
    TextField num1,num2,num3;

   //方法
   public void loadframe(){
        //3个文本框
        num1 = new TextField(10);//字符数,框的大小
        num2 = new TextField(10);
        num3 = new TextField(20);
        //1个按钮
        Button button = new Button("=");
        //1个标签
        Label label = new Label("+");
        //按钮的监听事件
        button.addActionListener(new MyCalculatorListener());
        //布局
        setLayout(new FlowLayout());
        add(num1);
        add(label);
        add(num2);
        add(button);
        add(num3);
        pack();
        setVisible(true);
    }

    //监听器类
    // 内部类最大的好处,就是可以畅通无阻的访问外部的属性和方法
    private  class MyCalculatorListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            //1.获取加数和被加数
            int n1 = Integer.parseInt(num1.getText());
            int n2 = Integer.parseInt(num2.getText());
            num3.setText(""+(n1+n2));
            num1.setText("");
            num2.setText("");
        }
    }
}

3.Swing

Swing部分内容和awt中的内容非常的相似,awt属于底层的内容,然而Swing则是封装之后的内容。因此swing做出来的页面更美观,也有很多的花样。

区别:

awt:frame类、Panel类、Button类、

Swing:Jframe类、JPanel类、JButton类

3.1窗口
  • Jframe属于一个容器,需要将Contain容器类实例化才能够使得Jframe窗口中设置的颜色才能显示        代码:
    Container contentPane = jf.getContentPane();
    contentPane.setBackground(Color.cyan);
  • 窗口关闭已经被封装到f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);方法中
import javax.swing.*;
import java.awt.*;
public class JframeDemo {
    //init();初始化
    public void init(){
        //顶级窗口
        Jframe jf = new Jframe("这是一个Jframe窗口");
        jf.setVisible(true);
        //jf.setBackground(Color.cyan);     因为在容器中,直接颜色没效果,需要容器实例化
        jf.setBounds(100,100,200,200);
        JLabel jLabel = new JLabel("欢迎来到狂神说Java系列节目");  //标签
        jf.add(jLabel);
        //让文本标签居中,设置水平对齐
        jLabel.setHorizontalAlignment(SwingConstants.CENTER);
        //需要容器实例化,颜色才能现象
        Container contentPane = jf.getContentPane();
        contentPane.setBackground(Color.cyan);
        //关闭事件
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        //建立一个窗口
        new JframeDemo().init();
    }
}

3.2弹窗

绝对布局:相对容器自动定位

container.setLayout(null);

通过JDialog的继承类的对象来实现对弹窗的实现

关键代码:

button.addActionListener(new ActionListener() {           //监听器
    @Override
    public void actionPerformed(ActionEvent e) {
        //监听弹窗
        new MyDialogDemo();
    }

class MyDialogDemo extends JDialog{
    public MyDialogDemo() {
        this.setVisible(true);
        this.setBounds(100,100,500,500);
        Container container = this.getContentPane();
        container.setLayout(null);
        JLabel jp = new JLabel("竹间");
        jp.setVisible(true);
        jp.setBounds(100,100,500,100);
        container.add(jp);
    }
}
package com.shu.lesson02;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class DialogDemo extends Jframe {
    public DialogDemo() {
        this.setVisible(true);      //可见
        this.setSize(700, 500);          //尺寸
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);       //关闭事件
        //Jframe 放东西,容器
        Container container = this.getContentPane();
        //绝对布局,会相对容器自动定位
        container.setLayout(null);
        //按钮
        JButton button = new JButton("点击弹出一个对话框");      //创建
        button.setBounds(30, 30, 200, 50);
        //点击这个按钮的时候,弹出一个弹窗
        button.addActionListener(new ActionListener() {           //监听器
            @Override
            public void actionPerformed(ActionEvent e) {
                //监听弹窗
                new MyDialogDemo();
            }
        });
        container.add(button);      //将按钮放进容器中
    }

    public static void main(String[] args) {
        new DialogDemo();

    }
}
class MyDialogDemo extends JDialog{
    public MyDialogDemo() {
        this.setVisible(true);
        this.setBounds(100,100,500,500);
        // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);    弹窗可以被关掉,不需要额外添加事件,该部分在JDialog类中已经封装好了,不需要显示的写出来。
        Container container = this.getContentPane();
        container.setLayout(null);
        JLabel jp = new JLabel("竹间");
        jp.setVisible(true);
        jp.setBounds(100,100,500,100);
        container.add(jp);
    }
}

3.3标签

3.3.1普通标签

Icon接口中的两个需要重写的方法:


        public int getIconWidth() {
        return this.width;
    }


          public int getIconHeight() {
        return this.height;
    }


public void paintIcon(Component c, Graphics g, int x, int y) {
        g.fillOval(x,y,width,height);
    }

  • public void paintIcon方法在系统中被自动调用

        这里的g表示画笔,x,y表示该图标所在的位置

        我们在之前调用了

        JLabel label = new JLabel("icontest", iconDemo, SwingConstants.CENTER);

        设置相应位置,swing包类会自动获取x,y值并调用该方法                

import javax.swing.*;
import java.awt.*;

//图片,需要实现类,frame 继承
public class IconDemo extends Jframe implements Icon {

    private int width;
    private int height;

    public IconDemo(){}

    public IconDemo(int width,int height){
        this.width = width;
        this.height = height;
    }


    public void init(){     //图标
        IconDemo iconDemo = new IconDemo(15,15);
        //图标放在标签上,也可以放在按钮上!
        //标签,图标,位置
        JLabel label = new JLabel("icontest", iconDemo, SwingConstants.CENTER);

        Container container = getContentPane();
        container.add(label);

        this.setVisible(true);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    
    public static void main(String[] args) {
        new IconDemo().init();
    }
    @Override       //图标尺寸
    public void paintIcon(Component c, Graphics g, int x, int y) {
        g.fillOval(x,y,width,height);
    }

    @Override
    public int getIconWidth() {
        return this.width;
    }

    @Override
    public int getIconHeight() {
        return this.height;
    }
}

3.3.2图片标签

该类继承了Jframe类因此不需要重新创建Jframe类的对象直接获取container

        Container contentPane = getContentPane();

将图标添加到lable中之后再将lable添加到container当中

label.setIcon(imageIcon);


 contentPane.add(label);
 

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class ImageIconDemo extends Jframe {
    public ImageIconDemo()  {
        //获取图片的地址
        JLabel label = new JLabel("ImageIcon");
        URL url = ImageIconDemo.class.getResource("xxx.jpg");//获取当前类以下的东西

        ImageIcon imageIcon = new ImageIcon(url);//命名不要冲突
        label.setIcon(imageIcon);
        label.setHorizontalAlignment(SwingConstants.CENTER);

        Container contentPane = getContentPane();
        contentPane.add(label);

        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBounds(100,100,300,500);
    }
    public static void main(String[] args) {
        new ImageIconDemo();
    }
}

3.4面板

JPanel类必须要要放置到container容器当中

import javax.swing.*;
import java.awt.*;


public class JPanelDemo extends Jframe {
    public JPanelDemo() {
        Container container = this.getContentPane();
        //后面参数的意思,面板与面板的间距
        container.setLayout(new GridLayout(2,1,10,10));

        JPanel panel1 = new JPanel(new GridLayout(1, 3));   //GridLayout网格布局
        JPanel panel2 = new JPanel(new GridLayout(2, 1));
        JPanel panel3 = new JPanel(new GridLayout(2, 3));

        panel1.add(new JButton("1"));
        panel1.add(new JButton("1"));
        panel1.add(new JButton("1"));
        panel2.add(new JButton("2"));
        panel2.add(new JButton("2"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));

        container.add(panel1);
        container.add(panel2);
        container.add(panel3);

        this.setVisible(true);
        this.setSize(500,500);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }
    public static void main(String[] args) {
        new JPanelDemo();
    }
}
import javax.swing.*;
import java.awt.*;

public class JScrollDemo extends Jframe {
    public JScrollDemo() {
        Container container = this.getContentPane();
        //文本域
        Jtextarea textarea = new Jtextarea(20, 50);
        textarea.setText("欢迎学习狂神说Java");
        //Scroll 面板
        JScrollPane scrollPane = new JScrollPane(textarea);
        container.add(scrollPane);

        this.setBounds(100,100,300,350);
        this.setVisible(true);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JScrollDemo();
    }
}

3.5按钮

3.5.1图片按钮

图片按钮使用按钮类的

  • 按钮类添加到container中:button.setIcon(icon);
  • 方法将图片放置到按钮中:container.add(button);
import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class JButtonDemo01 extends Jframe {
    public JButtonDemo01() {
        Container container = this.getContentPane();
        //将一个图片变为图标
        URL resource = JButtonDemo01.class.getResource("123.jpg");  //图片路径
        ImageIcon icon = new ImageIcon(resource);       //转换为图标

        //把这个图标放到按钮上
        JButton button = new JButton();
        button.setIcon(icon);
        button.setToolTipText("图片按钮");      //图片按钮提示
        //add
        container.add(button);

        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }

    public static void main(String[] args) {
        new JButtonDemo01();
    }
}

 3.5.2单选按钮
  • 每个单选框需要创建一个对象:

JRadioButton radioButton1 = new JRadioButton("JRadioButton01");

  • 需要实现单选的对个单选框需要创建一个分组,并且将单个的单选框对象添加进去:

ButtonGroup group = new ButtonGroup();      //组
        group.add(radioButton1);                    
        group.add(radioButton2);
        group.add(radioButton3);

  • 创建分组周任然需要将按钮添加到container当中
            container.add(radioButton1,BorderLayout.CENTER);
            container.add(radioButton2,BorderLayout.NORTH);
            container.add(radioButton3,BorderLayout.SOUTH);
import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class JButtonDemo02 extends Jframe{
    public JButtonDemo02() {
        Container container = this.getContentPane();
        //将一个图片变为图标
        URL resource = JButtonDemo01.class.getResource("123.jpg");  //图片路径
        ImageIcon icon = new ImageIcon(resource);       //转换为图标

        //单选框
        JRadioButton radioButton1 = new JRadioButton("JRadioButton01");
        JRadioButton radioButton2 = new JRadioButton("JRadioButton02");
        JRadioButton radioButton3 = new JRadioButton("JRadioButton03");
        //由于单选框只能选择一个,可以将他们分组,一个组只能选一个。
        ButtonGroup group = new ButtonGroup();      //组
        group.add(radioButton1);                    
        group.add(radioButton2);
        group.add(radioButton3);

        container.add(radioButton1,BorderLayout.CENTER);
        container.add(radioButton2,BorderLayout.NORTH);
        container.add(radioButton3,BorderLayout.SOUTH);


        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }

    public static void main(String[] args) {
        new JButtonDemo02();
    }
}

3.5.3多选框
  • 多选框不需要创建分组,只需要单独的创建多选框对象即可:

        JCheckBox checkBox01 = new JCheckBox("checkBox01");

  • 多选框也需要添加到container当中:

        container.add(checkBox01,BorderLayout.NORTH);                    container.add(checkBox02,BorderLayout.SOUTH);

import javax.swing.*;
import java.awt.*;
import java.net.URL;

public class JButtonDemo03 extends Jframe {
    public JButtonDemo03() {
        Container container = this.getContentPane();
        //将一个图片变为图标
        URL resource = JButtonDemo01.class.getResource("123.jpg");  //图片路径
        ImageIcon icon = new ImageIcon(resource);       //转换为图标

        //多选框
        JCheckBox checkBox01 = new JCheckBox("checkBox01");
        JCheckBox checkBox02 = new JCheckBox("checkBox02");
        
        container.add(checkBox01,BorderLayout.NORTH);
        container.add(checkBox02,BorderLayout.SOUTH);

        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }
    public static void main(String[] args) {
        new JButtonDemo03();
    }
}

3.6列表

3.6.1下拉框
  • 主要是使用JComboBox类创建对象之后使用该对象的add()方法。

关键代码:

        JComboBox status = new JComboBox();
        status.addItem(null);
        status.addItem("正在上映");
        status.addItem("已下架");
        status.addItem("即将上映");


  • JComboBox类的对象也要添加到container当中:

        container.add(status);

import javax.swing.*;
import java.awt.*;

public class TsetComboboxDemo01 extends Jframe {
    public TsetComboboxDemo01() {
        Container container = this.getContentPane();
        JComboBox status = new JComboBox();
        status.addItem(null);
        status.addItem("正在上映");
        status.addItem("已下架");
        status.addItem("即将上映");

        // status.addActionListener(); 监听获取值

        container.add(status);

        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new TsetComboboxDemo01();
    }
}

3.6.2列表框

动态的创建数组并可以实现动态的将标题加入到container中

  • 使用Vector模型创建列表

Vector contents =new Vector();
JList ji=new JList(contents);
contents.add(“1”);
contents.add(“2”);
contents.add(“3”);

可以使用已有的模型

String arr[]= {“3”,“2”,“1”,“sd”,“asj”,“shxb”,“sbxj”,“agsz”,“shxn”};
JListjc=new JList<>();
DefaultListModel mo=new DefaultListModel<>();
for(String tmp:arr) {//向列表载入数据
mo.addElement(tmp);
}


使用已有的模型好处是可以再添加其他的标题的。

import javax.swing.*;
import java.awt.*;
import java.util.Vector;

public class TsetComboboxDemo02 extends Jframe {
    public TsetComboboxDemo02() {
        Container container = this.getContentPane();
        //生产列表的内容
        //String[] contents = {"1","2","3"};    静态数组

        Vector contents = new Vector();

        //列表中需要放入内容
        JList jList = new JList(contents);      //列表

        //动态数组
        contents.add("zhangsan");
        contents.add("lisi");
        contents.add("wangwu");
        
        container.add(jList);

        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) {
        new TsetComboboxDemo02();
    }
}

3.7文本框

3.7.1文本框
  • 文本框只能实现一行文字的编辑
  • 使用JTextField类创建对象

                JTextField textField1 = new JTextField("hello",50);

  • 需要将JTextField类加入到container中

        container.add(textField1,BorderLayout.NORTH);         container.add(textField2,BorderLayout.SOUTH);

import javax.swing.*;
import java.awt.*;

public class TestTextDemo01 extends Jframe  {
    public TestTextDemo01() throws HeadlessException {
        Container container = this.getContentPane();


        JTextField textField1 = new JTextField("hello",50);    //文本框+尺寸
        JTextField textField2 = new JTextField("world");

        container.add(textField1,BorderLayout.NORTH);
        container.add(textField2,BorderLayout.SOUTH);


        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new TestTextDemo01();
    }
}

3.7.2密码框
  • 密码框的特殊之处在于可以隐藏输入的值
  • 使用的JPasswordField类常见对象

        JPasswordField passwordField = new JPasswordField();

可以使用setEchoChar()方法替换隐藏时候的符号——默认*

        passwordField.setEchoChar('?');

import javax.swing.*;
import java.awt.*;

public class TestTextDemo02 extends Jframe {
    public TestTextDemo02() throws HeadlessException {
        Container container = this.getContentPane();

        JPasswordField passwordField = new JPasswordField();    //密码框***
        passwordField.setEchoChar('?');                         //密码框显示符号

        container.add(passwordField);


        this.setVisible(true);
        this.setSize(500,300);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new TestTextDemo02();
    }
}

3.7.3文本域
  • 文本域可以实现多行文字的编辑
  • 创建Jtextarea 类的对象;

        Jtextarea textarea = new Jtextarea(20, 50);

  • JScrollPane类是创建的带有华东边框的窗口

        JScrollPane scrollPane = new JScrollPane(textarea);

这里是以textarea的大小为标准窗口,当窗口小于标准窗口的时候就会出现滑动边框

import javax.swing.*;
import java.awt.*;

public class JScrollDemo extends Jframe {
    public JScrollDemo() {
        Container container = this.getContentPane();
        //文本域
        Jtextarea textarea = new Jtextarea(20, 50);
        textarea.setText("欢迎学习狂神说Java");
        //Scroll 面板
        JScrollPane scrollPane = new JScrollPane(textarea);
        container.add(scrollPane);


        this.setBounds(100,100,300,350);
        this.setVisible(true);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JScrollDemo();
    }
}

4.贪吃蛇项目

4.1程序编写思路

4.1.1需要创建的类与其各自的作用
  • 创建三个类及其作用:
    • 游戏启动类(内置主方法)
    • 游戏面板类(控制页面中元素的位置、页面的刷新、后台数据的处理等)
    • 数据类(主要负责将项目所需要的图片的素材导入相应的对象中)

4.1.2GamePanel类的编写过程
  • 需要考虑的因素        
    • 各个图标的相应位置
    • 小蛇的图形如何呈现
    • 小蛇如何实现运动(方向、越界)
    • 小蛇的的身体如何变长(食物、通关)
    • 食物和小蛇如何实现互动
    • 游戏的控制(暂停、开始、结束游戏)
  • 编写过程
    • 首先画出静态的小蛇的画面(确定每个图标的位置,标识小蛇头的方向)
    • 通过定时器小蛇动起来
    • 加入游戏控制(小蛇怎样会死;怎样换方向(使用键盘监听器);怎样暂停)
    • 画出积分位置

4.2源码

4.2.1Data类
import javax.swing.*;
import java.net.URL;
//数据中心
public class Data {

    //相对路径 tx.jpg
    //绝对路径 /  相当于当前的项目
    public static URL  biaotiURL = Data.class.getResource("statics/biaoti.png");
    public static ImageIcon biaoti = new ImageIcon(biaotiURL);

    public static URL shetousURL = Data.class.getResource("statics/sss.png");
    public static URL shetouxURL = Data.class.getResource("statics/xxx.png");
    public static URL shetouzURL = Data.class.getResource("statics/zzz.png");
    public static URL shetouyURL = Data.class.getResource("statics/yyy.png");
    public static ImageIcon up = new ImageIcon(shetousURL);
    public static ImageIcon down = new ImageIcon(shetouxURL);
    public static ImageIcon left = new ImageIcon(shetouzURL);
    public static ImageIcon right = new ImageIcon(shetouyURL);

    public static URL lvURL = Data.class.getResource("statics/lv.png");
    public static URL qiuURL = Data.class.getResource("statics/qiu.png");
    public static ImageIcon body = new ImageIcon(lvURL);
    public static ImageIcon food = new ImageIcon(qiuURL);

}

4.1.2StartGame类
public class StartGame {
    public static void main(String[] args) {
        Jframe frame = new Jframe();

        frame.add(new GamePanel() );


        //窗口大小在设定游戏时,就已经设计好的
        frame.setBounds(10,10,900,720);
        frame.setResizable(false);      //窗口大小不可变
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        frame.setVisible(true);
    }
}

4.1.3GamePanel类(核心)
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;
    int[] snakeX = new int[600];    //蛇的x坐标
    int[] snakeY = new int[500];    //蛇的x坐标
    String  fx;                     //初始化方法

    //食物的坐标
    int foodx;
    int foody;
    Random random = new Random();

    //积分
    int score;

    //游戏开始、结束状态
    boolean isStart = false;        //默认不开始
    boolean isFail = false;         //默认失败状态


    //定时器  以 ms 为单位 1000ms = 1s
    Timer timer = new Timer(100,this);  //100毫秒执行一次





    //构造器
    public GamePanel() {
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);    //获得焦点事件
        this.addKeyListener(this);//获得当前类键盘监听事件
        timer.start();  //游戏一开始定时器就启动
    }

    //初始化小蛇
    public void init(){
        length = 3;
        snakeX[0] = 100;snakeY[0] = 100;    //脑袋的坐标
        snakeX[1] = 75;snakeY[1] = 100;     //第一个身体的坐标
        snakeX[2] = 50;snakeY[2] = 100;     //第二个身体的坐标
        fx = "R";                           //初始化方法向右
        score = 0;

        //食物随机分布
        foodx = 25 + 25*random.nextInt(34); //25*34=850为整个界面大小
        foody = 75 +25*random.nextInt(24);

    }





    //绘制面板,我们游戏中所有东西,都是用这个画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);        //清屏,提高画面
        //绘制静态的面板
        this.setBackground(Color.WHITE);
       Data.biaoti.paintIcon(this,g,15,11);      //头部广告栏画上去
        g.fillRect(15,75,850,600);      //默认的游戏界面

        //画积分
        g.setColor(Color.WHITE);
        g.setFont(new Font("微软雅黑",Font.BOLD,18));
        g.drawString("长度"+length,750,30);
        g.drawString("分数"+score,750,50);

        //食物
        Data.food.paintIcon(this,g,foodx,foody);

        //把小蛇画上去
        if (fx.equals("R")){
            Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);//蛇头
        }else if (fx.equals("L"))
        {Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);   //蛇头
        }else if (fx.equals("U"))
        {Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);   //蛇头
        }else if (fx.equals("D"))
        {Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);   //蛇头
        }

        for (int i = 1; i < length ; i++) {         //for循环根据length身体的长度,对身体进行制作。
            Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);    //身体
        }
         //游戏状态

        if (isStart == false){  //字体
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,40)); //设置字体;类型-粗、斜-大小
            g.drawString("按下空格开始游戏",300,300);
        }
        if (isFail){
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑",Font.BOLD,40)); //设置字体;类型-粗、斜-大小
            g.drawString("游戏失败,按下空格重新开始",300,300);
        }



    }

    //键盘监听
    @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!="D"){
            fx = "U";
        }else if (keyCode == KeyEvent.VK_DOWN&& fx!="U") {
            fx = "D";
        }else if (keyCode == KeyEvent.VK_LEFT&& fx!="R") {
            fx = "L";
        }else if (keyCode == KeyEvent.VK_RIGHT&& fx!="L") {
            fx = "R";
        }

    }
    //事件监听——需要通过固定事件刷新,1s = 10次
    @Override
    public void actionPerformed(ActionEvent e) {

        if (isStart && isFail == false){//如果游戏是开始状态,且不是游戏失败
            //食物
            if (snakeX[0] == foodx && snakeY[0] == foody){
                //长度+1
                length ++;
                //积分+10
                score = score+10;
                //再次随机食物
                foodx = 25 + 25*random.nextInt(34);
                foody = 75 +25*random.nextInt(24);

            }

            //就让小蛇动起来,默认右移
            for (int i = length-1; i >0 ; i--) {    //后一节移到前一节的位置 snakeX[1] = snakeX[1-1=0];
                snakeX[i] = snakeX[i-1];
                snakeY[i] = snakeY[i-1];
            }
            //边界判断,走向
            if (fx.equals("R")){
                snakeX[0] = snakeX[0]+25;
                if (snakeX[0]>850){ snakeX[0] = 15;
                }
            }else if (fx.equals("L")){
                snakeX[0] = snakeX[0]-25;
                if (snakeX[0]<15){ snakeX[0] = 850;
                }}else if (fx.equals("U")){
                snakeY[0] = snakeY[0]-25;
                if (snakeY[0]<75){ snakeY[0] = 650;
                }}else if (fx.equals("D")){
                snakeY[0] = snakeY[0]+25;
                if (snakeY[0]>650){ snakeY[0] = 75;
                }}
            //如果头碰到身体,则isFail为true 失败
            for (int i = 1; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
                    isFail = true;
                }

            }



            repaint();  //重画页面
        }
        timer.start();  //定时器开启
    }


    @Override
    public void keyReleased(KeyEvent e) {

    }
    @Override
    public void keyTyped(KeyEvent e) {

    }


}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/328808.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号