探秘JDK 7之三:JLayer装饰Swing组件(2)
时间:2010-08-31 来源:mydear
其中createLayer()方法是最重要的代码,它创建了一个匿名LayerUI子类的实例,绘制了墙纸和JPanel视图,创建了UI,在实例中包含了UI的面板容器。
绘制操作是由LayerUI's public void paint(Graphics g,JComponent c)方法实现的,第二个参数引用了视图(被装饰的组件)中的JLayer实例,不是引用的视图。
在视图后创建了渐变渲染墙纸后,调用paint()方法确保视图(没有嵌套面板的单一面板)是透明的,它将会隐藏墙纸,然后绘制视图。
paint()对比paintLayer()
JDK文档中除了提到paint()方法外,还提到了paintLayer()方法,我这里之所以选择paint()方法,是因为LayerUI中 不存在paintLayer(),此外,文档还错误地引用paintLayer() doesn't exist in LayerUI. Furthermore,the documentation incorrectly refers to addPropertyChange(),configureGraphics(),processComponentEvent(),processFocusEvent(),processHierarchyBoundsEvent(),processHierarchyEvent(),processKeyEvent(),processMouseEvent(),processMouseMotionEvent(),processMouseWheelEvent(),and repaintLayer()这些在LayerUI中根本不存在的方法,当然这些方法也可能在JDK 7最终发布时会包含进来。
图1显示了有墙纸背景的UI。
498)this.style.width=498;" class="fit-image" />
图1 在用户界面后加了一层墙纸背景
ReverseText程序演示了自定义绘制,避开了事件触发,不需要检测事件,因为程序只关心墙纸的绘制效果。相反,清单2显示了一个需要响应鼠标移动事件的程序代码。
清单2. BrandedUI.java
- // BrandedUI.java
- import java.awt.AWTEvent;
- import java.awt.Color;
- import java.awt.Component;
- import java.awt.EventQueue;
- import java.awt.Font;
- import java.awt.GradientPaint;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.GridLayout;
- import java.awt.Point;
- import java.awt.event.MouseEvent;
- import javax.swing.JComponent;
- import javax.swing.JFrame;
- import javax.swing.JLabel;
- import javax.swing.JLayer;
- import javax.swing.JPanel;
- import javax.swing.JTextField;
- import javax.swing.SwingUtilities;
- import javax.swing.plaf.LayerUI;
- public class BrandedUI
- {
- private static Color PALE_BLUE = new Color (0.0f, 0.0f, 1.0f, 0.3f);
- private static Color PALE_RED = new Color (1.0f, 0.0f, 0.0f, 0.3f);
- private static Font BRAND_FONT = new Font ("Arial", Font.BOLD, 18);
- private static String MSG = "My brand";
- private static JLayer<JPanel> createLayer ()
- {
- LayerUI<JPanel> layerUI;
- layerUI = new LayerUI<JPanel> ()
- {
- private Color color = PALE_BLUE;
- public void installUI (JComponent c)
- {
- super.installUI (c);
- ((JLayer) c).setLayerEventMask (AWTEvent.MOUSE_MOTION_EVENT_MASK);
- }
- public void eventDispatched (AWTEvent e,
- JLayer <? extends JPanel> l)
- {
- MouseEvent me = (MouseEvent) e;
- Point pt = SwingUtilities.convertPoint ((Component) me.getSource (),
- me.getX (), me.getY (), l);
- int cx = l.getWidth ()/2;
- int cy = l.getHeight ()/2;
- if (pt.x > cx-45 && pt.x < cx+45 && pt.y > cy-10 && pt.y < cy+10)
- color = PALE_RED;
- else
- color = PALE_BLUE;
- l.repaint ();
- }
- public void paint (Graphics g, JComponent c)
- {
- // Paint the view.
- super.paint (g, c);
- // Paint the brand.
- g.setColor (color);
- g.setFont (BRAND_FONT);
- int width = g.getFontMetrics ().stringWidth (MSG);
- int height = g.getFontMetrics ().getHeight ();
- g.drawString (MSG, (c.getWidth ()-width)/2,
- c.getHeight ()/2+height/4);
- }
- public void uninstallUI (JComponent c)
- {
- super.uninstallUI (c);
- ((JLayer) c).setLayerEventMask (0);
- }
- };
- // Create a user interface to be decorated.
- JPanel pnlMain = new JPanel ();
- pnlMain.setLayout (new GridLayout (2, 1));
- JPanel pnlTemp = new JPanel ();
- JLabel lblName = new JLabel ("Name:");
- pnlTemp.add (lblName);
- JTextField txtName = new JTextField (20);
- pnlTemp.add (txtName);
- pnlMain.add (pnlTemp);
- pnlTemp = new JPanel ();
- JLabel lblAddr = new JLabel ("Address:");
- pnlTemp.add (lblAddr);
- JTextField txtAddr = new JTextField (20);
- pnlTemp.add (txtAddr);
- pnlMain.add (pnlTemp);
- // Create the layer for the main panel using our custom layerUI.
- return new JLayer<JPanel> (pnlMain, layerUI);
- }
- private static void createAndShowUI ()
- {
- JFrame frame = new JFrame ("Branded UI");
- frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
- frame.add (createLayer ());
- frame.pack ();
- frame.setLocationRelativeTo (null);
- frame.setVisible (true);
- }
- public static void main (String [] args)
- {
- Runnable r = new Runnable ()
- {
- public void run ()
- {
- createAndShowUI ();
- }
- };
- EventQueue.invokeLater (r);
- }
- }
上面的代码渲染UI上的文本印记,我们通常使用印记提醒用户使用的是试用软件,印记文本是半透明的,以便背景可以全部显示,我们不希望这个印记给用户造成太大的干扰。
另一方面,我们希望用户能注意到这个印记,让他们下定决心购买这款软件,清单2中的代码通过改变印记的颜色(改成淡红色)来达到这个目的,当鼠标移到初始值是绿色的印记面板上时,颜色就变成淡红色。