黑马程序员_java GUI编程

GUI:Graphical User Interface.(图形用户界面)

GUI组件分为两大类:基本组件和容器。分别是java.awt.Component和java.awt.Container的直接或间接子类。
容器也算是组件,只是特殊的组件。所以java.awt.Container也是java.awt.Component的子类。

程序的GUI部分由AWT线程管理。

Frame对象可以调用方法dispose()释放由此 Window、其子组件及其拥有的所有子组件所使用的所有本机屏幕资源。
即这些 Component 的资源将被破坏,它们使用的所有内存都将返回到操作系统,并将它们标记为不可显示。
通过随后调用 pack() 或 setVisible(true) 重新构造本机资源,可以再次显示 Window 及其子组件。
重新创建的 Window 及其子组件的状态与释放 Window 时这些对象的状态一致(不考虑这些操作之间的其他更改)。 
注:当 Java 虚拟机 (VM) 中最后的可显示窗口被释放后,虚拟机可能会终止。

一般关闭一个窗口的顺序是:setVisible(false)---隐藏窗口; dispose()---释放窗口资源; System.exit(0)---退出程序;

WindowEvent对象可以调用方法getWindow()来返回一个Window对象。可以调用getSource()来返回一个Object对象,
可以调用getComponent()来返回一个Component对象,这样可以通过强制类型转换((Window)we.getSource(),(Window)we.getComponent())来得到Window对象。

面向对象的编程思想:编程人员脑海里面想的应该是程序运行时各个时刻各个对象的内存布局和变化状态,以及每行代码执行后对这些对象产生的影响,
而不是仅仅盯住静止的代码和表象,孤立的去琢磨每条语句的语法是否正确。

用户界面操作在触发低级事件(如:MouseEvent)的同时,有可能同时触发高级事件(语义事件(如:ActionEvent))。

一个组件上的一个动作可以产生多种不同类型的事件;
一个事件监听器对象可以注册到多个事件源上;
在一个事件源上也可以注册对同一类事件进行处理的多个事件监听器对象。

我们还可以修改组件的默认事件处理方式。
当一个组件上发生了某种事件以后,系统就会调用组件对象的processEvent()方法,默认的processEvent()方法将根据事件的类型去调用相应的processXxxEvent()方法。
processXxxEvent()方法再去调用事件监听器中的方法,并将事件对象传递过去。
如果我们想改变某个组件的默认的事件处理方式,需要覆盖组件的processEvent()方法或者processXxxEvent()方法。
processEvent()方法是处理所有事件的总入口,processXxxEvent()方法则是专门处理某种事件的分叉路口。

如果没有在组件上注册某某事件的事件监听器,组件上就不会发生某某事件,当然也就不会产生某某事件的事件对象。
所以组件中的processXxxEvent()方法也就不可能被调用,但是如果程序调用了组件的enableEvents((long eventsToEnable))方法,
那么就可以在即使没有注册事件监听器的情况下,组件也能够对某些类型的事件进行响应和产生相应的事件对象。
enableEvents((long eventsToEnable))方法中的eventsToEnable参数,指定了代表某种或者某几种事件类型的数值。
代表事件类型的数值中的每一个bit位都代表一种事件类型。对应的bit位位置上的数值为1的话,就表示对某类事件进行相应。
表示不同事件类型的long类型整数是AWTEvent类中的一些常量。

我们看如下例子程序:
import java.awt.*;
import java.awt.event.*;
class MyButton extends Button
{
 private MyButton friend;
 public void setFriend(MyButton friend)
 {
  this.friend = friend;
 }
 public MyButton(String name)
 {
  super(name);
  enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
 }
 protected void processMouseMotionEvent(MouseEvent e)
 {
  setVisible(false);
  friend.setVisible(true);
 }
}
public class TestMyButton extends Frame
{
 public TestMyButton() {
  addWindowListener(new WindowAdapter() {
   @Override
   public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0);
   }
  });
 }
 public static void main(String [] args)
 {
  TestMyButton f =new TestMyButton();
  
  MyButton btn1 =new MyButton("你来抓我呀!");
  MyButton btn2 =new MyButton("你来抓我呀!");
  btn1.setFriend(btn2);
  btn2.setFriend(btn1);
  
  f.add(btn1, "North");//将btn1增加到f的北部
  f.add(btn2, "South");//将btn2增加到f的南部
  f.setSize(300,300);
  f.setVisible(true);
  btn1.setVisible(false); 
 }
}


Component提供了getGraphics方法返回一个Graphics类对象。
getGraphics()为组件创建一个图形上下文。如果组件当前是不可显示的,则此方法返回 null。所以Component对象首先是可显示的,
才会返回实际的Graphics对象,否则将返回null。

Graphics类提供了在组件上绘制图形,打印文字和显示图像等操作的方法。

new Font(null, Font.ITALIC|Font.BOLD, 30); 中的Font.ITALIC|Font.BOLD表示字体的样式是斜体和加粗效果。

窗口的重绘:其实一个窗口在最小化以后,这个窗口在显存中已经消失,只是在内存中保存了窗口本身相关的参数,
在还原窗口的时候,是根据内存的数据把窗口重新画出来,但是窗口表面用Graphics类所绘画的东西不会重新绘出来。
这个过程称之为曝光。
窗口每次被重绘以后,AWT线程会调用组件的paint(Graphics g)方法。
AWT线程对组件重绘的调用过程:当曝光(窗口改变大小,程序需要在显卡中重新绘制窗口)的时候,
AWT线程会调用组件的paint(Graphics g)方法(paint(Graphics g)方法是由AWT线程调度和管理的,我们不应该在程序中直接调用paint(Graphics g)方法。)
如果我们想让窗口的内容刷新,我们可以调用repaint()方法,repaint()会自动调用组件的update()方法,update()方法会清除组件表面内容,
然后调用paint(Graphics g)方法。

使用Component对象.getToolkit().getImage(String path)语句可以获得Image实例对象。
创建Image类对象的时候,并没有真正的在内存中创建图像数据,而是在需要的时候才去加载Image类对象所表示的图像数据。
又因为drawImage方法是异步方法,也就是说图像还没加载完的时候drawImage的方法已经返回了。
所以我们要用如下的方法来画一幅图像:while(!g.drawImage(img, 0, 0, frame)); 这是一个空循环,直到drawImage返回true的时候就结束循环。
看如下例子:
ex1:这里没有重写paint()方法实现重绘,所以需要while(!g.drawImage(img, 0, 0, frame));来画出图像
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;

public class ImageDraw extends Frame{

 public ImageDraw() {
  setSize(500, 500);
  setVisible(true);
 }
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  ImageDraw imgD = new ImageDraw();
  Image img = imgD.getToolkit().getImage("caidai.jpg");
  Graphics g = imgD.getGraphics();
  while(!g.drawImage(img, 0, 0, imgD));
 }
}

ex2:这里重写了paint()方法实现重绘,在paint方法里面使用g.drawImage(img, 0, 0, this)即可画出图像。
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;

public class ImageDraw extends Frame{

 public ImageDraw() {
  setSize(500, 500);
  setVisible(true);
 }
 
 public void paint(Graphics g) {
  Image img = getToolkit().getImage("caidai.jpg");
  g.drawImage(img, 0, 0, this);
 }
 public static void main(String[] args) {
  
  ImageDraw imgD = new ImageDraw();
 }
}

 

使用双缓冲技术将会非常方便和快速的实现对组件表面所有图形的重绘。
使用双缓冲技术的过程:
1,Component对象.createImage(int width, int height)方法创建内存Image对象;
(如:Dimension d = getSize(); img = createImage(d.width, d.height))
注意:在调用createImage(int width, int height)方法之前,首先Component对象是可见的,也就是先setVisible(true);才能返回一个Image对象,否则将返回null。
2,在Image对象上进行绘制的结果就成了一幅图像;(如:g = img.getGraphics(); 用g对象即可进行绘制。)
3,在Image对象上执行与组件表面同样的绘制,那么Image对象中的图像就是组件表面内容的复制,当组件重绘时,只需将内存中的Image对象在组件上画出。

一个使用了双缓冲技术的例子:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class LineDraw extends Frame {
 
 Image oImg;
 
 public LineDraw() {
  
  setSize(500, 500);
  setVisible(true);
  
  Dimension size = getSize();
  oImg = createImage(size.width, size.height);
  
  addWindowListener(new WindowAdapter() {
   @Override
   public void windowClosing(WindowEvent e) {
    dispose();
    System.exit(0);
   }
  });
  addMouseListener(new MouseAdapter() {
   int orgX;
   int orgY;
   @Override
   public void mousePressed(MouseEvent e) {
    orgX = e.getX();
    orgY = e.getY();
   }
   @Override
   public void mouseReleased(MouseEvent e) {
    /*Graphics g = getGraphics();
    g.setColor(Color.RED);
    g.drawLine(orgX, orgY, e.getX(), e.getY());
    
    Graphics oG = oImg.getGraphics();
    oG.setColor(Color.RED);
    oG.drawLine(orgX, orgY, e.getX(), e.getY());*/

    Graphics oG = oImg.getGraphics();
    oG.setColor(Color.RED);
    oG.drawLine(orgX, orgY, e.getX(), e.getY());

    repaint();
   }
  });
 }

 @Override
 public void paint(Graphics g) {
  if(oImg != null) {
   g.drawImage(oImg, 0, 0, this);
  }
 }
 
 public static void main(String[] args) {
  
  new LineDraw();
 }

}

 


当要设计自定制的具有GUI功能的组件类时,继承Canvas将会大大的简化编程难度。可以自定义外观(覆盖父类的update()方法或者paint()方法)和功能。
要设置Canvas的背景颜色,用public void fill3DRect(int x, int y, int width, int height, boolean raised)方法。会以当前的显示颜色填充矩形区域。

一般情况下,我们需要定制自己的组件的时候才需要修改组件的默认事件处理方式。在子类中重写processEvent()方法或者processXxxEvent()方法,
再调用enableEvents((long eventsToEnable))方法。

一个完整的菜单系统由菜单条(MenuBar),菜单(Menu),菜单项(MenuItem)组成。CheckboxMenuItem是具有复选功能的菜单项。
Menu类有一个方法addSeparator()可以在菜单项上添加分隔条。
调用Frame类中的setMenuBar(MenuBar mb)方法即可将MenuBar放在一个Frame窗口中。

ActionEvent类中的方法getActionCommand()可获得与此动作相关的命令字符串;
对于能够触发出ActionEvent事件的组件都能够调用setActionCommand(String command)来设置由此菜单项引发的动作事件的命令名。
默认情况下,动作命令设置为菜单项的标题文本。但是在国际化应用中,不同的语言版本会显示不同的标题文本,
所以此时只能通过setActionCommand(String command)来设置命令名。


Window类是可自由拼驳的自由窗口,没有标题栏,一般很少用。他的常用子类有Frame(带有标题栏的窗口)和Dialog(对话框)。


模态对话框和非模态对话框:模态对话框显示的时候,用户不能操作同一个程序中的其他窗口。
Dialog类用于产生对话框。方法getOwner()返回此对话框的拥有者对象,
注意:返回的是Window类对象,此时需要用返回的这个对象调用里面的方法的话,记得进行强制转换。
如:((MyFrame)getOwner()).getInfo();(假如你所继承Frame类里面有getInfo()这个成员方法。)
方法isModal()返回此对话框是否为模态对话框。
对话框本身也是一个容器类,可以添加如TextField,Button之类的组件。
记住,一般关闭对话框用dispose()方法来释放窗口资源。

FileDialog是Dialog的子类,在打开文件或者存储文件的时候可以用FileDialog类。


Checkbox用来创建单选按钮和多选按钮(复选框)。单选按钮必须为它指定一个组CheckboxGroup。
单选按钮和多选按钮的语义事件是ItemEvent,对应的监听器接口为ItemListener。

Choice用来制作单选下拉列表框。语义事件是ItemEvent,对应的监听器接口为ItemListener。

Panel类是一个容器类,用于产生一种特殊的空白面板,可以容纳其他组件,但不能独立存在。通常用于集合若干个组件,方便布局。

ScrollPanel类也是一个容器类,用于产生滚动窗口,通过滚动条在一个较小的容器窗口中显示较大的子部件。也不能独立存在。
ScrollPanel类本身没有布局管理器,他只能容纳一个组件。如果要添加多个组件,可以先将多个组件添加到Panel容器中先,然后添加Panel容器。

setLayout()方法用来设置容器的布局管理器。

BorderLayout布局管理器。是Window类默认的布局管理器,BorderLayout分为“东南西北中”五个区域。
FlowLayout布局管理器。 是Panel类默认的布局管理器,FlowLayout是流式布局。
GridLayout布局管理器。 将容器分为行列来布局。
GridBagLayout布局管理器。 功能比较强大,使用也比较复杂。一般较少使用。在swing中有更简单的替代办法。
CardLayout布局管理器。 使用这种布局的时候,添加组件要为组件指定一个标识字符串。如:add(new Button("hello"), "one"); 
BoxLayout布局管理器。 是在Swing中新增加的一种布局管理器,它允许多个组件全部垂直摆放或水平摆放。

setLayout(null)可取消布局管理器,然后使用setBounds()来设置组件的大小和绝对位置。


所有的Swing组件都位于javax.swing包中,他们是构筑在awt上层的GUI组件,Swing中所有的组件都是JComponent的子类,JComponent又是java.awt.Container的子类。
为了保证可移植性,Swing完全用java语言编写。

JFC(java Foundation Class)是指Sun对早期的JDK进行扩展的部分,集合了Swing组件和其他能简化开发的API类,
包括Swing,java 2D,accessibility,internationalization。

JFrame上面只能有一个唯一的组件,这个组件为JRootPane,调用JFrame.getContentPane()方法可获得JFrame中内置的JRootPane对象。

应用程序不能直接在JFrame实例对象上增加组件和设置布局管理器,而应该在JRootPane对象上增加子组件和设置布局管理器。

调用JFrame的setDefaultCloseOperation(int)方法,可以设置单击窗口上的关闭按钮时的处理方式,例如:当设置值为JFrame.EXIT_ON_CLOSE时,
单击JFrame窗口上的关闭按钮,将直接关闭JFrame框架窗口并结束程序运行。默认的行为只是简单地隐藏JFrame。

最基本的JScrollPane由水平和垂直方向上的JScrollBar以及一个JViewport组成。JViewport代表滚动窗口中的视图区域,JScrollBar代表滚动条。
调用JScrollPane.getViewport()方法,可以获得代表滚动窗口中的视图区域的JViewport对象。
调用JScrollPane.setViewport(JViewport viewport)方法,可以将滚动窗口中要显示的内容作为子组件增加到JViewport上。

JOptionPane类提供了若干个showXxxDialog()静态方法,可以用来产生简单的标准对话框。

JFileChooser类为用户选择文件提供了一种简单的机制,专门用来实现文件存取对话框。

在GUI程序开发中,应尽量使用Swing组件。

要快速掌握新组件的用法,最好找一个例子程序看看,并查看API文档。JDK的demo程序目录中有一些例子程序,java指南中也有。


javascript和Applet可以互相访问。例子程序如下:

//Test.java
package com.heima;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Test extends Applet {

 Image oImg;
 public String text;

 public void init() {

  setBackground(new Color(200, 200, 200));

  Dimension size = getSize();
  oImg = createImage(size.width, size.height);

  text = getParameter("param1");
  
  addMouseListener(new MouseAdapter() {
   int orgX;
   int orgY;
   @Override
   public void mousePressed(MouseEvent e) {
    orgX = e.getX();
    orgY = e.getY();
   }
   @Override
   public void mouseReleased(MouseEvent e) {
    Graphics oG = oImg.getGraphics();
    oG.setColor(Color.RED);
    oG.drawLine(orgX, orgY, e.getX(), e.getY());
    repaint();
   }
  });
 }

 public void paint(Graphics g) {
  if(oImg != null) {
   g.drawImage(oImg, 0, 0, this);
  }
  g.drawString(text, 100, 100);
 }
}

<!--这里是html代码-->
<applet code="com.heima.Test" name="app" width="100%" height="700">
 <param name="param1" value="哈哈哈,我是网页传递过来的参数。" />
</applet>
<script>
 var setText = function() {
  document.app.text = content.value;
  document.app.repaint();
 }
</script>
<input type="text" name="content" />
<input type="button" value="改变文本" οnclick="setText()" />

 

W3C标准建议用<object></object>标记来代替<applet></applet>
我们可以用JDK自带的HtmlConverter命令来转换。
使用<object>标记,执行Applet小程序的java解释器被作为一个ActiveX插件引用。

转换后的代码如下:
<object
    classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
    codebase = "http://java.sun.com/update/1.6.0/jinstall-6u18-windows-i586.cab#Version=6,0,0,7"
    WIDTH = "100%" HEIGHT = "700" NAME = "app" >
    <PARAM NAME = CODE VALUE = "com.heima.Test" >
    <PARAM NAME = NAME VALUE = "app" >
    <param name = "type" value = "application/x-java-applet;version=1.6">
    <param name = "scriptable" value = "false">
    <PARAM NAME = "param1" VALUE="哈哈哈,我是网页传递过来的参数。" />

    <comment>
 <embed
            type = "application/x-java-applet;version=1.6" \
            CODE = "com.heima.Test" \
            NAME = "app" \
            WIDTH = "100%" \
            HEIGHT = "700" \
            param1 ="?" /
     scriptable = false
     pluginspage = "http://java.sun.com/products/plugin/index.html#download">
     <noembed>
            
            </noembed>
 </embed>
    </comment>
</object>

注意:上面代码中的classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"表示使用的插件是java小程序插件。
codebase = "http://java.sun.com/update/1.6.0/jinstall-6u18-windows-i586.cab#Version=6,0,0,7"表示java小程序插件的下载位置,
如果客户端访问网页的时候没有安装java小程序插件,那么网页会提示安装,上面的那个参数就指定了下载位置。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值