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.
Related
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
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();
}
}
I have a jtable with a custom editor and renderer applied to a column to turn the column's contents into a Button, however once i press on any of the buttons, the table loses focus, and the only interactive object in the panel is the button that was just clicked on, which can be clicked on repeatedly.
Here is the button renderer code:
public class ButtonRenderer implements TableCellRenderer {
private Border dsd_originalBorder;
private int in_mnemonic;
private Border dsd_focusBorder;
private JButton dsd_renderButton;
/**
* empty constructor
*/
public ButtonRenderer() {
dsd_renderButton = new JButton();
}
public Component getTableCellRendererComponent(JTable dsd_table, Object dsd_value,
boolean bo_isSelected, boolean bo_hasFocus, int in_row, int in_column) {
if (!WorkplaceConstants.STR_INACTIVE.equals(dsd_table.getValueAt(in_row, dsd_table
.getColumn(Main.hm_language.get(Language.STATUS))
.getModelIndex())))
return new JLabel("");
if (bo_isSelected) {
dsd_renderButton.setForeground(dsd_table.getSelectionForeground());
dsd_renderButton.setBackground(dsd_table.getSelectionBackground());
} else {
dsd_renderButton.setForeground(dsd_table.getForeground());
dsd_renderButton.setBackground(UIManager.getColor("Button.background"));
}
if (bo_hasFocus) {
dsd_renderButton.setBorder(dsd_focusBorder);
} else {
dsd_renderButton.setBorder(dsd_originalBorder);
}
// renderButton.setText( (value == null) ? "" : value.toString() );
if (dsd_value == null) {
dsd_renderButton.setText("");
dsd_renderButton.setIcon(null);
} else if (dsd_value instanceof Icon) {
dsd_renderButton.setText("");
dsd_renderButton.setIcon((Icon) dsd_value);
} else {
dsd_renderButton.setText(dsd_value.toString());
dsd_renderButton.setIcon(null);
}
return dsd_renderButton;
}
/**
* returns the mnemonic to activate the button when the cell has focus
*
* #return the mnemonic
*/
public int m_getMnemonic() {
return in_mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param p_in_mnemonic
* the mnemonic
*/
public void m_setMnemonic(int p_in_mnemonic) {
this.in_mnemonic = p_in_mnemonic;
dsd_renderButton.setMnemonic(p_in_mnemonic);
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border m_getFocusBorder() {
return dsd_focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param dsd_focusBorder
* the foreground color
*/
public void m_setFocusBorder(Border dsd_focusBorder) {
this.dsd_focusBorder = dsd_focusBorder;
}
Here is the button Editor code:
public class ButtonEditor extends AbstractCellEditor implements TableCellEditor, ActionListener, MouseListener{
private JTable dsd_table;
private int in_mnemonic;
private Border dsd_originalBorder;
private Border dsd_focusBorder;
private JButton dsd_editButton;
private Object dsd_editorValue;
private boolean bo_isButtonColumnEditor;
/**
* Constructor
* #param dsdp_table the table to which the editor is going to be applied.
* #param action the action which is to be executed when the button is clicked
*/
public ButtonEditor(JTable dsdp_table) {
this.dsd_table = dsdp_table;
dsd_editButton = new JButton();
dsd_editButton.setFocusPainted( false );
dsd_editButton.addActionListener( this );
dsd_originalBorder = dsd_editButton.getBorder();
m_setFocusBorder( new LineBorder(Color.BLUE) );
dsdp_table.addMouseListener( this );
}
public Object getCellEditorValue() {
return dsd_editorValue;
}
/**
* returns the mnemonic to activate the button when the cell has focus
*
* #return the mnemonic
*/
public int m_getMnemonic()
{
return in_mnemonic;
}
/**
* The mnemonic to activate the button when the cell has focus
*
* #param in_mnemonic the mnemonic
*/
public void m_setMnemonic(int in_mnemonic)
{
this.in_mnemonic = in_mnemonic;
dsd_editButton.setMnemonic(in_mnemonic);
}
/**
* Get foreground color of the button when the cell has focus
*
* #return the foreground color
*/
public Border m_getFocusBorder() {
return dsd_focusBorder;
}
/**
* The foreground color of the button when the cell has focus
*
* #param dsdp_focusBorder
* the foreground color
*/
public void m_setFocusBorder(Border dsdp_focusBorder) {
this.dsd_focusBorder = dsdp_focusBorder;
dsd_editButton.setBorder(dsdp_focusBorder);
}
public void actionPerformed(ActionEvent arg0) {
int in_modelRow = dsd_table.convertRowIndexToModel( dsd_table.getEditingRow() );
fireEditingStopped();
// Here i start a custom thread to run in the background.
}
public void mouseClicked(MouseEvent arg0) {
}
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
public void mousePressed(MouseEvent arg0) {
if (dsd_table.isEditing() && dsd_table.getCellEditor() == this)
bo_isButtonColumnEditor = true;
}
public void mouseReleased(MouseEvent arg0) {
if (bo_isButtonColumnEditor && dsd_table.isEditing())
dsd_table.getCellEditor().stopCellEditing();
bo_isButtonColumnEditor = false;
}
public void addCellEditorListener(CellEditorListener arg0) {
}
public void cancelCellEditing() {
}
public void removeCellEditorListener(CellEditorListener arg0) {
}
public boolean shouldSelectCell(EventObject arg0) {
return false;
}
public boolean stopCellEditing() {
return false;
}
public Component getTableCellEditorComponent(JTable dsd_table, Object dsd_value,
boolean bo_isSelected, int in_row, int in_column) {
if (!WorkplaceConstants.STR_INACTIVE.equals(dsd_table.getValueAt(in_row, dsd_table
.getColumn(Main.hm_language.get(Language.STATUS))
.getModelIndex())))
return new JLabel("");
if (dsd_value == null)
{
dsd_editButton.setText( "" );
dsd_editButton.setIcon( null );
}
else if (dsd_value instanceof Icon)
{
dsd_editButton.setText( "" );
dsd_editButton.setIcon( (Icon)dsd_value );
}
else
{
dsd_editButton.setText( dsd_value.toString() );
dsd_editButton.setIcon( null );
}
bo_isButtonColumnEditor = true;
this.dsd_editorValue = dsd_value;
dsd_editButton.setBorder(dsd_originalBorder);
return dsd_editButton;
}
public boolean isCellEditable(EventObject e){
return true;
}
public Border m_getoriginalBorder() {
return dsd_originalBorder;
}
public void m_set_originalBorder(Border dsd_originalBorder) {
this.dsd_originalBorder = dsd_originalBorder;
}
}
Here is how i am assigning the editor and renderer to the table
public static void m_setButtonColumnConfiguration(JTable table) {
ButtonEditor dsd_btn_edit = new ButtonEditor(table);
dsd_btn_edit.m_setMnemonic(KeyEvent.VK_D);
table.getColumn(/*i get the identifier for the column here*/).setCellEditor(dsd_btn_edit);
ButtonRenderer dsd_btn_rend = new ButtonRenderer();
dsd_btn_rend.m_setMnemonic(KeyEvent.VK_D);
table.getColumn(/*i get the identifier for the column here*/)
.setCellRenderer(dsd_btn_rend);
}
Button, however once i press on any of the buttons, the table loses focus
Yes, anytime you click on a component it gets focus, so this makes sense.
and the only interactive object in the panel is the button that was just clicked on,
Not sure I understand this statement. You can click on the table again and it will regain focus. You can then navigate around the table.
Maybe you are just suggesting the button renderer/editor isn't working the way you expect. We can't test this because you didn't post a SSCCE.
Anyway, check out Table Button Column for another example of a button renderer/editor that responds to mouse clicks or key board events.
I am using a JXComboBox as cell editor in a modified JXTable/RXTable with custom models. I am noticing a delay when starting to type inside the cell.
Edit: also, if you type more keys faster in the box, the first one you typed will not appear first in the editor.
The table:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import org.jdesktop.swingx.JXTable;
/**
* This is a modified version of RXTable following this thread:
* http://stackoverflow.com/questions/7365397/combining-jxtable-with-rxtable.
* The JRXTable provides some extensions to the default JTable
*
* 1) Select All editing - when a text related cell is placed in editing mode
* the text is selected. Controlled by invoking a "setSelectAll..." method.
*
* 2) reorderColumns - static convenience method for reodering table columns
*/
public class JRXTable extends JXTable {
private boolean isSelectAllForMouseEvent = false;
private boolean isSelectAllForActionEvent = false;
private boolean isSelectAllForKeyEvent = false;
//
// Constructors
//
/**
* Constructs a default
* <code>JRXTable</code> that is initialized with a default data model, a
* default column model, and a default selection model.
*/
public JRXTable() {
this(null, null, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model, a default column model, and a default
* selection model.
*
* #param dm the data model for the table
*/
public JRXTable(TableModel dm) {
this(dm, null, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model,
* <code>cm</code> as the column model, and a default selection model.
*
* #param dm the data model for the table
* #param cm the column model for the table
*/
public JRXTable(TableModel dm, TableColumnModel cm) {
this(dm, cm, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model,
* <code>cm</code> as the column model, and
* <code>sm</code> as the selection model. If any of the parameters are
* <code>null</code> this method will initialize the table with the
* corresponding default model. The
* <code>autoCreateColumnsFromModel</code> flag is set to false if
* <code>cm</code> is non-null, otherwise it is set to true and the column
* model is populated with suitable
* <code>TableColumns</code> for the columns in
* <code>dm</code>.
*
* #param dm the data model for the table
* #param cm the column model for the table
* #param sm the row selection model for the table
*/
public JRXTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
super(dm, cm, sm);
}
/**
* Constructs a
* <code>JRXTable</code> with
* <code>numRows</code> and
* <code>numColumns</code> of empty cells using
* <code>DefaultTableModel</code>. The columns will have names of the form
* "A", "B", "C", etc.
*
* #param numRows the number of rows the table holds
* #param numColumns the number of columns the table holds
*/
public JRXTable(int numRows, int numColumns) {
this(new DefaultTableModel(numRows, numColumns));
}
/**
* Constructs a
* <code>JRXTable</code> to display the values in the
* <code>Vector</code> of
* <code>Vectors</code>,
* <code>rowData</code>, with column names,
* <code>columnNames</code>. The
* <code>Vectors</code> contained in
* <code>rowData</code> should contain the values for that row. In other
* words, the value of the cell at row 1, column 5 can be obtained with the
* following code:
* <p>
* <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
* <p>
*
* #param rowData the data for the new table
* #param columnNames names of each column
*/
public JRXTable(Vector rowData, Vector columnNames) {
this(new DefaultTableModel(rowData, columnNames));
}
/**
* Constructs a
* <code>JRXTable</code> to display the values in the two dimensional array,
* <code>rowData</code>, with column names,
* <code>columnNames</code>.
* <code>rowData</code> is an array of rows, so the value of the cell at row
* 1, column 5 can be obtained with the following code:
* <p>
* <pre> rowData[1][5]; </pre>
* <p>
* All rows must be of the same length as
* <code>columnNames</code>.
* <p>
*
* #param rowData the data for the new table
* #param columnNames names of each column
*/
public JRXTable(final Object[][] rowData, final Object[] columnNames) {
super(rowData, columnNames);
}
//
// Overridden methods
//
/*
* Override to provide Select All editing functionality
*/
#Override
public boolean editCellAt(int row, int column, EventObject e) {
boolean result = super.editCellAt(row, column, e);
// my editing
//
// if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
// KeyEvent keyEvent = (KeyEvent) e;
// Character keyChar = keyEvent.getKeyChar();
// if (keyChar == KeyEvent.VK_ESCAPE) {
// return result;
// }
// }
// my editing
if (isSelectAllForMouseEvent
|| isSelectAllForActionEvent
|| isSelectAllForKeyEvent) {
selectAll(e);
}
return result;
}
/*
* Select the text when editing on a text related cell is started
*/
private void selectAll(EventObject e) {
final Component editor = getEditorComponent();
// add suport for the text editor from a ComboBox
// move to editCellAt method?
if (getEditorComponent() instanceof JComboBox) {
final JComboBox combo = (JComboBox) getEditorComponent();
ComboBoxEditor comboEditor = combo.getEditor();
final JTextField comboTextField = (JTextField) comboEditor.getEditorComponent();
// comboEditor.selectAll();
if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
KeyEvent keyEvent = (KeyEvent) e;
final Character keyChar = keyEvent.getKeyChar();
if (keyChar == KeyEvent.VK_ESCAPE) {
System.out.println("escape");
// combo.getFocusCycleRootAncestor().requestFocus();
// combo.transferFocus();
} else {
comboEditor.selectAll();
comboTextField.setText(comboTextField.getText());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// set null value if the Delete key is pressed
if (keyChar == KeyEvent.VK_DELETE) {
combo.setSelectedItem(null);
comboTextField.setText(null);
} else {
comboTextField.selectAll();
// comboTextField.setText("");
}
}
});
}
}
return;
}
if (editor == null
|| !(editor instanceof JTextComponent
|| editor instanceof JFormattedTextField)) {
return;
}
if (e == null) {
((JTextComponent) editor).selectAll();
return;
}
// Typing in the cell was used to activate the editor
if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
((JTextComponent) editor).selectAll();
return;
}
// If the cell we are dealing with is a JFormattedTextField
// force to commit, and invoke selectall
if (editor instanceof JFormattedTextField) {
invokeSelectAll((JFormattedTextField) editor);
return;
}
// F2 was used to activate the editor
if (e instanceof ActionEvent && isSelectAllForActionEvent) {
((JTextComponent) editor).selectAll();
return;
}
// A mouse click was used to activate the editor.
// Generally this is a double click and the second mouse click is
// passed to the editor which would remove the text selection unless
// we use the invokeLater()
if (e instanceof MouseEvent && isSelectAllForMouseEvent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
((JTextComponent) editor).selectAll();
}
});
}
}
private void invokeSelectAll(final JFormattedTextField editor) {
// old trick: force to commit, and invoke selectall
editor.setText(editor.getText());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
editor.selectAll();
}
});
}
//
// Newly added methods
//
/*
* Sets the Select All property for for all event types
*/
public void setSelectAllForEdit(boolean isSelectAllForEdit) {
setSelectAllForMouseEvent(isSelectAllForEdit);
setSelectAllForActionEvent(isSelectAllForEdit);
setSelectAllForKeyEvent(isSelectAllForEdit);
}
/*
* Set the Select All property when editing is invoked by the mouse
*/
public void setSelectAllForMouseEvent(boolean isSelectAllForMouseEvent) {
this.isSelectAllForMouseEvent = isSelectAllForMouseEvent;
}
/*
* Set the Select All property when editing is invoked by the "F2" key
*/
public void setSelectAllForActionEvent(boolean isSelectAllForActionEvent) {
this.isSelectAllForActionEvent = isSelectAllForActionEvent;
}
/*
* Set the Select All property when editing is invoked by
* typing directly into the cell
*/
public void setSelectAllForKeyEvent(boolean isSelectAllForKeyEvent) {
this.isSelectAllForKeyEvent = isSelectAllForKeyEvent;
}
//
// Static, convenience methods
//
/**
* Convenience method to order the table columns of a table. The columns are
* ordered based on the column names specified in the array. If the column
* name is not found then no column is moved. This means you can specify a
* null value to preserve the current order of a given column.
*
* #param table the table containing the columns to be sorted
* #param columnNames an array containing the column names in the order they
* should be displayed
*/
public static void reorderColumns(JTable table, Object... columnNames) {
TableColumnModel model = table.getColumnModel();
for (int newIndex = 0; newIndex < columnNames.length; newIndex++) {
try {
Object columnName = columnNames[newIndex];
int index = model.getColumnIndex(columnName);
model.moveColumn(index, newIndex);
} catch (IllegalArgumentException e) {
}
}
}
} // End of Class JRXTable
The test class:
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.HashMap;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXComboBox;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.jdesktop.swingx.autocomplete.ComboBoxCellEditor;
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.renderer.StringValue;
public class TestSwingXComboCellEditor {
public static void main(String[] args) {
TestSwingXComboCellEditor test = new TestSwingXComboCellEditor();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create and add a tabbed pane to the frame
JTabbedPane tabbedPane = new JTabbedPane();
frame.getContentPane().add(tabbedPane);
//create a table and add it to a scroll pane in a new tab
JRXTable table = new JRXTable();
table.setModel(new DefaultTableModel(new Object[]{"A", "B"}, 5));
table.setSelectAllForEdit(true);
JScrollPane scrollPane = new JScrollPane(table);
tabbedPane.addTab("test", scrollPane);
// create a simple JComboBox and set is as table cell editor on column A
UserRepository rep = new UserRepository();
UserInfo[] comboElements = rep.getAllUsers();
DefaultComboBoxModel model = new DefaultComboBoxModel(comboElements);
JXComboBox comboBox = new JXComboBox(model);
StringValue stringValue = new StringValue() {
public String getString(Object value) {
if (value instanceof UserInfo) {
UserInfo userInfo = (UserInfo) value;
return userInfo.getFirstName();
} else {
return "";
}
}
};
ComboBoxCellEditor cellEditor = new ComboBoxCellEditor(comboBox);
comboBox.setRenderer(new DefaultListRenderer(stringValue));
comboBox.setEditable(true);
AutoCompleteDecorator.decorate(comboBox, new ObjectToStringConverter() {
#Override
public String getPreferredStringForItem(Object item) {
if (item instanceof UserInfo) {
return ((UserInfo) item).getFirstName();
} else {
return null;
}
}
});
table.getColumn("A").setCellEditor(cellEditor);
table.getColumn("A").setCellRenderer(new DefaultTableRenderer(stringValue));
// pack and show frame
frame.pack();
frame.setVisible(true);
}
public class UserInfo {
private String firstName;
private String lastName;
public UserInfo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
public class UserRepository {
UserInfo[] comboElements;
HashMap<String, UserInfo> objectsMap;
public UserRepository() {
comboElements = new UserInfo[5];
comboElements[0] = new UserInfo("John", "Doe");
comboElements[1] = new UserInfo("Betty", "Doe");
comboElements[2] = new UserInfo("Elenor", "Smith");
comboElements[3] = new UserInfo("Helen", "Kelly");
comboElements[4] = new UserInfo("Joe", "Black");
objectsMap = new HashMap<>();
for (int i = 0; i < 5; i++) {
objectsMap.put(comboElements[i].getFirstName(), comboElements[i]);
}
}
public UserInfo getUserInfo(String name) {
return objectsMap.get(name);
}
public UserInfo[] getAllUsers() {
return comboElements;
}
}
}
This is probably an elementary question. However, I have completed reading the 12th Chapter of Java Programming for the Absolute Beginner and have approached the Challenges section. I cannot quite get the progam to display a labeled button with the extended class.
The specification states:
Extend the JPRButton3D class to create a button that displays a label just like
the AWT Button class you're so familiar with by now. As an extra test, override
the isFocusable() method so that your button class can be traversed and make sure you
paint some special graphic to make it obvious when your button has focus.
How can I edit my code of LabelButton3D and LabelButton3DTest to accomplish this task?
An answer to this specification can potentially aid many new Java programmers in extending their own classes.
Thank you very much for your time and cooperation reagrding this matter.
HERE IS THE CODE FOR JPRButton3D:
package jpr.lightweight;
import java.awt.*;
import java.awt.event.*;
/**
* A lightweight 3D Button class that fires actions when clicked.
* When it is enabled it appears {#link #RAISED RAISED}, when
* it is pressed it appears {#link #SUNK SUNK}, and when it is
* not enabled, it appears {#link #FLAT FLAT}.
*/
public class JPRButton3D extends JPRRectComponent3D {
private boolean pressed;
/**
* This <code>JPRButton3D</code>'s <code>ActionListener</code>.
*/
protected ActionListener actionListener;
private String actionCommand;
/**
* Constructs a new <code>JPRButton3D</code> with minimum size
*/
public JPRButton3D() {
this(ABSOLUTE_MIN_WIDTH, ABSOLUTE_MIN_HEIGHT, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions.
* #param wide the width
* #param high the height
*/
public JPRButton3D(int wide, int high) {
this(wide, high, 1);
}
/**
* Constructs a new <code>JPRButton3D</code> with the given dimensions
* and border magnitude.
* #param wide the width
* #param high the height
* #param border_magnitude the border's magnitude
*/
public JPRButton3D(int wide, int high, int border_magnitude) {
super(wide, high, RAISED, border_magnitude);
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
public void processMouseEvent(MouseEvent e) {
if (isEnabled() & e.getModifiers() == MouseEvent.BUTTON1_MASK) {
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
pressed = true;
current_appearance = SUNK;
repaint();
break;
case MouseEvent.MOUSE_EXITED:
if (pressed) {
pressed = false;
current_appearance = RAISED;
repaint();
}
break;
case MouseEvent.MOUSE_RELEASED:
if (pressed) {
current_appearance = RAISED;
repaint();
if (actionListener != null) {
actionListener.actionPerformed(new ActionEvent(this,
ActionEvent.ACTION_PERFORMED, actionCommand,
e.getModifiers()));
}
}
break;
}
}
super.processMouseEvent(e);
}
/**
* Adds the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to add
*/
public void addActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.add(actionListener, listener);
}
/**
* Removes the specified <code>ActionListener</code>
* #param listener <code>ActionListener</code> to remove
*/
public void removeActionListener(ActionListener listener) {
actionListener = AWTEventMulticaster.remove(actionListener,
listener);
}
/**
* Sets the action command associated with action events.
* #param command The action command.
*/
public void setActionCommand(String command) {
actionCommand = command;
}
/**
* Gets the action command associated with action events.
* #return the action command
*/
public String getActionCommand() {
return actionCommand;
}
/**
* Enables or disables this <code>JPRButton3D</code>.
* #param b <code>true</code> to enable, <code>false</code> to disable
*/
public void setEnabled(boolean b) {
if (b) current_appearance = RAISED;
else current_appearance = FLAT;
repaint();
super.setEnabled(b);
}
}
HERE IS MY CODE FOR LabelButton3DTest (to extend JPRButton3D):
import java.awt.*;
import java.awt.event.*;
import jpr.lightweight.JPRButton3D;
public class LabelButton3DTest extends GUIFrame {
LabelButton3D[] b;
String s;
public LabelButton3DTest() {
super("LabelButton3D Test");
setLayout(new FlowLayout());
b = new LabelButton3D[1];
b[0] = new LabelButton3D("Favorite Button");
b[0] = new LabelButton3D(75, 35, 1);
add(b[0]);
pack();
setVisible(true);
}
public static void main(String args[]) {
new LabelButton3DTest();
}
}
HERE IS MY CODE FOR LabelButton3D:
public class LabelButton3D extends JPRButton3D {
public LabelButton3D(String label) {
}
public LabelButton3D(int wide, int high, int border_magnitude) {
super(wide, high, border_magnitude);
}
}