Java Swing JXDatePicker
Posted
技术标签:
【中文标题】Java Swing JXDatePicker【英文标题】: 【发布时间】:2013-04-13 06:41:57 【问题描述】:我正在使用 SwingX JXDatePicker,但我不知道如何提供下一个/上一年的按钮(默认情况下它只提供下一个/上一个月的按钮)。
另外,SwingX 似乎不再维护:我应该使用更新的组件作为日期选择器吗?
任何帮助/提示将不胜感激。 谢谢,托马斯
更新:
为了澄清这个问题,我添加了一个 JXDatePicker 屏幕截图,并以红色突出显示了下个月/上个月按钮。 因此,问题是:如何添加将日历带到下一年/上一年的按钮? 请注意,新按钮必须是标准组件,因为它们需要由特定的外观管理器呈现(在本例中为不确定)。
非常感谢
【问题讨论】:
查看this 问题以获取最新替代方案列表。我建议尝试其中一些。 它已维护 - 当前版本为 1.6.5-1,但不明白你在追求什么:你到底想要什么?为什么swingx demos(项目页面上的webstartable链接)中描述的自定义没有帮助) @MrD 为什么传播不相关的链接?那是关于一个完全不相关的问题...... 感谢您的提示。 SwingX 演示没有给出带有“下/上一年”按钮的示例(它只有标准的下/上个月)。我错过了什么?谢谢 【参考方案1】:我知道这是一个老问题,但我终于在这里找到了答案,来自 kleopatra 对 SwingsLab 演示的评论。
SwingsLab 演示提供了如何为每个组件设置自定义日历标题的示例,但这是我实际使用的代码(这是全局的;每个应用程序):
UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
datePicker = new JXDatePicker();
datePicker.getMonthView().setZoomable(true); //this is needed for custom header
这似乎是实验性代码(尚未完全公开),因此使用风险自负。希望对您有所帮助。
【讨论】:
很好,有人真的看了演示 :-) @Radiace Wei Q Ong 感谢您的发帖,但使用您的代码不会显示图片中显示的年份。我也有同样的要求。 @Syed Muhammad Mubashir 它对我有用。也许试试 SwingsLab 演示中的代码?图片来自演示。【参考方案2】:我会推荐使用 Microba DatePicker。它高度可定制,完全符合您的要求。
http://microba.sourceforge.net/
编辑:
好的,我明白了。好吧,我做了一些研究,看来您正在寻找的功能实际上并不存在于 JXDatePicker 中。
我发现的另一种选择是:http://sourceforge.net/projects/jdatepicker/ 的 JDatePicker。
主站:https://jdatepicker.org/
这个还是支持的,好像有你想要的功能。
【讨论】:
不幸的是,这个组件不再维护(过去 5 年没有发布):这对我们来说太冒险了,因为 Java / Swing 的未来版本可能会破坏它并且不会被修复.. . @Omid 你能告诉我如何在 Swing 组件中添加它并拖动到 jframe 中,我使用 JPallete Manager 添加但这个组件不会拖动到 jframe 中。 我在唱 Net Beans 7.1,这是否与 NeBeans 7.1 和 Swing 框架兼容。【参考方案3】:这是我几年前整理的。您可以对其进行修改以满足您的需求。
您将需要此图像来运行主要测试:。只需将其放在与名称为 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);
【讨论】:
【参考方案4】:改进:
datetimePicker 距离按钮太远 所以
在第 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 创建公共静态点位置 在面板中添加 dateTimePiker 把我说的那行放在按钮动作里面祝你好运
Grine_Amine 改进 :)
【讨论】:
【参考方案5】:JXDatePicker 中缺少内置的上一年/下一年按钮是我最终没有在我的软件中使用该软件包的主要原因。否则,它是现有的更好的日期选择器之一。
作为替代方案,我推荐 LGoodDatePicker。它具有用于在年份上前后移动的按钮,以及用于选择任何所需年份的菜单。公平披露:我是这个项目的主要开发者。如果它满足您的需求,请告诉我。
LGoodDatePicker 主页:https://github.com/LGoodDatePicker/LGoodDatePicker
在发布部分有一个工作演示(一个可执行的 jar 文件),在 gitub 页面上有一个核心功能列表。
截图如下。
【讨论】:
以上是关于Java Swing JXDatePicker的主要内容,如果未能解决你的问题,请参考以下文章