使用Decorator模式实现日期选择组件(5)

1/5/2008来源:Java教程人气:5724


  弹出对话框
  对话框包装器有2个类组成:第一个是Popup_dialog,继续与JDialog实现小的如前所示的框架。
  生成常规对话框的主要难点是所有的装饰(框架与标题栏)的消失问题,因此假如你需要生成自己的标题栏,下面提供了具体实现的大部分代码:
  标题栏是包含一个显示标题的标签和一个按钮(关闭按钮,如导航箭头一样加载图象资源)。
  代码如下:
  public class Popup_dialog extends JDialog
  {
    PRivate Color TITLE_BAR_COLOR = com.holub.ui.Colors.LIGHT_YELLOW;
    private Color CLOSE_BOX_COLOR = com.holub.ui.Colors.DARK_RED;
  
    private JLabel title = new JLabel("xxxxxxxxxxxxxx");
    {  title.setHorizontalAlignment(SwingConstants.CENTER);
      title.setOpaque( false );
      title.setFont( title.getFont().deriveFont(Font.BOLD) );
    }
  
    private JPanel header = new JPanel();
    {  header.setBackground( TITLE_BAR_COLOR );
      header.setLayout( new BorderLayout() );
      header.setBorder( BorderFactory.createEmptyBorder(2,2,2,2) );
      header.add( title          , BorderLayout.CENTER );
      header.add( create_close_button()  , BorderLayout.EAST  );
    }
  
    private JPanel content_pane = new JPanel();
    {  content_pane.setLayout( new BorderLayout() );
    }
  
    public Popup_dialog( Frame owner ){ super(owner); setModal(true); }
    public Popup_dialog( Dialog owner){ super(owner); setModal(true); }
  
    /* Code common to all constrUCtors. */
    {
      init_dragable();
  
      setUndecorated( true );
      JPanel contents = new JPanel();
      contents.setBorder( BorderFactory.createLineBorder(Color.BLACK,1) );
      contents.setLayout(new BorderLayout());
      contents.add(header,    BorderLayout.NORTH);
      contents.add(content_pane, BorderLayout.CENTER);
      contents.setBackground( Color.WHITE );
  
      setContentPane( contents ); // , BorderLayout.CENTER );
      setLocation(100,100);
    }
  
    private JButton create_close_button()
    {
      URL image = getClass().getClassLoader().getResource(
                          "images/8px.red.X.gif");
  
      JButton b = (image!=null) ? new JButton( new ImageIcon(image) )
                   : new JButton( " X " )
                   
  
      Border outer = BorderFactory.createLineBorder(CLOSE_BOX_COLOR,1);
      Border inner = BorderFactory.createEmptyBorder(2,2,2,2);
  
      b.setBorder( BorderFactory.createCompoundBorder(outer,inner) );
  
      b.setOpaque( false );
      b.addActionListener
      (  new ActionListener()
        {  public void actionPerformed(ActionEvent e)
          {  Popup_dialog.this.setVisible(false);
            Popup_dialog.this.dispose();
          }
        }
      );
  
      b.setFocusable( false );
      return b;
    }
  
    /** Set the dialog title to the indicated text. */
    public void setTitle( String text ){ title.setText( text ); }
  
    /** Add your widgets to the window returned by this method, in
     * a manner similar to a JFrame. Do not modify the Popup_dialog
     * itself. The returned container is a {@link JPanel JPanel}
     * with a preinstalled {@link BorderLayout}.
     * By default, it's colored dialog-box gray.
     * @return the content pane.
     */
  
  
    public Container getContentPane(){ return content_pane; }
  有点意思实现拖拉功能的代码。主要的思路是设置2个监听器。扑捉按纽的鼠标监听器与使用变量reference_position存储鼠标点击在标题标签中的上层窗口位置。
  当鼠标移动时,鼠标移动监听器将被激活。问题是和拖动联系一起的事件一般和屏幕联系在一起而不是和上层窗口联系一起。拉句柄在当前鼠标位置移动对话框到原始的reference_position位置。就象从原始位置拖动窗体到现在鼠标位置一样。
  下面是代码:
  private Point reference_position = new Point(0,0);
  private MouseMotionListener movement_handler;
  private MouseListener click_handler;
  
  private void init_dragable()
  {
    movement_handler =
      new MouseMotionAdapter()
      {  public void mouseDragged( MouseEvent e )
        {  // The reference position is the (window-relative)
          // cursor position when the click occurred. The
          // current_mouse_position is mouse position
          // now, and the deltas represent the distance
          // moved.
  
          Point current_mouse_position = e.getPoint();
          Point current_window_location = getLocation();
  
          int delta_x=current_mouse_position.x - reference_position.x;
          int delta_y=current_mouse_position.y - reference_position.y;
  
          // Move the window over by the computed delta. This move
          // effectively shifts the window-relative, current mouse
          // position back to the original reference position.
  
          current_window_location.translate(delta_x, delta_y);
          setLocation(current_window_location);
        }
      };
  
    click_handler =
      new MouseAdapter()
      {  public void mousePressed( MouseEvent e )
        {  reference_position = e.getPoint(); // Start of the drag
        }
      };
  
    setDragable(true);
  }
  
  /** Turn dragability on or off.
  */
  public void setDragable( boolean on )
  {  if( on )
    {  title.addMouseMotionListener ( movement_handler );
      title.addMouseListener    ( click_handler  );
    }
    else
    {  title.removeMouseMotionListener ( movement_handler );
      title.removeMouseListener    ( click_handler );
    }
  }
  
  
  
  日期对话框
  
    剩下的都是些微不足道的包装。Date_selector_dialog 修饰者把包装的Date_selector放在弹出框中。它从Titled_date_selector中复制了一些代码用来显示对话框标题栏(当前日期和月份)这里根本就没有考虑导航条问题。因为Date_selector已经包含了导航条等等。。
  public class Date_selector_dialog extends Popup_dialog implements Date_selector
  {
    private Date_selector selector = new Date_selector_panel();
  
    /** Creates a dialog box with the indicated parent that holds
     * a standard {@link Date_selector_panel Date_selector_panel}
     * (as created using the no-arg constructor).
     */
    public Date_selector_dialog( Frame parent )
    {  super(parent);
      selector = new Navigable_date_selector( new Date_selector_panel() );
      init();
    }
  
    /* Like {@link #Date_selector_dialog(Frame),
     * but for a {@link Dialog} parent.
     */
    public Date_selector_dialog( Dialog parent )
    {  super(parent);
      selector = new Navigable_date_selector( new Date_selector_panel() );
      init();
    }
  
    /** Creates a dialog box with the indicated parent that holds
     * the indicated Date_selector.
     * Note that the current month and year display in the
     * dialog-box title bar, so there's no need to display them in
     * the selector