java委托设计模式之ComponentUI
来源:互联网 发布:陶瓷产品设计软件 编辑:程序博客网 时间:2024/06/05 18:34
Swing的体系结构被称为模型委托结构而不是模式-视图-控制器结构,Swing将每个组件(JComponent及其派生类)的视图和控制都封装到一个与其相对应的UI委托的对象之中(ComponentUI及其派生类的对象)。可插拔LAF的设计意味着实现组件展现(Look)和事件处理(Feel)的部分是被代理到独立的UI对象中的,这些UI对象是由当前的LAF提供的,它们可以被动态地修改。每个JComponent对象都有一个与其相对应的JComponentUI对象,例如与JButton相对应的UI delegate为ButtonUI,JSlider相对应的UI delegate为SliderUI,JComponent组件自身的绘制都是通过ComponentUI绘制的。
ComponentUI的方法描述了一个UI委托和使用它的组件之间进行通讯的基本原理。 下面给出了ComponentUI的几个重要方法:
◆staticComponentUI createUI(JComponent c):该方法通常用来返回UI委托的一个共享实例,该UI委托通过定义ComponentUI子类本身而定义。这个共享实例用于相同类型的组件之间的共享(例如,所有使用金属外观的JButtons共享同样的静态UI委托实例,默认情况下,该委托实例在javax.swing.plaf.metal.MetalButtonUI中定义。
◆InstallUI(JComponentc):该方法在特定的组件上安装ComponentUI。通常会给组件和它的模型添加一个监听器,当状态发生改变时来通知UI委托进行视图的更新。
◆Update(Graphics g, JComponent c):如果组件是不透明的,那么应该描绘它的背景并调用paint(Graphics g,JComponent C)方法。
◆Paint(Graphics g, JComponent c):为了能够正确地描绘,该方法要从组件收集所有需要的信息以及可能的模型。
下面详细叙述Swing类JComponent类通过UI绘制自身的过程:
窗口的绘制都是事件触发的,例如当窗口应用程序的启动,窗口的大小改变,窗口的平移,被覆盖部分重新恢复等都会触发窗口重绘,也就是调用JComponent或者其子类的paint()方法,这里需要注意,Container类负责管理所有的子窗口,例如JFrame窗口需要重绘时,它首先调用paintComponent()方法绘制自身,然后调用paintBorder()绘制边框,再调用paintChildren()方法绘制通过JComponent.add()方法放置在其上的组件。
下面我们来看下JComponent.paint()的介绍及其源代码:
This method actually delegates the work ofpainting to three protected methods: <code>paintComponent</code>,<code>paintBorder</code>,and <code>paintChildren</code>.
这三个方法调用是有次序的,首先画自身,然后画边框,最后才能画子件。
public void paint(Graphics g) {
boolean shouldClearPaintFlags = false;
if ((getWidth() <= 0) || (getHeight() <= 0)) {
return;
}
Graphics componentGraphics = getComponentGraphics(g);
Graphics co = componentGraphics.create();
try {
RepaintManager repaintManager = RepaintManager.currentManager(this);
Rectangle clipRect = co.getClipBounds();
int clipX;
int clipY;
int clipW;
int clipH;
if (clipRect == null) {
clipX = clipY = 0;
clipW = getWidth();
clipH = getHeight();
}
else {
clipX = clipRect.x;
clipY = clipRect.y;
clipW = clipRect.width;
clipH = clipRect.height;
}
if(clipW > getWidth()) {
clipW = getWidth();
}
if(clipH > getHeight()) {
clipH = getHeight();
}
if(getParent() != null && !(getParent() instanceof JComponent)){
adjustPaintFlags();
shouldClearPaintFlags =true;
}
int bw,bh;
boolean printing = getFlag(IS_PRINTING);
if (!printing && repaintManager.isDoubleBufferingEnabled()&&
!getFlag(ANCESTOR_USING_BUFFER)&& isDoubleBuffered() &&
(getFlag(IS_REPAINTING) ||repaintManager.isPainting()))
{
repaintManager.beginPaint();
try {
repaintManager.paint(this,this, co, clipX, clipY, clipW,
clipH);
} finally {
repaintManager.endPaint();
}
}
else {
// Will ocassionaly happen in1.2, especially when printing.
if (clipRect == null) {
co.setClip(clipX, clipY,clipW, clipH);
}
if(!rectangleIsObscured(clipX,clipY,clipW,clipH)) {
if (!printing) {
paintComponent(co);
paintBorder(co);
}
else {
printComponent(co);
printBorder(co);
}
}
if (!printing) {
paintChildren(co);
}
else {
printChildren(co);
}
}
} finally {
co.dispose();
if(shouldClearPaintFlags) {
setFlag(ANCESTOR_USING_BUFFER,false);
setFlag(IS_PAINTING_TILE,false);
setFlag(IS_PRINTING,false);
setFlag(IS_PRINTING_ALL,false);
}
}
}
前端部分代码确定了绘制区的边界坐标。主要看paint 方法中调用了 paintComponent()方法。protected void paintComponent(Graphics g) {
if (ui != null) {
Graphics scratchGraphics = (g == null) ? null : g.create();
try {
ui.update(scratchGraphics,this);
}
finally {
scratchGraphics.dispose();
}
}
}
这里需要注意,Graphics类对象和剪裁区域(也就是需要画图的区域),画笔的颜色,字体等等有关。例如当JPanel调用自身的paint()方法时,它将与其自身相关的Graphics类对象g传递下去,因此只以特定的画笔等设置绘制它自身的区域。
这里最重要的是paintComponent()调用了ComponentUI.update()方法:
public void update(Graphics g, JComponentc) {
if (c.isOpaque()) {
g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(),c.getHeight());
}
paint(g, c);
}
ComponentUI的update()方法首先清除整个区域(将整个组件的区域刷成背景色),然后调用ComponentUI.paint()方法
public void paint(Graphics g, JComponent c){},该方法是一个空方法,对于不同的子类有不同的实现方式,例如画按钮和画进度条完全是不一样的实现。
但是JComponent和ComponentUI是如何关联起来的呢?
我们在JComponent中找到如下语句:
/** The look and feel delegate for thiscomponent. */
protectedtransient ComponentUI ui;
也就是说,ComponentUI是管理组件的外观展示和感觉的,这里的感觉就是事件处理,也就是说组件的事件处理是由ComponentUI来做的,对于不同的组件,事件处理方式不同,任意组件都有默认的UI,也就是有默认的外观和事件处理。对于不同的Look and Feel,显示时的效果不同,所以有时我们称Look and Feel为皮肤。
通过上面的分析,我们知道,窗口在需要重绘的情况下,需要调用paint(),默认的paint()方法会调用paintComponent()方法,paintComponent方法会调用与其相对应的UI delegate的update()方法,该方法会调用UI delegate的paint()方法,至此,才真正的绘制组件,当然,组件的绘制方法会因为组件的不同而不同,因此,对于每一个JComponent组件,都有与其相对象的ComponentUI,例如JButton有ButtonUI,JPanel有PanelUI等。这样,组件自身的绘制就转移到了与其相对应的UI上了,这就是委托设计模式。
- java委托设计模式之ComponentUI
- java设计模式之——委托模式
- PHP之设计模式—委托模式
- IOS设计模式之委托模式
- javascript设计模式之委托模式
- 设计模式 之 观察者--委托与事件
- 设计模式之委托代理(delegate)
- IOS-设计模式之委托(delegate)
- OC设计模式之代理(委托)设计模式
- 设计模式--【委托模式】
- 【设计模式】委托模式
- 六 设计模式之代理模式(或称委托模式)
- Cocosd-x设计模式之八 :委托和委托设计模式
- Cocosd-x设计模式之九 :委托和委托设计模式
- Cocos2d-x设计模式之九:委托和委托设计模式
- cocos2d-x设计模式之九:委托模式
- 设计模式之观察者模式与事件委托
- 设计模式之观察者模式与事件委托
- MySql 多表数据删除
- gcc c 关于结构体对齐
- struts中request、session、application对象的生成
- Spring事务管理---利用TransactionProxyFactoryBean生成事务代理
- @ManyToMany mappedby
- java委托设计模式之ComponentUI
- 【刮油减肥食谱】
- 简单地封装一个className
- 使用 Nautilus
- mmap详解
- 自定义css+html滚动条和js实现自定义html滚动条
- FRG图像文件格式(三):性能测试
- 显示中文的小例子 qt4 (补充)
- QT中定时器的使用方法