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介绍(抽象的窗口工具)
- 包含了很多类和接口。GUI:图形用户界面编程
- 元素: 窗口, 按钮, 文本框
- java.awt包
![]()
2.2组件和容器
- 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("你按下了上键");
}
}
}
}


浙公网安备 33010602011771号