jlayer.docx
《jlayer.docx》由会员分享,可在线阅读,更多相关《jlayer.docx(11页珍藏版)》请在冰点文库上搜索。
![jlayer.docx](https://file1.bingdoc.com/fileroot1/2023-6/8/e0d6165c-5657-47c0-921d-7f90565af682/e0d6165c-5657-47c0-921d-7f90565af6821.gif)
jlayer
JLayer和LayerUI概述
根据JDK的文档描述,JLayer委托处理LayerUI对象的绘制和输入事件,LayerUI负责装饰,你可以使用这些类修改现有组件的外观和行为使它们的装饰效果更好。
实际上,你可以自己动手扩展LayerUI,废除它们自带的方法,自己定制绘制和事件处理方法,然后将这个类的实例和装饰后的组件一道,传递给下面的JLayer构造器:
publicJLayer(Vview,LayerUIui)
第一个参数可以是任何类的延伸java.awt.Component,表示你要装饰的Swing组件,这个组件可以是一个JPanel或其它容器,这个容器和它里面所有的组件都将被装饰,第二个参数代表装饰器。
使用这些构造器创建JLayer时,可以延迟指定LayerUI实例和/或视图。
如果初始化时不指定视图,之后你可以调用JLayer'spublicvoidsetView(Vview)方法来提供一个视图,这个类也提供了一个publicVgetView()方法返回组件是否被装饰,没有装饰就返回null。
如果初始化时不指定LayerUI实例,之后你可以调用JLayer'spublicvoidsetUI(LayerUIui方法提供一个实例,这个类也提供了一个publicLayerUIgetUI()方法返回当前的装饰器,没有装饰器就返回null。
JLayer自定义绘制
为了演示JLayer的自定义绘制特性,我创建了一个ReverseText程序,其代码显示在清单1中,当按下按钮时,输入到textfield中的文本将全部颠倒,这个程序使用JLayer在用户界面后绘制了一个墙纸图案。
清单1.ReverseText.java
1.//ReverseText.java
2.importjava.awt.Color;
3.importjava.awt.EventQueue;
4.importjava.awt.GradientPaint;
5.importjava.awt.Graphics;
6.importjava.awt.Graphics2D;
7.importjava.awt.event.ActionEvent;
8.importjava.awt.event.ActionListener;
9.importjavax.swing.JButton;
10.importjavax.swing.JComponent;
11.importjavax.swing.JFrame;
12.importjavax.swing.JLabel;
13.importjavax.swing.JLayer;
14.importjavax.swing.JPanel;
15.importjavax.swing.JTextField;
16.importjavax.swing.plaf.LayerUI;
17.publicclassReverseText
18.{
19. privatestaticColorPALE_YELLOW=newColor(1.0f,1.0f,0.0f,0.2f);
20. privatestaticColorPALE_GREEN=newColor(0.0f,1.0f,0.0f,0.2f);
21. privatestaticJLayercreateLayer()
22. {
23. LayerUIlayerUI;
24. layerUI=newLayerUI()
25. {
26. publicvoidpaint(Graphicsg,JComponentc)
27. {
28. //Paintthewallpaper.
29. Graphics2Dg2=(Graphics2D)g;
30. g2.setPaint(newGradientPaint(0,0,PALE_YELLOW,
31. 5,0,PALE_GREEN,true));
32. g2.fillRect(0,0,c.getWidth(),c.getHeight());
33. //Makesurethatlayer'spanelviewisnotopaque.
34. JLayerl=(JLayer)c;
35. if(l.getView().isOpaque())
36. ((JPanel)l.getView()).setOpaque(false);
37. //Painttheviewminusitsbackground.
38. super.paint(g,c);
39. }
40. };
41. //Createauserinterfacetobedecorated.
42. JPanelpnl=newJPanel();
43. JLabellblName=newJLabel("Name:
");
44. pnl.add(lblName);
45. finalJTextFieldtxtName=newJTextField(20);
46. pnl.add(txtName);
47. JButtonbtnReverse=newJButton("Reverse");
48. pnl.add(btnReverse);
49. ActionListeneral;
50. al=newActionListener()
51. {
52. publicvoidactionPerformed(ActionEventae)
53. {
54. Stringtxt=txtName.getText();
55. txt=newStringBuffer(txt).reverse().toString();
56. txtName.setText(txt);
57. }
58. };
59.btnReverse.addActionListener(al);
60.//CreatethelayerforthepanelusingourcustomlayerUI.
61.returnnewJLayer(pnl,layerUI);
62.}
63.privatestaticvoidcreateAndShowUI()
64.{
65.JFrameframe=newJFrame("ReverseText");
66.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
67.frame.add(createLayer());
68.frame.pack();
69.frame.setLocationRelativeTo(null);
70.frame.setVisible(true);
71.}
72.publicstaticvoidmain(String[]args)
73.{
74.Runnabler=newRunnable()
75.{
76.publicvoidrun()
77.{
78.createAndShowUI();
79.}
80.};
81.EventQueue.invokeLater(r);
82.}
83.}
其中createLayer()方法是最重要的代码,它创建了一个匿名LayerUI子类的实例,绘制了墙纸和JPanel视图,创建了UI,在实例中包含了UI的面板容器。
绘制操作是由LayerUI'spublicvoidpaint(Graphicsg,JComponentc)方法实现的,第二个参数引用了视图(被装饰的组件)中的JLayer实例,不是引用的视图。
在视图后创建了渐变渲染墙纸后,调用paint()方法确保视图(没有嵌套面板的单一面板)是透明的,它将会隐藏墙纸,然后绘制视图。
paint()对比paintLayer()
JDK文档中除了提到paint()方法外,还提到了paintLayer()方法,我这里之所以选择paint()方法,是因为LayerUI中不存在paintLayer(),此外,文档还错误地引用paintLayer()doesn'texistinLayerUI.Furthermore,thedocumentationincorrectlyreferstoaddPropertyChange(),configureGraphics(),processComponentEvent(),processFocusEvent(),processHierarchyBoundsEvent(),processHierarchyEvent(),processKeyEvent(),processMouseEvent(),processMouseMotionEvent(),processMouseWheelEvent(),andrepaintLayer()这些在LayerUI中根本不存在的方法,当然这些方法也可能在JDK7最终发布时会包含进来。
ReverseText程序演示了自定义绘制,避开了事件触发,不需要检测事件,因为程序只关心墙纸的绘制效果。
相反,清单2显示了一个需要响应鼠标移动事件的程序代码。
清单2.BrandedUI.java
1.//BrandedUI.java
2.importjava.awt.AWTEvent;
3.importjava.awt.Color;
4.importjava.awt.Component;
5.importjava.awt.EventQueue;
6.importjava.awt.Font;
7.importjava.awt.GradientPaint;
8.importjava.awt.Graphics;
9.importjava.awt.Graphics2D;
10.importjava.awt.GridLayout;
11.importjava.awt.Point;
12.importjava.awt.event.MouseEvent;
13.importjavax.swing.JComponent;
14.importjavax.swing.JFrame;
15.importjavax.swing.JLabel;
16.importjavax.swing.JLayer;
17.importjavax.swing.JPanel;
18.importjavax.swing.JTextField;
19.importjavax.swing.SwingUtilities;
20.importjavax.swing.plaf.LayerUI;
21.publicclassBrandedUI
22.{
23. privatestaticColorPALE_BLUE=newColor(0.0f,0.0f,1.0f,0.3f);
24. privatestaticColorPALE_RED=newColor(1.0f,0.0f,0.0f,0.3f);
25. privatestaticFontBRAND_FONT=newFont("Arial",Font.BOLD,18);
26. privatestaticStringMSG="Mybrand";
27. privatestaticJLayercreateLayer()
28. {
29. LayerUIlayerUI;
30. layerUI=newLayerUI()
31. {
32. privateColorcolor=PALE_BLUE;
33. publicvoidinstallUI(JComponentc)
34. {
35. super.installUI(c);
36. ((JLayer)c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
37. }
38. publicvoideventDispatched(AWTEvente,
39. JLayer
extendsJPanel>l)
40. {
41. MouseEventme=(MouseEvent)e;
42. Pointpt=SwingUtilities.convertPoint((Component)me.getSource(),
43. me.getX(),me.getY(),l);
44. intcx=l.getWidth()/2;
45. intcy=l.getHeight()/2;
46. if(pt.x>cx-45&&pt.xcy-10&&pt.y 47. color=PALE_RED;
48. else
49. color=PALE_BLUE;
50. l.repaint();
51. }
52. publicvoidpaint(Graphicsg,JComponentc)
53. {
54. //Painttheview.
55. super.paint(g,c);
56. //Paintthebrand.
57. g.setColor(color);
58. g.setFont(BRAND_FONT);
59. intwidth=g.getFontMetrics().stringWidth(MSG);
60. intheight=g.getFontMetrics().getHeight();
61. g.drawString(MSG,(c.getWidth()-width)/2,
62. c.getHeight()/2+height/4);
63. }
64. publicvoiduninstallUI(JComponentc)
65. {
66. super.uninstallUI(c);
67. ((JLayer)c).setLayerEventMask(0);
68. }
69. };
70. //Createauserinterfacetobedecorated.
71. JPanelpnlMain=newJPanel();
72. pnlMain.setLayout(newGridLayout(2,1));
73. JPanelpnlTemp=newJPanel();
74. JLabellblName=newJLabel("Name:
");
75. pnlTemp.add(lblName);
76. JTextFieldtxtName=newJTextField(20);
77. pnlTemp.add(txtName);
78. pnlMain.add(pnlTemp);
79. pnlTemp=newJPanel();
80. JLabellblAddr=newJLabel("Address:
");
81. pnlTemp.add(lblAddr);
82. JTextFieldtxtAddr=newJTextField(20);
83. pnlTemp.add(txtAddr);
84. pnlMain.add(pnlTemp);
85. //CreatethelayerforthemainpanelusingourcustomlayerUI.
86. returnnewJLayer(pnlMain,layerUI);
87. }
88. privatestaticvoidcreateAndShowUI()
89. {
90. JFrameframe=newJFrame("BrandedUI");
91. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
92. frame.add(createLayer());
93. frame.pack();
94. frame.setLocationRelativeTo(null);
95. frame.setVisible(true);
96. }
97. publicstaticvoidmain(String[]args)
98. {
99. Runnabler=newRunnable()
100. {
101. publicvoidrun()
102. {
103. createAndShowUI();
104. }
105. };
106. EventQueue.invokeLater(r);
107. }
108.}
上面的代码渲染UI上的文本印记,我们通常使用印记提醒用户使用的是试用软件,印记文本是半透明的,以便背景可以全部显示,我们不希望这个印记给用户造成太大的干扰。
另一方面,我们希望用户能注意到这个印记,让他们下定决心购买这款软件,清单2中的代码通过改变印记的颜色(改成淡红色)来达到这个目的,当鼠标移到初始值是绿色的印记面板上时,颜色就变成淡红色。
事件检测
JLayer和LayerUI结合起来可以检测视图任意区域上发生的事件(包括嵌套的子组件),这些类共同提供了4个方法来检测事件。
·publicvoidsetLayerEventMask(longlayerEventMask)
调用这个JLayer方法时必须使用位掩码AWTEvent常量选择它检测到的事件类型,如:
setLayerEventMask(AWTEvent.KEY_EVENT_MASK|AWTEvent.FOCUS_EVENT_MASK);可以检测到按键和焦点改变事件。
◆publicvoidinstallUI(JComponentc)
这个LayerUI方法通常放在setLayerEventMask()方法之前,这个方法类的代码首先调用超类方法(super.installUI(c);),然后是引用JLayer的JComponent参数,最后使用setLayerEventMask():
((JLayer)c).setLayerEventMask(AWTEvent.KEY_EVENT_MASK);返回的结果。
◆publicvoiduninstallUI(JComponentc)
这个LayerUI方法放在没有参数的setLayerEventMask()方法后,这个方法内的代码首先调用超类方法(super.uninstallUI(c);),然后是引用JLayer的JComponent参数,最后使用setLayerEventMask():
((JLayer)c).setLayerEventM