Java 图形界面基础

Java图形界面基础

当你开始验证自己的PC的JDK环境是否配置完成的时候有没有想过这个窗体是怎么做出来的呢?
这里写图片描述
用几句简单的Java语言就可以做出这样的窗体,不信我可以写给给位看。

import java.awt.Frame;

public class MyTest{
public static void main(String[][]args){
Frame w = new Frame();
w.setSize(300,400);
w.show;
}
}

我将这段代码写入eclipse运行看看会出现什么
这里写图片描述
这里写图片描述
确实是出现了一个窗体。大小是300*400
下面我们来分析一下代码

import java.awt.Frame

这里的awt全名(Abstract Windowing Toolkit),是Sun公司在发布JDK1.0时一个重要的组成部分,是Java提供的用来建立和设置Java的图形界面的基本工具。AWT中所有的工具类都保存在java.awt包中,此包中的所有操作类可以用来建立与平台无关的图形界面(GUI)的类。这些类又被叫做组件(Components)。 Frame这个当然是awt这个包中的类啦,通俗的将就是要借一下awt包中的Frame类。下面的代码,main是程序入口不用解释,那么main下面的代码又怎么解释呢

Frame w = new Frame();
w.setSize(300,400);
w.show;

其实啊这个w是Frame的一个对象,new Frame()的意思就是借Frame()一用我新建一个叫w的窗体,setSize很好理解,就是字面意思设置w窗体的大小,400和300分别是长和宽,最后的show()就是展示出w窗体的意思。
代码中的等号我要解释一下,这可和数学里的等号不是一个意思,编程语言里的等号是赋值的意思,比如说a=b,这句话在程序里的意思就是把b的值赋给a,所以等号左边通常是装东西的容器,这样的容器,Java里叫做变量。
我们先看一下属于程序的内存是怎么管理的,下面是一个内存的示意图
这里写图片描述
可以看到内存被划分为两个区域,一个是栈,另一个是堆,看的出来栈相对于堆来说是很小的,栈是操作系统按照薯片桶的管理方式管理的,先放进去的薯片,会在最后被取出来,而堆没有管理限制。
还是回到等号,见到等号,我们就要看等号右边,看到第一个单词是new,new就意味着咱堆里分配了一块内存,分配内存干什么?new 后面跟着Frame这个类,那么分配内存就是为了装Frame的对象w,也就是说,等于号的右边已经创建了对象,如图
这里写图片描述
那么等于号左边是干什么的,上面提到过,在Java里等于号意味着将右边的东西送到左边去,左边通常是一个变量,变量在Java里分配内存的另一个手段。既然new用于在堆里分配对象,那么对象就被放在栈里,我们已经得到了一个Frame对象,为什么还要一个变量呢?是因为我们得到的这个对象不方便操作,new的那一刻之后就没办法找到它了,如果把这个对象的地址存到一个变量里,我们以后就可以通过这个变量随时随地找到这个对象,这个变量起到了电视遥控器的作用,为了方便操作,变量也不是什么都可以装的,需要提前说明它能装什么东西,这里的声明Frame w,及时表明w是能够装Frame对象的变量,我们管这种指向对象的变量叫做引用
这里写图片描述
上面的这段代码我讲一个通俗一点的例子:
你想买一台电视机,你得到了一台电视机加上一个遥控器叫做w,遥控器w上面有很多功能键,这在Java里对象的引用提供的函数就是
w的功能键,在Java里叫做方法。
## Java绘图 ##
讲完了如何创建窗体,下一步就要说怎么在窗体里做点事儿了,就是怎么在窗体里绘画。这里有一个前提,Java语言不允许直接将图形画在窗体上,必须画在一个画布上,然后将画布放到窗体上。好消息是系统直接给你提供了画布类。那么之后我将带领大家做第一项目,那就是画一个王八,这个同样是我学Java时候的第一个项目。大家可以想一想,该怎么画呢。画布类不可能提供王八的画法,所以该怎么办呢?聪明的看官老爷应该已经想到了,是不是将系统提供的画布类new 成对象,然后在这个对象上画,可以的,如果可以想到这一点,说明对Java的理解已经越来越升入了。
但是面向对象思想意味着有另一种方式能够更好的解决这个问题。如果我有一个类叫动物,我希望得到一个人的类,你会发现动物有的一切人也有,能不能把动物拿来改造一下呢,添加上人特有的就完成对人的定义,如果这样可行,那就太棒了,因为动物类描述的内容有太多类需要了,我们因此会得到一个叫做代码重用的好处,那么这个叫做继承。人类是从动物类继承而来的,所以人类拥有动物类的一切,事实上人类也是动物,是动物类的一个特例,那么动物类咱Java的术语中被称作是父类,而人类叫做子类,有一个说法,继承自什么就是什么,人类继承自动物,所以人类就是动物。当继承的想法真的主宰了你的思路时,你就会在一切可能的情况下优先使用继承这个手段。
回到我们这个问题里,我现在有一个类,提供了一个没有内容的画布,你希望得到一个有内容的画布,怎么办?当然是通过继承产生一个有王八的新画布,Java代码是这么写的:

class MyPanel extends Panel{

}

新的类叫做MyPanel,注意:这是一个类与类之间的关系,不是对象与对象之间的关系,extends是关键字。也就是Java里的继承,用于实现继承的类MyPanel叫做子类,被继承的类Panel叫做父类。
Panel 就是系统提供的空画布,问题是在整个程序前面都需要导入这个类。

import java.awt.Panel;

还有一个小问题,随着程序越来越大,使用的类也越来越大,一个个类导入会占据很大的区域,所以Java允许用一种简洁的方式,将镇一个包中所有的类都导入。在现代的代码中,

import java.awt.Panel;
w.setSize(300,400);

可以被替换成

import java.awt.*;

代码是节约了,但这样会将很多不需要的类都导入进来,这个完全不用担心,因为类知识定义,并不存在,在JDK进行翻译的时候,没有被使用的类会被完全的丢弃。

import java.awt.*;

public class MyTest{
}

我们来看看这段新代码

class MyPanel extends Panel{

}

继承意味着,如果Panel中有5000行的代码,那么MyPanel相当于已经拥有了5000行的代码,如果Panel里有50个方法,那么MyPanel里已经有了50个方法。方法就是之前叫做函数的东西,以后就不能用函数这个叫法了。
如果加上一个方法aaa,继续假设Panel里已经有50个方法了,那么现在MyPanel里有多少个方法?没错就是51个,我们增加一个。

class MyPanel extends Panel{
public class aaa(){

}
}

继承是面向对象的三大特征之一,是非常重要的代码手段,不过Java只支持淡了继承,也就是说一个子类只能有一个直接的父类,就好像是你只有一个亲爹一样。Java里有一个非常特殊的类叫做Object,这就是我们常说的单根结构,Object是所有类的根。比如之前写的public class MyTest(){},表面看起来这个类没有继承,他等效于public MyTest extends Object{},这意味着Object中有的成员在Java中任何类都有。
可是我现在要增加的不是这个叫aaa的方法,而是一个叫paint的方法。

class MyPanel extends Panel{ 
public void paint(Graphics g){ 
} 
} 

看的出来,这个paint方法不是随随便便写出来的,如果Panel里有50个方法,那么加上paint方法,现在MyPanel里依旧是50个方法,因为Panel里也有一个paint方法,这就等于说是把父类的方法重写了一遍。这个行为在Java中叫做方法的覆盖。举例来说,父亲是动物,动物会有吃喝拉撒的方法,今天我们要继承一个人出来,但是人不能使用动物的”吃”的这个方法,所以我就在人的这个类里又写了一个”吃”的方法,那么父类的”吃”的方法去哪里了,动物的”吃”不起作用了,现在人的”吃”在起作用。
我们看paint方法的参数Graphics g,注意到的第一个字母是大写的,第一个字母大写意味着什么?说明它是一个类,这个类也包含在java.awt.*里,第一句话就给导入了。这个类是系统提供了,千万不要写错了。
我们来仔细看看这个paint方法是干什么的。用鼠标单机菜单栏里随便一个菜单,你看到了什么?一个弹出的菜单
这里写图片描述
我们注意到这个弹出的菜单成为屏幕最上面的一层,他盖住了后面的内容。在今天的计算机中,这种现象比比皆是,我们可以想象目前计算机上的第一层是这个菜单,第二层是记事本,记事本下面至少还盖着一个桌面,是不是?其实这些都是假的,计算机的屏幕只能显示一层,这么多层是假的,为了欺骗大多数人,菜单的边缘甚至还画上了阴影,让眼睛误以为后面的东西还在,其实后面的东西早就没有了,在这个菜单消失后,如果后面的东西立刻显示出来,人们才能认为后面的东西并没有消失,只是被盖住了。那么是怎么做到的呢?在Dos年代其实都是这么做的,如果你的程序准备弹出这个菜单,需要先计算好要盖住的区域是哪一个部分,在显示菜单前,程序要到显卡的显存里将马上就要被盖住的内容取出来,放到内存的一个地方保管下来,在菜单消失后,立刻将刚才保管住的内容重新放到显卡的那个区域里,因为计算机的速度很快,所以可以欺骗人的眼睛。
刚才说的都是Dos的做法,windows并不是这么做的。在Windows里,程序如果想弹出菜单,什么都不要做,就在那个地方花菜单就好了,背后的东西当然是看不见了,菜单消失就消失好了,程序还是什么都不需要做。那么背后的东西是怎么出现的呢?在windows里,计算机一直砸扫描屏幕,就像之前说的扫描键盘一样,当菜单消失的时候,windows的操作系统会立刻发现屏幕上有一个区域没人管了,于是windows就会去追查由谁来管理负责这个区域,于是windows操作系统就会给记事本发出一道命令,让记事本重新将这块区域画好。windows如何向程序下达命令?只有一个办法,调用程序中特定的方法,此前系统让一个程序运行起来,是调用main方法,现在系统让程序重画一个区域就会调用paint方法,这既是为什么要重写一个paint的原因。
不过为何windows不按照Dos的做法来做呢?貌似Dos更加合理。谁弄得谁负责。因为Windows里用户常常会运行很多程序,大多数程序会弹出一个窗口,而且往往是全屏的,按照Dos的做法,弹出一个窗口要盖住已经存在的整个屏幕,这就意味着如果屏幕的分辨率是1024*768De话,就要消耗1024*768再乘上了区分颜色的内存空间,这样或许同时打开几个程序,为了保存被挡住的内容将内存消耗完了,Dos年代同时打开几个程序的情况很少见,所以那个时代才不是问题,而且Dos的做法也有好处,虽然浪费了内存但是节约了CPU。回头看Windows的做法,虽然节约了内存,但是CPU要做很多事情,查找哪一个窗口是当前的,要调用paint方法里的语句来画图。这是一个程序员要考虑的权衡内存和CPU之间关系的问题。
有人说为什么main是主函数,因为main是程序的入口,现在看来好像不能这么说,paint也是程序的入口,只不过这两个方法的进入时机不同,main是程序最初运行的时候被操作系统调用的。而paint是需要画界面的时候被调用的,别的书上做的总结:
1.在界面第一次显示的时候paint方法被调用。
2.当窗体改变大小的时候paint被调用
3.当窗体被盖住重新显露出来的时候paint被调用
第三点好像根本就不用去记,你想一下,你是操作系统,你什么时候去调用paint方法呢,当然是想用的时候。
这样我们就清楚了。你准备一个paint方法给操作系统在需要的时候调用,你是方法的提供者,操作系统就是调用者,那么Graphics就是操作系统提供的参数,是在特定的区域画图的权利,我管他叫画笔。
那么看看画笔的遥控器g有啥子功能,专业叫法不是遥控器,叫做引用。Graphics提供了如下用于绘制图形的方法。
drawLine:绘制直线
drawString: 绘制字符串
drawRect:绘制矩形
drawRoundRect:绘制圆角矩形
drawOval:绘制椭圆
drawPolygon:绘制多边形边框
drawArc:绘制圆弧
drawPolyline:绘制折线
fillRect:填充一个矩形
fillRoundRect:填充一个圆角矩形
fillOval:填充椭圆
fillPolygon:填充一个多边形
fillArc:填充圆弧所包围的区域
drawImage:绘制位图
有兴趣的可以去多了解一些Java的API手册
下面我们来尝试用Java语言来画一条直线

   import java.awt.*;

public class Test {

    public static void main(String args[]){
        Frame w = new Frame();
        w.setSize(300, 400);
        MyPanel mp = new MyPanel();
        w.add(mp);
        w.show();
    }
}
class MyPanel extends Panel{
    public void paint(Graphics g){
        g.drawLine(30, 30, 100, 100);
    }
} 

看一下

g.drawLine(x1, y1, x2, y2);

大家一眼就能看出来这是两个点的坐标,两点确定一条直线。
MyPanel类产生一个叫mp的引用对象,将mp这个画布放到窗体w上,我们看一下运行的结果
这里写图片描述
那么椭圆怎么画,而且是一个有颜色的圆呢,大家可以先尝试一下然后再看我的代码

import java.awt.*;

public class Test {

    public static void main(String args[]){
        Frame w = new Frame();
        w.setSize(300, 400);
        MyPanel mp = new MyPanel();
        w.add(mp);
        w.show();
    }
}
class MyPanel extends Panel{
    public void paint(Graphics g){
        g.setColor(Color.BLUE);
        g.drawOval(30, 30, 50, 100);
    }
}

这里写图片描述
setColor(Color.BLUE)用于选择颜色
你可以用这些方法画出任何你想要的图形。下一次带大家画一个组合图形-乌龟
或许你已经有能力可以尝试着自己画一只乌龟了 ,大家多多练习这些代码,最好可以不用过大脑就可以敲出来。
3月22日
5:53pm
by WhiteJavaCoder

  • 18
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值