I Have created a JSpinner object that moves up and down daily, and skips weekends when clicked on. I then added a feature that if you open the program during a Saturday or Sunday it should roll back to Friday. The issue is rather than changing to Friday the JSpinner jumps back one week.
I tried isolating the issue in a new program and have had no success. Code should be the exact same so I am not sure what is causing this issue.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.annotation.PostConstruct;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class MainFrame extends JFrame {
DecimalFormat df = new DecimalFormat("#.00");
SpinnerDateModel spinnerModel;
JSpinner spinner;
Integer loopStep;
Integer firstloopStep = 0;
MainFrame() {
super("Spinner Control");
setLayout(new BorderLayout());
JPanel panel1 = new JPanel();
JPanel panelNorth = new JPanel();
// spinner for date information
spinnerModel = new SpinnerDateModel();
spinnerModel.setCalendarField(Calendar.WEEK_OF_MONTH);
spinner = new JSpinner(spinnerModel);
JSpinner.DateEditor editor = new JSpinner.DateEditor(spinner, "EEEEE, dd MMMMM, yyyy");
spinner.setEditor(editor);
// add panels/buttons/etc to page
add(panel1, BorderLayout.PAGE_START);
panel1.setPreferredSize(new Dimension(1280, 100));
panelNorth.setPreferredSize(new Dimension(1280, 40));
panel1.add(panelNorth, BorderLayout.NORTH);
panelNorth.add(spinner, BorderLayout.PAGE_START);
//method executes on start up
skipWeekends();
loopStep = 0;
//rotate the date, skip weekends, works fine here
spinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent arg0) {
Date date = (Date) spinner.getValue();
System.out.println("todays date " + date);
SimpleDateFormat sdf = new SimpleDateFormat("EEEEE, dd MMMMM, yyyy");
String stringDate = sdf.format(date);
System.out.println(stringDate);
char c = stringDate.charAt(0);
char c2 = stringDate.charAt(1);
//skip the weekends
if ((c == 'S') && (c2 == 'a') && (loopStep == 0)) {
loopStep = 1;
spinner.setValue(spinner.getNextValue());
spinner.setValue(spinner.getNextValue());
System.out.println("Saturday Spinner going back 2");
}
if ((c == 'S') && (c2 == 'u') && (loopStep == 0)) {
loopStep = 1;
spinner.setValue(spinner.getPreviousValue());
spinner.setValue(spinner.getPreviousValue());
System.out.println("Sunday Spinner going back 2");
}
if (loopStep == 1) {
loopStep = 2;
}
if (loopStep == 2) {
loopStep = 0;
}
}
});
setExtendedState(MAXIMIZED_BOTH);
setMinimumSize(new Dimension(1280, 485));
setSize(640, 485);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
#PostConstruct
private void skipWeekends(){
//skips weekends when program opens, skips weeks for some reason
Date date = (Date) spinner.getValue();
System.out.println("todays date " + date);
SimpleDateFormat sdf = new SimpleDateFormat("EEEEE, dd MMMMM, yyyy");
String stringDate = sdf.format(date);
System.out.println(stringDate);
char c = stringDate.charAt(0);
char c2 = stringDate.charAt(1);
if ((c == 'S') && (c2 == 'a')) {
spinner.setValue(spinner.getPreviousValue());
System.out.println("Saturday Spinner going back 2");
}
if ((c == 'S') && (c2 == 'u')) {
spinner.setValue(spinner.getPreviousValue());
spinner.setValue(spinner.getPreviousValue());
System.out.println("Sunday Spinner going back 2");
}
}
}
You're setting the SpinnerDateModel's calendar field to Calendar.WEEK_OF_MONTH instead of Calendar.DAY_OF_WEEK.
When using the Spinner buttons, this gets corrected silently, because the Spinner will set the calendar field before it commits the change (this is mentioned in the SpinnerDateModel documentation). Your #PostConstruct method runs before this had a chance to happen, though.
If I may add another suggestion: your way of figuring out the current day of the week is quite complicated and really brittle (it would break in Germany for example, because "Sunday" is "Sonntag" here). Here's an alternative. Call it with initial == true from the constructor and initial == false from stateChanged().
private Calendar cal = new GregorianCalendar();
private void skipWeekends(boolean initial) {
cal.setTime(spinnerModel.getDate());
switch (cal.get(Calendar.DAY_OF_WEEK)) {
case Calendar.SATURDAY:
cal.add(Calendar.DAY_OF_WEEK, initial ? -1 : 2);
break;
case Calendar.SUNDAY:
cal.add(Calendar.DAY_OF_WEEK, -2);
break;
}
spinnerModel.setValue(cal.getTime());
}
I think you need to select the current calendar field which then will be affected by getNextValue() and getPreviousValue() methods of JSpinner.
To make the selection you can use:
spinner.setCalendarField(Calendar.DAY_OF_YEAR);
Related
I have a problem and I can't get past it...
I am writing a program in Java using swing. That program will be used to to chose a day from a displayed calendar and put an hours of Your work (e.g 8:00 - 16:00) then the program will calculate how many hours You have worked in month and will calculate Your salary.
I've written some code so when starting the program you see a representation of current month. I wanted to add an ActionListenerto a button which will rearrange look of calendar to previous month. I wanted to use the same method that generates the current month but sending a different argument (previous month date).
To test it I used that method on the ActionListener (so when I start it I see blank form and after pressing that button it will show me the current method) and the problem is that nothing at all is happening... That method works fine when I put it in the constructor of my class but doesn't work when it is used as action performed and I don't know why.
I hope You will help me to figure it out and maybe tell me where I made a mistake and what I can do about it. This is a hobby for me I don't have any professional experience in programming.
My code:
package zadanie;
import javax.swing.*;
import java.awt.*;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
class Panel extends JPanel {
private JButton[] buttonArray = new JButton[42];
private JButton nextButton, previousButton;
private JLabel monthYear;
private Color buttonColor = new Color(116, 185, 255);
private Color buttonColorInactive = new Color(255,255,255);
private Color sundey = new Color(0, 184, 148);
private Color saturday = new Color(85, 239, 196);
private Color labelColor = new Color(255, 211, 42);
private LocalDate dateNow = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
Panel(){
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(getMonthLabel());
add(getWeekDaysPanel());
add(Box.createRigidArea(new Dimension(0,5)));
add(getMonthPanel());
calendarGenerator();
getWeekDaysPanel().setAlignmentX(Component.CENTER_ALIGNMENT);
getMonthPanel().setAlignmentX(Component.CENTER_ALIGNMENT);
}
private JComponent getMonthPanel(){
JPanel monthPanel = new JPanel();
monthPanel.setLayout(new GridLayout(6,7));
monthPanel.setMaximumSize(new Dimension(710,460));
monthPanel.setPreferredSize(new Dimension(710,460));
monthPanel.setMaximumSize(new Dimension(710,460));
//Loop that in every iteration creates a "b" button set it properties and to a "p" panel and a buttonArray.
for (int i=0; i<42; i++){
JButton b = new JButton();
b.setMaximumSize(new Dimension(95,70));
b.setPreferredSize(new Dimension(95,70));
b.setMaximumSize(new Dimension(95,70));
b.setBorderPainted(false);
b.setRolloverEnabled(false);
b.setVisible(true);
JPanel p = new JPanel();
p.add(b);
buttonArray[i] = b;
monthPanel.add(p);
}
return monthPanel;
}
// Similar to getMonthPanel method - it adds a 7 labels with the names of the days
private JComponent getWeekDaysPanel(){
JPanel daysPanel = new JPanel();
daysPanel.setBackground(labelColor);
daysPanel.setMinimumSize(new Dimension(700,35));
daysPanel.setPreferredSize(new Dimension(700,35));
daysPanel.setMaximumSize(new Dimension(700,35));
String[] daysList = {"pn.", "wt.", "śr.", "czw.", "pt.", "sob.", "niedz."};
for (int i = 0; i < 7; i++){
JLabel e = new JLabel("", JLabel.CENTER);
e.setMinimumSize(new Dimension(95,25));
e.setPreferredSize(new Dimension(95,25));
e.setMaximumSize(new Dimension(95,25));
e.setLayout(new GridLayout(1,7));
e.setText(daysList[i]);
daysPanel.add(e);
}
return daysPanel;
}
// a method that adds a two buttons (to switch to previous and next month) and a label that displays the displayed month and year
private JComponent getMonthLabel(){
JPanel monthLabel = new JPanel();
monthLabel.setMinimumSize(new Dimension(700,45));
monthLabel.setPreferredSize(new Dimension(700,45));
monthLabel.setMaximumSize(new Dimension(700,45));
monthLabel.setBackground(buttonColorInactive);
monthLabel.revalidate();
nextButton = new JButton();
ImageIcon nIcon = new ImageIcon("n.png");
nextButton.setMinimumSize(new Dimension(25,25));
nextButton.setPreferredSize(new Dimension(25,25));
nextButton.setMaximumSize(new Dimension(25,25));
nextButton.setIcon(nIcon);
nextButton.setBorderPainted(false);
nextButton.setBackground(new Color(255,255,255));
// nextButton.addActionListener();
previousButton = new JButton();
ImageIcon pIcon = new ImageIcon("p.png");
previousButton.setMinimumSize(new Dimension(25,25));
previousButton.setPreferredSize(new Dimension(25,25));
previousButton.setMaximumSize(new Dimension(25,25));
previousButton.setIcon(pIcon);
previousButton.setBorderPainted(false);
previousButton.setBackground(new Color(255,255,255));
monthYear = new JLabel("MIESIĄC_ROK", JLabel.CENTER);
monthYear.setMinimumSize(new Dimension(620,25));
monthYear.setPreferredSize(new Dimension(620,25));
monthYear.setMaximumSize(new Dimension(620,25));
monthLabel.add(previousButton);
monthLabel.add(monthYear);
monthLabel.add(nextButton);
return monthLabel;
}
// A method that change the appearance of the buttons in the "buttonArray" so the whole thing looks like calendar of the month
private void calendarGenerator(){
int noOfDays = dateNow.lengthOfMonth(); /// getting number of days in a month
int firstDayIndex = (dateNow.getDayOfWeek().getValue() - 1); // gettin the value (number) of the first day of month (it is decreased because getValue starts with 1 and buttonArray with 0)
int dayNo = 1; // variable that is used to set number of day in the setText() method of button
int month = (dateNow.getMonth().getValue() - 1); // variable that has a number of the previous month, that is why I decreased it by 1
int year = dateNow.getYear(); // getting current year
if (month == 0){ // safety - when the month variable hits 0 it is set for December (no 12) and year is decreased by 1
month = 12;
year --;
}
LocalDate previousMonthDate = LocalDate.of(year, month, 1); // a new variable for the previous month
int dayNo2 = previousMonthDate.lengthOfMonth() - (firstDayIndex - 1); // getting number of days of the previous mont (similar to dayNo but it responsible for the previous month during displaying
for (int i = 0; i < firstDayIndex; i++){ // loop that fill days in buttons that represent previous month
buttonArray[i].setText(""+dayNo2);
buttonArray[i].setVisible(true);
buttonArray[i].setEnabled(false);
buttonArray[i].setBackground(buttonColorInactive);
dayNo2++;
}
for (int i = firstDayIndex; i < noOfDays + firstDayIndex; i++){ // loop that fill days in buttons that represent current month
buttonArray[i].setText(""+dayNo);
buttonArray[i].setVisible(true);
if (i == 6 || i == 13 || i == 20 || i == 27 || i == 34 || i == 41){
buttonArray[i].setBackground(sundey);
}
else if (i == 5 || i == 12 || i == 19 || i == 26 || i == 33 || i == 40){
buttonArray[i].setBackground(saturday);
}
else{
buttonArray[i].setBackground(buttonColor);
}
monthYear.setText(""+translate(dateNow.getMonth().getValue())+" "+year); // "translate()" method is used for translating month names from English to my native language
dayNo++;
}
dayNo = 1; // setting dayNo 1 because next month always starts with 1
for (int i = (noOfDays + firstDayIndex); i < 42; i++){ // loop that fills the rest, empty buttons that represent next month
buttonArray[i].setText(""+ dayNo);
buttonArray[i].setVisible(true);
buttonArray[i].setEnabled(false);
buttonArray[i].setBackground(buttonColorInactive);
dayNo++;
}
}
// Method for translating English names to my native Language
private String translate(int a){
String monthInPolish = "";
switch (dateNow.getMonth()){
case JANUARY: monthInPolish = "Styczeń"; break;
case FEBRUARY: monthInPolish = "Luty"; break;
case MARCH: monthInPolish = "Marzec"; break;
case APRIL: monthInPolish = "Kwiecień"; break;
case MAY: monthInPolish = "Maj"; break;
case JUNE: monthInPolish = "Czerwiec"; break;
case JULY: monthInPolish = "Lipiec"; break;
case AUGUST: monthInPolish = "Sierpień"; break;
case SEPTEMBER: monthInPolish = "Wrzesień"; break;
case OCTOBER: monthInPolish = "Październik"; break;
case NOVEMBER: monthInPolish = "Listopad"; break;
case DECEMBER: monthInPolish = "Grudzień"; break;
}
return monthInPolish;
}
}
The method that I'm talking about is called calendarGenerator()
Thanks for the effort!
This is how it looks when I use that method in the constructor
This is how it looks when I not use that method in the constructor
Edit: I've added pictures of how it looks when I use calendarGenerator() method in constructor and when that method is not used. Using that method in that form (as showed above) when the button is pressed, I wanted to see if my approach is correct (I know that I can send arguments and thus use it to switch months). So I removed the calendarGenerator() method from constructor (the second picture shows how the program looks like without it) and put it to ActionPerformed method for the button (that black arrow). I thought that when I press the button the window will change the look so it will look like on the first picture but only text on the label above is changing nothing else and I still don't know why.
Change calendarGenerator so it accepts an argument which is an arbitrary date in the month you want to generate:
private void calendarGenerator(LocalDate dateInMonth){
int noOfDays = dateInMonth.lengthOfMonth(); /// getting number of days in a month
.........
}
To generate the current month call it by calendarGenerator(dateNow);
To generate next month: calendarGenerator(dateNow.plusMonths(1));
The following is an mre(1) demonstrating how to use the modified method:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
class Panel extends JPanel {
private JPanel monthPanel;
private JLabel monthYear;
private final static Color buttonColor = new Color(116, 185, 255), buttonColorInactive = new Color(255,255,255),
sundey = new Color(0, 184, 148), saturday = new Color(85, 239, 196), labelColor = new Color(255, 211, 42);
private final static int DAYS=7, WEEKS =6;
private final LocalDate dateNow = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
private LocalDate calendarDate;
private final JButton[] buttonArray = new JButton[DAYS*WEEKS];
Panel(){
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(getMonthLabel());
add(getWeekDaysPanel());
add(Box.createRigidArea(new Dimension(0,5)));
makeMonthPanel();
add(monthPanel);
calendarGenerator(dateNow);
}
private void makeMonthPanel(){
monthPanel = new JPanel();
monthPanel.setLayout(new GridLayout(WEEKS,DAYS));
monthPanel.setPreferredSize(new Dimension(710,460));
monthPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
//Loop that in every iteration creates a "b" button set it properties and to a "p" panel and a buttonArray.
for (int i=0; i< DAYS * WEEKS; i++){
JButton b = new JButton();
b.setPreferredSize(new Dimension(95,70));
b.setBorderPainted(false);
b.setRolloverEnabled(false);
JPanel p = new JPanel();
p.add(b);
buttonArray[i] = b;
monthPanel.add(p);
}
}
// Similar to getMonthPanel method - it adds a 7 labels with the names of the days
private JComponent getWeekDaysPanel(){
JPanel daysPanel = new JPanel();
daysPanel.setBackground(labelColor);
daysPanel.setPreferredSize(new Dimension(700,35));
String[] daysList = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
for (int i = 0; i < daysList.length ; i++){
JLabel e = new JLabel("", JLabel.CENTER);
e.setPreferredSize(new Dimension(95,25));
e.setText(daysList[i]);
daysPanel.add(e);
}
return daysPanel;
}
// a method that adds a two buttons (to switch to previous and next month) and a label that displays the displayed month and year
private JComponent getMonthLabel(){
JPanel monthLabel = new JPanel();
monthLabel.setBackground(buttonColorInactive);
JButton nextButton = new JButton(">");;
nextButton.setBorderPainted(false);
nextButton.setBackground(new Color(255,255,255));
nextButton.addActionListener(e -> calendarGenerator(calendarDate.plusMonths(1)));
JButton previousButton = new JButton("<");
previousButton.setBorderPainted(false);
previousButton.setBackground(new Color(255,255,255));
previousButton.addActionListener(e -> calendarGenerator(calendarDate.minusMonths(1)));
monthYear = new JLabel("MIESIĄC_ROK", JLabel.CENTER);
monthYear.setPreferredSize(new Dimension(620,25));
monthLabel.add(previousButton);
monthLabel.add(monthYear);
monthLabel.add(nextButton);
return monthLabel;
}
// A method that change the appearance of the buttons in the "buttonArray" so the whole thing looks like calendar of the month
private void calendarGenerator(LocalDate dateInMonth){
calendarDate = dateInMonth;
int noOfDays = dateInMonth.lengthOfMonth(); /// getting number of days in a month
int firstDayIndex = dateInMonth.getDayOfWeek().getValue() - 1; // gettin the value (number) of the first day of month (it is decreased because getValue starts with 1 and buttonArray with 0)
int dayNo = 1; // variable that is used to set number of day in the setText() method of button
int month = dateInMonth.getMonth().getValue() - 1; // variable that has a number of the previous month, that is why I decreased it by 1
int year = dateInMonth.getYear(); // getting current year
if (month == 0){ // safety - when the month variable hits 0 it is set for December (no 12) and year is decreased by 1
month = 12;
year --;
}
LocalDate previousMonthDate = LocalDate.of(year, month, 1); // a new variable for the previous month
int dayNo2 = previousMonthDate.lengthOfMonth() - (firstDayIndex - 1); // getting number of days of the previous mont (similar to dayNo but it responsible for the previous month during displaying
for (int i = 0; i < firstDayIndex; i++){ // loop that fill days in buttons that represent previous month
buttonArray[i].setText(""+dayNo2);
buttonArray[i].setEnabled(false);
buttonArray[i].setBackground(buttonColorInactive);
dayNo2++;
}
for (int i = firstDayIndex; i < noOfDays + firstDayIndex; i++){ // loop that fill days in buttons that represent current month
buttonArray[i].setText(""+dayNo);
buttonArray[i].setVisible(true);
if (i == 6 || i == 13 || i == 20 || i == 27 || i == 34 || i == 41){
buttonArray[i].setBackground(sundey);
}
else if (i == 5 || i == 12 || i == 19 || i == 26 || i == 33 || i == 40){
buttonArray[i].setBackground(saturday);
}
else{
buttonArray[i].setBackground(buttonColor);
}
monthYear.setText(""+dateInMonth.getMonth()+" "+year);
dayNo++;
}
dayNo = 1; // setting dayNo 1 because next month always starts with 1
for (int i = noOfDays + firstDayIndex; i < 42; i++){ // loop that fills the rest, empty buttons that represent next month
buttonArray[i].setText(""+ dayNo);
buttonArray[i].setVisible(true);
buttonArray[i].setEnabled(false);
buttonArray[i].setBackground(buttonColorInactive);
dayNo++;
}
monthPanel.revalidate();
}
public static void main(String[] args) {
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel calendarPane = new Panel();
frame.getContentPane().add(calendarPane);
frame.pack();
frame.setVisible(true);
}
}
(1) Please consider mre when posting questions and answers. To achieve it remove every thing that is not essential (like translation in this case) to show the problem. mre should demonstrate the problem and not necessarily your application.
This question already has answers here:
Dynamic Clock in java
(7 answers)
Closed 4 years ago.
I am creating a program that gets the time and displays it in a JFrame (it also updates the background to be the color #[HOUR][MIN][SEC] like on rhysperry.co.nf ). My problem is the timer seams to only update every 2-4 seconds(on lower end machines). I have the code and am wondering how I would go about optimizing an already small program.
Please tolerate bad coding practices as I still don't fully understand Java.
Here is my code - Window.java:
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
public class Window {
/**
* Simple color changing clock based on the website the website rhysperry.co.nf
*
* #author Rhys Perry
*/
public static void main(String[] args) throws IOException, FontFormatException, InterruptedException {
//Import font
InputStream in = Window.class.getResourceAsStream("Lato-Hairline.ttf");
Font font = Font.createFont(Font.TRUETYPE_FONT, in).deriveFont(50f);
//Initialise the Frame, Panel and label
JFrame frame= new JFrame("Hex Clock");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JLabel label = new JLabel();
label.setFont(font);
label.setPreferredSize(new Dimension(200, 350));
label.setForeground(Color.WHITE);
//Merge Frame, Panel and "This is a test")Label. Make window visible
panel.add(label);
frame.add(panel);
frame.setSize(700, 400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//Setup calendar
Calendar calendar;
//Initialise some variables to do with time management
String formattedhour;
String formattedmin;
String formattedsec;
//Main loop to get the time and update the background ad Label
while(true) {
//Get hours, minutes and seconds
calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if (hour < 10) { formattedhour = "0" + hour; } else { formattedhour = hour + "";}
int min = calendar.get(Calendar.MINUTE);
if (min < 10) { formattedmin = "0" + min; } else { formattedmin = min + "";}
int sec = calendar.get(Calendar.SECOND);
if (sec < 10) { formattedsec = "0" + sec; } else { formattedsec = sec + "";}
//Format and update the necessary components
String time = formattedhour + ":" + formattedmin + " " + formattedsec;
label.setText(time);
String hex = "#" + formattedhour + formattedmin + formattedsec;
panel.setBackground(Color.decode(hex));
panel.repaint();
}
}
}
You can use javax.swing.Timmer instead. It executes a task repeatedly after interval of time. https://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
Timer timer = new Timer(10 ,taskPerformer);
timer.start();
So I have a Calendar GUI using a borderlayout. There is a header (north) with combo boxes of month and years. When I select an item in the month combo box say, June, then it will update the calendar and repaint the center (The center has 42 JButtons). The center is a JPanel filled with button. The buttons are intractable to display events of that day (Just listing as much information as I can).
My problem is repainting the panel and stretching the frame. When I stretch the frame, for some reason the Center Panel repeats itself. When I call revalidate, it continues to repeat itself.
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
public class cPan extends JPanel implements ChangeListener
{
String date;
public HashMap<String, ArrayList<Event>> haM;
DataModel data;
JButton dayB;
MyCalendar cal;
public cPan(MyCalendar c, HashMap<String, ArrayList<Event>> hm, DataModel d)
{
haM = hm;
data = d;
cal = c;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
System.out.println(month);
int day = cal.get(Calendar.DAY_OF_MONTH);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
Calendar calForDay = Calendar.getInstance();
calForDay.set(Calendar.DATE, day);
calForDay.set(Calendar.MONTH, month);
calForDay.set(Calendar.YEAR, year);
calForDay.set(Calendar.DAY_OF_MONTH, 1);
Date firstDayOfMonth = calForDay.getTime();
int counter = 0;
SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
String fDOM = sdf.format(firstDayOfMonth);
//print empty buttons
if(fDOM.equalsIgnoreCase("SUNDAY")) {counter = 1;}
if(fDOM.equalsIgnoreCase("MONDAY")) {counter = 2;}
if(fDOM.equalsIgnoreCase("TUESDAY")) {counter = 3;}
if(fDOM.equalsIgnoreCase("WEDNESDAY")) {counter = 4;}
if(fDOM.equalsIgnoreCase("THURSDAY")) {counter = 5;}
if(fDOM.equalsIgnoreCase("FRIDAY")) {counter = 6;}
if(fDOM.equalsIgnoreCase("SATURDAY")) {counter = 7;}
setLayout(new GridLayout(7,7));
DAYS[] arrOfDays = DAYS.values();
for(DAYS s : arrOfDays)
{
dayB = new JButton(s.name());
dayB.setBackground(new Color(255, 204, 153 , 255));
add(dayB);
}
for (int j = 1; j < counter; j++)
{
dayB.setBackground(new Color(255, 229, 204, 255));
dayB = new JButton("");
add(dayB);
}
//print day buttons
for(int i = 1; i <= daysInMonth; i++)
{
String dayNum = String.valueOf(i);
String monthNum = String.valueOf(month + 1);
String yearNum = String.valueOf(year);
String dayNum2 = dayNum;
if(dayNum.length() == 1)
{
dayNum2 = "0" + dayNum;
}
if(String.valueOf(month).length() == 1)
{
monthNum = "0" + monthNum;
}
date = yearNum + monthNum + dayNum2;
dayB = new JButton(dayNum);
if(i == day)
{
dayB.setBackground(new Color(153, 255, 153, 255));
}
else if(haM.containsKey(date))
{
dayB.setBackground(new Color(255, 255, 153, 255));
}
else
{
dayB.setBackground(new Color(255, 229, 204, 255));
}
dayB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
DayFrame dayF = new DayFrame(date, haM);
}
});
add(dayB);
counter++;
}
//print empty buttons
for(int i = counter; i <= 42; i++)
{
dayB = new JButton("");
dayB.setBackground(new Color(255, 229, 204, 255));
add(dayB);
}
}
public void stateChanged(ChangeEvent e) {
System.out.println("Something is going on in statechange");
cal.set(Calendar.MONTH, 10); // only did this to test it out
cPan.this.revalidate();
cPan.this.repaint();
}
}
Your paintComponent method is doing many things that it should never do, such as create and place components. It should paint and paint only.
I suggest that instead you place your components into your GUI inside of your class's constructor, and again use paintComponent just for painting and nothing else. If you're wanting to display a calendar, consider displaying each day as a JPanel held in a GridLayout-using JPanel. The DayPanel could be in its own class in order to refactor out the information.
Also, you should rename your class, since by convention class names should begin with an upper case letter, and so something like CalendarPanel would be better.
I have a datepicker program, which allows me to choose date. I want to highlight the current date in the current month and current year only. All others not to be highlighted. I have buttons on which I display the dates in a month. I am able to highlight the current date in the current month and current year, but the same cell is highlighted in all the months in all years. How can I avoid this?
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.Component;
import java.awt.event.*;
import java.awt.*;
import java.awt.Toolkit;
import java.awt.Component.*;
import java.awt.Graphics;
import java.awt.Cursor.*;
import java.text.*;
public class DatePicker
{
int month = Calendar.getInstance().get(Calendar.MONTH);
int year = Calendar.getInstance().get(Calendar.YEAR);
JLabel l = new JLabel("", JLabel.CENTER);
String day = "";
JDialog d;
JButton[] button = new JButton[49];
public DatePicker(JFrame parent)
{
d = new JDialog();
d.setModal(true);
String[] header = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
JPanel p1 = new JPanel(new GridLayout(7, 7));
p1.setPreferredSize(new Dimension(430, 120));
for(int x = 0; x < button.length; x++)
{
final int selection = x;
button[x] = new JButton();
button[x].setFocusPainted(false);
button[x].setBackground(Color.white);
if(x > 6)
button[x].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
day = button[selection].getActionCommand();
d.dispose();
}
});
if(x < 7)
{
button[x].setText(header[x]);
button[x].setForeground(Color.red);
}
p1.add(button[x]);
}
JPanel p2 = new JPanel(new GridLayout(1, 3));
JButton previous = new JButton("<< Previous");
previous.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
month--;
displayDate();
}
});
p2.add(previous);
p2.add(l);
JButton next = new JButton("Next >>");
next.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
month++;
displayDate();
}
});
p2.add(next);
d.add(p1, BorderLayout.CENTER);
d.add(p2, BorderLayout.SOUTH);
d.pack();
d.setLocationRelativeTo(parent);
displayDate();
d.setVisible(true);
}
public void displayDate()
{
for(int x = 7; x < button.length; x++)
button[x].setText("");
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("MMMM yyyy");
Calendar cal = Calendar.getInstance();
cal.set(year, month, 1);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
int daysInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
Font font = new Font("Courier", Font.BOLD, 12);
Calendar curr = new GregorianCalendar();
int currdate = curr.get(Calendar.DAY_OF_MONTH);
int currmon = curr.get(Calendar.MONTH);
int curryear = curr.get(Calendar.YEAR);
int date = cal.get(Calendar.DAY_OF_MONTH);
int mon = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
int day1 = cal.get(Calendar.DAY_OF_WEEK);
int start = (7 - (date - day1) % 7) % 7;
int days = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
System.out.println("currdate : " + currdate);
System.out.println("currmon : " + currmon);
System.out.println("mon : " + mon);
System.out.println("curryear : " + curryear);
System.out.println("year : " + year);
for(int x = 6 + dayOfWeek, day = 1; day <= daysInMonth; x++, day++)
{
button[x].setText("" + day);
System.out.println("x : " + x);
System.out.println("day : " + day);
if(currdate == (x - 12) && currmon == mon && curryear == year)
{
// button[x].setFont(font);
button[day].setBackground(Color.GREEN);
}
else
button[x].setBackground(Color.white);
}
// for(int i = 1; i <= days; i++)
l.setText(sdf.format(cal.getTime()));
d.setTitle("Date Picker");
}
public String setPickedDate()
{
if(day.equals(""))
return day;
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("MM-dd-yyyy");
Calendar cal = Calendar.getInstance();
cal.set(year, month, Integer.parseInt(day));
return sdf.format(cal.getTime());
}
}
update my post
You are missing else block:
if(currdate == (x - 12) && currmon == mon && curryear == year) {
button[x].setFont(font);
button[x].setBackground(Color.GREEN);
} else {
button[x].setFont(?); //<-- replace ? with desired font
button[x].setBackground(?); //<-- replace ? with desired color
}
How can a step be specified for JSpinner? (for example of 10 minutes instead of 1)
There is a model that allow select step size for numbers
SpinnerNumberModel(value, min, max, step);
but how to set it for Dates?
This code
JSpinner timeSpinner = new JSpinner( new SpinnerDateModel() );
DateEditor timeEditor = new DateEditor(timeSpinner, "HH:mm:ss");
timeSpinner.setEditor(timeEditor);
timeSpinner.setValue(new Date()); // will only show the current time
(From this answer Is there any good and free Date AND Time Picker available for Java Swing?)
Allows edit time only, but the steps are always 1 hour, 1 minute, or 1 second depending on if "HH", "HH:mm", or "HH:mm:ss" is specified.
Is there any simple way to have min, max, and step for minutes?
Thanks
Use DateEditor.getModel() to get the SpinnerDateModel which provides setStart,setEnd and setCalendarField.
As you can see in the code of SpinnerDateModel:
public Object getNextValue() {
Calendar cal = Calendar.getInstance(); //Current date.
cal.setTime(value.getTime()); //Set the date to the current value of the model.
cal.add(calendarField, 1); //Increment the date by 1 unit of the selected calendar field (e.g. 1 month).
Date next = cal.getTime(); //Convert back to Date Object.
return ((end == null) || (end.compareTo(next) >= 0)) ? next : null;
}
public Object getPreviousValue() {
Calendar cal = Calendar.getInstance(); //Current date.
cal.setTime(value.getTime()); //Set the date to the current value of the model.
cal.add(calendarField, -1); //Decrement the date by 1 unit of the selected calendar field (e.g. 1 month).
Date prev = cal.getTime(); //Convert back to Date Object.
return ((start == null) || (start.compareTo(prev) <= 0)) ? prev : null;
}
It works with adding or substracting 1 unit of the specified calendar field.
You want to customize this number 1 to something else.
So I see two options here:
Reimplement AbstractSpinnerModel. Just copy-paste SpinnerDateModel (it's NOT big), then introduce your integer field "step" for example, and instead of the number 1, just put "step" in getNext and getPrevious.
Implement a SpinnerDateModel, which also works internally with a SpinnerDateModel. It's going to be a lot smaller, but is a bit hackish I guess.
Follows the code of such an SpinnerDateModel (case 2):
import java.awt.GridLayout;
import java.util.Calendar;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
public class MultiStepDateSpinner extends JPanel {
private static class StepperSpinnerDateModel extends SpinnerDateModel {
private final SpinnerDateModel internal; //We let the internal SpinnerDateModel do the work for us.
private final int step; //The number of steps to increment and decrement per click.
private Object currentValue; //Needed to get restored each time getPreviousValue and getNextValue is called.
private StepperSpinnerDateModel(final Date value, final Comparable start, final Comparable end, final int calendarField, final int step) {
internal = new SpinnerDateModel(value, start, end, calendarField);
if (step <= 0)
throw new IllegalArgumentException("Non positive step.");
this.step = step;
currentValue = internal.getValue();
}
private StepperSpinnerDateModel(final int step) {
this(new Date(), null, null, Calendar.DAY_OF_MONTH, step);
}
#Override
public Object getValue() {
return currentValue;
}
#Override
public void setValue(final Object value) {
internal.setValue(value);
currentValue = value;
fireStateChanged(); //Important step for the spinner to get updated each time the model's value changes.
}
#Override
public Object getNextValue() {
Object next = null;
for (int i=0; i<step; ++i) { //Calculate step next values:
next = internal.getNextValue();
internal.setValue(next); //We have to set the next value internally, in order to recalculate the next-next value in the next loop.
}
internal.setValue(currentValue); //Restore current value.
return next;
}
#Override
public Object getPreviousValue() {
Object prev = null;
for (int i=0; i<step; ++i) { //Calculate step previous values:
prev = internal.getPreviousValue();
internal.setValue(prev); //We have to set the previous value internally, in order to recalculate the previous-previous value in the next loop.
}
internal.setValue(currentValue); //Restore current value.
return prev;
}
}
private MultiStepDateSpinner() {
super(new GridLayout(0, 1));
//Increment and decrement by 4 minutes each step.
//The null values indicate there shall be no minimum nor maximum date.
//The current value is set to the current date.
final JSpinner spinner = new JSpinner(new StepperSpinnerDateModel(new Date(), null, null, Calendar.MINUTE, 4));
final JButton getValueButton = new JButton("Get value");
getValueButton.addActionListener(e -> {
JOptionPane.showMessageDialog(null, spinner.getValue(), "Got value", JOptionPane.PLAIN_MESSAGE);
});
add(spinner);
add(getValueButton);
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MultiStepDateSpinner());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
The example code above, is runnable, so you can see it in practice.
Why not just let it be an AbstractSpinnerModel instead of SpinnerDateModel? Because we need it to be identified as an instance of SpinnerDateModel so the JSpinner internally allocates by default a DateEditor for the editor.
Even if you extend AbstractSpinnerModel and supply the spinner with a DateEditor, you will get an exception complaining about the model not being a SpinnerDateModel.
The cleanest way though as I see it, is to reimplement AbstractSpinnerModel and copy paste the code of SpinnerDateModel if needed (which is not big) and introduce any fields you feel.
Incrementa JSpinnerDateEditor_15_+_15_minutos
Calendar Horacalendario = Calendar.getInstance();
Horacalendario.setTime(cita_hora.getDate());
Date HoraParaCita = Horacalendario.getTime();//para asignar luego del incremento de 15 formato date()'
int minutos = Horacalendario.get(Calendar.MINUTE);
Horacalendario.set(Horacalendario.get(Calendar.YEAR), Horacalendario.get(Calendar.MONTH),
Horacalendario.get(Calendar.DATE), Horacalendario.get(Calendar.HOUR), 0);//hago cero los minutos
if (minutos >= 1 & minutos <= 14) {
Horacalendario.add(Calendar.MINUTE, 15); //minutos A Sumar
HoraParaCita = Horacalendario.getTime();
cita_hora.setDate(HoraParaCita);
}
if (minutos >= 16 & minutos <= 29) {
Horacalendario.add(Calendar.MINUTE, 30);
HoraParaCita = Horacalendario.getTime();
cita_hora.setDate(HoraParaCita);
}
if (minutos >= 31 & minutos <= 44) {
Horacalendario.add(Calendar.MINUTE, 45);
HoraParaCita = Horacalendario.getTime();
cita_hora.setDate(HoraParaCita);
}
if (minutos >= 46 & minutos <= 59) {
Horacalendario.set(Horacalendario.get(Calendar.YEAR), Horacalendario.get(Calendar.MONTH),
Horacalendario.get(Calendar.DATE), Horacalendario.get(Calendar.HOUR), 0);//hago cero los minutos
HoraParaCita = Horacalendario.getTime();
cita_hora.setDate(HoraParaCita);
}