天天看点

Java GUI实现的日期时间选择器

package cn.edu.hactcm;

import java.awt.basicstroke;

import java.awt.borderlayout;

import java.awt.color;

import java.awt.component;

import java.awt.cursor;

import java.awt.dimension;

import java.awt.font;

import java.awt.graphics;

import java.awt.graphics2d;

import java.awt.gridlayout;

import java.awt.point;

import java.awt.polygon;

import java.awt.stroke;

import java.awt.toolkit;

import java.awt.event.focusevent;

import java.awt.event.focuslistener;

import java.awt.event.mouseadapter;

import java.awt.event.mouseevent;

import java.awt.event.mouselistener;

import java.awt.event.mousemotionlistener;

import java.text.simpledateformat;

import java.util.arraylist;

import java.util.calendar;

import java.util.comparator;

import java.util.date;

import java.util.list;

import javax.swing.borderfactory;

import javax.swing.jbutton;

import javax.swing.jframe;

import javax.swing.jlabel;

import javax.swing.jpanel;

import javax.swing.popup;

import javax.swing.popupfactory;

import javax.swing.swingutilities;

import javax.swing.event.ancestorevent;

import javax.swing.event.ancestorlistener;

/**

*

* @author hadeslee

*/

public class datechooser extends jpanel{

    private date initdate;

    private calendar now=calendar.getinstance();

    private calendar select;

    private jpanel monthpanel;//月历

    private jp1 jp1;//四块面板,组成

    private jp2 jp2;

    private jp3 jp3;

    private jp4 jp4;

    private font font=new font("宋体",font.plain,12);

    private final labelmanager lm=new labelmanager();

    private jlabel showdate;//,toselect;

    private simpledateformat sdf=new simpledateformat("yyyy年mm月dd日");

    private boolean isshow=false;

    private popup pop;

    /**

     * creates a new instance of datechooser

     */

    public datechooser() {

        this(new date());

    }

    public datechooser(date date){

        initdate=date;

        select=calendar.getinstance();

        select.settime(initdate);

        initpanel();

        initlabel();

    public void setenabled(boolean b){

        super.setenabled(b);

        showdate.setenabled(b);

     *得到当前选择框的日期

    public date getdate(){

        return select.gettime();

    //根据初始化的日期,初始化面板

    private void initpanel(){

        monthpanel=new jpanel(new borderlayout());

        monthpanel.setborder(borderfactory.createlineborder(color.blue));

        jpanel up=new jpanel(new borderlayout());

        up.add(jp1=new jp1(),borderlayout.north);

        up.add(jp2=new jp2(),borderlayout.center);

        monthpanel.add(jp3=new jp3(),borderlayout.center);

        monthpanel.add(up,borderlayout.north);

        monthpanel.add(jp4=new jp4(),borderlayout.south);

        this.addancestorlistener(new ancestorlistener(){

            public void ancestoradded(ancestorevent event) {

            }

            public void ancestorremoved(ancestorevent event) {

            //只要祖先组件一移动,马上就让popup消失

            public void ancestormoved(ancestorevent event) {

                hidepanel();

        });

    //初始化标签

    private void initlabel(){

        showdate=new jlabel(sdf.format(initdate));

        showdate.setrequestfocusenabled(true);

        showdate.addmouselistener(new mouseadapter(){

            public void mousepressed(mouseevent me){

                showdate.requestfocusinwindow();

// toselect=new jlabel(sdf.format(initdate));

// toselect.setborder(borderfactory.createlineborder(color.black));

// toselect.setrequestfocusenabled(true);

        this.setbackground(color.white);

        this.add(showdate,borderlayout.center);

// this.add(toselect,borderlayout.east);

        this.setpreferredsize(new dimension(90,25));

        this.setborder(borderfactory.createlineborder(color.gray));

            public void mouseentered(mouseevent me){

                if(showdate.isenabled()){

                    showdate.setcursor(new cursor(cursor.hand_cursor));

                    showdate.setforeground(color.red);

                }

            public void mouseexited(mouseevent me){

                    showdate.setcursor(new cursor(cursor.default_cursor));

                    showdate.setforeground(color.black);

                    showdate.setforeground(color.cyan);

                    if(isshow){

                        hidepanel();

                    }else{

                        showpanel(showdate);

                    }

            public void mousereleased(mouseevent me){

        showdate.addfocuslistener(new focuslistener(){

            public void focuslost(focusevent e){

            public void focusgained(focusevent e){

    //根据新的日期刷新

    private void refresh(){

        jp1.updatedate();

        jp3.updatedate();

        swingutilities.updatecomponenttreeui(this);

    //提交日期

    private void commit(){

        system.out.println("选中的日期是:"+sdf.format(select.gettime()));

        showdate.settext(sdf.format(select.gettime()));

        hidepanel();

    private void hidepanel(){

        if(pop!=null){

            isshow=false;

            pop.hide();

            pop=null;

        }

    private void showpanel(component owner){

        point show=new point(0,showdate.getheight());

        swingutilities.convertpointtoscreen(show,showdate);

        dimension size=toolkit.getdefaulttoolkit().getscreensize();

        int x=show.x;

        int y=show.y;

        if(x<0){

            x=0;

        if(x>size.width-295){

            x=size.width-295;

        if(y<size.height-170){

        }else{

            y-=188;

        pop=popupfactory.getsharedinstance().getpopup(owner,monthpanel,x,y);

        pop.show();

        isshow=true;

    private class jp1 extends jpanel{

        jlabel left,right,center;

        public jp1(){

            super(new borderlayout());

            this.setbackground(new color(160,185,215));

            initjp1();

        private void initjp1(){

            left=new jlabel(" << ",jlabel.center);

            left.settooltiptext("上一月");

            right=new jlabel(" >> ",jlabel.center);

            right.settooltiptext("下一月");

            left.setborder(borderfactory.createemptyborder(10,0,0,0));

            right.setborder(borderfactory.createemptyborder(10,0,0,0));

            center=new jlabel("",jlabel.center);

            updatedate();

            this.add(left,borderlayout.west);

            this.add(center,borderlayout.center);

            this.add(right,borderlayout.east);

            this.setpreferredsize(new dimension(295,25));

            left.addmouselistener(new mouseadapter(){

                public void mouseentered(mouseevent me){

                    left.setcursor(new cursor(cursor.hand_cursor));

                    left.setforeground(color.red);

                public void mouseexited(mouseevent me){

                    left.setcursor(new cursor(cursor.default_cursor));

                    left.setforeground(color.black);

                public void mousepressed(mouseevent me){

                    select.add(calendar.month,-1);

                    left.setforeground(color.white);

                    refresh();

                public void mousereleased(mouseevent me){

            });

            right.addmouselistener(new mouseadapter(){

                    right.setcursor(new cursor(cursor.hand_cursor));

                    right.setforeground(color.red);

                    right.setcursor(new cursor(cursor.default_cursor));

                    right.setforeground(color.black);

                    select.add(calendar.month,1);

                    right.setforeground(color.white);

        private void updatedate(){

            center.settext(select.get(calendar.year)+"年"+(select.get(calendar.month)+1)+"月");

    private class jp2 extends jpanel{

        public jp2(){

            this.setpreferredsize(new dimension(295,20));

        protected void paintcomponent(graphics g){

            g.setfont(font);

            g.drawstring("星期日 星期一 星期二 星期三 星期四 星期五 星期六",5,10);

            g.drawline(0,15,getwidth(),15);

    private class jp3 extends jpanel{

        public jp3(){

            super(new gridlayout(6,7));

            this.setpreferredsize(new dimension(295,100));

            initjp3();

        private void initjp3(){

        public void updatedate(){

            this.removeall();

            lm.clear();

            date temp=select.gettime();

            calendar select=calendar.getinstance();

            select.settime(temp);

            select.set(calendar.day_of_month,1);

            int index=select.get(calendar.day_of_week);

            int sum=(index==1?8:index);

            select.add(calendar.day_of_month,0-sum);

            for(int i=0;i<42;i++){

                select.add(calendar.day_of_month,1);

                lm.addlabel(new mylabel(select.get(calendar.year),

                        select.get(calendar.month),select.get(calendar.day_of_month)));

            for(mylabel my:lm.getlabels()){

                this.add(my);

    private class mylabel extends jlabel implements comparator<mylabel>,

            mouselistener,mousemotionlistener{

        private int year,month,day;

        private boolean isselected;

        public mylabel(int year,int month,int day){

            super(""+day,jlabel.center);

            this.year=year;

            this.day=day;

            this.month=month;

            this.addmouselistener(this);

            this.addmousemotionlistener(this);

            this.setfont(font);

            if(month==select.get(calendar.month)){

                this.setforeground(color.black);

            }else{

                this.setforeground(color.light_gray);

            if(day==select.get(calendar.day_of_month)){

                this.setbackground(new color(160,185,215));

                this.setbackground(color.white);

        public boolean getisselected(){

            return isselected;

        public void setselected(boolean b,boolean isdrag){

            isselected=b;

            if(b&&!isdrag){

                int temp=select.get(calendar.month);

                select.set(year,month,day);

                if(temp==month){

                    swingutilities.updatecomponenttreeui(jp3);

                }else{

            this.repaint();

            if(day==select.get(calendar.day_of_month)&&

                    month==select.get(calendar.month)){

                //如果当前日期是选择日期,则高亮显示

                g.setcolor(new color(160,185,215));

                g.fillrect(0,0,getwidth(),getheight());

            if(year==now.get(calendar.year)&&

                    month==now.get(calendar.month)&&

                    day==now.get(calendar.day_of_month)){

                //如果日期和当前日期一样,则用红框

                graphics2d gd=(graphics2d)g;

                gd.setcolor(color.red);

                polygon p=new polygon();

                p.addpoint(0,0);

                p.addpoint(getwidth()-1,0);

                p.addpoint(getwidth()-1,getheight()-1);

                p.addpoint(0,getheight()-1);

                gd.drawpolygon(p);

            if(isselected){//如果被选中了就画出一个虚线框出来

                stroke s=new basicstroke(1.0f,basicstroke.cap_square,

                        basicstroke.join_bevel,1.0f,new float[]{2.0f,2.0f},1.0f);

                gd.setstroke(s);

                gd.setcolor(color.black);

            super.paintcomponent(g);

        public boolean contains(point p){

            return this.getbounds().contains(p);

        private void update(){

            repaint();

        public void mouseclicked(mouseevent e) {

        public void mousepressed(mouseevent e) {

            isselected=true;

            update();

        public void mousereleased(mouseevent e) {

            point p=swingutilities.convertpoint(this,e.getpoint(),jp3);

            lm.setselect(p,false);

            commit();

        public void mouseentered(mouseevent e) {

        public void mouseexited(mouseevent e) {

        public void mousedragged(mouseevent e) {

            lm.setselect(p,true);

        public void mousemoved(mouseevent e) {

        public int compare(mylabel o1, mylabel o2) {

            calendar c1=calendar.getinstance();

            c1.set(o1.year,o2.month,o1.day);

            calendar c2=calendar.getinstance();

            c2.set(o2.year,o2.month,o2.day);

            return c1.compareto(c2);

    private class labelmanager{

        private list<mylabel> list;

        public labelmanager(){

            list=new arraylist<mylabel>();

        public list<mylabel> getlabels(){

            return list;

        public void addlabel(mylabel my){

            list.add(my);

        public void clear(){

            list.clear();

        public void setselect(mylabel my,boolean b){

            for(mylabel m:list){

                if(m.equals(my)){

                    m.setselected(true,b);

                    m.setselected(false,b);

        public void setselect(point p,boolean b){

            //如果是拖动,则要优化一下,以提高效率

            if(b){

                //表示是否能返回,不用比较完所有的标签,能返回的标志就是把上一个标签和

                //将要显示的标签找到了就可以了

                boolean findprevious=false,findnext=false;

                for(mylabel m:list){

                    if(m.contains(p)){

                        findnext=true;

                        if(m.getisselected()){

                            findprevious=true;

                        }else{

                            m.setselected(true,b);

                        }

                    }else if(m.getisselected()){

                        findprevious=true;

                        m.setselected(false,b);

                    if(findprevious&&findnext){

                        return;

                mylabel temp=null;

                        temp=m;

                if(temp!=null){

                    temp.setselected(true,b);

    private class jp4 extends jpanel{

        public jp4(){

            simpledateformat sdf=new simpledateformat("yyyy年mm月dd日");

            final jlabel jl=new jlabel("今天: "+sdf.format(new date()));

            jl.settooltiptext("点击回到今天日期");

            this.add(jl,borderlayout.center);

            jl.addmouselistener(new mouseadapter(){

                    jl.setcursor(new cursor(cursor.hand_cursor));

                    jl.setforeground(color.red);

                    jl.setcursor(new cursor(cursor.default_cursor));

                    jl.setforeground(color.black);

                    jl.setforeground(color.white);

                    select.settime(new date());

                    commit();

    public static void main(string[] args) {

        final datechooser mp=new datechooser();

        jframe jf=new jframe("test");

        jf.add(mp,borderlayout.center);

        jf.add(new jbutton("测试用的"),borderlayout.north);

        jf.pack();

        jf.setlocationrelativeto(null);

        jf.setvisible(true);

        jf.setdefaultcloseoperation(jframe.exit_on_close);

}