java 图形程序设计(GUI)
GUI(Graphical User Interface) 图形用户界面
在java刚出现的时候,包含了一个用于基本GUI程序设计的类库。Sun将他称为抽象窗口工具箱(Abstract Window ToolKit,awt)。基本awt库采用将处理用户界面元素的任务委派给每个目标平台(Window,Solaris,Macintosh等)的本地GUI工具箱的方式,由本地GUI工具箱负责用户界面元素的创建和动作。例如,如果使用最初的AWT在Java窗口中放置一个文本框,就会有一个低层的对等体文本框,用来真正的处理文本输入。从理论上来说,结果程序可以运行在任何平台上,但是观感(look and feel)的效果却依赖于目标平台,因此,Sun公司的口号是:一次编写,随处使用
对于简单的应用程序来说,基于对等体方法的效果还是不错的,但是要想编写依赖于本地用户界面元素的高质量、可移植可图形库就会暴露出一些缺陷。例如:菜单,滚动条和文本域这些用户界面元素,在不同的平台上,操作行为存在一些微妙的区别,因此,有些图形环境(如X11/Motif)并没有像Windows或者Macintosh这样丰富的用户界面组件集合。这也就将基于对等体的可移植库限制在了“最小公分母”的范围内。其结果使AWT构建的GUI应用程序看起来没有Windows或者Macintosh那么漂亮,也没有提供哪些平台用户所认知的功能。更糟糕的是,在不同平台上的AWT用户界面库中存在不同的bug。研发人员必须在每一个平台上测试应用程序。
后来,Netscape创建了一种称为IFC(Internet Foundation Class)的GUI库,它采用了与AWT完全不同的工作方式,他将按钮,菜单这样的用户界面元素绘制在空白窗口上,而对等*需要创建和绘制窗口。因此,Netscape的IFC组件在程序运行的所有平台上的外观和动作都一样。Sun与Netscape合作创建了一个名为Swing的用户界面库
Swing没有完全代替AWT,而是基于AWT的架构之上。Swing仅仅提供了能力更强大的用户界面组件。尤其在采用Swing编写的程序中,还需要使用基本的AWT处理时间。从现在开始,Swing是指被绘制的用户界面类,AWT是指向事件处理这样的窗口工具箱的底层机制
创建框架
—-
在java中,顶层窗口(就是没有包含在其他窗口中的窗口)被称为框架(frame)在AWT库中,有一个称为Frame的类,用于描述顶层窗口,这个类的Swing版本名为JFrame,他扩展于Frame类,JFrame是极少数几个不绘制在画布上的Swing组建之一。因此,他的修士部件)如按钮,标题栏,图标等)由用户的窗口系统绘制,而不是由Swing绘制。
绝大多数Swing组件类都以J开头,例如JButton,JFrame等。在Java中,有Button和Frame这样的类,但是他们属于AWT组件。如果偶然的忘记了书写J,程序仍然可以进行编译和运行,但是将Swing和AWT组件混合在一起使用将会导致视觉和行为的不一致
以下将介绍有关Swing的JFrame常用方法。
java.awt
Class EventQueue
java.lang.Object
java.awt.EventQueue
public class EventQueue
extends Object
EventQueue是一个独立于平台的类,用于从底层对等类和可信应用程序类排队事件。
它封装了从队列中提取事件,并通过调用调度它们异步事件指派机制dispatchEvent(AWTEvent)这种方法EventQueue与该事件被分派作为参数。 这种机器的特殊行为是依赖于实现的。 唯一的要求是实际排队到这个队列的事件(注意,发布到EventQueue事件可以合并)被调度:
package NEW_DATE_SEQUENCE_PACKAGE;
import java.awt.*;
import javax.swing.*;
/**
*
* @author cmx
*/
public class J_9_1_6_swing
{
public static void main(String [] args)
{
EventQueue.invokeLater(()->
{
SimpleFrame3 a=new SimpleFrame3();
a.setVisible(true);
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
});
}
}
class SimpleFrame3 extends JFrame
{
private static final int DEFAULT_WIDTH=300;
private static final int DEFAULT_HIGHT=200;
public SimpleFrame3()
{
setSize(DEFAULT_WIDTH,DEFAULT_HIGHT);
}
}
运行结果:一个空白的窗口
框架定位
—-
JFrame类本身只包含若干个改变框架外观的方法。当然,通过继承,从JFrame的超类中继承了很多用于处理框架大小和位置的方法。其中最重要的有下面几个:
setLocation和setBounds方法用于设置框架的位置
setLocation
public void setLocation(int x,
int y)
将组件移到新位置。通过此组件父级坐标空间中的 x 和 y 参数来指定新位置的左上角。
参数:
x - 父级坐标空间中新位置左上角的 x 坐标
y - 父级坐标空间中新位置左上角的 y 坐标
从以下版本开始:
JDK1.1
=============
setBounds
public void setBounds(int x,
int y,
int width,
int height)
移动组件并调整其大小。由 x 和 y 指定左上角的新位置,由 width 和 height 指定新的大小。
参数:
x - 组件的新 x 坐标
y - 组件的新 y 坐标
width - 组件的新 width
height - 组件的新 height
从以下版本开始:
JDK1.1
setIconImage用于告诉窗口系统在标题栏、任务切换窗口等位置显示那个图标
setIconImage
public void setIconImage(Image image)
设置要作为此窗口图标显示的图像。
将单个图像指定为窗口的图标时,可以使用此方法代替 setIconImages()。
以下语句:
setIconImage(image);
等价于:
ArrayList imageList = new ArrayList();
imageList.add(image);
setIconImages(imageList);
注:根据上下文的不同(例如,窗口装饰、窗口列表、任务栏等),本机窗口系统可以使用不同尺寸的不同图像表示一个窗口。也可以对所有上下文使用一个图像,或者根本不用图像。
覆盖:
类 Frame 中的 setIconImage
参数:
image - 要显示的图标图像。
setTitle 用于改变标题栏的文字
setTitle
public void setTitle(String title)
将此窗体的标题设置为指定的字符串。
参数:
title - 要显示在窗体边框中的标题。 null 值视为空字符串 ""
setResizable 利用一个boolean值确定框架的大小是否允许用户改变
setResizable
public void setResizable(boolean resizable)
设置此窗体是否可由用户调整大小。
参数:
resizable - 如果此窗体是可调整大小的,则为 true;否则为 false。
JFrame继承框架:
javax.swing
类 JFrame
java.lang.Object
继承者 java.awt.Component
继承者 java.awt.Container
继承者 java.awt.Window
继承者 java.awt.Frame
继承者 javax.swing.JFrame
JPanel继承框架
javax.swing
类 JPanel
java.lang.Object
继承者 java.awt.Component
继承者 java.awt.Container
继承者 javax.swing.JComponent
继承者 javax.swing.JPanel
对于Component类和window类(是Frame的超类)要仔细研究,从中找到缩放和改变框架的方法。例如:在Component类中的setLocation方法是重定位组建的一个方法。
如果调用setLocation(x,y)
则将窗口放置在左上角水平x像素,垂直y像素的位置。坐标(0,0)位于屏幕的左上角。同样的,Component中的setBounds方法可以实现一步重定位组件,
setBounds(x,y,width,height)
可以让窗口系统控制窗口的位置,如果在显示串口之前调用
setLocationByPlatform (true);
窗口系统会选用窗口的位置(而不是大小),通常是距离最后一个显示窗口最小偏移量的位置。
对于框架来说,setLocation和setBounds中的坐标均相对于整个屏幕。
在容器中包含的组件所指的坐标均相对于容器。
**框架属性**
组件类的很多方法是以获取/设置方法对形式出现的,例如:Frame类的下列方法:
public String getTitle();
public void setTitle(String title);
这样的一个获取/设置方法对就被称为一种属性。属性中包含属性名和类型。将get或者set之后的第一个字母改为小写字母就可以得到相应的属性名。例如:Frame类有一个名为title且类型为String的属性。
从概念上讲,title是框架的一个属性,当设置这个属性的时候,我们不关心如何实现这个属性。
针对get/set约定由一个例外:对于类型为boolean的属性,获取方法由is开头。例如:下面两个方法定义了locationByPlatform属性:
public boolean isLocationByPlatform();
public void setLocationByPlatform();
=======================
isLocationByPlatform
public boolean isLocationByPlatform()
如果此窗口下次可见时,出现在本机窗口操作系统的默认位置,则返回 true。如果窗口显示在屏幕上,则此方法始终返回 false。
返回:
此窗口是否将出现在默认位置
==========================
setLocationByPlatform
public void setLocationByPlatform(boolean locationByPlatform)
设置窗口下次可见时应该出现的位置:本机窗口系统的默认位置,还是当前位置(由 getLocation 返回)。此行为模拟显示的本机窗口,而不是以编程方式设置其位置。如果未显式设置窗口的位置,那么大多数窗口操作系统将重叠显示窗口。一旦窗口显示在屏幕上,其实际位置就被确定
确定合适的框架大小
———
要记住:如果没有明确的指定框架的大小,所有框架的默认值为0*0像素,为了让示例程序尽可能的简单,这里将框架的大小重置为大多数情况下都可以接受的显式尺寸。然而,对于专业应用程序来说,应该检查屏幕的分辨率,并根据其分辨率编写代码重置框架的大小,如在微型电脑的屏幕上,正常显示的窗口在高分辨率屏幕上可能变为一张邮票的大小。
为了得到屏幕的大小,需要按照下列步骤操作。调用Toolkit类的静态方法getDefaultToolkit得到一个Toolkit对象(Toolkit类包含许多与本地窗口系统打交道的方法)。然后,调用getScreenSize方法,这个方法以Dimension对象的形式返回屏幕的大小,Dimension对象同时用公有实例变量width和height保存着屏幕的宽度和高度。下面是相关的代码:
package NEW_DATE_SEQUENCE_PACKAGE;
import java.awt.*;
import javax.swing.*;
/**
*
* @author cmx
*/
public class J_9_1_6_swing
{
public static void main(String [] args)
{
EventQueue.invokeLater(()->
{
SimpleFrame3 a=new SimpleFrame3();
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit kit= Toolkit.getDefaultToolkit();
Dimension screenSize=kit.getScreenSize();
int screenWidth=screenSize.width;
int screenHeight=screenSize.height;
/**
* 下面,将框架大小设置为上面取值得50%,然后,告知窗口系统定位框架
*/
a.setSize(screenWidth/2,screenHeight/2);
a.setLocationByPlatform((true));
a.setVisible(true);
});
}
}
class SimpleFrame3 extends JFrame
{
private static final int DEFAULT_WIDTH=300;
private static final int DEFAULT_HIGHT=200;
public SimpleFrame3()
{
setSize(DEFAULT_WIDTH,DEFAULT_HIGHT);
}
}
另外,还提供了一个图标,由于图像的描述与系统有关,所以需要再次使用工具箱加载图像。然后,将这个图像设置为框架的图标:
public abstract class Image
extends
Object
抽象类 Image 是表示图形图像的所有类的超类。必须以特定于平台的方式获取图像。
对于不同的操作系统,所看到的图标显示位置可能不同。例如:在Windows中,图标显示在窗口的左上角,按下ALT+TAB,可以在活动任务的里表中看到相应程序的图标。
下面是为了处理框架给予的一些提示:
如果框架中只包含标准的组件,如按钮和文本框,那么通过调用pack方法设置框架大小。
pack
public void pack()
调整此窗口的大小,以适合其子组件的首选大小和布局。如果该窗口和/或其所有者还不可显示,则在计算首选大小之前都将变得可显示。在计算首选大小之后,将会验证该窗口。
框架将被设置为刚好能放下所有组件的大小。在通常情况下,将程序的主框架尺寸设置为最大,可以通过调用下面方法将框设置的最大。
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
//setExtendedState
public void setExtendedState(int state)
设置此窗体的状态。该状态表示为逐位掩码。
MAXIMIZED_BOTH
public static final int MAXIMIZED_BOTH
此状态位掩码指示将窗体完全最大化(水平和垂直方向)。它只是 MAXIMIZED_VERT | MAXIMIZED_HORIZ 的一种便捷别名。
牢记用户定位应用程序的框架位置、重置框架大小,并且在应用程序再次启动时恢复这些内容是一个不错的想法。
GraphicsDevice类还允许以全屏模式执行应用。
//
isFullScreenSupported
public boolean isFullScreenSupported()
如果此 GraphicsDevice 支持全屏独占模式,则返回 true。如果安装了 SecurityManager,则将使用 AWTPermission("fullScreenExclusive") 调用它的 checkPermission 方法。只有授权时 isFullScreenSupported 才会返回 true。
ImageIcon
public ImageIcon(String filename)
根据指定的文件创建一个 ImageIcon。使用 MediaTracker 预载图像以监视图像的加载状态。指定 String 可以是一个文件名或是一条文件路径。在指定一条路径时,可使用 Internet 标准正斜杠 ("/") 作为分隔符。(该字符串被转换成一个 URL,而正斜杠适用于所有系统。)例如,指定:
new ImageIcon("images/myImage.gif")
================
getImage
public Image getImage()
返回此图标的 Image。
================
setIconImage
public void setIconImage(Image image)
设置要作为此窗口图标显示的图像。
将单个图像指定为窗口的图标时,可以使用此方法代替 setIconImages()。
以下语句:
setIconImage(image);
等价于:
ArrayList imageList = new ArrayList();
imageList.add(image);
setIconImages(imageList);
注:根据上下文的不同(例如,窗口装饰、窗口列表、任务栏等),本机窗口系统可以使用不同尺寸的不同图像表示一个窗口。也可以对所有上下文使用一个图像,或者根本不用图像。
覆盖:
类 Frame 中的 setIconImage
参数:
image - 要显示的图标图像。
一、问题
ImageIcon icon = new ImageIcon(“a.gif”);
执行结果是icon无法显示
二、解决
类中有如下调用:
ImageIcon icon = new ImageIcon(“a.gif”);
很自然地认为当前类文件和图片在同一路径下即可。
其实所谓的相对路径起点是工程的根目录,即project。
这行代码执行时在project目录下查找名为a.gif的文件,结果当然是找不到。
要得到工程的相对路径可通过System.getProperty(“user.dir”)得到。
对图片和对文件的查找应该是一致的,如new File()。
假如你的工程根目录为:project1
你的图片文件放在:project1/src/images/a.gif
所以正确的调用是:
ImageIcon icon = new ImageIcon(“src//images//a.gif”);
这行代码执行时在project/test目录下查找到了文件
总结起来就是一句话:所谓相对路径就是相对于工程根目录的位置^_^
三、其他
查看了一下ImageIcon的构造函数。
Public ImageIcon(String filename)//参数可以是绝对路径也可以是相对路径
Public ImageIcon(URL url)
第一种构造不在赘述。
第二种通过URL来得到图片
URL url = getClass().getResource(“a.gif”); //当前编译后class文件所在目录查找
ImageIcon icon = new ImageIcon(url);
ImageIcon支持GIF、JPG、PNG等格式。
java.awt.Component
boolean isVisible()
void setVisible(boolean b)
获取或者设置visible属性,组件最初是可见的,但是JFrame这样的顶层组件例外
void setSize(int width, int height)
使用给定的宽度和高度,重新设置组建的大小;
void setLocation(int x ,int y)
将组件移到一个新的位置上,如果这个组件不是顶层组件,x和y坐标(或者p.x和p.y)是容器坐标;否则是屏幕坐标
void setBounds(int x,int y, int width, int height)
移动并重新设置组件的大小
Dimension getSize()
void setSize(Dimension d)
获取或者设置当前组件的size属性
java.awt.Window
void toFront()
将这个窗口显示的到其他窗口的前面
void toBack()
将这个窗口移到桌面窗口栈的后面,并相应的重新排列所有的可见窗口。
boolean isLocationByPlatform()
void setLocationByPlatform(boolean b);
获取或者设置locationByPlatform属性。这个属性在窗口显示之前被设置,由平台选择一个合适的位置;
java.awt.Frame
boolean isResizable()
void setResizable(boolean b)
获取或者设置resizable属性,这个属性设置后,用户可以重新设置框架的大小
String getTitle()
void setTitle(String s)
获取或者设置title属性,这个属性确定框架标题栏中的文字
Image getIconImage()
void setIconImage(Image image)
获取或者设置iconImage属性,这个属性确定框架的图标,窗口系统可能会将图表作为框架装饰或者其他部位的一部分显式。
boolean isUndecorated()
void setUndecorated(boolean b)
获取或者设置undecorated属性,这个属性设置后,框架显式中将没有标题栏或关闭按钮这样的装饰。在框架显式之前,必须调用这个方法
int getExtendedState()
void setExtendedState(int state)
获取或者设置窗口状态
java.awt.Toolkit
static Toolkit getDefaultToolkit()
返回默认的工具箱
Dimension getScreenSize()
返回用户屏幕的尺寸
java.swing.ImageIcon
ImageIcon(String filename)
构造一个图标,其图像存储在一个文件中
Image getImage()
获得该图标的图像。
在组件中显示信息
接下来将讨论如何在框架内显示信息。例如,我们不再像以前那样,采用文本方式在控制台窗口中显示信息。而是在框架中显示这个信息。
可以将消息字符串直接绘制在框架中,但这并不一定是一种很好的编程习惯。在Java中,框架被设计为放置组件的容器,可以将菜单栏和其他的用户界面元素放置在其中。在通常情况下,应该在另一组件上绘制信息,并将这个组件添加到框架中。
JFrame的结构相当复杂。在图中给出了JFrame的结构。可以看到,在JFrame中有四层面板,其中的根面板,层级面板,和玻璃面板我们不太关心,他们是用来组织菜单栏和内容窗格以及实现观感的。swing程序员最关心的是内容窗格(content pane)在设计框架的时候,要使用以下代码将所有的组件添加到内容窗格中:
getContentPane
javax.swing
类 JFrame
java.lang.Object
继承者 java.awt.Component
继承者 java.awt.Container
继承者 java.awt.Window
继承者 java.awt.Frame
继承者 javax.swing.JFrame
getContentPane
public Container getContentPane()
返回此窗体的 contentPane 对象
指定者:
接口 RootPaneContainer 中的 getContentPane
返回:
contentPane 属性
Container
public class Container
extends
Component
一般的 Abstract Window Toolkit(AWT) 容器对象是一个可包含其他 AWT 组件的组件。
添加到容器中的组件放在一个列表中。列表的顺序将定义组件在容器内的正向堆栈顺序。如果将组件添加到容器中时未指定索引,则该索引将被添加到列表尾部(此后它位于堆栈顺序的底部)。
java.awt
类 Container
java.lang.Object
继承者 java.awt.Component
继承者 java.awt.Container
=================
getPreferredSize
public Dimension getPreferredSize()
返回此容器的首选大小。如果尚未通过 Component.setPreferredSize(Dimension) 显式设置首选大小,并且此 Container 有一个 non-null LayoutManager,则使用 LayoutManager.preferredLayoutSize(Container) 来计算首选大小。
注:一些实现可能缓存从 LayoutManager 返回的值。每次调用此方法时,这些缓存实现不需要在 LayoutManager 上调用 preferredLayoutSize,而是只在 Container 变得无效之后查询 LayoutManager。
覆盖:
类 Component 中的 getPreferredSize
//代码
Container contentPane=frame.getContentPane();
Component c=...;
contentPane.add(c);
在java SE 中,JFrame类中的add方法抛出了一个异常信息“Do not use JFrame.add. Use JFrame.getContentPane().add instead.如今,JFrame.add方法不再显示这些提示信息,只是简单的调用内容窗格的add
因此,可以直接调用
frame.add(c);
在这里,打算将一个绘制消息的组件添加到框架中。绘制一个组件,需要定义一个扩展JComponent类,并覆盖其中的paintComponent方法
paintComponent方法有一个Graphics类型的参数,这个参数保存着用于绘制图像和文本的设置,例如,设置字体或者当前的颜色。在Java中,所有的绘制都必须使用Graphics对象,其中包含了绘制图案,图像和文本的方法。
Graphics参数与Windows中的设备环境或者X11程序设计中的图形环境基本相似.
有些程序员更喜欢扩展JPanel,而不是JComponent。JPanel是一个可以包含其他组建的容器(container),但同样可以在器上面绘制。有一点不同之处是,面板不透明,意味着需要在面板的边界绘制所有的像素。最容易实现的方法是:在每个面板子类的paintComponent方法中调用super.paintComponent来用背景色绘制面板
class Not extends JPane;
{
public void paintComponent(Graphics g)
{
super.paintComonent(g);
...
}
class component3 extends JPanel
{
private int Width1=75;
private int Height1=100;
public void paintComponent(Graphics g)
{
// super.paintComponent(g);
g.drawString("wel0001212..........", Width1, Height1);
}
}
//对比
class component3 extends JPanel
{
private int Width1=75;
private int Height1=100;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString("wel0001212..........", Width1, Height1);
}
}
//显示是一样的
javax.swing.JFrame
Container getContentPane()
返回这个JFrame的内容窗格对象
Component add(Component c)
讲一个给定的组件添加到该框架的内容窗格中
(在框架类中add,不需要隐式对象)
//如
class NotHello extends JFrame
{
public NotHello()
{
add(new NotComponent);
pack();
}
}
总结:定义一个框架
class XFrame extends JFrame
{
public XFrame()
{
...
}
}
//中间可以为setSize();add(组件);
//总结:定义一个组件
class NotHello extends JComponent
{
public void paintComponent(Graphics g)
{
... //Graphics 操作
}
public Dimension getPreferredSize() //组件必须有一个首选大小,或者是默认大小
{
return new Dimension(width, height);
}
}
//或者
class Not extends JPane
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
...
}
}
//总结:添加JFrame(Component在JFrame类中添加,不在这里添加,层次分明)
public static void main(String[] args)
{
EventQueue.invokeLater(()->
{
JFrame f=new NotHello(); //引入一个框架就是创建一个框架类
f.setTitle();
f.setDefaultCloseOperation(Frame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
java.awt.Component
void repaint()
尽可能快的重新绘制组件
Dimension getPreferredSize()
要覆盖这个方法,返回这个组建的首选大小 //组件都应该有一个首选大小
javax.swing.JComponent
void paintComponent(Graphics g)
覆盖这个方法来描述如何绘制自己的组件
java.awt.Window
void pack()
调整窗口的大小,当有多个组件,只想使用它们的首选大小,可以调用pack()
上一篇: Python学习笔记(持续更新)
下一篇: PythonGUI学习笔记