GUI编程一

GUI编程

怎么学?
这是什么?
它该怎么玩?
该如何在我们平时运用

组件
* 窗口
* 弹窗
* 面板
* 文本框
* 列表框
* 按钮
* 图片
* 监听事件
* 鼠标
* 键盘事件
* 外挂一般用java写,C写直接跑硬件检测exe不让跑,java跑在jvm里,游戏一定会让jvm运行
* 破解工具

1. 简介

JAVA核心技术Gui: Swing AWT,因为界面不美观。需要jre环境大。如贪吃蛇几M,但是jre几百M
为什么要学习?
1. 可以写出自己心中的小工具
2. 工作时,可能需要维护swing界面
3. 了解MVC架构,了解监听!

2. AWT(底层实现)

2.1 AWT介绍(抽象的窗口工具)

  1. 包含了很多类和接口。GUI:图形用户界面编程
  2. 元素: 窗口, 按钮, 文本框
  3. java.awt包

2.2组件和容器

  1. Frame
import java.awt.*;
public class TestFrame {
      public static void main(Srting[] args){
            //Frame, JDK, 看源码
            Frame frame = new Frame("我的第一个Java图形界面窗口");

            //方法名直接打点看,frame new后存在内存中,需要设置可见性
            frame.setVisible(true);

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

            //color不会用直接代码打color看源码,IDEA左面显示出颜色还可以直接点击,调节色彩
            frame.setBackground(new Color(85,150,68));
            
            //弹出的初始位置
            frame.setLocation(200,200,200);

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

写多个窗口,把上面窗口封装

class MyFrame extends Frame{
      static int id =0;//可能存在多个窗口,我们需要一个计数器
      public MyFrame(int x, int y, int w, int h){
            super("Myframe"+(++id));
            setBackground(color)
            setBounds(z,y,w,h);
            setVisible(true);
      }

}
public static void main(String[] args){
      MyFrame myFrame1 = new MyFrame(100,200,200,Color.blue);
      MyFrame myFrame1 = new MyFrame(300,200,200,Color.yellow);
      MyFrame myFrame1 = new MyFrame(100,300,200,Color.red);
      MyFrame myFrame1 = new MyFrame(300,300,200,Color.MAGENTA);

}

2.Panel可内嵌,不能单独存在

Frame frame = new Frame();

Panel panel = new Panel();
//设置布局
frame.setLayout(null);

frame.setBounds(300,300,500,500);
frame.setBackground(new Color(1,2,1))

//panel嵌入容器里,写的是相对坐标
panel.setBounds(50,50,400,400);
panel.setBackground(new Color(193,15,60));

//frame.add(component)panel的祖父类就是component符合add参数
frame.add(panel);
frame.setVisible(true);

//frame.addWindowListener(new Windows(){...N多方法需要重写}),使用适配器有默认实现,只要重写覆盖你需要的实现即可
frame.addWindowListener(new WindowAdapter()){
      public void windowClosing(WindowEvent e){
            System.exit(0);//1是异常退出
      }
}

2.3 布局管理器

  • 流式布局(从左到右)flowlayout
  • 东西南北中(上下结构)
  • 表格布局 (三行两列)
    流式布局 TestFlowLayout
Frame frame = new Frame();

new button1 = new Button("button1");
new button2 = new Button("button2");
new button3 = new Button("button3");

//frame.setLayout(new FlowLayout());默认居中布局,上面add的东西居中
frame.setLayout(new FlowLayout(Flowlayout.LEFT));//设置add的components从左到右一次次排列

frame.setSize(200,200);
frame.add(button1);
frame.add(button2);
frame.add(button3);
frame.setVisible(true);

东西南北中 TestBorderLayout.(布局是可以嵌套的。可以先东西南北中,然后在每个里面嵌套流式布局)

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.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.setVisble(true);

表格布局

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.setVisible(true);

练习题

思路 Frame 1, panel4, button*10 (80%时间思考,20%代码)
东西装在容器里,此处应该用面板,这样面板里面才会再次调整布局,先上下border布局放两panel

Frame frame = new Frame();
frame.setLayout(new GridLayout(2,1));//一分为2的布局
frame.setSize(400,300);
frame.setLocation(300,400);
frame.setBackground(Color.Black)
frame.setVisible(true);

Panel p1 = new Panel(new BorderLayout());
Panel p2 = new Panel(new GridLayout(2,1))
Panel p3 = new Panel(new BorderLayout());
Panel p4 = new Panel(new GridLayout(2,2));

p1.add(newButton(East-1),BorderLaout.EAST);
p1.add(newButton(East-1),BorderLaout.WEST);
//按表格自动布局
p2.add(new Button("p2-btn-1"));
p2.add(new Button("p2-btn-2"));
p1.add(p2,BorderLayout.CENTER);

//下面
p3.add(newButton(East-2),BorderLaout.EAST);
p3.add(newButton(East-2),BorderLaout.WEST);
//按表格自动布局
for(int i =0;i<4;i++){
      p4.add(new Button("for "+i))
}
p3.add(p4,BorderLayout.CENTER);
frame.add(p1);
frame.add(p3);

2.4 事件监听ActionListener

Test ActionEvent

public class TestActionEvent{
      public static void main(String[] args){
      Frame frame = new Frame();
      Button button = new Button();

      //因为,addActionListener()需要一个ActionListner,所以我们需要构建一个ActionListner
      MyactionListner myActionListner = new MyActionListner();
      button.addActionListener(myActionListner);
      
      frame.add(buttonon, BorderLayout.CENTER);
      frame.pack();
      frame.setVisible(true);
      windowClose(frame);
      }
      private static void windowClose(Frame frame){
            frame.addWindowListener(new WindowAdapter()){
                  public void windowClosing(WindowEvent e){
                        System.exit(0);
                  }
            }
      }
}
//事件监听
class MyActionListner implements ActionListner{
      public void actionPerformed(ActionEvent e){
            System.out.println("aaa");
      }
}

例 两个按钮用一个监听器

public class TestActionTwo{
      public static void main(String[] args){
            Frame frame = new Frame("开始  停止");
            Button button1 = new Button("start");
            Button button2 = new Button("stop");
            
            //如果不显示定义,则会走默认信息stop,可以多个按钮只写一个action
            button2.setActionCommand("button2-stop")

            MyMonitor myMonitor = new MyMontior();
            button1.addActionListner(myMonitor);
            button1.addActionListner(myMonitor);

            frame.add(button1,BorderLayout.NORTH);
            frame.add(button1,BorderLayout.SOUTH);
      
            frame.pack();
            frame.setVisible(true);

      }
}
class MyMonitor implements ActionListerner{

      public void actionPerformed(ActionEvent e){
            
            System.out.println("按钮呗点击了"+e.getActionCommand);

            if(e.getActionCommand().equals("start")){

            }
      }

}

总结:
1.Frame是一个顶级窗口
2.Panel无法单独显示,不许添加到某个容器中
3. 布局管理器
1.流式
2.东西南北中
3.表格
4.大小,定位,监听

2.5输入框TextField监听

例子 输入框

public class TestText01{
      public static void main(String[] args){
            //正常java的main方法只负责启动,不写其他的代码
            new MyFrame();
      }
} 
class MyFrame extends Frame{
      public MyFrame(){
      //TextField单行输入文本框
      TextField textField = new TextField();
      add(textField);

      //监听这个文本框输入的文字
      MyActionListener2 = new MyActionListener2();
      textField.addActionListener(MyActionListener2 );
      
      //设置密码替换符,前台看不见输入的明文,只有后台可见
      textField.setEchoChar('*');      
     
      setVisible();
      pack();
      }      
}

class MyActionListener2 implements ActionListerner{
      public void actionPerformed(ActionEvent e){
            //获得一些资源,返回一个Object超类对象,可以向下强制转型为任意类
            TextField field = (TetField) e.getSource();
            //获得输入框的文本
            System.out.println(field.getText());
            //每次获得输入回车后将文本框清空,设置为""空串,而不是null
            field.setText("");
      }
}

2.6 例子:简易计算器,组合+内部类回顾学习

oop原则:组合(B的对象是A的成员),大于继承(B继承A)

注意:建议计算器前两个框在按下等于键计算等于后被清空。该题包含三个TextField,一个label,一个button。
关键要解决的是怎么把三个TextField传递给监听器内。下面有三种方法

解法一 在计算器类的构造方法里布局组件,将三个field作为构造参数传递个actionListener

//测试类
public class TestCalc{
      public static void main(Srting[]args){
            new Calculator();
      }
}
//计算器类
class Calculator extends Frame{

      public Calculator(){
      //3个文本框
      TextField num1 =  new TextField(10);//最大填的字符数
      TextField num2 =  new TextField(10);
      TextField num3 =  new TextField(20);

      //1个按钮等于号
      Button button = new Button("=");

      button.addActinListener(new MyCalculatorListener(num1,num2,num3));

      //1个标签 加号直接在frame里
      Label label = new Label("+");
      setLayout(new FlowLayout());//从左到右布局
      
      add(num1);
      add(label);
      add(button);
      add(num3);
      pack();
      setVisible(True);
      }
}
//监听器类
class MyCalculatorListener implements ActionListener{
      //怎么获取三个textField变量?直接构造器传过来就好了
      private TextField num1,num2,num3;

      public void MyCalculatorListener(TextField num1,TextField num2,TextField num3){
      this.num1 = num1;
      this.num2 = num2;
      this.num3 = num3;
      }
      public void actionPerformed(ActionEvent e){     
           //获得加数和被加数,getText得到string类型对象,通过Integer包装类转化为int
           Int n1= Integer.paserInt( num1.getText());
           Int n2 = Integer.parserInt(num2.getText());

            //将这个值+法运算后,放到第三个框
            num3.setTextField((n1+n2)+"");

            //清除前两个框
            num1.setText("");
            num2.setText("");

      }
}

解法二 利用组合改进代码,不在使用面向过程而是面向对象,全都是属性方法.
将计算器对象作为ActionListener的成员对象,由构造器传递给ActionListner
先把组件写好,然后添加监听器,最后一次性布局

//计算器类
class Calculator extends Frame{
//属性
TextField num1,num2,num3;

//方法
public void loadFrame(){
      //先写组件
      num1 =  new TextField(10);//最大填的字符数
      num2 =  new TextField(10);
      num3 =  new TextField(20);
      //1个按钮等于号
      Button button = new Button("=");
      //1个标签 加号直接在frame里
      Label label = new Label("+");
      
      //加组件的监听器
      button.addActinListener(new MyCalculatorListener(this));

      //一次性布局
      setLayout(new FlowLayout());//从左到右布局
      
      add(num1);
      add(label);
      add(button);
      add(num3);
      pack();
      setVisible(True);
}

}
//监听器类
class MyCalculatorListener implements ActionListener{
      //获取计算这个对象
      Calculator calculator = null;
      
      public void MyCalculatorListener(Calculator calculator){
      this.calculator = calculator;
      }
      public void actionPerformed(ActionEvent e){     
           //获得加数和被加数,getText得到string类型对象,通过Integer包装类转化为int
           Int n1= Integer.paserInt( calculator.num1.getText());
           Int n2 = Integer.parserInt(calculator.num2.getText());

            //将这个值+法运算后,放到第三个框
            calculator.num3.setTextField((n1+n2)+"");

            //清除前两个框
           calculator.num1.setText("");
           calculator.num2.setText("");

      }
}
//测试类
public class TestCalc{
      public static void main(Srting[]args){
            new Calculator().loadFrame();
      }
}

解法三 完全改成面向对象,将ActionListener作为计算器的内部类使用,直接可以获取外部类的属性

//计算器类
class Calculator extends Frame{
//属性
TextField num1,num2,num3;

//方法
public void loadFrame(){
      //先写组件
      num1 =  new TextField(10);//最大填的字符数
      num2 =  new TextField(10);
      num3 =  new TextField(20);
      //1个按钮等于号
      Button button = new Button("=");
      //1个标签 加号直接在frame里
      Label label = new Label("+");
      
      //加组件的监听器
      button.addActinListener(new MyCalculatorListener());

      //一次性布局
      setLayout(new FlowLayout());//从左到右布局
      
      add(num1);
      add(label);
      add(button);
      add(num3);
      pack();
      setVisible(True);
}


//监听器类
private class MyCalculatorListener implements ActionListener{
      //不需要再使用构造器传递计算器对象
      public void actionPerformed(ActionEvent e){     
           //直接使用外部类属性num
           Int n1= Integer.paserInt( num1.getText());
           Int n2 = Integer.parserInt(num2.getText());

            //将这个值+法运算后,放到第三个框
            num3.setTextField((n1+n2)+"");

            //清除前两个框
           num1.setText("");
           num2.setText("");

      }
}
}
//测试类
public class TestCalc{
      public static void main(Srting[]args){
            new Calculator().loadFrame();
      }
}

2.7 画笔

publi class TestPaint{
      public void static main(String[] args){
            new MyPaint().loadFrame();
      }

}
class MyPaint extends Frame{
      public void loadFrame(){
            setBounds(200,200,600,500);
            setVisible(true)
      }
      //画笔
      public void paint(Graphics g){
          //  super.paint(g); 父类没做初始化操作,可以注释掉我们自己写
           //画笔需要有颜色
            g.setColor(Color.red);
            //g.drawOval(100,100,100,100);
            //画实心的圆
            g.fillOval(100,100,100,100);
            g.setColor(Color.GREEN);
            g.fillRect(150 0,200,200,200)
            //养成习惯,画笔用完,将他还原到最初的颜色
      }
}

2.8 鼠标监听MouseListener(MouseAdapter)

目的:模拟画图工具,想要实现鼠标点击画点监听,多次点击画面出现多个点

public class TestMouseListener{
      public static void main(String[] args){
            new MyFrame("画图")
      }
}
class MyFrame exends Frame{
      //画笔,需要监听鼠标当前的位置,需要集合来存储这个点
      ArrayList points;
      public MyFrame(String title){
            super(title);
            setBounds(200,200,400,300)
            //存鼠标点击的点
            points = new ArrayList<>();
            setVisible(true);

            //鼠标监听器,针对这个窗口
            this.addMouseListener(new MyMouseListener());


      }
      //实际上执行画点的方法,每次都把整个集合里所有点都画出来,paint覆盖父类的方法默认的只执行一次
      public void paint(Graphics g){
            //画画,监听鼠标的事件
            //优先使用迭代器而不是for循环,思考迭代器和for循环比较优缺点???
            Iterator iterator = points.iterator();
            while (iterator.hasNext()){
                Point point = iterator.next();
                g.setColor(Color.BLUE);
                //画点就是画小的实心圆
                g.fillOval(point.x,point.y,10,10)
            }
            
      }
      //添加点集合
      public void addPaint (Point point){
            points.add(point);
      }
       
      private class MyMouseListener extends MouseAdapter{
            //鼠标 按下,弹起,按住不放
            super.mousePressed(MouseEvent e){
                  MyFrame frame = (MyFrame) e.getSource();
                  //这里我们点击的时候就会在界面上产生一个点。这个点就是鼠标的坐标
                 frame.addPaint(new Point(e.getX(),e.getY()));

                 frame.repaint();//刷新会再执行paint放法 30帧/秒人眼就识别不了
            }
            
      }

}

(监听鼠标画线,要监听鼠标按压的时间,用定时器一直刷新画点才可以,涉及多线程)

2.9 窗口监听WindowLister(WindowAdapdater)

public class TestWindow { 
      public static void main(String[] args){
      
      }
}
class windwoFrame extends Frame{
      public windowFrame(){
            setBackground(Color.blue);
            setBounds(100,100,200,200);
            setVisible(true);
            //正常不写成员内部类,而是采用匿名内部类
           // addWindowListener(new MyWindowListener());
            this.addWindowLister{
                  new WindowAdapter(){
                        public void windowClosing(WindowEvent e){
                              super.windwClosing(e);
                        }
                        //当点击别的窗口再点回来的时候,窗口就被激活了
                        public void windowActivated((WindowEvent e){
                              WindowFrame source = (WindowFrame) e.getSource();
                              source.setTitle("被激活了");
                              System.out.println(windowActivated);
                  }
            }
      }
      class MywindowListener extends WindowAdapdater{

            public void windowClosing(WindowEvent e){
                  setVisible(false);//通过按钮,隐藏当前窗口button监听,e.getResource获得frame->setVisible
                  System.exist(0);//代表程序结束,所有窗口都关闭,0正常退出
            }    

            }
      }
}

2.10 键盘监听keyListener,keyAdapter

public class TestKeyListner{
      public static void main(String[] args){

      }
 }
class KeyFrame extends Frame{
      public KeyFrame(){
            setBounds(1,2,300,400);
            setVisible(true);
      }
      this.addKeyListener{new keyAdapter{
            @Override
            public  void keyPressed(KeyEvent e){
                  super.keyPressed(e);
                  //获得当前键盘的码,直接.看静态属性常量,不需要再源码里翻找
                  int keyCode = e.getKeyCode(); 
                  if (keyCode == KeyEvent.VK_UP){
                        System.out.println("你按下了上键");
                  }     
            }
      }
}

3. SWING(画界面)见下一章

posted @ 2021-02-02 14:48  晒网达人  阅读(137)  评论(0)    收藏  举报