SWT做的一个日历控件

时间:2021-08-12 20:35:59

    下面是我用SWT写的一个日历控件,主要是用于让用记选择日期,可以通过按钮 上一年、下一年、上一月 和 下一月 调整到要切换的月份,也可以通过改 年 和 月 的下拉框中的选择项来切换到指定年月,还可以直接在 年 和 月 的下拉框中输入要切换到的年月后按 回车键 切换到指定年月。运行后的效果如下图所示:

SWT做的一个日历控件

 

    源代码如下:

  1. package com.hmw.tools;
  2. import java.util.Calendar;
  3. import org.eclipse.swt.SWT;
  4. import org.eclipse.swt.custom.CLabel;
  5. import org.eclipse.swt.events.KeyAdapter;
  6. import org.eclipse.swt.events.KeyEvent;
  7. import org.eclipse.swt.events.KeyListener;
  8. import org.eclipse.swt.events.MouseAdapter;
  9. import org.eclipse.swt.events.MouseEvent;
  10. import org.eclipse.swt.events.MouseListener;
  11. import org.eclipse.swt.events.SelectionAdapter;
  12. import org.eclipse.swt.events.SelectionEvent;
  13. import org.eclipse.swt.events.SelectionListener;
  14. import org.eclipse.swt.graphics.Color;
  15. import org.eclipse.swt.graphics.Rectangle;
  16. import org.eclipse.swt.layout.GridData;
  17. import org.eclipse.swt.layout.GridLayout;
  18. import org.eclipse.swt.widgets.Button;
  19. import org.eclipse.swt.widgets.Combo;
  20. import org.eclipse.swt.widgets.Display;
  21. import org.eclipse.swt.widgets.Shell;
  22. /**
  23.  * 日历弹出窗口
  24.  *
  25.  * @author Carl He
  26.  *
  27.  */
  28. public class CalendarWidget{
  29.     /** 显示对象 */
  30.     private Display display = null;
  31.     /** 窗口对象 */
  32.     private Shell shell = null;
  33.     /** 窗口的宽度 */
  34.     private static final int SHELLWIDTH = 380;
  35.     /** 窗口的高度 */
  36.     private static final int SHELLHEIGHT = 280;
  37.     /**Clabel大小的宽度*/
  38.     private static final int GRIDDATAHINT = 20;
  39.     /** 上一年 */
  40.     private static final String TOOPTIPTEXT_PREVIOUSYEAR = "上一年";
  41.     /** 下一年 */
  42.     private static final String TOOPTIPTEXT_NEXTYEAR = "下一年";
  43.     /** 上一月 */
  44.     private static final String TOOPTIPTEXT_PREVIOUSMONTH = "上一月";
  45.     /** 下一月 */
  46.     private static final String TOOPTIPTEXT_NEXTMONTH = "下一月";
  47.     /** 星期日 —— 星期六 */
  48.     private static final String[] weekdays = { "星期日""星期一""星期二""星期三",
  49.             "星期四""星期五""星期六" };
  50.     /**年下拉框显示到当前年的前后多少年*/
  51.     private static final int halfYearItemCount = 20;
  52.     /**年份下拉框选项的数组*/
  53.     private static final String[] years = new String[halfYearItemCount*2+1];
  54.     /**月份:1 —— 12 */
  55.     private static final String[] months = { "1""2""3""4","5""6""7""8""9""10","11""12",};
  56.     /**选择的日期:yyyy-MM-dd*/
  57.     private String selectedDate="";
  58.     /**年的下拉框*/
  59.     Combo cbo_year;
  60.     /**月的下拉框*/
  61.     Combo cbo_month;
  62. /**显示日的Clable数组*/
  63.     private final CLabel[] clbl_days = new CLabel[42]; // 6 * 7
  64.     /** 日历窗体的背景颜色*/
  65.     private Color COLOR_SHELL_BACKGROUND = null;
  66.     /** 星期X标签的背景颜色*/
  67.     private Color COLOR_CLBLWEEKDAY_BACKGROUND = null;
  68.     /** 白色(得到的为系统的颜色,不需要对其进行资源释放)*/
  69.     private Color COLOR_SYSTEM_WHITE = null;
  70.     /** 蓝色(得到的为系统的颜色,不需要对其进行资源释放)*/
  71.     private Color COLOR_SYSTEM_BLUE = null;
  72.     public CalendarWidget(Shell parent) {
  73.         Rectangle parentRec = parent.getBounds();
  74.         display = parent.getDisplay();
  75.         COLOR_SHELL_BACKGROUND = new Color(display,219235250);
  76.         COLOR_CLBLWEEKDAY_BACKGROUND = new Color(display, 64128128);
  77.         COLOR_SYSTEM_WHITE = display.getSystemColor(SWT.COLOR_WHITE);
  78.         COLOR_SYSTEM_BLUE = display.getSystemColor(SWT.COLOR_BLUE);
  79.         shell = new Shell(parent, SWT.CLOSE | SWT.APPLICATION_MODAL);
  80.         shell.setText("选择日期");
  81.         // 保证显示在父窗体的正中间
  82.         shell.setBounds(parentRec.x + (parentRec.width - SHELLWIDTH) / 2,
  83.                 parentRec.y + (parentRec.height - SHELLHEIGHT) / 2, SHELLWIDTH,
  84.                 SHELLHEIGHT);
  85.         GridLayout gridLayout = new GridLayout();
  86.         gridLayout.numColumns = 7;
  87.         gridLayout.makeColumnsEqualWidth = true;
  88.         shell.setLayout(gridLayout);
  89.         shell.setBackground(COLOR_SHELL_BACKGROUND);
  90.         // 上一年
  91.         Button btn_yearPrevious = new Button(shell, SWT.ARROW | SWT.UP);
  92.         btn_yearPrevious.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  93.         btn_yearPrevious.setToolTipText(TOOPTIPTEXT_PREVIOUSYEAR);
  94.         btn_yearPrevious.addSelectionListener(btnSelectionListener);
  95.         // 上一月
  96.         Button btn_monthPrevious = new Button(shell, SWT.ARROW | SWT.LEFT);
  97.         btn_monthPrevious.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  98.         btn_monthPrevious.setToolTipText(TOOPTIPTEXT_PREVIOUSMONTH);
  99.         btn_monthPrevious.addSelectionListener(btnSelectionListener);
  100.         cbo_year = new Combo(shell, SWT.DROP_DOWN);
  101.         cbo_year.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  102.         cbo_year.addSelectionListener(cboSelectionListener);
  103.         cbo_year.addKeyListener(cboKeyListener);
  104.         CLabel clabel = new CLabel(shell, SWT.CENTER | SWT.SHADOW_OUT);
  105.         clabel.setBackground(COLOR_SYSTEM_WHITE);
  106.         clabel.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  107.         clabel.setText("-");
  108.         cbo_month = new Combo(shell, SWT.DROP_DOWN);
  109.         cbo_month.setItems(months);
  110.         cbo_month.select(Calendar.getInstance().get(Calendar.MONTH));
  111.         cbo_month.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  112.         cbo_month.addSelectionListener(cboSelectionListener);
  113.         cbo_month.addKeyListener(cboKeyListener);
  114.         // 下一月
  115.         Button btn_monthNext = new Button(shell, SWT.ARROW | SWT.RIGHT);
  116.         btn_monthNext.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  117.         btn_monthNext.setToolTipText(TOOPTIPTEXT_NEXTMONTH);
  118.         btn_monthNext.addSelectionListener(btnSelectionListener);
  119.         // 下一年
  120.         Button btn_yearNext = new Button(shell, SWT.ARROW | SWT.DOWN);
  121.         btn_yearNext.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,true,false));
  122.         btn_yearNext.setToolTipText(TOOPTIPTEXT_NEXTYEAR);
  123.         btn_yearNext.addSelectionListener(btnSelectionListener);
  124.         GridData gridData_1 = null;
  125.         // 将 星期日 —— 星期六 的标签显示出来
  126.         for (int i = 0; i < weekdays.length; i++) {
  127.             CLabel clbl_weekDay = new CLabel(shell, SWT.CENTER | SWT.SHADOW_OUT);
  128.             clbl_weekDay.setForeground(COLOR_SYSTEM_WHITE);
  129.             clbl_weekDay.setBackground(COLOR_CLBLWEEKDAY_BACKGROUND);
  130.             gridData_1 = new GridData(SWT.FILL,SWT.CENTER,true,false);
  131.             gridData_1.widthHint = GRIDDATAHINT;
  132.             gridData_1.heightHint = GRIDDATAHINT;
  133.             clbl_weekDay.setLayoutData(gridData_1);
  134.             clbl_weekDay.setText(weekdays[i]);
  135.         }
  136.         // 将当月的所有 日 的标签显示出来
  137.         for (int i = 0; i < clbl_days.length; i++) {
  138.             clbl_days[i] = new CLabel(shell, SWT.FLAT | SWT.CENTER);
  139.             clbl_days[i].setLayoutData(new GridData(GridData.FILL_HORIZONTAL
  140.                     | GridData.FILL_VERTICAL));
  141.             clbl_days[i].setCursor(display.getSystemCursor(SWT.CURSOR_HAND));
  142.             clbl_days[i].addMouseListener(clblMouseListener);
  143.         }
  144.     }
  145.     /**
  146.      * 给年的下拉框设置设置选项
  147.      * @param middleYear 中间年份
  148.      */
  149.     private void setCboYearItems(int middleYear){
  150.         int selectIndex = halfYearItemCount;
  151.         //确保不出现负的年份
  152.         if(middleYear < halfYearItemCount){
  153.             selectIndex = middleYear;
  154.             middleYear =  halfYearItemCount;
  155.         }
  156.         int index = 0;
  157.         for (int i = middleYear-halfYearItemCount; i <= middleYear+halfYearItemCount; i++) {
  158.             years[index++] = ""+i;
  159.         }
  160.         cbo_year.setItems(years);
  161.         cbo_year.select(selectIndex);
  162.     }
  163.     /**
  164.      * 得到指定年月的天数
  165.      *
  166.      * @param year
  167.      *            年
  168.      * @param month
  169.      *            月(1-12)
  170.      * @return 指定年月的天数,如:year=2008,month=1 就返回 2008年1月的天数:31
  171.      */
  172.     private int getDayCountOfMonth(int year, int month) {
  173.         Calendar cal = Calendar.getInstance();
  174.         cal.set(year, month - 11); // 因为 Calendar中的 month 是 0-11,故month要减去1
  175.         Calendar cal2 = (Calendar) cal.clone();
  176.         cal2.add(Calendar.MONTH, 1);
  177.         cal2.add(Calendar.DAY_OF_MONTH, -1);
  178.         return cal2.get(Calendar.DAY_OF_MONTH);
  179.     }
  180.     /**
  181.      * 得到下拉框中的年和月
  182.      */
  183.     private int[] getYearAndMonth(){
  184.         Calendar now = Calendar.getInstance();
  185.         int year = now.get(Calendar.YEAR); //年
  186.         int month = now.get(Calendar.MONTH)+1//月
  187.         if("".equals(cbo_year.getText().trim()))
  188.             cbo_year.setText(year+"");
  189.         else{
  190.             try {
  191.                 year = Integer.parseInt(cbo_year.getText().trim());
  192.             } catch (NumberFormatException e) {
  193.                 //年 下拉框中的文本不是一个Int型数字,则设为当前年
  194.                 cbo_year.setText(year+"");
  195.             }
  196.         }
  197.         if("".equals(cbo_month.getText().trim()))
  198.             cbo_month.setText(month+"");
  199.         else{
  200.             try {
  201.                 month = Integer.parseInt(cbo_month.getText().trim());
  202.                 if(month<1){
  203.                     month = 1;
  204.                     cbo_month.setText("1");
  205.                 }else if(month>12){
  206.                     month = 12;
  207.                     cbo_month.setText("12");
  208.                 }
  209.             } catch (NumberFormatException e) {
  210. //              月 下拉框中的文本不是一个Int型数字,则设为当前月
  211.                 cbo_month.setText(month+"");
  212.             }
  213.         }
  214.         return new int[]{year, month};
  215.     }
  216.     /**
  217.      * 为所有的 日 标签设置相关属性
  218.      * @param reflushCboYearItems 是否刷新年下拉框中的选项
  219.      */
  220.     private void displayClblDays(boolean reflushCboYearItems) {
  221.         Calendar calendar = Calendar.getInstance();
  222.         int currentDate = calendar.get(Calendar.DATE); // 日
  223.         int[] yearAndMonth = getYearAndMonth();
  224.         int year = yearAndMonth[0]; //年
  225.         int month = yearAndMonth[1]; //月
  226.         calendar.set(year,month-1,1); //Calendar中的month为0-11,故在此处month要减去1
  227.         int beginIndex = calendar.get(Calendar.DAY_OF_WEEK) - 1//得到指定月份的第一天为星期几,Calendar对象返回的1-7对应星期日-星期六,故减去1
  228.         int endIndex = beginIndex + getDayCountOfMonth(year, month) - 1;
  229.         if(reflushCboYearItems)
  230.             setCboYearItems(year);
  231.         int day=1;
  232.         for (int i = 0; i < clbl_days.length; i++) {
  233.             if (i >= beginIndex && i <= endIndex) {
  234.                 clbl_days[i].setText(day + "");
  235.                 clbl_days[i].setToolTipText(year + "-" + month+"-"+day);
  236.                 if (day == currentDate)
  237.                     clbl_days[i].setBackground(COLOR_SYSTEM_BLUE);
  238.                 else
  239.                     clbl_days[i].setBackground(COLOR_SYSTEM_WHITE);
  240.                 day++;
  241.             } else {
  242.                 clbl_days[i].setText("");
  243.                 clbl_days[i].setToolTipText("");
  244.                 clbl_days[i].setBackground(COLOR_SYSTEM_WHITE);
  245.             }
  246.         }
  247.     }
  248.     public String open() {
  249.         displayClblDays(true);
  250.         shell.open();
  251.         while (!shell.isDisposed()) {
  252.             if (!display.readAndDispatch()) {
  253.                 display.sleep();
  254.             }
  255.         }
  256.         COLOR_SHELL_BACKGROUND.dispose();
  257.         COLOR_CLBLWEEKDAY_BACKGROUND.dispose();
  258.         return selectedDate;
  259.     }
  260.     private MouseListener clblMouseListener = new MouseAdapter() {
  261.         /*
  262.          * (non-Javadoc)
  263.          *
  264.          * @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent)
  265.          */
  266.         @Override
  267.         public void mouseDown(MouseEvent e) {
  268.             selectedDate = ((CLabel) e.widget).getToolTipText();
  269.             if (!"".equals(selectedDate))
  270.                 shell.close();
  271.         }
  272.     };
  273.     private SelectionListener btnSelectionListener = new SelectionAdapter() {
  274.         public void widgetSelected(SelectionEvent e) {
  275.             String tooptip = ((Button)e.widget).getToolTipText();
  276.             int[] yearAndMonth = getYearAndMonth();
  277.             int year = yearAndMonth[0];
  278.             int month = yearAndMonth[1];
  279.             boolean reflushCboyearItems = true;
  280.             //前一年
  281.             if(TOOPTIPTEXT_PREVIOUSYEAR.equals(tooptip))
  282.                 cbo_year.setText((year-1)+"" );
  283.             //后一年
  284.             else if(TOOPTIPTEXT_NEXTYEAR.equals(tooptip))
  285.                 cbo_year.setText((year+1)+"" );
  286.             //前一月
  287.             else if(TOOPTIPTEXT_PREVIOUSMONTH.equals(tooptip)){
  288.                 if(month == 1){
  289.                     setCboYearItems(year-1 );
  290.                     cbo_month.select(11);
  291.                 }else{
  292.                     cbo_month.select(month-2);
  293.                     reflushCboyearItems = false;
  294.                 }
  295.                 //后一月
  296.             }else if(TOOPTIPTEXT_NEXTMONTH.equals(tooptip)){
  297.                 if(month == 12){
  298.                     setCboYearItems(year+1 );
  299.                     cbo_month.select(0);
  300.                 }else{
  301.                     cbo_month.select(month);
  302.                     reflushCboyearItems =  false;
  303.                 }
  304.             }
  305.             displayClblDays(reflushCboyearItems);
  306.         }
  307.     };
  308.     private SelectionListener cboSelectionListener = new SelectionAdapter() {
  309.         public void widgetSelected(SelectionEvent e) {
  310.             boolean reflushCboyearItems = e.widget == cbo_year ? true : false;
  311.             displayClblDays(reflushCboyearItems);
  312.         }
  313.     };
  314.     private KeyListener cboKeyListener = new KeyAdapter(){
  315.         /* (non-Javadoc)
  316.          * @see org.eclipse.swt.events.KeyAdapter#keyPressed(org.eclipse.swt.events.KeyEvent)
  317.          */
  318.         @Override
  319.         public void keyPressed(KeyEvent event) {
  320.             //小键盘的Enter或Enter,显示日历
  321.             if (event.keyCode == 16777296 || event.keyCode == 13) {
  322.                 boolean reflushCboyearItems = event.widget == cbo_year ? true : false;
  323.                 displayClblDays(reflushCboyearItems);
  324.             }else{
  325.                 //只能输入数字
  326.                 if((event.keyCode<'0' || event.keyCode >'9') && !(event.keyCode == SWT.BS || event.keyCode == SWT.ARROW_UP || event.keyCode == SWT.ARROW_DOWN))
  327.                     event.doit = false;
  328.             }
  329.         }
  330.     };
  331.     public static void main(String args[]) {
  332.         try {
  333.             Display display = Display.getDefault();
  334.             Shell shell = new Shell(display, SWT.SHELL_TRIM);
  335.             shell.setSize(500375);
  336.             shell.open();
  337.             shell.layout();
  338.             CalendarWidget ca = new CalendarWidget(shell);
  339.             System.out.println(ca.open());
  340.             while (!shell.isDisposed()) {
  341.                 if (!display.readAndDispatch())
  342.                     display.sleep();
  343.             }
  344.         } catch (Exception e) {
  345.             e.printStackTrace();
  346.         }
  347.     }
  348. }