技术开发 频道

Swing最新特性:增加透明窗体及不规则窗体

  视频反射

  现在让我们做些更为激动人心的事情。在 Romain Guy 的博客条目 重画管理器演示(第 11 章) 中,它显示了提供反射功能的 Swing 组件。从他与 Chet Haase 合著的 《 肮脏的富客户机 》 书中抽取一段测试应用程序,其中显示该组件提供了 QuickTime 电影的实时反射。在窗口绑定 之外 进行反射如何?

  首先要有实际应用中的反射帧的屏幕截图。图 6 显示了正在播放 “Get a Mac” 广告的形状规则的 Swing 帧( 使用嵌入式 QuickTime 播放器 ), 伴随着覆盖桌面的透明的实时反射:

图 6. QuickTime 电影的反射

  该实现重用了来自 Romain 的几个构造块并将它们扩展到“桢外”。它还有一个重画管理器 ( 要了解关于重画管理器方面的详细信息,请参见 使用重画管理器的验证覆盖 条目 )以便将主桢内容与反射窗口保持同步。还需要在主桢上注册组件侦听器和窗口侦听器以便确保反射窗口与主窗口的可见性、位置和大小保持同步。除此之外,还要有一个自定义窗格将其内容绘画到脱屏缓冲区。脱屏缓冲区被用于绘画主桢和在反射窗口内的反射。

  让我们看一下代码。主类是扩展 JFrame 的 JReflectionFrame。构造器创建了反射窗口并向其中添加非双重缓冲和透明的面板。还重写了面板的 paintComponent() 以便绘画主桢内容的反射。在初始化反射桢的位置和大小后,我们安装了一个自定义重画管理器。

  public JReflectionFrame(String title) {   super(title);   reflection = new JWindow();   reflectionPanel = new JPanel() {   @Override   protected void paintComponent(Graphics g) {   // paint the reflection of the main window   paintReflection(g);   }   };   // mark the panel as non-double buffered and non-opaque   // to make it translucent.   reflectionPanel.setDoubleBuffered(false);   reflectionPanel.setOpaque(false);   reflection.setLayout(new BorderLayout());   reflection.add(reflectionPanel, BorderLayout.CENTER);   // register listeners - see below   ...   // initialize the reflection size and location   reflection.setSize(getSize());   reflection.setLocation(getX(), getY() + getHeight());   reflection.setVisible(true);   // install custom repaint manager to force re-painting   // the reflection when something in the main window is   // repainted   RepaintManager.setCurrentManager(new ReflectionRepaintManager());   }

  下面是保持反射窗口与主桢同步的侦听器:

  this.addComponentListener(new ComponentAdapter() {   @Override   public void componentHidden(ComponentEvent e) {   reflection.setVisible(false);   }   @Override   public void componentMoved(ComponentEvent e) {   // update the reflection location   reflection.setLocation(getX(), getY() + getHeight());   }   @Override   public void componentResized(ComponentEvent e) {   // update the reflection size and location   reflection.setSize(getWidth(), getHeight());   reflection.setLocation(getX(), getY() + getHeight());   }   @Override   public void componentShown(ComponentEvent e) {   reflection.setVisible(true);   // if the reflection window is opaque, mark   // it as per-pixel translucent   if (com.sun.awt.AWTUtilities.isWindowOpaque(reflection)) {   com.sun.awt.AWTUtilities.setWindowOpaque(reflection, false);   }   }   });   this.addWindowListener(new WindowAdapter() {   @Override   public void windowActivated(WindowEvent e) {   // force showing the reflection window   reflection.setAlwaysOnTop(true);   reflection.setAlwaysOnTop(false);   }   });

  重画管理器相当简单:它强制主桢的整个根窗格重画,然后更新反射窗口。这样可以最优化更新区域反射的同步,对于示例应用程序要达到的目的,这点就足够了。

  private class ReflectionRepaintManager extends RepaintManager {   @Override   public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {   Window win = SwingUtilities.getWindowAncestor(c);   if (win instanceof JReflectionFrame) {   // mark the entire root pane to be repainted   JRootPane rp = ((JReflectionFrame) win).getRootPane();   super.addDirtyRegion(rp, 0, 0, rp.getWidth(), rp.getHeight());   // workaround bug 6670649 - should call reflection.repaint()   // but that will not repaint the panel   reflectionPanel.repaint();   } else {   super.addDirtyRegion(c, x, y, w, h);   }   }   }

  主桢 (脱屏缓冲区) 和反射窗口的绘图代码在 Romain 的 反射教程 中进行了详细描述。

  结束语

  对这一结果我们期待已久,现在终于如愿以偿。尽管创建透明和不规则窗口的 API 还没有官方支持的包,但是它们仍可用于创建可视的富跨平台 UI。从 Romain 的博客 透明和不规则窗口( Extreme GUI Makeover ) 条目展示 JNA 项目,用于创建动画的透明不规则窗口的可视化竞争应用。现在您可以使用核心 JDK 做同样的处理。本文全面介绍了显示实际应用中的核心 JDK API 的三个示例。我确信您能想出更多的例子。

0
相关文章