Java Swing JXDatePicker

5
我正在使用SwingX JXDatePicker,但我无法找到如何提供下一个/上一个年份按钮(因为默认情况下它只提供下一个/上一个月份按钮)。
另外,似乎SwingX不再维护了:我应该使用更近期的日期选择器组件吗?
非常感谢任何帮助/提示。 谢谢,Thomas
更新: 为了澄清问题,我添加了JXDatePicker截图,并在红色部分突出显示了下一个/上一个月份按钮。 问题是:如何添加按钮,以便将日历调整到下一年/上一年? 请注意,新按钮需要是标准组件,因为它们需要由特定的外观管理器(在这种情况下是Insusbtantial)呈现。
非常感谢

请查看这个问题,以获取最新的备选方案列表。我建议尝试其中一些。 - Kezz
它正在维护 - 当前版本为1.6.5-1,但我不明白你想要什么:你到底想要什么?为什么swingx演示中描述的定制(项目页面上的Webstartable链接)没有帮助? - kleopatra
@MrD为什么要传播无关的链接?那个链接与完全无关的问题有关... - kleopatra
谢谢提示。SwingX演示没有提供“下一年/上一年”按钮的示例(它只有标准的下一个/上一个月)。我错过了什么吗?谢谢。 - Tom
5个回答

5

我知道这是一个老问题,但我最终在kleopatra关于SwingsLab演示的评论中找到了答案。

SwingsLab演示提供了一个示例,展示如何按组件设置自定义日历标题,但这是我实际使用的代码(全局;适用于整个应用程序):

UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
datePicker = new JXDatePicker();
datePicker.getMonthView().setZoomable(true); //this is needed for custom header

这似乎是实验性代码(尚未完全公开),因此使用时需自行承担风险。希望它有所帮助。 SwingsLab演示

不错,有人“真正”查看了演示 :-) - kleopatra
@Radiace Wei Q Ong,感谢您的帖子,但是使用您的代码并没有像您在图片中展示的那样显示年份。我有同样的需求。 - Syed Muhammad Mubashir
@Syed Muhammad Mubashir,这对我有效。也许您可以尝试在SwingsLab演示中运行代码?图片来自演示。 - Radiance Wei Qi Ong

2

这是我几年前整理的内容。您可以根据自己的需求进行修改。

在此输入图片描述

您需要这张图片来运行主要测试:日历图标。只需将其与源代码放在同一目录下,并将名称命名为datepicker.gif。

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Popup;
import javax.swing.PopupFactory;

public class DatePicker extends JPanel {

    private static final long serialVersionUID = 1L;

    protected boolean controlsOnTop;
    protected boolean removeOnDaySelection;

    protected Calendar currentDisplayDate;

    protected JButton prevMonth;
    protected JButton nextMonth;
    protected JButton prevYear;
    protected JButton nextYear;

    protected JTextField textField;

    protected List<ActionListener> popupListeners = 
        new ArrayList<ActionListener>();

    protected Popup popup;

    protected SimpleDateFormat dayName   = new SimpleDateFormat("d");
    protected SimpleDateFormat monthName = new SimpleDateFormat("MMMM");

    protected String iconFile = "datepicker.gif";
    protected String[] weekdayNames = 
        {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    public DatePicker() {
        super();
        currentDisplayDate   = Calendar.getInstance();
        controlsOnTop        = true;
        removeOnDaySelection = true;
        createPanel();
    }

    public DatePicker(Calendar date) {
        super();
        setDate(date);
        controlsOnTop        = true;
        removeOnDaySelection = true;
        createPanel();
    }

    public DatePicker(int month, int day, int year) {
        super();
        setDate(month, day, year);
        controlsOnTop        = true;
        removeOnDaySelection = true;
        createPanel();
    }

    public void setDate(String date) {
        currentDisplayDate = Calendar.getInstance();
        editDate(date);
    }

    public void setDate(Calendar date) {
        currentDisplayDate = date;
        createPanel();
        validate();
        repaint();
    }

    public void setDate(int month, int day, int year) {
        currentDisplayDate = Calendar.getInstance();
        currentDisplayDate.set(expandYear(year), month - 1, day);
        createPanel();
        validate();
        repaint();
    }

    protected int expandYear(int year) {
        if (year < 100) {                   // 2 digit year
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            int current2DigitYear = currentYear % 100;
            int currentCentury    = currentYear / 100 * 100;
            // set 2 digit year range +20 / -80 from current year
            int high2DigitYear    = (current2DigitYear + 20) % 100;
            if (year <= high2DigitYear) {
                year += currentCentury;
            }
            else {
                year += (currentCentury - 100);
            }
        }
        return year;
    }

    public void setControlsOnTop(boolean flag) {
        controlsOnTop = flag; 
        createPanel();
        validate();
        repaint();
    }

    public void setRemoveOnDaySelection(boolean flag) {
        removeOnDaySelection = flag;
    }

    public Popup getPopup(Container c) {
        if (popup == null) {
            Point p = c.getLocation();
            PopupFactory factory = PopupFactory.getSharedInstance();
            popup = factory.getPopup(c, this, p.x, p.y);
        }
        return popup;
    }

    public void popupShow(Container c) {
        getPopup(c);
        popup.show();
    }

    public void popupHide() {
        popup.hide();
    }

    public Calendar getCalendarDate() {
        return currentDisplayDate;
    }

    public Date getDate() {
        return currentDisplayDate.getTime();
    }

    public String getFormattedDate() {
        return Integer.toString(getMonth()) + "/" + 
            Integer.toString(getDay()) + "/" +
            Integer.toString(getYear());
    }

    public int getMonth() {
        return currentDisplayDate.get(Calendar.MONTH) + 1;
    }

    public int getDay() {
        return currentDisplayDate.get(Calendar.DAY_OF_MONTH);
    }

    public int getYear() {
        return currentDisplayDate.get(Calendar.YEAR);
    }

    public ImageIcon getImage() {
        return createImageIcon(iconFile, "Calendar date picker");
    }

    /* 
     * Returns an ImageIcon, or null if the path was invalid. 
     */
    protected ImageIcon createImageIcon(String path, String description) {
        URL imgURL = getClass().getResource(path);
        String fileName = imgURL.getFile().replace("bin/", "src/");
        fileName = fileName.replace("%20", " ").substring(1);
        ImageIcon icon = new ImageIcon(fileName, description);
        return icon;
    }

    protected void createPanel() {
        removeAll();
        setBorder(BorderFactory.createLineBorder(Color.black, 3));
        setFocusable(true);
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        if (controlsOnTop) {
            add(createControls());
            add(createCalendar());
        } else {
            add(createCalendar());
            add(createControls());
        }
        Dimension d = getPreferredSize();
        setPreferredSize(new Dimension(d.width, d.height + 8));
    }

    protected JPanel createControls() {        
      JPanel c = new JPanel();
      c.setBorder(BorderFactory.createRaisedBevelBorder());
      c.setFocusable(true);
      c.setLayout(new FlowLayout(FlowLayout.CENTER));

      prevYear = new JButton("<<");
      c.add(prevYear);
      prevYear.setMargin(new Insets(0,0,0,0));
      prevYear.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                addYear(-1);        
            }
      });

      prevMonth = new JButton("<");
      c.add(prevMonth);
      prevMonth.setMargin(new Insets(0,0,0,0));
      prevMonth.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                addMonth(-1);       
            }
      });


      textField = new JTextField(getFormattedDate(), 10);
      c.add(textField);
      textField.setEditable(true);
      textField.setEnabled(true);
      textField.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                editDate(textField.getText());
            }
      });

      nextMonth = new JButton(">");
      c.add(nextMonth);
      nextMonth.setMargin(new Insets(0,0,0,0));
      nextMonth.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                addMonth(+1);   
            }
      });

      nextYear = new JButton(">>");
      c.add(nextYear);
      nextYear.setMargin(new Insets(0,0,0,0));
      nextYear.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                addYear(+1);    
            }
      });

      return c;
    }

    protected JPanel createCalendar() {
        JPanel x = new JPanel();
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c  = new GridBagConstraints();

        x.setFocusable(true);
        x.setLayout(gridbag);

        String month = monthName.format(currentDisplayDate.getTime());
        String year  = Integer.toString(getYear());

        c.gridx      = 0;
        c.gridy      = 0;
        c.gridwidth  = 7;
        c.gridheight = 1;
        JLabel title = new JLabel(month + " " + year);
        x.add(title, c);
        Font font      = title.getFont();
//        Font titleFont = new Font(font.getName(), font.getStyle(),
//              font.getSize() + 2);
        Font weekFont = new Font(font.getName(), font.getStyle(),
                font.getSize() - 2);
        title.setFont(font);

        c.gridy      = 1;
        c.gridwidth  = 1;
        c.gridheight = 1;
        for (c.gridx = 0; c.gridx < 7; c.gridx++) {
            JLabel label = new JLabel(weekdayNames[c.gridx]);
            x.add(label, c);
            label.setFont(weekFont);
        }

        Calendar draw = (Calendar) currentDisplayDate.clone();
        draw.set(Calendar.DATE, 1);
        draw.add(Calendar.DATE, -draw.get(Calendar.DAY_OF_WEEK) + 1);
        int monthInt = currentDisplayDate.get(Calendar.MONTH);
//      monthInt = 0;
//      System.out.println("Current month: " + monthInt);

        c.gridwidth  = 1;
        c.gridheight = 1;
        int width    = getFontMetrics(weekFont).stringWidth(" Wed ");
        int width1   = getFontMetrics(weekFont).stringWidth("Wed");
        int height   = getFontMetrics(weekFont).getHeight() + 
                (width - width1);

        for (c.gridy = 2; c.gridy < 8; c.gridy++) {
            for (c.gridx = 0; c.gridx < 7; c.gridx++) {
                JButton dayButton;
//              System.out.print("Draw month: " + draw.get(Calendar.MONTH));
                if (draw.get(Calendar.MONTH) == monthInt) {
                    String dayString = dayName.format(draw.getTime());
                    if (draw.get(Calendar.DAY_OF_MONTH) < 10)
                        dayString = " " + dayString;
                    dayButton = new JButton(dayString);
                } else {
                    dayButton = new JButton();
                    dayButton.setEnabled(false);
                }
//              System.out.println(", day: " + dayName.format(draw.getTime()));
                x.add(dayButton, c);
                Color color = dayButton.getBackground();
                if ((draw.get(Calendar.DAY_OF_MONTH) == getDay()) &&
                        (draw.get(Calendar.MONTH) == monthInt)) { 
                    dayButton.setBackground(Color.yellow);
//                  dayButton.setFocusPainted(true);
//                  dayButton.setSelected(true);
                } else
                    dayButton.setBackground(color);
                dayButton.setFont(weekFont);
                dayButton.setFocusable(true);
                dayButton.setPreferredSize(new Dimension(width, height));
                dayButton.setMargin(new Insets(0,0,0,0));
                dayButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        changeDay(e.getActionCommand());
                    }

                });
                draw.add(Calendar.DATE, +1);
            }
//          if (draw.get(Calendar.MONTH) != monthInt) break;
        }
        return x;
    }

    public void addMonth(int month) {
        currentDisplayDate.add(Calendar.MONTH, month);
        createPanel();
        validate();
        repaint();
    }

    public void addYear(int year) {
        currentDisplayDate.add(Calendar.YEAR, year);
        createPanel();
        validate();
        repaint();
    }

    public void editDate(String date) {
        parseDate(date);
        createPanel();
        validate();
        repaint();
    }

    protected void parseDate(String date) {
        String[] parts = date.split("/");
        if (parts.length == 3) {
            currentDisplayDate.set(Calendar.MONTH, 
                    Integer.valueOf(parts[0]) - 1);
            currentDisplayDate.set(Calendar.DAY_OF_MONTH, 
                    Integer.valueOf(parts[1]));
            currentDisplayDate.set(Calendar.YEAR, 
                    expandYear(Integer.valueOf(parts[2])));
        } else if (parts.length == 2) {
            currentDisplayDate = Calendar.getInstance();
            currentDisplayDate.set(Calendar.MONTH, 
                    Integer.valueOf(parts[0]) - 1);
            currentDisplayDate.set(Calendar.DAY_OF_MONTH, 
                    Integer.valueOf(parts[1]));
        } else {
            // invalid date
            currentDisplayDate = Calendar.getInstance();
        }
    }

    public void changeDay(String day) {
        currentDisplayDate.set(Calendar.DAY_OF_MONTH, 
                Integer.valueOf(day.trim()));
        if (removeOnDaySelection) {
            firePopupEvent(new ActionEvent(this, 1, "hide"));
            popup = null;
        } else {
            createPanel();
            validate();
            repaint();
        }
    }

    public void addPopupListener(ActionListener l) {
        popupListeners.add(l);
    }

    public void removePopupListener(ActionListener l) {
        popupListeners.remove(l);
    }

    public void firePopupEvent(ActionEvent e) {
        for (int i = popupListeners.size() - 1; i >= 0; i--) {
            ActionListener l = popupListeners.get(i);
            l.actionPerformed(e);
        }
    }

    public static void main(String[] args) {
        final JFrame frame = new JFrame("Date Picker");
        Container pane = frame.getContentPane();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(450, 250));
        pane.setLayout(new FlowLayout(FlowLayout.LEFT));
        pane.add(new JLabel("Birthdate: "));
        final JTextField testDate = new JTextField(10);
        pane.add(testDate);
        final DatePicker dp = new DatePicker();
        ImageIcon ii = dp.getImage();
//      System.out.println(ii.getIconWidth());
//      System.out.println(ii.getIconHeight());
        final JButton datePicker = new JButton(ii);
        pane.add(datePicker);
        datePicker.setPreferredSize(new Dimension(30, 24));
        datePicker.setMargin(new Insets(0,0,0,0));
        datePicker.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dp.setDate(testDate.getText());
                dp.popupShow(datePicker);
            }
        });
        dp.addPopupListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                testDate.setText(dp.getFormattedDate());
                dp.popupHide();
            }
        });
        frame.pack();
        frame.setFocusable(true);
        frame.setResizable(true);
        frame.setVisible(true);
    }
}

2

很遗憾,这个组件已经不再维护了(已经五年没有发布更新版本):对我们来说风险太大了,因为未来的Java / Swing版本可能会破坏它,而且无法修复... - Tom
@Omid,你能告诉我如何在Swing组件中添加并拖动到JFrame中吗?我已经使用JPallete Manager添加了它,但是这个组件无法拖动到JFrame中。 - Syed Muhammad Mubashir
我正在使用 Net Beans 7.1,这个版本与 NeBeans 7.1 和 Swing 框架兼容吗? - Syed Muhammad Mubashir

1
JXDatePicker 缺少内置的上/下一年按钮,这是我没有在我的软件中使用该包的主要原因。否则,它是市面上较好的日期选择器之一。
作为替代方案,我建议使用 LGoodDatePicker。它有向前和向后的年份按钮,以及一个菜单可以选择任何所需的年份。公平披露:我是该项目的主要开发人员。如果符合您的需求,请告诉我。
LGoodDatePicker 主页:https://github.com/LGoodDatePicker/LGoodDatePicker 发布版中有一个可运行的演示(可执行 jar 文件),并且在 gitub 页面上列出了核心功能列表。
以下是屏幕截图。

enter image description here


0

改进:

日期时间选择器与按钮距离太远

因此,在第139行:

public Popup getPopup(Container c) {

    if (popup == null) {

        Point p = c.getLocation();

        PopupFactory factory = PopupFactory.getSharedInstance();


 // FramePrinc.Location.x ==>  public static Point Location ;  in class FramePrinc

     popup = factory.getPopup(c, this, FramePrinc.Location.x,FramePrinc.Location.y);

    }

    return popup;

}

在操作内部,您可以获取组件的位置

datePicker.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent e) {

            //Add this Line and you will get a good result

            Location = datePickerButton.getLocationOnScreen();

            dp.setDate(testDate.getText());

            dp.popupShow(datePicker);
        }
    });

所以:

  • 创建另一个类:例如FramePrinc
  • 创建公共静态点Location
  • 将dateTimePiker放入面板中
  • 在按钮操作中添加我说的那行代码

祝你好运

Grine_Amine改进 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接