For the life of me, I cannot figure out why this program does not work in Java 7. I've run it with no problems in using Java 6, but as soon as I run it with Java 7, it doesn't work.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class HelloWorld implements ActionListener {
JButton button;
boolean state;
public HelloWorld(){
init();
state = false;
System.out.println("state - "+state);
while (true){
if (state == true){
System.out.println("Success");
}
}
}
private void init(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button = new JButton("Button");
button.addActionListener(this);
frame.add(button);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getSource();
if (source == button){
state = !state;
System.out.println("state - "+state);
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new HelloWorld();
}
}
Using Java 6, if I press the button, it will print out the phrase "Success" until I hit the button again. Using Java 7 registers that the button was pressed and the value of state was changed to true, but the phrase "Success" is never printed. What's going on?
Add volatile to the field declaration.
Without volatile, changes in the field are not guaranteed to be visible on other threads.
In particular, the JITter is free to believe that the field never changes on the main thread, allowing it to remove the if entirely.
When you show the JFrame
frame.setVisible(true);
The Java Show the window and stop the execution on this line.
You configured the window to exit on close:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
This program will terminate after you close the window.
So the code after the init() call will never be executed.
Related
How do I successfully call setPreferredSize in a method? I'm calling setPreferredSize twice. If I remove the call inside the constructor, the panel doesn't appear at all, whereas it had earlier appeared with the undesired size (500,300). This demonstrates that setPreferredSize is being executed in the constructor, but not in the method of the same class. Note that this is the only issue (as far as I have tested) with my code; there's no unexpected interference outside the code below.
...
public abstract class XYGrapher extends JPanel{
...
JFrame frame;
JPanel contentPane;
...
public XYGrapher() {
frame = new JFrame("Grapher");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setPreferredSize(new Dimension(500, 300));
contentPane.setLayout(new SpringLayout());
this.setPreferredSize(new Dimension(500, 300));
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);
contentPane.add(this);
}
//
public void drawGraph(int xPixelStart, int yPixelStart, int pixelsWide, int pixelsHigh) {
...
contentPane.setPreferredSize(new Dimension(pixelsWide, pixelsHigh));
this.setPreferredSize(new Dimension(pixelsWide, pixelsHigh));
...
}
//*/
}
For reference, this is how XYGrapher eventually gets used:
public class GrapherTester extends XYGrapher{
...
public static void main(String[] args) {
GrapherTester g = new GrapherTester();
g.drawGraph(0,0,100,100);
}
}
I have managed to fix the issue in the meantime. Simply add
frame.pack();
to the method.
I read much about the JavaFX GUI Model, Plattform->RunLater and Threads, but I still do not figure out how to get this right. I had a JavaFX GUI which on a button click executed a process and updated a Progress Bar and Label. This was running well with Threading and Platform, but I had to Change this to an Observer Model.
I invoke a Progress Tracker in a Singleton Model, which gets updated by the class executing the process and is Observable. I implemented an Observer as well which should update the two UI Elements.
GUI Controller with Button Event
private void createKeyPressed(ActionEvent event) {
// Make Progressbar visible
pbKeyProgress.visibleProperty().set(true);
if (!Check.keyFileExistant() || cbKeyOverwrite.selectedProperty().get()) {
ProgressTracker.getTracker().addObserver(new ProgressObserver(pbKeyProgress, lblKeyProgress));
Creator.createKey(cbKeyLength.getValue());
} else {
}
}
Progress Observer
public class ProgressObserver implements Observer {
private final ProgressBar progressBar;
private final Label statusLabel;
public ProgressObserver(ProgressBar progressBar, Label statusLabel) {
this.progressBar = progressBar;
this.statusLabel = statusLabel;
}
#Override
public void update(Observable o, Object o1) {
Platform.runLater(() -> {
System.out.println("Tracker set to "+ProgressTracker.getProgress() + " " + ProgressTracker.getStatus());
progressBar.setProgress(ProgressTracker.getProgress());
statusLabel.setText(ProgressTracker.getStatus());
});
}
}
Progress Tracker
public synchronized void setTracker(int currentStep, String currentStatus) {
checkInstance();
instance.step = currentStep;
instance.status = currentStatus;
instance.notifyObservers();
System.out.println(instance.countObservers());
}
Creator
public static void createKey(String length) {
Task<Void> task;
task = new Task<Void>() {
#Override
public Void call() throws Exception {
initTracker(0,"Start");
doStuff();
ProgressTracker.getTracker().setTracker(1,"First");
doStuff();
ProgressTracker.getTracker().setTracker(2,"Second");
// and so on
return null;
}
};
new Thread(task)
.start();
}
The Print within the ProgressTracker gets executed. However, if I add a print within the update of the Observer nothing will be printed. If I check within the Progresstracker, the Observer Count is 1.
Why does the Observer not get notified or execute anything, even if the Notify is called? Did I get the Threading and Execution Modell wrong?
The Progress Bar and the Label will also stay on their initial values.
Don't reinvent the wheel. The JavaFX Properties Pattern is a ready-made implementation of the Observable pattern: there is no need to implement it yourself. Additionally, Task already defines methods for updating various properties, which can be called from any thread but will schedule the actual updates on the FX Application Thread. See updateProgress() and updateMessage(), for example.
So you can do, for example:
public static Task<Void> createKey(String length) {
Task<Void> task;
task = new Task<Void>() {
final int totalSteps = ... ;
#Override
public Void call() throws Exception {
updateProgress(0, totalSteps);
updateMessage("Start");
doStuff();
updateProgress(1, totalSteps);
updateMessage("First");
doStuff();
updateProgress(2, totalSteps);
updateMessage("Second");
// and so on
return null;
}
};
new Thread(task)
.start();
return task ;
}
and
private void createKeyPressed(ActionEvent event) {
// Make Progressbar visible
pbKeyProgress.visibleProperty().set(true);
if (!Check.keyFileExistant() || cbKeyOverwrite.selectedProperty().get()) {
Task<Void> task = Creator.createKey(cbKeyLength.getValue());
pbKeyProgress.progressProperty().bind(task.progressProperty());
lblKeyProgress.textProperty().bind(task.messageProperty());
} else {
}
}
I'm new guy here :)
I have a small problem which concerns binding in JavaFX. I have created Task which is working as a clock and returns value which has to be set in a special label (label_Time). This label presents how many seconds left for player's answer in quiz.
The problem is how to automatically change value in label using the timer task? I tried to link value from timer Task (seconds) to label_Time value in such a way...
label_Time.textProperty().bind(timer.getSeconds());
...but it doesn't work. Is it any way to do this thing?
Thanks in advance for your answer! :)
Initialize method in Controller class:
public void initialize(URL url, ResourceBundle rb) {
Timer2 timer = new Timer2();
label_Time.textProperty().bind(timer.getSeconds());
new Thread(timer).start();
}
Task class "Timer2":
public class Timer2 extends Task{
private static final int SLEEP_TIME = 1000;
private static int sec;
private StringProperty seconds;
public Timer2(){
Timer2.sec = 180;
this.seconds = new SimpleStringProperty("180");
}
#Override protected StringProperty call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1000; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
System.out.println("TIK! " + sec);
seconds.setValue(String.valueOf(sec));
System.out.println("TAK! " + seconds.getValue());
// From the counter we subtract one second
sec--;
//Block the thread for a short time, but be sure
//to check the InterruptedException for cancellation
try {
Thread.sleep(10);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
return seconds;
}
public StringProperty getSeconds(){
return this.seconds;
}
}
Why your app does not work
What is happening is that you run the task on it's own thread, set the seconds property in the task, then the binding triggers an immediate update of the label text while still on the task thread.
This violates a rule for JavaFX thread processing:
An application must attach nodes to a Scene, and modify nodes that are already attached to a Scene, on the JavaFX Application Thread.
This is the reason that your originally posted program does not work.
How to fix it
To modify your original program so that it will work, wrap the modification of the property in the task inside a Platform.runLater construct:
Platform.runLater(new Runnable() {
#Override public void run() {
System.out.println("TIK! " + sec);
seconds.setValue(String.valueOf(sec));
System.out.println("TAK! " + seconds.getValue());
}
});
This ensures that when you write out to the property, you are already on the JavaFX application thread, so that when the subsequent change fires for the bound label text, that change will also occur on the JavaFX application thread.
On Property Naming Conventions
It is true that the program does not correspond to JavaFX bean conventions as Matthew points out. Conforming to those conventions is both useful in making the program more readily understandable and also for making use of things like the PropertyValueFactory which reflect on property method names to allow table and list cells to automatically update their values as the underlying property is updated. However, for your example, not following JavaFX bean conventions does not explain why the program does not work.
Alternate Solution
Here is an alternate solution to your countdown binding problem which uses the JavaFX animation framework rather than the concurrency framework. I prefer this because it keeps everything on the JavaFX application thread and you don't need to worry about concurrency issues which are difficult to understand and debug.
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.*;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountdownTimer extends Application {
#Override public void start(final Stage stage) throws Exception {
final CountDown countdown = new CountDown(10);
final CountDownLabel countdownLabel = new CountDownLabel(countdown);
final Button countdownButton = new Button(" Start ");
countdownButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
countdownButton.setText("Restart");
countdown.start();
}
});
VBox layout = new VBox(10);
layout.getChildren().addAll(countdownLabel, countdownButton);
layout.setAlignment(Pos.BASELINE_RIGHT);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 20; -fx-font-size: 20;");
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
class CountDownLabel extends Label {
public CountDownLabel(final CountDown countdown) {
textProperty().bind(Bindings.format("%3d", countdown.timeLeftProperty()));
}
}
class CountDown {
private final ReadOnlyIntegerWrapper timeLeft;
private final ReadOnlyDoubleWrapper timeLeftDouble;
private final Timeline timeline;
public ReadOnlyIntegerProperty timeLeftProperty() {
return timeLeft.getReadOnlyProperty();
}
public CountDown(final int time) {
timeLeft = new ReadOnlyIntegerWrapper(time);
timeLeftDouble = new ReadOnlyDoubleWrapper(time);
timeline = new Timeline(
new KeyFrame(
Duration.ZERO,
new KeyValue(timeLeftDouble, time)
),
new KeyFrame(
Duration.seconds(time),
new KeyValue(timeLeftDouble, 0)
)
);
timeLeftDouble.addListener(new InvalidationListener() {
#Override public void invalidated(Observable o) {
timeLeft.set((int) Math.ceil(timeLeftDouble.get()));
}
});
}
public void start() {
timeline.playFromStart();
}
}
Update for additional questions on Task execution strategy
Is it possible to run more than one Task which includes a Platform.runLater(new Runnable()) method ?
Yes, you can use multiple tasks. Each task can be of the same type or a different type.
You can create a single thread and run each task on the thread sequentially, or you can create multiple threads and run the tasks in parallel.
For managing multiple tasks, you can create an overseer Task. Sometimes it is appropriate to use a Service for managing the multiple tasks and the Executors framework for managing multiple threads.
There is an example of a Task, Service, Executors co-ordination approach: Creating multiple parallel tasks by a single service In each task.
In each task you can place no runlater call, a single runlater call or multiple runlater calls.
So there is a great deal of flexibility available.
Or maybe I should create one general task which will be only take data from other Tasks and updating a UI?
Yes you can use a co-ordinating task approach like this if complexity warrants it. There is an example of such an approach in in Render 300 charts off screen and save them to files.
Your "Timer2" class doesn't conform to the JavaFX bean conventions:
public String getSeconds();
public void setSeconds(String seconds);
public StringProperty secondsProperty();
I am making an application using LWUIT.
There is a form
There is a list embedded on the form.
The list has 5 elements.
Initially, when I first load the app, if I choose the 1st element, 2nd gets chosen; when I choose the second the 3rd gets chose and and so on (Weird!)
I am not able to click any button on the screen either
next what I do is, shift to a different from using arrow keys (of the keyboard... I am running the app on a simulator btw)
Then I come back to the first form and now everything works as expected(no weird behaviour).
What could be the issue?
I am using Sun Java Micro Edition SDK 3.0 (default touch screen for testing)
My code is:
List dummy = new List();
dummy.addItem("wewerwer");
dummy.addItem("wewerdswer");
dummy.addItem("wewqweerwer");
dummy.addItem("dscxwewerwer");
dummy.addItem("jhgwewerwer");
mainListForm.setLayout(new BorderLayout());
mainListForm.addComponent(BorderLayout.CENTER,dummy);
mainListForm.show();
What could possible be going wrong here?
UPDATE 1
I think there is a bug here. I have attached the complete code below along with the screen shot
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
public class Demo extends MIDlet implements ActionListener {
private Form mForm;
List abc;
public void startApp() {
Display.init(this);
try {
Resources r = Resources.open("/Test.res");
UIManager.getInstance().setThemeProps(r.getTheme(
r.getThemeResourceNames()[0])
);
} catch (Exception e){
System.out.println(e.toString());
}
if (mForm == null) {
Button click = new Button("Press me!");
click.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("I have been pressed");
}
});
abc = new List();
abc.addItem("Str1");
abc.addItem("Str2");
abc.addItem("Str3");
abc.addItem("Str4");
abc.addItem("Str5");
abc.addItem("Str6");
Form f = new Form("Hello, LWUIT!");
abc.addActionListener(this);
f.addComponent(abc);
Command exitCommand = new Command("Exit");
f.addCommand(exitCommand);
f.addCommandListener(this);
f.addComponent(click);
f.show();
}
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void actionPerformed(ActionEvent ae) {
System.out.println(abc.getSelectedIndex());
}
}
So now when I click on 'Str1' of the list Str2 gets selected and so on.
IDE: Netbeans
Emulator: Default Touch screen phone
On the action event set the list to active again after the event by invoking setHandlesInput(true)
OK....so this is how you resolve it.
After the form is displayed remove the list from the form and again add it to the form and then repaint the form.
Earlier Code
1) form.addComponenet(BorderLayout.center,list);
2) form.show();
Word Around for the problem
1)form.addComponenet(BorderLayout.center,list);
2)form.show();
3)form.setScrollable(false);
I know its kind of strange, but this way the list index selection works smooth for touch screen phones.
so i'm trying to set up an application where i have multiple panels inside a jframe. lets say 3 of them are purely for display purposes, and one of them is for control purposes. i'm using a borderLayout but i don't think the layout should really affect things here.
my problem is this: i want the repainting of the three display panels to be under the control of buttons in the control panel, and i want them to all execute in sync whenever a button on the control panel is pressed. to do this, i set up this little method :
public void update(){
while(ButtonIsOn){
a.repaint();
b.repaint()
c.repaint();
System.out.println("a,b, and c should have repainted");
}
}
where a,b, and c are all display panels and i want a,b,and c to all repaint continously until i press the button again. the problem is, when i execute the loop, the message prints in an infinite loop, but none of the panels do anything, ie, none of them repaint.
i've been reading up on the event dispatch thread and swing multithreading, but nothing i've found so far has really solved my problem. could someone give me the gist of what i'm doing wrong here, or even better, some sample code that handles the situation i'm describing? thanks...
The java.util.concurrent package provides very powerful tools for concurrent programing.
In the code below, I make use of a ReentrantLock (which works much like the Java synchronized keyword, ensuring mutually exclusive access by multiple threads to a single block of code). The other great thing which ReentrantLock provides are Conditions, which allow Threads to wait for a particular event before continuing.
Here, RepaintManager simply loops, calling repaint() on the JPanel. However, when toggleRepaintMode() is called, it blocks, waiting on the modeChanged Condition until toggleRepaintMode() is called again.
You should be able to run the following code right out of the box. Pressing the JButton toggle repainting of the JPanel (which you can see working by the System.out.println statements).
In general, I'd highly recommend getting familiar with the capabilities that java.util.concurrent offers. There's lots of very powerful stuff there. There's a good tutorial at http://docs.oracle.com/javase/tutorial/essential/concurrency/
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RepaintTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel()
{
#Override
public void paintComponent( Graphics g )
{
super.paintComponent( g );
// print something when the JPanel repaints
// so that we know things are working
System.out.println( "repainting" );
}
};
frame.add( panel );
final JButton button = new JButton("Button");
panel.add(button);
// create and start an instance of our custom
// RepaintThread, defined below
final RepaintThread thread = new RepaintThread( Collections.singletonList( panel ) );
thread.start();
// add an ActionListener to the JButton
// which turns on and off the RepaintThread
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
thread.toggleRepaintMode();
}
});
frame.setSize( 300, 300 );
frame.setVisible( true );
}
public static class RepaintThread extends Thread
{
ReentrantLock lock;
Condition modeChanged;
boolean repaintMode;
Collection<? extends Component> list;
public RepaintThread( Collection<? extends Component> list )
{
this.lock = new ReentrantLock( );
this.modeChanged = this.lock.newCondition();
this.repaintMode = false;
this.list = list;
}
#Override
public void run( )
{
while( true )
{
lock.lock();
try
{
// if repaintMode is false, wait until
// Condition.signal( ) is called
while ( !repaintMode )
try { modeChanged.await(); } catch (InterruptedException e) { }
}
finally
{
lock.unlock();
}
// call repaint on all the Components
// we're not on the event dispatch thread, but
// repaint() is safe to call from any thread
for ( Component c : list ) c.repaint();
// wait a bit
try { Thread.sleep( 50 ); } catch (InterruptedException e) { }
}
}
public void toggleRepaintMode( )
{
lock.lock();
try
{
// update the repaint mode and notify anyone
// awaiting on the Condition that repaintMode has changed
this.repaintMode = !this.repaintMode;
this.modeChanged.signalAll();
}
finally
{
lock.unlock();
}
}
}
}
jComponent.getTopLevelAncestor().repaint();
You could use SwingWorker for this. SwingWorker was designed to perform long running tasks in the background without blocking the event dispatcher thread. So, you need to extend SwingWorker and implement certain methods that will make sense to you. Note that all long running action should happen in the doInBackground() method, and the Swing UI elements should be updated only on the done() method.
So here is an example :
class JPanelTask extends SwingWorker<String, Object>{
JPanel panel = null;
Color bg = null;
public JPanelTask(JPanel panel){
this.panel = panel;
}
#Override
protected String doInBackground() throws Exception {
//loooong running computation.
return "COMPLETE";
}
#Override
protected void done() {
panel.repaint();
}
}
Now, in your "control" button's action performed event, you could do the following :
controlButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
JPanelTask task1 = new JPanelTask(panel1);
task1.execute();
JPanelTask task2 = new JPanelTask(panel2);
task2.execute();
//so on..
}
});
Another way is using javax.swing.Timer. Timer helps you to fire a change to your ui elements in a timely fasthion.This may not be the most appropriate solution. But it gets the work done too.
Again you should be careful about updating UI elements in right places.