custom spinnerdatemodel not doing anything - java

custom spinnerdatemodel with overriden getPrevious() and getNext() is not doing anything. what am i doing wrong?
Here is my code. This looks correct to me; so yeah, any help would be much appreciated. Thanks!
/**
* Custom spinner model for the times (hhmm)
*/
class SpinnerTimeModel extends SpinnerDateModel {
/**
* Constructor
*/
public SpinnerTimeModel() {
cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
setValue(cal.getTime());
setStart(cal.getTime());
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
setEnd(cal.getTime());
}
/**
* Returns a time 30 minutes prior to the current time
*
* #return a time 30 minutes prior to the current time
*/
#Override
public Object getPreviousValue() {
Calendar previous = Calendar.getInstance();
previous.setTime(getDate());
previous.add(Calendar.MINUTE, -30);
return previous.getTime();
}
/**
* Returns a time 30 minutes after the current time
*
* #return a time 30 minutes after the current time
*/
#Override
public Object getNextValue() {
Calendar next = Calendar.getInstance();
next.setTime(getDate());
next.add(Calendar.MINUTE, 30);
return next.getTime();
}
private Calendar cal;
}

if you set the JSpinner editor type as DateEditor then the existing code will work fine. The code commented.
public class spinnerdemo {
public void show() {
JFrame f = new JFrame("JSpinner Demo");
f.setSize(500, 100);
f.setLayout(new GridLayout(1, 1));
JSpinner ctrlSpin = new JSpinner();
ctrlSpin.addChangeListener(new javax.swing.event.ChangeListener() {
#Override
public void stateChanged(javax.swing.event.ChangeEvent evt) {
System.out.println("" + ctrlSpin.getValue());
}
});
ctrlSpin.setModel(new SpinnerTimeModel());
//set the DateEditor
ctrlSpin.setEditor(new JSpinner.DateEditor(ctrlSpin, "dd/MM/yyyy HH:mm:ss.SS"));
f.add(ctrlSpin);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
public static void main(String[] args) {
new spinnerdemo().show();
}
}

Related

Java Timer Countdown from certain time

using Java and Java Swing for a GUI. The scenario is that I want a user to enter in a desired time (in a JTextbox) in the format of HH:MM:SS and from that given time, countdown by seconds until it hits zero.
Currently I am using a timer and the timer.between function. I create an Instant() from the user input time and also use instant.now().
The instants are being created, however, the countdown clock doesn't count down from the user input time, but rather some random numbers that I can't figure out where they are coming from. Can anyone else see the problem?
javax.swing.Timer countDown = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
autoShutOffTF.setText(String.format("%02d:%02d:%02d",
countingDown.toHours(),
countingDown.toMinutes() % 60,
countingDown.getSeconds() % 60));
}
});
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Getting user input, parsing String in the form of HH:MM:SS
String countdownInput = autoShutOffTF.getText();
String getHours = countdownInput.substring(0,2);
int hours = Integer.parseInt(getHours);
String getMins = countdownInput.substring(3,5);
int mins = Integer.parseInt(getMins);
String getSecs = countdownInput.substring(6,8);
int seconds = Integer.parseInt(getSecs);
//Creating a date instance, to get the current year, month and date
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
//creating a new instant with the new calendar with all of the data
userInputCountDown = cal.toInstant();
//starting timer
countDown.start();
}
});
Don't use Date or Calendar, the java.time API is more the capable of achieving what you want.
Looking at this...
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
//creating a new calendar with all of the data
Calendar cal = Calendar.getInstance();
cal.set(year, month, day, hours, mins, seconds);
You're creating a new time, based on the hours/mins/seconds, but, what worries me is, is what happens if the time is less than now? This "might" be the issue you're having.
So, some thing you might want to do is verify if the time is before or after the current time and roll the day accordingly - assuming you want to use an absolute time (ie create a timer which counts down from now to 6pm)
This...
Duration countingDown = Duration.between(Instant.now(), userInputCountDown);
also seems off to me, as userInputCountDown should be in the future
The following example takes a slightly different approach, as it creates a "timer" that will create a target in the future (based on the input) from the current time (adding the hours, mins and seconds) and use it as the anchor point for the count down.
So, you might say, "create a 1 hour" timer, for example.
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;
class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextField targetHours;
private JTextField targetMins;
private JTextField targetSeconds;
private Instant futureTime;
private Timer timer;
private JLabel countDown;
public TestPane() {
setLayout(new GridBagLayout());
targetHours = new JTextField("00", 2);
targetMins = new JTextField("00", 2);
targetSeconds = new JTextField("00", 2);
JPanel targetPane = new JPanel(new GridBagLayout());
targetPane.add(targetHours);
targetPane.add(new JLabel(":"));
targetPane.add(targetMins);
targetPane.add(new JLabel(":"));
targetPane.add(targetSeconds);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(targetPane, gbc);
JButton btn = new JButton("Start");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
futureTime = LocalDateTime.now()
.plusHours(Long.parseLong(targetHours.getText()))
.plusMinutes(Long.parseLong(targetMins.getText()))
.plusSeconds(Long.parseLong(targetSeconds.getText()))
.atZone(ZoneId.systemDefault()).toInstant();
if (timer != null) {
timer.stop();
}
countDown.setText("---");
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Duration duration = Duration.between(Instant.now(), futureTime);
if (duration.isNegative()) {
timer.stop();
timer = null;
countDown.setText("00:00:00");
} else {
String formatted = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
countDown.setText(formatted);
}
}
});
timer.start();
}
});
add(btn, gbc);
countDown = new JLabel("---");
add(countDown, gbc);
}
}
}
WARNING - I do NO validation on the input, so you will have to be careful.
If, instead, you wanted to count down to a particular point in time (ie count down from now to 6pm), then you would need to use LocalDateTime#withHour(Long)#withMinute(Long)#withSecond(Long) chain instead. But, beware, you'll have to verify if the time is in the future or past and take appropriate action, because if you want to countdown to 6pm, but it's 7pm ... what does that actually mean :/ ?

Clock Display in BlueJ with GUI

Currently the display works fine. I coded the minutes run act as seconds for simulation clock display. It's works fine but when it is 12:59, it should be 1 instead of 0. I couldn't figure it out to remove 00:00 should be 01:00 after 12:59.
clock.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class Clock
{
private JFrame frame;
private JLabel label;
private ClockDisplay clock;
private boolean clockRunning = false;
private TimerThread timerThread;
/**
* Constructor for objects of class Clock
*/
public Clock()
{
makeFrame();
clock = new ClockDisplay();
}
/**
*
*/
private void start()
{
clockRunning = true;
timerThread = new TimerThread();
timerThread.start();
}
/**
*
*/
private void stop()
{
clockRunning = false;
}
/**
*
*/
private void step()
{
clock.timeTick();
label.setText(clock.getTime());
}
/**
* 'About' function: show the 'about' box.
*/
private void showAbout()
{
JOptionPane.showMessageDialog (frame,
"Clock Version 1.0\n" +
"A simple interface for the 'Objects First' clock display project",
"About Clock",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Quit function: quit the application.
*/
private void quit()
{
System.exit(0);
}
/**
* Create the Swing frame and its content.
*/
private void makeFrame()
{
frame = new JFrame("Clock");
JPanel contentPane = (JPanel)frame.getContentPane();
contentPane.setBorder(new EmptyBorder(1, 60, 1, 60));
makeMenuBar(frame);
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(12, 12));
// Create the image pane in the center
label = new JLabel("00:00", SwingConstants.CENTER);
Font displayFont = label.getFont().deriveFont(96.0f);
label.setFont(displayFont);
//imagePanel.setBorder(new EtchedBorder());
contentPane.add(label, BorderLayout.CENTER);
// Create the toolbar with the buttons
JPanel toolbar = new JPanel();
toolbar.setLayout(new GridLayout(1, 0));
JButton startButton = new JButton("Start");
startButton.addActionListener(e -> start());
toolbar.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stop());
toolbar.add(stopButton);
JButton stepButton = new JButton("Step");
stepButton.addActionListener(e -> step());
toolbar.add(stepButton);
// Add toolbar into panel with flow layout for spacing
JPanel flow = new JPanel();
flow.add(toolbar);
contentPane.add(flow, BorderLayout.SOUTH);
// building is done - arrange the components
frame.pack();
// place the frame at the center of the screen and show
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(d.width/2 - frame.getWidth()/2, d.height/2 - frame.getHeight()/2);
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
*
* #param frame The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame)
{
final int SHORTCUT_MASK =
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu menu;
JMenuItem item;
// create the File menu
menu = new JMenu("File");
menubar.add(menu);
item = new JMenuItem("About Clock...");
item.addActionListener(e -> showAbout());
menu.add(item);
menu.addSeparator();
item = new JMenuItem("Quit");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
item.addActionListener(e -> quit());
menu.add(item);
}
class TimerThread extends Thread
{
public void run()
{
while (clockRunning) {
step();
pause();
}
}
private void pause()
{
try {
Thread.sleep(300); // pause for 300 milliseconds
}
catch (InterruptedException exc) {
}
}
}
}
clock.java should be locked as this is working properly.
numDisplay.java
/**
* The NumberDisplay class represents a digital number display that can hold
* values from zero to a given limit. The limit can be specified when
* creating the display. The values range from zero (inclusive) to limit-1.
* If used,
* for example, for the seconds on a digital clock, the limit would be 60,
* resulting in display values from 0 to 59. When incremented, the display
* automatically rolls over to zero when reaching the limit.
*/
public class NumberDisplay
{
private int limit = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay.
* Set the limit at which the display rolls over.
*/
public NumberDisplay(int rollOverLimit)
{
limit = rollOverLimit;
value = 1;
}
/*
*
*/
/**
* Return the current value.
*/
public int getValue()
{
return value;
}
/**
* Return the display value (that is, the current value as a two-digit
* String. If the value is less than ten, it will be padded with a leading
* zero).
*/
public String getDisplayValue()
{
if(value < 10) {
return "0" + value; // stay 0 appears in left
}
else {
return "" + value; // none to show in right of the display
}
}
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public void setValue(int replacementValue)
{
if((replacementValue >= 2) & (replacementValue < limit)) {
value = replacementValue;
}
}
/**
* Increment the display value by one, rolling over to zero if the
* limit is reached.
*/
public void increment()
{
value = (value + 1) % limit; // this is already the time by 1
}
}
I also left comments to help understanding what they are running program.
This is last one called "Display" which is named ClockDisplay.java:
/**
* The ClockDisplay class implements a digital clock display for a
* European-style 24 hour clock. The clock shows hours and minutes. The
* range of the clock is 00:00 (midnight) to 23:59 (one minute before
* midnight).
*
* The clock display receives "ticks" (via the timeTick method) every minute
* and reacts by incrementing the display. This is done in the usual clock
* fashion: the hour increments when the minutes roll over to zero.
*/
public class ClockDisplay
{
private NumberDisplay hours; // runs from 1 am/pm to 11:59 am/pm
private NumberDisplay minutes; // This will running like
// seconds act as minutes.
private String displayString; // simulates the actual display
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at 00:00.
*/
public ClockDisplay()
{
hours = new NumberDisplay(13); // set great than 13; runs from 1am to 12 noon
minutes = new NumberDisplay(60); // 60 minutes is one hour
updateDisplay();
}
/**
* Constructor for ClockDisplay objects. This constructor
* creates a new clock set at the time specified by the
* parameters.
*/
public ClockDisplay(int hour, int minute)
{
hours = new NumberDisplay(13);
minutes = new NumberDisplay(60);
setTime(hour, minute);
}
/**
* This method should get called once every minute - it makes
* the clock display go one minute forward.
*/
public void timeTick()
{
minutes.increment();
if(minutes.getValue() == 1) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
/**
* Set the time of the display to the specified hour and
* minute.
*/
public void setTime(int hour, int minute)
{
hours.setValue(hour); // hours will be set on display
minutes.setValue(minute); // minutes will be set on display
updateDisplay(); // updating the value to display
}
/**
* Return the current time of this display in the format HH:MM.
*/
public String getTime()
{
return displayString; // appears as messagebox to display the clock
}
/**
* Update the internal string that represents the display.
*/
private void updateDisplay()
{
displayString = hours.getDisplayValue() + ":" +
minutes.getDisplayValue(); //Updated the clock simulator
}
}
I'm still stuck with 00:00. need help?
There are a lot of areas in your code which could better managed.
Let's start with...
public void increment() {
value = (value + 1) % limit; // this is already the time by 1
}
I can see what you're trying to do, but remember 13 % 13 is 0, which is the starting point of your issues, while certainly clever, I would have used setValue(value + 1) and allowed setValue to perform the validation.
The reason for this is, you could supply a minimum and maximum allowable values, which setValue could then manage.
I would then change the increment method to return true when it "rolls" the value, this way it would be easier to determine when the value has reverted to its minimum state.
For brevity, these are the basic changes...
NumberDisplay
public class NumberDisplay {
private int minimum = 1;
private int maximum = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay. Set the limit at
* which the display rolls over.
*/
public NumberDisplay(int maxumum, int minimum) {
this.maximum = maxumum;
this.minimum = minimum;
value = 1;
}
//...
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public boolean setValue(int replacementValue) {
if (replacementValue >= maximum) {
value = minimum;
return true;
} else {
value = replacementValue;
return false;
}
}
/**
* Increment the display value by one, rolling over to zero if the limit
* is reached.
*/
public boolean increment() {
// value = (value + 1) % maximum; // this is already the time by 1
return setValue(value + 1);
}
}
ClockDisplay
public class ClockDisplay {
//...
/**
* This method should get called once every minute - it makes the clock
* display go one minute forward.
*/
public void timeTick() {
if (minutes.increment()) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
//...
}
Full example....
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class Clock {
private JFrame frame;
private JLabel label;
private ClockDisplay clock;
private boolean clockRunning = false;
private TimerThread timerThread;
public static void main(String[] args) {
System.out.println((13 % 13));
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Clock();
}
});
}
/**
* Constructor for objects of class Clock
*/
public Clock() {
makeFrame();
clock = new ClockDisplay(12, 0);
}
/**
*
*/
private void start() {
clockRunning = true;
timerThread = new TimerThread();
timerThread.start();
}
/**
*
*/
private void stop() {
clockRunning = false;
}
/**
*
*/
private void step() {
clock.timeTick();
label.setText(clock.getTime());
}
/**
* 'About' function: show the 'about' box.
*/
private void showAbout() {
JOptionPane.showMessageDialog(frame,
"Clock Version 1.0\n"
+ "A simple interface for the 'Objects First' clock display project",
"About Clock",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Quit function: quit the application.
*/
private void quit() {
System.exit(0);
}
/**
* Create the Swing frame and its content.
*/
private void makeFrame() {
frame = new JFrame("Clock");
JPanel contentPane = (JPanel) frame.getContentPane();
contentPane.setBorder(new EmptyBorder(1, 60, 1, 60));
makeMenuBar(frame);
// Specify the layout manager with nice spacing
contentPane.setLayout(new BorderLayout(12, 12));
// Create the image pane in the center
label = new JLabel("12:00", SwingConstants.CENTER);
Font displayFont = label.getFont().deriveFont(96.0f);
label.setFont(displayFont);
//imagePanel.setBorder(new EtchedBorder());
contentPane.add(label, BorderLayout.CENTER);
// Create the toolbar with the buttons
JPanel toolbar = new JPanel();
toolbar.setLayout(new GridLayout(1, 0));
JButton startButton = new JButton("Start");
startButton.addActionListener(e -> start());
toolbar.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(e -> stop());
toolbar.add(stopButton);
JButton stepButton = new JButton("Step");
stepButton.addActionListener(e -> step());
toolbar.add(stepButton);
// Add toolbar into panel with flow layout for spacing
JPanel flow = new JPanel();
flow.add(toolbar);
contentPane.add(flow, BorderLayout.SOUTH);
// building is done - arrange the components
frame.pack();
// place the frame at the center of the screen and show
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(d.width / 2 - frame.getWidth() / 2, d.height / 2 - frame.getHeight() / 2);
frame.setVisible(true);
}
/**
* Create the main frame's menu bar.
*
* #param frame The frame that the menu bar should be added to.
*/
private void makeMenuBar(JFrame frame) {
final int SHORTCUT_MASK
= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
JMenu menu;
JMenuItem item;
// create the File menu
menu = new JMenu("File");
menubar.add(menu);
item = new JMenuItem("About Clock...");
item.addActionListener(e -> showAbout());
menu.add(item);
menu.addSeparator();
item = new JMenuItem("Quit");
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, SHORTCUT_MASK));
item.addActionListener(e -> quit());
menu.add(item);
}
class TimerThread extends Thread {
public void run() {
while (clockRunning) {
step();
pause();
}
}
private void pause() {
try {
Thread.sleep(300); // pause for 300 milliseconds
} catch (InterruptedException exc) {
}
}
}
public class NumberDisplay {
private int minimum = 1;
private int maximum = 13;
private int value;
/**
* Constructor for objects of class NumberDisplay. Set the limit at
* which the display rolls over.
*/
public NumberDisplay(int maxumum, int minimum) {
this.maximum = maxumum;
this.minimum = minimum;
value = 1;
}
/*
*
*/
/**
* Return the current value.
*/
public int getValue() {
return value;
}
/**
* Return the display value (that is, the current value as a two-digit
* String. If the value is less than ten, it will be padded with a
* leading zero).
*/
public String getDisplayValue() {
if (value < 10) {
return "0" + value; // stay 0 appears in left
} else {
return "" + value; // none to show in right of the display
}
}
/**
* Set the value of the display to the new specified value. If the new
* value is less than zero or over the limit, do nothing.
*/
public boolean setValue(int replacementValue) {
if (replacementValue >= maximum) {
value = minimum;
return true;
} else {
value = replacementValue;
return false;
}
}
/**
* Increment the display value by one, rolling over to zero if the limit
* is reached.
*/
public boolean increment() {
// value = (value + 1) % maximum; // this is already the time by 1
return setValue(value + 1);
}
}
public class ClockDisplay {
private NumberDisplay hours; // runs from 1 am/pm to 11:59 am/pm
private NumberDisplay minutes; // This will running like
// seconds act as minutes.
private String displayString; // simulates the actual display
/**
* Constructor for ClockDisplay objects. This constructor creates a new
* clock set at 00:00.
*/
public ClockDisplay() {
hours = new NumberDisplay(13, 1); // set great than 13; runs from 1am to 12 noon
minutes = new NumberDisplay(60, 0); // 60 minutes is one hour
updateDisplay();
}
/**
* Constructor for ClockDisplay objects. This constructor creates a new
* clock set at the time specified by the parameters.
*/
public ClockDisplay(int hour, int minute) {
this();
setTime(hour, minute);
}
/**
* This method should get called once every minute - it makes the clock
* display go one minute forward.
*/
public void timeTick() {
if (minutes.increment()) { // on clock at after 12 am or pm.
hours.increment(); // after 60 mins, next per hour.
}
updateDisplay(); // updating to return
}
/**
* Set the time of the display to the specified hour and minute.
*/
public void setTime(int hour, int minute) {
System.out.println("setTime " + hour + ":" + minute);
hours.setValue(hour); // hours will be set on display
minutes.setValue(minute); // minutes will be set on display
updateDisplay(); // updating the value to display
}
/**
* Return the current time of this display in the format HH:MM.
*/
public String getTime() {
return displayString; // appears as messagebox to display the clock
}
/**
* Update the internal string that represents the display.
*/
private void updateDisplay() {
displayString = hours.getDisplayValue() + ":"
+ minutes.getDisplayValue(); //Updated the clock simulator
}
}
}
Side note
You also need a better understanding of concurrency in Swing. Swing is NOT thread safe and you should never modify the UI, or something the UI relies on, from outside the context of the Event Dispatching Thread, see Concurrency in Swing for more details. A Swing Timer would be a better choice then Thread in this case

How to highlight dates inside JCalendar in JDateChooser?

I am using a JDateChooser component from an external library toedter(jcalendar1.4). I used a custom DateEvaluator by implementing IDateEvaluator which is later added to JDateChooser component:
public static class HighlightEvaluator implements IDateEvaluator {
private final List<Date> list = new ArrayList<>();
public void add(Date date) {
list.add(date);
}
public void remove(Date date) {
list.remove(date);
}
public void setDates(List<Date> dates) {
list.addAll(dates);
}
#Override
public Color getInvalidBackroundColor() {
return Color.BLACK;
}
#Override
public Color getInvalidForegroundColor() {
return null;
}
#Override
public String getInvalidTooltip() {
return null;
}
#Override
public Color getSpecialBackroundColor() {
return Color.GREEN;
}
#Override
public Color getSpecialForegroundColor() {
return Color.RED;
}
#Override
public String getSpecialTooltip() {
return "filled";
}
#Override
public boolean isInvalid(Date date) {
return false;
}
#Override
public boolean isSpecial(Date date) {
return list.contains(date);
}
}
and here is my main method:
public static void main(){
JDateChooser dateChooser = new JDateChooser();
List<Date> dates = new ArrayList<Date>();
dates.add(new Date());
HighlightEvaluator evaluator = new HighlightEvaluator();
evaluator.setDates(dates);
dateChooser.getJCalendar().getDayChooser().addDateEvaluator(evaluator);
}
Now the current date is supposed to be highlighted by the code but its not getting highlighted. Please tell a fix for this
You need to alter the Date variable a little bit. When you create a Date variable it grabs the current day month year along with time(hours, minutes, seconds, milliseconds)
However setting the same date to evaluator will not work because evaluator expects date to be devoid of the time details. So alternatively you can use Calendar object in your main function as illustrated below:
public static void main(){
JDateChooser dateChooser = new JDateChooser();
List<Date> dates = new ArrayList<Date>();
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, desiredyear);
c.set(Calendar.MONTH, desiredmonth);
c.set(Calendar.DAY_OF_MONTH, desiredday);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
dates.add(c.getTime());
HighlightEvaluator evaluator = new HighlightEvaluator();
evaluator.setDates(dates);
dateChooser.getJCalendar().getDayChooser().addDateEvaluator(evaluator);
}

How to set custom week-start in JCalendar?

I am having trouble setting custom first-day-of-week, in JCalendar.
The first-day-of-week does change if I change locale.
However changing the first-day-of-week in the underlying calendar, has no effect.
Here is a short demonstration code:
public class TestJChooser extends JFrame {
/**
*
*/
public TestJChooser() {
setLayout(new BorderLayout(5,5));
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
Locale locale = Locale.forLanguageTag("de-DE");
Calendar calendar = Calendar.getInstance(locale);
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
JCalendar jCal = new JCalendar(calendar);
jCal.setLocale(locale);
jCal.setPreferredSize(new Dimension(500, 400));
jCal.getDayChooser().setDayBordersVisible(true);
jCal.setTodayButtonVisible(true);
getContentPane().add(jCal,BorderLayout.CENTER);
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJChooser();
}
}
Changing the value of
calendar.setFirstDayOfWeek(Calendar.TUESDAY);
Does not change the first day of the week in JCalendar, nor the weekend day.
To achieve the functionality I needed with com.toedter.calendar.JDateChooser I had to extend it.
First a demo: set Sunday as the first day of the week (although it is set to Monday by the locale) . The test class:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser(){
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
getContentPane().setLayout(new BorderLayout(5,5));
//set locale and calendar
Locale locale = Locale.forLanguageTag("de-DE");
Calendar cal = Calendar.getInstance(locale);
cal.setTime(new Date());
//set first day of week
int firstWeekDay = Calendar.SUNDAY;
cal.setFirstDayOfWeek(firstWeekDay);
//-- Toedter JCalendar
JCalendar jCalendar = new JCalendarExt(null, locale, true, true, false);
jCalendar.setCalendar(cal);
jCalendar.setPreferredSize(new Dimension(120, 160));
jCalendar.getDayChooser().setDayBordersVisible(true);
jCalendar.setTodayButtonVisible(true);
jCalendar.setWeekOfYearVisible(false);
getContentPane().add(jCalendar,BorderLayout.CENTER);
//-- Toedter JDateChooser
JCalendar jCalendar2 = new JCalendarExt(null, locale, true, true, false);
jCalendar2.setCalendar(cal);
JDateChooser dateChooser = new JDateChooser(jCalendar2, null , "dd.mm.yyyy",null);
dateChooser.setLocale(locale);
getContentPane().add(dateChooser,BorderLayout.SOUTH);
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
The result can be seen in the image.
The second image demonstrates setting the first-day-of-week to Tuesday.
Two classes were extended. The class extending JCalendar:
/**
* Extended to gain control on week-first-day.
* It also enables the option to display in different color the
* last-day-of-week, rather than <code>JCalendar</code> default which is
* always display Sunday in a different color.
*
* #version
* $Log: JCalendarExt.java,v $
*
*
* #author Ofer Yuval
* 27 Nov 2015
*
*/
public class JCalendarExt extends JCalendar {
/**
*
* #param date
* #param locale
* #param monthSpinner
* #param weekOfYearVisible
* #param colorWeekend
* <br>When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* <br>When true, week-last-day will be painted in red.
*/
public JCalendarExt(Date date, Locale locale, boolean monthSpinner, boolean weekOfYearVisible,
boolean colorWeekend) {
super(date, locale, monthSpinner, weekOfYearVisible);
remove(dayChooser);
//add the extended date chooser
dayChooser = new JDayChooserExt(weekOfYearVisible) ;
dayChooser.addPropertyChangeListener(this);
((JDayChooserExt) dayChooser).setColorWeekend(colorWeekend);
monthChooser.setDayChooser(dayChooser);
yearChooser.setDayChooser(dayChooser);
add(dayChooser, BorderLayout.CENTER);
}
#Override
public void setCalendar(Calendar c) {
getDayChooser().setCalendar(c);
super.setCalendar(c);
}
}
And the class extending JDayChooser:
/**
*
* #version
* $Log: JDayChooserExt.java,v $
*
*
* #author Ofer Yuval
* 27 Nov 2015
*
*/
public class JDayChooserExt extends JDayChooser {
/**
* When false, week-first-day will be painted in red, as in <code>JDayChooser</code>.
* When true, week-last-day will be painted in red.
*/
private boolean isColorWeekend = false;
/**
* #param weekOfYearVisible
*/
public JDayChooserExt(boolean weekOfYearVisible) {
super(weekOfYearVisible);
}
/**
* Initializes the locale specific names for the days of the week.
*/
#Override
protected void init() {
JButton testButton = new JButton();
oldDayBackgroundColor = testButton.getBackground();
selectedColor = new Color(160, 160, 160);
drawDayNames();
drawDays();
}
/**
* Draws the day names of the day columns.
*/
private void drawDayNames() {
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols(locale);
dayNames = dateFormatSymbols.getShortWeekdays();
int Day = calendar.getFirstDayOfWeek();//firstDayOfWeek;
int coloredDay = (isColorWeekend ) ? Day -1 : Day;
if(coloredDay <= 0) {
coloredDay += 7;
}
for (int i = 0; i < 7; i++) {
if ((maxDayCharacters > 0) && (maxDayCharacters < 5)) {
if (dayNames[Day].length() >= maxDayCharacters) {
dayNames[Day] = dayNames[Day]
.substring(0, maxDayCharacters);
}
}
days[i].setText(dayNames[Day]);
if (Day == coloredDay) {
days[i].setForeground(sundayForeground);
} else {
days[i].setForeground(weekdayForeground);
}
if (Day < 7) {
Day++;
} else {
Day -= 6;
}
}
}
/**
* #param isColorWeekend the isColorWeekend to set
*/
public void setColorWeekend(boolean isColorWeekend) {
this.isColorWeekend = isColorWeekend;
}
// ///////////////////////////////////////////////////////////
// ////////////// DecoratorButton class //////////////////////
// ///////////////////////////////////////////////////////////
class DecoratorButton extends JButton {
private static final long serialVersionUID = -5306477668406547496L;
public DecoratorButton() {
setBackground(decorationBackgroundColor);
setContentAreaFilled(decorationBackgroundVisible);
setBorderPainted(decorationBordersVisible);
}
#Override
public void addMouseListener(MouseListener l) {
}
#Override
public boolean isFocusable() {
return false;
}
#Override
public void paint(Graphics g) {
if ("Windows".equals(UIManager.getLookAndFeel().getID())) {
// this is a hack to get the background painted
// when using Windows Look & Feel
if (decorationBackgroundVisible) {
g.setColor(decorationBackgroundColor);
} else {
g.setColor(days[7].getBackground());
}
g.fillRect(0, 0, getWidth(), getHeight());
if (isBorderPainted()) {
setContentAreaFilled(true);
} else {
setContentAreaFilled(false);
}
}
super.paint(g);
}
};
}
Here's the dirty way using reflection, you just need to override JCalendar:
private class MyJCalendar extends JCalendar {
MyJCalendar(Calendar c) {
super(c);
}
public void setFirstDayOfWeek(int firstdayofweek) {
try {
// Dirty hack to set first day of week :-)
Field f = JDayChooser.class.getDeclaredField("calendar");
f.setAccessible(true);
Calendar c = (Calendar) f.get(dayChooser);
c.setFirstDayOfWeek(firstdayofweek);
Method m = JDayChooser.class.getDeclaredMethod("drawDayNames");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
m = JDayChooser.class.getDeclaredMethod("drawDays");
m.setAccessible(true);
m.invoke(dayChooser, (Object[])null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I found a way to achieve the functionality I need with swingx JXMonthView:
public class TestJXChooser extends JFrame {
/**
*
*/
public TestJXChooser() {
//set locale
Locale locale = Locale.forLanguageTag("de-DE");
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
UIManager.put(CalendarHeaderHandler.uiControllerID, SpinningCalendarHeaderHandler.class.getName());
UIManager.put(SpinningCalendarHeaderHandler.ARROWS_SURROUND_MONTH, Boolean.TRUE);
UIManager.put(SpinningCalendarHeaderHandler.FOCUSABLE_SPINNER_TEXT, Boolean.TRUE);
final JXMonthView monthView = new JXMonthView();
//needed for the month change and year change arrows
monthView.setZoomable(true);
monthView.setLocale(locale);
//set first day of week to Tuesday
monthView.setFirstDayOfWeek(Calendar.TUESDAY);
//set Tuesday color
monthView.setDayForeground(Calendar.TUESDAY, Color.MAGENTA);
getContentPane().add(monthView );
pack();
setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestJXChooser();
}
}
I wasn't able to achieve it with com.toedter.calendar.JDateChooser.

LWUIT Calendar date format

I have a LWUIT code that supposed to print today date .
The problem with me is the date printed in "Mon dd hh:mm:ss GMT+...... yyyy" format
e.g Thu Nov 28 01:00:00 GMT+03:00 2013
So I have a couple of questions
How to get the format in "yyyy-mon-dd" format.
how to add a day to the today date after conversion to "yyyy-mon-dd" .
Observe that some classes wouldn't work in J2ME like Simpledateformat class.
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
public class myLibrary extends MIDlet {
Form f;
com.sun.lwuit.Calendar cal;
Button b;
public void startApp() {
com.sun.lwuit.Display.init(this);
f = new com.sun.lwuit.Form();
cal = new com.sun.lwuit.Calendar();
b = new Button("Enter");
f.addComponent(cal);
f.addComponent(b);
b.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent acv) {
System.out.println(""+cal.getDate());
}
});
f.show();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
In order to use the java.lwuit.Calendar class, to get your date in that format you will need to substring the data from the cal.getDate().
for example
System.out.println("DAY " + cal.getDate().toString().substring(0,3));
Doing that, you will get your data and after that reorder them in a String.
To change the Date from the Calendar view you will need to use Calendar.setDate(Date d);
I suggest you to use java.util.Calendar
java.util.Calendar c = Calendar.getInstnace();
c.set(Calendar.DAY_OF_THE_MONTH, day_that_you want);
c.set(Calendar.MONTH, month_that_you want);
c.set(Calendar.YEAR, year_that_you want);
java.lwuit.Calendar cal = new java.lwuit.Calendar();
cal.setDate(c.getDate().getTime());
If you still want to use the Date class, try this code, it will print the tomorrow day
private static final int DAY = 24 * 60 * 60 * 1000;
Date d = new Date(); d.setTime(d.getTime() + DAY);
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
public class myLibrary extends MIDlet {
Form f;
Button b;
public void startApp() {
com.sun.lwuit.Display.init(this);
private static final int DAY =86400000;
f = new com.sun.lwuit.Form();
b = new Button("Enter");
f.addComponent(b);
b.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent acv) {
java.util.Date d = new java.util.Date();
d.setTime(d.getTime() + DAY);
System.out.println(""+ d.toString());
}
});
f.show();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}

Categories