标题 这Date_selector_panel是重要部分。现在我们来看看他的装饰。Titled_date_selector类只做一件事情:给未装饰的日历增加个标题。这是对实现了Date_selector的JPanel面板的包装。它只显示现有的Date_selector和显示日期的标签。下面的实现是微不足道。和用户界面无相关值得说的只有那其中10行动作监听代码。监听器获取日期改变通知(通过用户导航或者方法调用)便做相应的标签日期更新。其他代码只是简单地创建面板和将Date_selector与JLable标题包装进面板中。 这表明这部分代码易写、易治理比较简单。假如它被混合在Date_selector_panel中,将会在 没有明显的优点的情况下增加了代码的复杂度。(代码有组织地放在某处比全混合在一个地方更加清楚。)假如我想要标题更加美观,只需要修改这一个类即可以实现根本就不需要动其他部分。 public class Titled_date_selector extends JPanel implements Date_selector { private Date_selector selector; private final JLabel title = new JLabel("XXXX"); /** Wrap an existing Date_selector to add a title bar showing * the displayed month and year. The title changes as the * user navigates. */ public Titled_date_selector( Date_selector selector ) { this.selector = selector; title.setHorizontalAlignment(SwingConstants.CENTER); title.setOpaque ( true ); title.setBackground ( com.holub.ui.Colors.LIGHT_YELLOW ); title.setFont ( title.getFont().deriveFont( Font.BOLD ) ); selector.addActionListener ( new ActionListener() { public void actionPerformed( ActionEvent e ) { if( e.getID() == Date_selector_panel.CHANGE_ACTION ) title.setText( e.getActionCommand() ); else my_subscribers.actionPerformed(e); } } ); setOpaque(false); setLayout( new BorderLayout() ); add( title, BorderLayout.NORTH ); add( (JPanel)selector, BorderLayout.CENTER ); } /** This constrUCtor lets you specify the background color of the * title strip that holds the month name and year (the default * is light yellow). * * @param label_background_color the color of the title bar, or * null to make it transparent. */ public Titled_date_selector( Date_selector selector, Color label_background_color ) { this(selector); if( label_background_color == null ) title.setOpaque( false ); else title.setBackground( label_background_color ); } private ActionListener my_subscribers = null; public synchronized void addActionListener(ActionListener l) { my_subscribers = AWTEventMulticaster.add(my_subscribers, l); } public synchronized void removeActionListener(ActionListener l) { my_subscribers = AWTEventMulticaster.remove(my_subscribers, l); } public Date get_selected_date() { return selector.get_selected_date(); } public Date get_current_date() { return selector.get_current_date(); } public void roll(int f, boolean up) { selector.roll(f,up); } public int get(int f) { return selector.get(f); } } NAVIGATION/导航 下面展示的就是导航栏的实现代码,虽然有点长,但同样非常地简单。代码由定义了4个图象文件的代码开始。(我计划以后放弃箭头采用代码实现,但是现在仍然在用图象文件。)用下面的代码,把图象作为资源获取过来。 ClassLoader loader = getClass().getClassLoader(); loader.getResource( "IMAGE_FILE_NAME" ); classloader在找类的地方找图象资源;比如,程序在文件系统中运行,它将要在classpath中查找文件路径。因为没有用到绝对路径,代码是更加轻易的打包成jar文件,并且文件也不再需要建立在文件系统中。导航栏是一个四个用图象做标签的按纽,按纽的动作监听通过Date_selector的roll()来包装日历对象,并且月份的改变也激发标题栏的改变。有一点非常重要就是导航条不知道也不影响标题。标题包装器是一个监听,所以它能自动的更新标题。导航条根本就不知道标题包装器的存在。 public class Navigable_date_selector extends JPanel implements Date_selector { private Date_selector selector; // Names of image files used for the navigator bar private static final String NEXT_YEAR = "images/10px.red.arrow.right.double.gif", NEXT_MONTH = "images/10px.red.arrow.right.gif", PREVIOUS_YEAR = "images/10px.red.arrow.left.double.gif", PREVIOUS_MONTH = "images/10px.red.arrow.left.gif"; // These constants are used to identify the button and // as the button caption in the event that the appropriate // image file can't be located private static final String FORWARD_MONTH = ">" , FORWARD_YEAR = ">>" , BACK_MONTH = "<" , BACK_YEAR = "<<" private JPanel navigation = new JPanel(); public Navigable_date_selector( Date_selector selector ) { this.selector = selector; setBorder( null ); setOpaque( false ); setLayout( new BorderLayout() ); add( (JPanel)selector, BorderLayout.CENTER ); navigation.setLayout(new FlowLayout()); navigation.setBorder( null ); navigation.setBackground( com.holub.ui.Colors.LIGHT_YELLOW ); navigation.add( make_navigation_button(BACK_YEAR ) ); navigation.add( make_navigation_button(BACK_MONTH ) ); navigation.add( make_navigation_button(FORWARD_MONTH) ); navigation.add( make_navigation_button(FORWARD_YEAR ) ); add(navigation, BorderLayout.SOUTH); } // ... // I left out a few constructors and utility methods that go here // ... private final Navigation_handler navigation_listener = new Navigation_handler(); /** Handle clicks from the navigation bar buttons */ private class Navigation_handler implements ActionListener { public void actionPerformed(ActionEvent e) { String direction = e.getActionCommand(); if (direction==FORWARD_YEAR )selector.roll(Calendar.YEAR,true); else if(direction==BACK_YEAR )selector.roll(Calendar.YEAR,false); else if(direction==FORWARD_MONTH) { selector.roll(Calendar.MONTH,true); if( selector.get(Calendar.MONTH) == Calendar.JANUARY ) selector.roll(Calendar.YEAR,true); } else if (direction==BACK_MONTH ) { selector.roll(Calendar.MONTH,false); if( selector.get(Calendar.MONTH) == Calendar.DECEMBER ) selector.roll(Calendar.YEAR,false); } else { assert false: "UneXPected direction"; } } } private JButton make_navigation_button(String caption) { ClassLoader loader = getClass().getClassLoader(); URL image = (cap
|