I have a minimal app to show Java Swing GUI update problem, seems it's not painting the components properly, the errors look like this :
Here is my program :
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import java.util.concurrent.*;
public class Java_Test extends JPanel
{
static JFrame frame=new JFrame("Java Test");
static int W=800,H=260,Executor_Count=12;
JPanel Progress_Panel=new JPanel(),Center_Panel;
JButton Do_Test_Button=new JButton("Do Test");
Get_Time Timer=new Get_Time();
ThreadPoolExecutor executor;
Progress_Bar Progress_bar;
Timer Display_Timer=new Timer(1);
public Java_Test()
{
setLayout(new BorderLayout());
JPanel Top_Panel=new JPanel();
Top_Panel.setPreferredSize(new Dimension(W-6,60));
add("North",Top_Panel);
Do_Test_Button.setFont(new Font("Times New Roman",0,16));
Do_Test_Button.setBackground(new Color(118,198,250));
Do_Test_Button.setForeground(new Color(0,28,218));
Do_Test_Button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Do_Test(); } });
Top_Panel.add(Do_Test_Button);
JPanel Center_Panel=new JPanel();
Center_Panel.setPreferredSize(new Dimension(W-2,170));
add("Center",Center_Panel);
Progress_Panel.setPreferredSize(new Dimension(W-2,160));
Center_Panel.add(Progress_Panel);
JLabel Progress_Label=new JLabel("Progress");
Progress_Label.setFont(new Font("Times New Roman",0,20));
Progress_Label.setBackground(new Color(253,253,253));
Progress_Label.setForeground(new Color(8,68,128));
Progress_Label.setPreferredSize(new Dimension(W-20,53));
Progress_Label.setHorizontalAlignment(SwingConstants.CENTER);
Progress_Panel.add(Progress_Label);
Progress_bar=new Progress_Bar(620,26);
Progress_Panel.add(Progress_bar);
JPanel Time_Used_Panel=new JPanel(new FlowLayout(FlowLayout.CENTER,6,26));
Time_Used_Panel.setPreferredSize(new Dimension(W-20,60));
Progress_Panel.add(Time_Used_Panel);
JLabel Time_Used_Label=new JLabel("Time : ");
Time_Used_Label.setFont(new Font("Times New Roman",0,14));
Time_Used_Label.setForeground(new Color(0,0,238));
Time_Used_Label.setHorizontalAlignment(SwingConstants.CENTER);
Time_Used_Panel.add(Time_Used_Label);
Display_Timer.setFont(new Font("Times New Roman",0,14));
Display_Timer.setForeground(new Color(0,0,238));
Display_Timer.setPreferredSize(new Dimension(50,17));
Time_Used_Panel.add(Display_Timer);
Clock clock=new Clock(0);
clock.setFont(new Font("Monospaced",Font.PLAIN,16));
clock.setBackground(new Color(0,110,220));
clock.setForeground(new Color(250,250,250));
clock.setOpaque(true);
clock.setPreferredSize(new Dimension(288,30));
clock.start();
JPanel Bottom_Panel=new JPanel();
Bottom_Panel.setPreferredSize(new Dimension(W-2,50));
Bottom_Panel.add(clock);
add("South",Bottom_Panel);
setPreferredSize(new Dimension(W,H));
}
void Do_Test()
{
String Info="",Result;
Out("Do_Test");
try
{
Display_Timer.start();
Timer.Start();
Output_Time("[ 1 ]");
Progress_bar.Set_Progress(1);
int Task_Count=222;
executor=new ThreadPoolExecutor(Executor_Count,Executor_Count*2,1,TimeUnit.SECONDS,new LinkedBlockingQueue());
ArrayList<Future<String>> futures=new ArrayList<>(Task_Count);
Test_Runner A_Runner;
try
{
for (int i=0;i<Task_Count;i++)
{
A_Runner=new Test_Runner();
futures.add(executor.submit(A_Runner));
}
executor.shutdown();
while (!executor.isTerminated()) { executor.awaitTermination(100,TimeUnit.MILLISECONDS); }
for (Future<String> future : futures)
{
Result=future.get();
if (Result!=null) Info+=Result;
}
}
catch (Exception e) { e.printStackTrace(); }
}
catch (Exception e) { e.printStackTrace(); }
Output_Time("[ 2 ]");
Progress_bar.Set_Progress(100);
Out("Done");
Display_Timer.stop();
}
String Output_Time(String Id)
{
Timer.End();
String Time_Duration=Id+" : Time = "+Timer.Get_Duration_Hour_Minute_Second();
Out(Time_Duration);
return Time_Duration;
}
private static void Out(String message) { System.out.println(message); }
static void Create_And_Show_GUI()
{
final Java_Test demo=new Java_Test();
frame.add(demo);
frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } });
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { Create_And_Show_GUI(); } }); }
}
class Progress_Bar extends JPanel implements Runnable
{
int W,H,Last_Progress=-99,Progress,counter=0,Unit_Size=20;
static JProgressBar b=new JProgressBar();
boolean Started_B=false,Do_Step_B=false;
Thread Progress_Bar_Runner_Thread;
public Progress_Bar(int W,int H)
{
setPreferredSize(new Dimension(W,H));
b.setPreferredSize(new Dimension(W-20,H-8));
b.setStringPainted(true);
add(b);
start();
}
public void Set_Progress(int Progress)
{
if (Progress==1 || (this.Progress<Progress && Progress<=100))
{
this.Progress=Progress;
b.setValue(Progress);
b.paintImmediately(0,0,b.getWidth(),b.getHeight());
Out(" Progress = "+Progress+" %");
}
if (Progress==1) Started_B=true;
else if (Progress>=100)
{
Started_B=false;
Do_Step_B=false;
}
}
public void run()
{
try
{
while (Progress<=100)
{
if ((Progress==0 || Progress==50 || Progress==100 || Do_Step_B) && Last_Progress!=Progress)
{
b.setValue(Progress);
// revalidate();
b.paintImmediately(0,0,b.getWidth(),b.getHeight());
Last_Progress=Progress;
}
Thread.sleep(200); // Delay the thread
Do_Step_B=(Started_B && (counter++ % Unit_Size ==0));
if (Progress<100 && Do_Step_B) Progress++;
}
}
catch (Exception e) { e.printStackTrace(); }
}
public void start()
{
if (Progress_Bar_Runner_Thread==null)
{
Progress_Bar_Runner_Thread=new Thread(this);
Progress_Bar_Runner_Thread.setPriority(Thread.NORM_PRIORITY);
Progress_Bar_Runner_Thread.start();
}
}
public void stop() { if (Progress_Bar_Runner_Thread!=null) Progress_Bar_Runner_Thread=null; }
private static void Out(String message) { System.out.println(message); }
}
class Test_Runner implements Callable<String>
{
int Start_Index=0,End_Index=6999;
StringBuilder StrBdr=new StringBuilder();
public Test_Runner() { }
public String call() throws InterruptedException
{
try { for (int i=Start_Index;i<End_Index;i++) StrBdr.append("Test_Runner + Test_Runner + Test_Runner + Test_Runner + Test_Runner + Test_Runner"); }
catch (Exception e) {}
return StrBdr.toString();
}
}
class Timer extends JLabel implements Runnable
{
public static final long serialVersionUID=26362862L;
private Thread Timer_Thread;
String Time_Text="";
int updateInterval=1000,Format=0;
Get_Time Timer=new Get_Time();
public Timer()
{
setFont(new Font("Monospaced",Font.PLAIN,16));
setVerticalAlignment(SwingConstants.CENTER);
setHorizontalAlignment(SwingConstants.CENTER);
}
public Timer(int Format) { this.Format=Format; }
public void start()
{
Timer.Start();
if (Timer_Thread==null)
{
Timer_Thread=new Thread(this);
Timer_Thread.setPriority(Thread.NORM_PRIORITY);
Timer_Thread.start();
}
}
public void run()
{
Thread myThread=Thread.currentThread();
while (Timer_Thread==myThread)
{
switch (Format)
{
case 1 : Time_Text=Timer.Get_Duration_Hour_Minute_Second();break;
}
setText(Time_Text);
paintImmediately(0,0,getWidth(),getHeight());
revalidate();
try { Thread.sleep(updateInterval); }
catch (InterruptedException e) { }
}
}
public void stop() { if (Timer_Thread != null) Timer_Thread=null; }
}
class Clock extends JLabel implements Runnable
{
public static final long serialVersionUID=26362862L;
private Thread clockThread;
String Time_Text="";
int updateInterval=1000,Format=0;
Get_Time Timer=new Get_Time();
public Clock() { start(); }
public Clock(int Format)
{
this.Format=Format;
start();
}
public void start()
{
setVerticalAlignment(SwingConstants.CENTER);
setHorizontalAlignment(SwingConstants.CENTER);
if (clockThread==null)
{
clockThread=new Thread(this);
// clockThread.setPriority(Thread.NORM_PRIORITY);
clockThread.setPriority(Thread.MIN_PRIORITY);
clockThread.start();
}
}
public void run()
{
Thread myThread=Thread.currentThread();
while (clockThread==myThread)
{
switch (Format)
{
case 0 : Time_Text=" "+new java.util.Date().toString().substring(0,19)+" ";break;
}
setText(Time_Text);
paintImmediately(0,0,getWidth(),getHeight());
revalidate();
try { Thread.sleep(updateInterval); }
catch (InterruptedException e) { }
}
}
public void stop() { if (clockThread != null) clockThread=null; }
}
class Get_Time
{
private long start,end;
public int Hours,Minutes,Seconds,Total_Seconds;
String ST_Hours,ST_Minutes,ST_Seconds;
public Get_Time() { Reset(); }
public void Start() { start=System.currentTimeMillis(); }
public void End()
{
int half_second;
end=System.currentTimeMillis();
Total_Seconds=(int)(end-start)/1000;
half_second=(int)(end-start)%1000;
if (half_second>499) Total_Seconds++;
Hours=Total_Seconds/3600;
Minutes=(Total_Seconds%3600)/60;
Seconds=(Total_Seconds%3600)%60;
ST_Hours=new String((Hours>9)?""+Hours:"0"+Hours);
ST_Minutes=new String((Minutes>9)?""+Minutes:"0"+Minutes);
ST_Seconds=new String((Seconds>9)?""+Seconds:"0"+Seconds);
}
public String Get_Duration_Hour_Minute_Second()
{
End();
return ST_Hours+":"+ST_Minutes+":"+ST_Seconds;
}
public void Reset() { start=0;end=0; }
}
My computer has a 12 core 3.33 GH Intel Corei7 x 980 CPU, with 24 GB of RAM, running on Windows 7, Java Version = 1.8.0_212
The question is how to fix it ?
Enumeration of Swing threading and painting problems:
All of the following code is called from the Swing event dispatch thread (EDT), and so far so good....
void Do_Test() {
String Info = "", Result;
Out("Do_Test");
try {
Display_Timer.start();
Timer.Start();
Output_Time("[ 1 ]");
Progress_bar.Set_Progress(1); // OK to call this on the event thread
int Task_Count = 222;
executor = new ThreadPoolExecutor(Executor_Count, Executor_Count * 2, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue());
ArrayList<Future<String>> futures = new ArrayList<>(Task_Count);
Test_Runner A_Runner;
try {
for (int i = 0; i < Task_Count; i++) {
A_Runner = new Test_Runner();
futures.add(executor.submit(A_Runner));
}
executor.shutdown();
OK, here we start seeing problems as you're calling a potentially long while loop on the EDT, potentially blocking it:
while (!executor.isTerminated()) {
executor.awaitTermination(100, TimeUnit.MILLISECONDS);
}
Same here, as the call to Future#get() is a blocking call:
for (Future<String> future : futures) {
Result = future.get();
if (Result != null)
Info += Result;
}
OK, now we start seeing some truly unusual Swing code where you make Swing calls, including setting a JProgressBar's value off the EDT and then try to force the EDT to do some painting via paintImmediately(....). Making calls off the EDT can result in intermittent and unpredictable errors, and can cause the painting to mess up, and the GUI to sometimes freeze:
class Progress_Bar extends JPanel implements Runnable {
// .....
public void Set_Progress(int Progress) {
if (Progress == 1 || (this.Progress < Progress && Progress <= 100)) {
this.Progress = Progress; // ****** being called off the EDT
b.paintImmediately(0, 0, b.getWidth(), b.getHeight()); // ***** Don't do this
Out(" Progress = " + Progress + " %");
}
// .....
}
public void run() {
try {
while (Progress <= 100) {
if ((Progress == 0 || Progress == 50 || Progress == 100 || Do_Step_B)
&& Last_Progress != Progress) {
// ***** called off the EDT -- don't do this
b.setValue(Progress);
// revalidate();
b.paintImmediately(0, 0, b.getWidth(), b.getHeight()); // **** and don't do this
Last_Progress = Progress;
}
Thread.sleep(200); // Delay the thread
Do_Step_B = (Started_B && (counter++ % Unit_Size == 0));
if (Progress < 100 && Do_Step_B)
Progress++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// .......
}
Similar strange goings-ons in this class, the Timer class, where you set a JLabel's text off of the EDT:
class Timer extends JLabel implements Runnable {
// ....
public void run() {
Thread myThread = Thread.currentThread();
while (Timer_Thread == myThread) {
switch (Format) {
case 1:
Time_Text = Timer.Get_Duration_Hour_Minute_Second();
break;
}
// again this is dangerous code **********
setText(Time_Text);
paintImmediately(0, 0, getWidth(), getHeight());
// ....
Same for the Clock class...
Solutions:
To repeatedly call code in a Swing GUI, use a javax.swing.Timer or "Swing Timer". For an example of use of this, please see my implementation of your MCVE, but using a Swing Timer for your threading code above.
The other code, the one that calls long-running tasks, should be done within a SwingWorker. This worker thread usually communicates with the Swing GUI in one of two ways (or both) -- either using a publish/process method pair, or (as in the example below), using a PropertyChangeListener attached to the Worker. Workers have several "bound" properties, fields that notify listeners of change, including the progress property, that can hold a value from 0 to 100, and the SwingWorker.StateValue, or "state" property:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
#SuppressWarnings("serial")
public class JavaTest2 extends JPanel {
private static final int W = 800;
private static final int H = 260;
private Action doTestAction = new DoTestAction("Do Test");
private JProgressBar progressBar = new JProgressBar(0, 100);
private MyClockPanel clockPanel = new MyClockPanel();
private MyTimerPanel timerPanel = new MyTimerPanel();
public JavaTest2() {
JPanel topPanel = new JPanel();
topPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 35, 5));
topPanel.add(new JButton(doTestAction));
progressBar.setStringPainted(true);
JPanel progressPanel = new JPanel(new GridBagLayout());
progressPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
progressPanel.add(progressBar, gbc);
JLabel progressLabel = new JLabel("Progress", SwingConstants.CENTER);
progressLabel.setFont(new Font("Times New Roman", 0, 20));
progressLabel.setForeground(new Color(8, 68, 128));
JPanel centralPanel = new JPanel(new BorderLayout(5, 5));
centralPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
centralPanel.add(progressLabel, BorderLayout.PAGE_START);
centralPanel.add(progressPanel);
JPanel clockWrapper = new JPanel();
clockWrapper.add(clockPanel);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.PAGE_AXIS));
bottomPanel.add(timerPanel, BorderLayout.PAGE_START);
bottomPanel.add(clockWrapper, BorderLayout.PAGE_END);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(topPanel, BorderLayout.PAGE_START);
add(bottomPanel, BorderLayout.PAGE_END);
add(centralPanel);
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSize;
} else {
int w = Math.max(superSize.width, W);
int h = Math.max(superSize.height, H);
return new Dimension(w, h);
}
}
private class DoTestAction extends AbstractAction {
private MyWorker myWorker = null;
public DoTestAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
if (myWorker != null && myWorker.getState() == SwingWorker.StateValue.STARTED) {
return; // still running
}
timerPanel.start();
progressBar.setValue(0);
myWorker = new MyWorker();
myWorker.addPropertyChangeListener(new WorkerListener());
myWorker.execute();
setEnabled(false);
}
}
class WorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// if the worker is changing its progress bound property:
if (evt.getPropertyName().equals("progress")) {
int progress = (int) evt.getNewValue();
// just for safety's sake, limit progress to 100 and no more
progress = Math.min(progress, 100);
progressBar.setValue(progress);
} else if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// else if worker is done
try {
// get the result to at least trap errors
String result = ((MyWorker) evt.getSource()).get();
// can display result in the GUI
timerPanel.stop();
} catch (Exception e) {
// worker's exception is available to the GUI if desired here
e.printStackTrace();
}
progressBar.setValue(100);
doTestAction.setEnabled(true);
}
}
}
private static class MyWorker extends SwingWorker<String, Void> {
private static final int EXECUTOR_COUNT = 12;
private static final int TASK_COUNT = 222;
#Override
protected String doInBackground() throws Exception {
ExecutorService executor = new ThreadPoolExecutor(EXECUTOR_COUNT, EXECUTOR_COUNT * 2, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<>());
List<Future<String>> futures = new ArrayList<>();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < TASK_COUNT; i++) {
Callable<String> aRunner = new ARunner();
futures.add(executor.submit(aRunner));
}
executor.shutdown();
int index = 0;
for (Future<String> future : futures) {
String result = future.get();
sb.append(result);
sb.append(" ");
index++;
int progress = (100 * index) / TASK_COUNT;
progress = Math.min(progress, 100);
setProgress(progress);
}
return sb.toString();
}
}
private static class ARunner implements Callable<String> {
private static final long SLEEP_TIME = 800;
#Override
public String call() throws Exception {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
return "Foo";
}
}
private static void createAndShowGui() {
JavaTest2 mainPanel = new JavaTest2();
JFrame frame = new JFrame("Java Test 2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyClockPanel extends JPanel {
private static final Color FG = new Color(250, 250, 250);
private static final Color BG = new Color(0, 110, 220);
private static final int TIMER_DELAY = 200;
private static final Font FONT = new Font("Monospaced", Font.PLAIN, 16);
private JLabel clockLabel = new JLabel("", SwingConstants.CENTER);
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E MMM dd yyyy kk:mm:ss");
public MyClockPanel() {
setBackground(BG);
clockLabel.setForeground(FG);
clockLabel.setFont(FONT);
displayDateTime();
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 50, 5, 50));
add(clockLabel);
new javax.swing.Timer(TIMER_DELAY, e -> {
displayDateTime();
}).start();
}
private void displayDateTime() {
LocalDateTime dateTime = LocalDateTime.now();
String text = dateTime.format(formatter);
clockLabel.setText(text);
}
}
#SuppressWarnings("serial")
class MyTimerPanel extends JPanel {
private static final Color FG = new Color(0, 0, 238);
private static final Font FONT = new Font("Times New Roman", 0, 14);
private static final int TIMER_DELAY = 40;
private static final String FORMAT_TXT = "Elapsed Time: %02d:%02d:%02d";
private JLabel timerLabel = new JLabel("", SwingConstants.CENTER);
private LocalDateTime startTime = null;
private Timer timer = null;
public MyTimerPanel() {
timerLabel.setForeground(FG);
timerLabel.setFont(FONT);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 50, 5, 50));
timerLabel.setText(String.format(FORMAT_TXT, 0, 0, 0));
add(timerLabel);
}
public void start() {
stop();
startTime = LocalDateTime.now();
timer = new Timer(TIMER_DELAY, e -> incrementTime());
timer.start();
}
public void stop() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
}
private void incrementTime() {
LocalDateTime currentTime = LocalDateTime.now();
long hours = ChronoUnit.HOURS.between(startTime, currentTime);
long minutes = ChronoUnit.MINUTES.between(startTime, currentTime) % 60;
long seconds = ChronoUnit.SECONDS.between(startTime, currentTime) % 60;
String text = String.format(FORMAT_TXT, hours, minutes, seconds);
timerLabel.setText(text);
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm developing a java component for my sudoku project. This component represents a sudoku box that can have two states: a digit or candidates (I use a CardLayout). So far, all works. I am now trying to add some MouseListener on my Labels. When I click on a candidate, I would like to change the value of the state with a simple number, then change the display (cardlayout.show (...)). The problem here is that the source of the event seems to be detected, but the change is not done ... Here is my code (Problem in CaseComponent > createController > candidate[i].addMouseListener():
package sudoku;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CaseComponent extends JPanel {
private static final long serialVersionUID = 1L;
private static final String CANDIDATES = "candidate";
private static final String DIGIT = "digit";
private GridBagConstraints gridBagConstraint;
private JLabel[] candidates;
private JLabel digit;
public CaseComponent(Color caseColor){
super();
setLayout(new CardLayout());
setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
setPreferredSize(new Dimension(60, 60));
setBackground(caseColor);
createView();
placeComponents();
createController();
}
private void createView() {
gridBagConstraint = new GridBagConstraints();
candidates = new JLabel[9];
for (int i = 0; i < 9; i++) {
candidates[i] = new JLabel(""+(i + 1));
}
digit = new JLabel();
}
private void placeComponents() {
JPanel p = new JPanel(new GridLayout(3, 3)); {
for (int i = 0; i < 9; i++) {
JPanel q = new JPanel(); {
q.add(candidates[i]);
}
q.setOpaque(false);
p.add(q);
}
}
p.setOpaque(false);
add(p, DIGIT);
p = new JPanel(new GridBagLayout()); {
p.add(digit, gridBagConstraint);
p.setOpaque(false);
}
add(p, CANDIDATES);
}
private void createController() {
digit.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
candidateDisplay();
}
}
});
for (int i = 0; i < 9; i++) {
candidates[i].addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
JLabel source = (JLabel) e.getSource();
if (SwingUtilities.isLeftMouseButton(e)) {
System.out.println("IN");
digitDisplay();
digit.setText(source.getText());
}
}
});
}
}
private void digitDisplay() {
CardLayout cl = (CardLayout) getLayout();
cl.show(this, DIGIT);
}
private void candidateDisplay() {
CardLayout cl = (CardLayout) getLayout();
cl.show(this, CANDIDATES);
}
}
package sudoku;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Sudoku {
// ATTRIBUTS
private JFrame mainFrame;
private Timer timer;
private JButton pauseButton;
private JButton resumeButton;
private JButton penaltyButton;
private JLabel chronoInfo;
private Chronometer chrono;
public Sudoku() {
createModel();
createView();
placeComponents();
createController();
}
// COMMANDES
/**
* Rend l'application visible au centre de l'écran.
*/
public void display() {
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
// OUTILS
private void createModel() {
chrono = new Chronometer();
}
private void createView() {
mainFrame = new JFrame("Sudoku");
resumeButton = new JButton("Reprendre");
resumeButton.setEnabled(false);
pauseButton = new JButton("Pause");
penaltyButton = new JButton("Penalité");
chronoInfo = new JLabel("00:00");
}
private void placeComponents() {
JPanel p = new JPanel(); {
p.add(resumeButton);
p.add(pauseButton);
p.add(penaltyButton);
}
mainFrame.add(p, BorderLayout.NORTH);
p = new JPanel(); {
p.add(chronoInfo);
}
mainFrame.add(p, BorderLayout.SOUTH);
p = new JPanel(); {
JPanel q = new JPanel(new GridLayout(3,3)); {
for (int i = 0; i < 9; i++) {
Color caseColor = i % 2 == 0 ? Color.WHITE : Color.GRAY;
JPanel r = new JPanel(new GridLayout(3,3)); {
for (int j = 0; j < 9; j++) {
r.add(new CaseComponent(caseColor));
}
}
r.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
q.add(r);
}
}
q.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
p.add(q);
}
mainFrame.add(p);
}
private void createController() {
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final int delay = 1000;
timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
chrono.increment();
chronoInfo.setText(chrono.toString());
}
});
timer.start();
resumeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
chrono.setPaused(false);
}
});
pauseButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.stop();
chrono.setPaused(true);
}
});
penaltyButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
chrono.penalty();
chronoInfo.setText(chrono.toString());
}
});
chrono.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
resumeButton.setEnabled(chrono.isPaused());
pauseButton.setEnabled(!chrono.isPaused());
}
});
}
// POINT D'ENTREE
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Sudoku().display();
}
});
}
}
package sudoku;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
public class Chronometer {
// ATTRIBUTS
private static final int MAX_SECONDS = 60;
private final EventListenerList listeners;
private final ChangeEvent changeEvent;
private int seconds;
private int minutes;
private boolean paused;
// CONSTRUCTEUR
public Chronometer() {
listeners = new EventListenerList();
changeEvent = new ChangeEvent(this);
seconds = 0;
minutes = 0;
paused = false;
}
// REQUETES
public int getSeconds() {
return seconds;
}
public int getMinutes() {
return minutes;
}
public boolean isPaused() {
return paused;
}
public ChangeListener[] getChangeListeners() {
return listeners.getListeners(ChangeListener.class);
}
// COMMANDES
public void setSeconds(int s) {
seconds = s;
}
public void setMinutes(int m) {
minutes = m;
}
public void setPaused(boolean b) {
paused = b;
fireStateChanged();
}
public void increment() {
seconds++;
if (seconds == MAX_SECONDS) {
seconds = 0;
minutes++;
}
}
public void penalty() {
seconds += 10;
if (seconds >= MAX_SECONDS) {
minutes++;
seconds -= MAX_SECONDS;
}
}
public void reset() {
seconds = 0;
minutes = 0;
fireStateChanged();
}
public void addChangeListener(ChangeListener listener) {
if (listener == null) {
return;
}
listeners.add(ChangeListener.class, listener);
}
public void removeChangeListener(ChangeListener listener) {
if (listener == null) {
return;
}
listeners.remove(ChangeListener.class, listener);
}
public String toString() {
return String.format("%02d:%02d", minutes, seconds);
}
// OUTILS
protected void fireStateChanged() {
ChangeListener[] listnrs = getChangeListeners();
for (ChangeListener lst : listnrs) {
lst.stateChanged(changeEvent);
}
}
}
I thank you in advance !
Now that looks like a nice program! I took a quick look and I believe I found the problem. In your placeComponents method you swapped the candidates and digit keys of your layout. I also remove unnecessary brackets.
private void placeComponents() {
JPanel p = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < 9; i++) {
JPanel q = new JPanel(); {
q.add(candidates[i]);
}
q.setOpaque(false);
p.add(q);
}
p.setOpaque(false);
add(p, CANDIDATES); // was DIGIT
p = new JPanel(new GridBagLayout()); {
p.add(digit, gridBagConstraint);
p.setOpaque(false);
}
add(p, DIGIT); // was CANDIDATES
}
I have form that button can auto re-size their size when mouse hover on button and default their size when mouse is exited. It work normally first time but after i try it more than one time their size is enlarged that i can not control normally.
ImageIcon ima=new ImageIcon("C:\\Users\\chen rina\\Pictures\\win.png");
ImageIcon icon;
Thread thr;
Runnable r=new Runnable() {
#Override
public void run() {
int i=40;
while(i!=80){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_FAST);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i+5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
thr=new Thread(r);
thr.start();
}
Runnable res=new Runnable() {
int i;
#Override
public void run() {
int i=80;
while(i!=40){
try{
Thread.sleep(20);
Image scale=ima.getImage().getScaledInstance(i,i,Image.SCALE_AREA_AVERAGING);
icon=new ImageIcon(scale);
btn2.setIcon(icon);
i=i-5;
}
catch(Exception ex){}
}
}
};
private void btn2MouseExited(java.awt.event.MouseEvent evt) {
thr=new Thread(res);
thr.start();
}
Your code violates Swing thread integrity rules by making Swing calls, here setIcon(...) from within a background state. Having said that, why not simplify all of this by:
Reading in and creating and storing your ImageIcons once and only once
Never ignore exceptions as you're doing. That's unsafe coding.
Most important, use a Swing Timer to simply swap icons every 20 msec, and have no fear about violating Swing threading rules.
Your grow Timer's ActionListener could be as simple as this:
// a private inner class
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
// assuming the button is called button and the list iconList
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
The iconList would look something like:
private List<Icon> iconList = new ArrayList<>();
And you could fill it with code looking something like:
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
And a more complete and runnable example:
import java.awt.Dimension;
import java.awt.Image;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeIconTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int START_LENGTH = 40;
private static final int END_LENGTH = 120;
private static final int STEP = 5;
private static final int TIMER_DELAY = 20;
private static final String URL_SPEC = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/2/2b/Oryx_gazella_-_Etosha_2014_square_crop.jpg/"
+ "600px-Oryx_gazella_-_Etosha_2014_square_crop.jpg";
private JButton button = new JButton();
private ResizeIcon resizeIcon;
public ResizeIconTest() throws IOException {
add(button);
URL imageUrl = new URL(URL_SPEC);
BufferedImage originalImg = ImageIO.read(imageUrl);
resizeIcon = new ResizeIcon(button, originalImg, START_LENGTH,
END_LENGTH, STEP, TIMER_DELAY);
button.setIcon(resizeIcon.getSmallestIcon());
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
resizeIcon.grow();
}
#Override
public void mouseExited(MouseEvent e) {
resizeIcon.shrink();
}
});
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ResizeIconTest mainPanel = null;
try {
mainPanel = new ResizeIconTest();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("ResizeIconTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ResizeIcon {
private List<Icon> iconList = new ArrayList<>();
private AbstractButton button;
private int delayTime;
private Timer growTimer;
private Timer shrinkTimer;
public ResizeIcon(AbstractButton button, BufferedImage originalImg,
int startLength, int endLength, int step, int delayTime) {
this.button = button;
this.delayTime = delayTime;
for (int i = startLength; i <= endLength; i += step) {
Image img = originalImg.getScaledInstance(i, i, Image.SCALE_FAST);
iconList.add(new ImageIcon(img));
}
}
public Icon getSmallestIcon() {
return iconList.get(0);
}
public void grow() {
if (growTimer != null && growTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(iconList.size() - 1)) {
return; // don't run if already at largest size
}
growTimer = new Timer(delayTime, new GrowListener());
growTimer.start();
}
public void shrink() {
if (shrinkTimer != null && shrinkTimer.isRunning()) {
return; // let's not run this multiple times
}
if (button.getIcon() == iconList.get(0)) {
return; // don't run if already at smallest size
}
shrinkTimer = new Timer(delayTime, new ShrinkListener());
shrinkTimer.start();
}
private class GrowListener implements ActionListener {
private int index = 0;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index++;
if (index >= iconList.size()) {
((Timer) e.getSource()).stop();
}
}
}
private class ShrinkListener implements ActionListener {
private int index = iconList.size() - 1;
#Override
public void actionPerformed(ActionEvent e) {
button.setIcon(iconList.get(index));
index--;
if (index < 0) {
((Timer) e.getSource()).stop();
}
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Alright, so, I am trying to make a game using a JFrame that, when you click a button, adds money, and show update some text(a JLabel).
You see, it should just update the Windows.Money variable and display ONLY the new variable on the screen, but, it adds more buttons. Please note: The money part works fine.
It's just that Java doesn't want to replace, only add.
Code:
package dev.bobdabiulder.classic.main;
import javax.swing.JLabel;
public class Bucket extends Window{
private static final long serialVersionUID = 1L;
public Bucket() throws InterruptedException {
for(int i = 0; !Window.Paused; ) {
Window.Money += 2;
this.wait(1000);
}
Window.Buckets++;
Window.BucketCounter = new JLabel("You have: " + Window.Buckets + " buckets!");
}
}
In the Windows class...
package dev.bobdabiulder.classic.main;
import java.awt.Button;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Window extends JFrame{
public static long Money = 0;
private static final long serialVersionUID = 1L;
private static Thread t1 = new Thread();
private static Thread t2 = new Thread();
private static Thread t3 = new Thread();
private static Thread t4 = new Thread();
private static Thread t5 = new Thread();
public JButton bucket = new JButton("Buy a Bucket!");
public JButton add$ = new JButton("Add Money!");
public JLabel money = new JLabel(Money + "");
public static long Buckets = 0;
public static JLabel BucketCounter = new JLabel("You have: " + Buckets + " buckets!");
public static JPanel buck = new JPanel();
public static boolean Paused = false;
static JFrame jf = new JFrame("Lol!");
//Window Method
public Window() {
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buck.add(bucket);
buck.add(money);
buck.add(add$);
buck.add(BucketCounter);
jf.setSize(500, 500);
jf.add(buck);
bucket.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(bucket)) {
try {
new Bucket();
} catch (Exception e1) {
e1.printStackTrace();
}
}
System.out.println("Action Performed!");
}
});
pack();
}
//End of ActionPerformed
//Start of start()
public static void start() {
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
//
//
//
#SuppressWarnings("deprecation")
public static void stop() {
t1.stop();
t2.stop();
t3.stop();
t4.stop();
t5.stop();
}
}
I made some requested edits, and I get errors where I put *, the errors all read:
Cannot make a static reference to the non-static field Window.(anything),
Error Spots:
for(int i = 0; !*Window.Paused; ) {
*Window.Money += 2;
this.wait(1000);
}
*Window.Buckets++;
*Window.BucketCounter = new JLabel("You have: " + *Window.Buckets + " buckets!");
Brief example of MVC, well really Model-View. What this does is uses a Swing Timer and not Threads (not directly that is) to increment a JLabel held in a different class. It also uses PropertyChangeListener and support to notify the view (the GUI) of changes in the state of the model.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
/**
* http://stackoverflow.com/q/22620807/522444
* http://stackoverflow.com/a/22621767/522444
* #author Pete
*
*/
#SuppressWarnings("serial")
public class ShortMvc extends JPanel {
private JTextField moneyField = new JTextField(10);
private JTextField bucketField = new JTextField(10);
private MoneyModel model = new MoneyModel();
private Timer timer = new Timer(model.getTimerDelay(), new TimerListener());
private JButton moneyButton = new JButton("Add Money");
private JButton bucketButton = new JButton("Add Bucket");
public ShortMvc() {
moneyField.setEditable(false);
moneyField.setFocusable(false);
bucketField.setEditable(false);
bucketField.setFocusable(false);
bucketField.setText(String.valueOf(model.getBuckets()));
add(new JLabel("Money:"));
add(moneyField);
add(moneyButton);
add(new JLabel("Buckets:"));
add(bucketField);
add(bucketButton);
moneyButton.getModel().addChangeListener(new MoneyBtnModelListener());
moneyButton.setMnemonic(KeyEvent.VK_M);
bucketButton.addActionListener(new BucketButtonListener());
bucketButton.setMnemonic(KeyEvent.VK_B);
model.addPropertyChangeListener(new ModelListener());
timer.setInitialDelay(0);
}
private class BucketButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
model.incrementBuckets();
}
}
private class MoneyBtnModelListener implements ChangeListener {
private boolean pressed = false;
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (pressed == model.isPressed()) {
return;
}
pressed = model.isPressed();
if (pressed) {
timer.start();
} else {
timer.stop();
}
}
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
model.incrementMoney(model.getMoneyIncrementAmount());
}
}
private class ModelListener implements PropertyChangeListener {
private NumberFormat moneyFormat = NumberFormat.getCurrencyInstance();
public ModelListener() {
moneyField.setText(moneyFormat.format(model.getMoney()));
}
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (MoneyModel.MONEY.equals(pcEvt.getPropertyName())) {
moneyField.setText(moneyFormat.format(model.getMoney()));
}
else if (MoneyModel.BUCKETS.equals(pcEvt.getPropertyName())) {
int buckets = model.getBuckets();
bucketField.setText(String.valueOf(buckets));
timer.setDelay(model.getTimerDelay());
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Short Mvc");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ShortMvc());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MoneyModel {
public static final String MONEY = "money";
public static final String BUCKETS = "buckets";
private static final int INIT_TIMER_DELAY = 500;
public static final long MONEY_INCREMENT_AMOUNT = 2L;
private long money = 0L;
private int buckets = 1;
private int timerDelay = INIT_TIMER_DELAY;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
public void setMoney(long money) {
long oldValue = this.money;
long newValue = money;
this.money = money;
pcSupport.firePropertyChange(MONEY, oldValue, newValue);
}
public long getMoneyIncrementAmount() {
return MONEY_INCREMENT_AMOUNT;
}
public void incrementMoney(long addToMoney) {
long oldValue = this.money;
long newValue = money + addToMoney;
this.money = newValue;
pcSupport.firePropertyChange(MONEY, oldValue, newValue);
}
public long getMoney() {
return money;
}
public void setBuckets(int buckets) {
int oldValue = this.buckets;
int newValue = buckets;
this.buckets = newValue;
timerDelay = INIT_TIMER_DELAY / buckets;
pcSupport.firePropertyChange(BUCKETS, oldValue, newValue);
}
public void incrementBuckets(int incrementAmount) {
int newValue = this.buckets + incrementAmount;
setBuckets(newValue);
}
// increment by one
public void incrementBuckets() {
incrementBuckets(1);
}
public int getBuckets() {
return buckets;
}
public int getTimerDelay() {
return timerDelay;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Note that I can't use an ActionListener for this to work since an ActionListener only gets activated when the button is released. I'm assuming that you want to accumulate money when the button is pressed, and then stop accumulating when it is released. To do this, you must extract the JButton's model, add a ChangeListener to it, and then react to changes to the model's isPressed() method. I use it to start and stop the Swing Timer that increments the model.
Edit
Next iteration with better MVC (model-view-control) separation:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.NumberFormat;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
import javax.swing.text.JTextComponent;
/**
* http://stackoverflow.com/q/22620807/522444
* http://stackoverflow.com/a/22621767/522444
* #author Pete
*
*/
public class ShortMvc {
private static void createAndShowGui() {
ShortView view = new ShortView();
MoneyModel model = new MoneyModel();
ShortControl control = new ShortControl(model, view);
control.init();
JFrame frame = new JFrame("Short MVC");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(view.getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ShortView {
private JTextField moneyField = new JTextField(10);
private JTextField bucketField = new JTextField(10);
private JButton moneyButton = new JButton();
private JButton bucketButton = new JButton();
private JPanel mainPanel = new JPanel();
public ShortView() {
moneyField.setEditable(false);
moneyField.setFocusable(false);
bucketField.setEditable(false);
bucketField.setFocusable(false);
mainPanel.add(new JLabel("Money:"));
mainPanel.add(moneyField);
mainPanel.add(moneyButton);
mainPanel.add(new JLabel("Buckets:"));
mainPanel.add(bucketField);
mainPanel.add(bucketButton);
}
public JComponent getMainPanel() {
return mainPanel;
}
public JTextComponent getMoneyField() {
return moneyField;
}
public JTextComponent getBucketField() {
return bucketField;
}
public AbstractButton getMoneyButton() {
return moneyButton;
}
public AbstractButton getBucketButton() {
return bucketButton;
}
}
#SuppressWarnings("serial")
class ShortControl {
private MoneyModel model;
private ShortView view;
private Timer timer;
private MoneyBtnAction moneyBtnAction = new MoneyBtnAction("Add Money", KeyEvent.VK_M);
private BucketButtonAction bucketAction = new BucketButtonAction("Add Buckets", KeyEvent.VK_B);
public ShortControl(MoneyModel model, ShortView view) {
this.model = model;
this.view = view;
timer = new Timer(model.getTimerDelay(), new TimerListener());
}
public void init() {
timer.setInitialDelay(0);
view.getBucketField().setText(String.valueOf(model.getBuckets()));
view.getMoneyButton().setAction(moneyBtnAction);
view.getMoneyButton().getModel().addChangeListener(moneyBtnAction);
view.getBucketButton().setAction(bucketAction);
model.addPropertyChangeListener(new ModelListener());
}
private class BucketButtonAction extends AbstractAction {
public BucketButtonAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
model.incrementBuckets();
}
}
private class MoneyBtnAction extends AbstractAction implements ChangeListener {
private boolean pressed = false;
public MoneyBtnAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// empty
}
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (pressed == model.isPressed()) {
return;
}
pressed = model.isPressed();
if (pressed) {
timer.start();
} else {
timer.stop();
}
}
}
private class ModelListener implements PropertyChangeListener {
private NumberFormat moneyFormat = NumberFormat.getCurrencyInstance();
public ModelListener() {
view.getMoneyField().setText(moneyFormat.format(model.getMoney()));
}
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (MoneyModel.MONEY.equals(pcEvt.getPropertyName())) {
view.getMoneyField().setText(moneyFormat.format(model.getMoney()));
}
else if (MoneyModel.BUCKETS.equals(pcEvt.getPropertyName())) {
int buckets = model.getBuckets();
view.getBucketField().setText(String.valueOf(buckets));
timer.setDelay(model.getTimerDelay());
}
}
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
model.incrementMoney(model.getMoneyIncrementAmount());
}
}
}
class MoneyModel {
public static final String MONEY = "money";
public static final String BUCKETS = "buckets";
private static final int INIT_TIMER_DELAY = 500;
public static final long MONEY_INCREMENT_AMOUNT = 2L;
private long money = 0L;
private int buckets = 1;
private int timerDelay = INIT_TIMER_DELAY;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
public void setMoney(long money) {
long oldValue = this.money;
long newValue = money;
this.money = money;
pcSupport.firePropertyChange(MONEY, oldValue, newValue);
}
public long getMoneyIncrementAmount() {
return MONEY_INCREMENT_AMOUNT;
}
public void incrementMoney(long addToMoney) {
long oldValue = this.money;
long newValue = money + addToMoney;
this.money = newValue;
pcSupport.firePropertyChange(MONEY, oldValue, newValue);
}
public long getMoney() {
return money;
}
public void setBuckets(int buckets) {
int oldValue = this.buckets;
int newValue = buckets;
this.buckets = newValue;
timerDelay = INIT_TIMER_DELAY / buckets;
pcSupport.firePropertyChange(BUCKETS, oldValue, newValue);
}
public void incrementBuckets(int incrementAmount) {
int newValue = this.buckets + incrementAmount;
setBuckets(newValue);
}
// increment by one
public void incrementBuckets() {
incrementBuckets(1);
}
public int getBuckets() {
return buckets;
}
public int getTimerDelay() {
return timerDelay;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Ok, this should help a bit... missing Timer but you can get an idea of how to manage ActionListeners:
Main class
public class WindowInit{
public static void main(String args[]){
WindowHelp wh = new WindowHelp();
}
}
WindowHelp (This one does the magic)
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import javax.swing.event.*;
public class WindowHelp{
JButton b1;
JButton b2;
JLabel label;
long money;
long buckets;
JFrame jf;
Timer timer;
public WindowHelp(){
money = 0;
buckets = 0;
b1 = new JButton("Add buckets");
b2 = new JButton("Add money");
label = new JLabel("");
jf = new JFrame("My Game");
b1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buckets += 2;
label.setText("Buckets: " + buckets);
}
});
b1.setBounds(50,50,100,30);
b2.setBounds(200,50,100,30);
label.setBounds(300,50,200,30);
jf.add(b1);
jf.add(b2);
jf.add(label);
jf.setSize(500,600);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Yes, one is the main class you compile "WindowInit" and run that one.
For timers, gimme some time while I implement it.
My t.stop(); method is not working. I am going crazy trying to figure out why my stop method is not working.
I'm using the a timer in my code and I can't get it to stop. Can anyone take a look at it and tell me what's going on?:
/*Gilberto Rose*/
package homework2;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class MultipleBalls extends JFrame implements ActionListener
{
int dx = 2;
int dy = 2;
int x = 1;
int y = 1;
int i = 0;
public static void main(String[] args)
{
Runnable balls = new Ball2();
Thread thread1 = new Thread(balls);
thread1.run();
}
#Override
public void actionPerformed(ActionEvent arg0)
{
repaint();
System.out.println(i++);
}
}// End of Ball class
class Ball2 extends JPanel implements Runnable
{
MultipleBalls b = new MultipleBalls();
JButton g = new JButton("resume");
JButton f = new JButton("suspend");
JButton e = new JButton("-1");
JButton d = new JButton("+1");
List<Ball2> L = new ArrayList<Ball2>();
Timer t = new Timer(50, b);
public int x = 6;
public void loopstop()
{
t.stop();
}// end of loopstop method
Ball2()
{
controller4();
controller3();
controller2();
controller();
add(d);
add(e);
add(f);
add(g);
}// End of Ball2 constructor
public void run()
{
Ball2 c = new Ball2();
b.setSize(500, 500);
b.setVisible(true);
b.add(c);
t.start();
} // End of run method
public void controller()
{
d.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
L.add(new Ball2());
}
});
}// End of controller
public void controller2()
{
e.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("subtracter");
L.remove(L.size()-1);
}
});
}// End of controller2
public void controller3()
{
f.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
loopstop();
}
});
}// End of controller3
public void controller4()
{
g.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Resume");
}
});
}// End of controller4
public void paintComponent(Graphics g)
{
if(L.size() > 0)
{
int i = 0;
do
{
g.fillOval(L.get(i).ballx(), L.get(i).bally(), 90, 90);
i++;
}while(i < L.size() && true ); // End of Do while loop
}// End of if statement
}// End of paintComponent
MultipleBalls bb = new MultipleBalls();
public int ballx()
{
if (bb.x == 0 || bb.x == 500)
{
bb.dx *= -1;
} // End of if statement
bb.x += bb.dx;
return bb.x;
}
public int bally()
{
if (bb.y == 0 || bb.y == 500 )
{
bb.dy *= -1;
}// end of if statement
bb.y += bb.dy;
return bb.y;
}// End of bally
}// End of Ball2 class
Your code is extremely convoluted, I believe that it's suffering from something called cyclomatic complexity, so much so, it is difficult for you or us to see what object is creating what other object, and what is running what. And this is your problem. You have at least two MultipleBall objects, two Ball2 objects, and you're starting the Timer for one of the Ball2 objects and stopping it for the other.
The solution: simplify this code greatly.
Create one MultipleBalls object, just one.
Don't have MultipleBalls implement ActionListener. Rather use an anonymous inner class for your ActionListener and create it on the spot where you need it.
Create just one Ball2 object, just one.
Also note that you almost never call run() on a Thread object but rather start(), but having said that, I'm not even sure that you should be using a Thread object where you're using it.
Edit
My main class would be simple, and would simply have a main method and supporting method that gets things started. Something like:
public class MultipleBalls {
private static void createAndShowGui() {
BallsPanel mainPanel = new BallsPanel();
JFrame frame = new JFrame("Multiple Balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit
For an example of a separation of concerns:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.*;
public class MultipleBallsZ {
private static void createAndShowGui() {
BallsPanelZ ballsPanel = new BallsPanelZ();
new Control(ballsPanel);
JFrame frame = new JFrame("Multiple Balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(ballsPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class BallsPanelZ extends JPanel {
private static final int TIMER_DELAY = 200;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private Timer timer = new Timer(TIMER_DELAY, new TimerListener());
private int counter = 0;
private Control control = null;
public BallsPanelZ() {
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public Timer getTimer() {
return timer;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
System.out.printf("Count: %03d%n", counter);
}
}
public void setControl(Control control) {
this.control = control;
for (Action action : control) {
add(new JButton(action));
}
}
}
#SuppressWarnings("serial")
class Control implements Iterable<Action> {
private List<Action> actionList = new ArrayList<>();
private BallsPanelZ ballsPanel;
public Control(BallsPanelZ ballsPanel) {
actionList.add(new PauseAction());
actionList.add(new ResumeAction());
this.ballsPanel = ballsPanel;
ballsPanel.setControl(this);
}
private class PauseAction extends AbstractAction {
public PauseAction() {
super ("Timer Pause");
putValue(MNEMONIC_KEY, KeyEvent.VK_P);
}
#Override
public void actionPerformed(ActionEvent e) {
ballsPanel.getTimer().stop();
}
}
private class ResumeAction extends AbstractAction {
public ResumeAction() {
super("Timer Resume");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
putValue(DISPLAYED_MNEMONIC_INDEX_KEY, 6);
}
#Override
public void actionPerformed(ActionEvent e) {
ballsPanel.getTimer().restart();
}
}
#Override
public Iterator<Action> iterator() {
return actionList.iterator();
}
}