I have a problem with a button in that it doesn't work on the first click. I have to click twice and it then gives double results:
Button button = new Button("Click Me");
button.addClickListener(
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
new Thread(new Runnable() {
#Override
public void run() {
DateChooser dateChooser = new DateChooser(new com.kopiright.xkopi.lib.type.Date(2013, 12, 9));
System.out.println(dateChooser.selectDate(com.kopiright.xkopi.lib.type.Date.now()).toString());
}
}).start();
}
}
);
DateChooser extends com.vaadin.ui.Panel class.
Vaadin Button is always immediate so that's not the problem here.
The problem is that you are starting an external thread, which updates the UI, and to see changes made to the UI by an external thread, you should use pollig or pushing. In this case the second button click polls the changes to the browser. But in this case you can just remove the thread:
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
DateChooser dateChooser = new DateChooser(new com.kopiright.xkopi.lib.type.Date(2013, 12, 9));
System.out.println(dateChooser.selectDate(com.kopiright.xkopi.lib.type.Date.now()).toString());
}
});
And when an external thread is used to update Vaadin components, the code must be synchronized correctly.
Is there a reason you create a new thread for this?
Please be aware that modifying the GUI from a thread mus be synchronized.
Look in the book of vaadin for this:
11.16.3. Accessing UI from Another Thread
https://vaadin.com/de/book/vaadin7/-/page/advanced.push.html
André
Related
I've been developing with codenameone for over a year, and I never ran into this problem before, I feel like I'm losing my mind. I just redesigned one part of an app I'm working on, and now the ActionListeners aren't firing. I'm attaching them to a Button and a SpanButton in the code:
ActionListener goToDoc = new ActionListener() {
String mDocId = docId;
#Override
public void actionPerformed(ActionEvent evt) {
mStateMachine.currentExpertId = mDocId;
mStateMachine.showForm("DoctorDetails", null);
}
};
name.addActionListener(goToDoc);
Util.downloadImageToStorage(mStateMachine.URL_PREFIX+"images/doctors/"+(String)value.get("doc_pic"),
"doc_post_pic_"+(String)value.get("doc_id")+".png", new Callback<Image>() {
#Override
public void onSucess(Image img) {
pic.setIcon(img.scaledWidth(mStateMachine.getProportionalWidth(.23)));
StateMachine.applyGreenBorder(pic);
pic.addActionListener(goToDoc);
pic.getParent().revalidate();
}
#Override
public void onError(Object sender, Throwable err, int errorCode, String errorMessage) {
System.out.println("Unable to download expert profile picture");
}
});
When I debug the code, the components do show that the ActionListener is attached, but the actionPerformed method is never reached, no matter how many times I click on the buttons. I experience this problem both on the simulator and on an Android device. I have yet to test on an iPhone.
Did you set a parent to be a lead component or focusable?
The reason the click event wasn't firing was because the Components weren't enabled, possibly a bug in the BUI Builder. After checking off the 'Enabled' and 'Focusable' checkboxes in the GUI Builder, and seeing they were unchecked every time I went back to that form, I just used component.setFocusable(true) and component.setEnabled(true) in the code, and it worked fine after that.
I've got this Controller connected to a FXML-file with several buttons, labels, a table, etc.
I've got some popups that get initialized and shown when different buttons get clicked and that works fine.
I've got another popup that I'd like to 'pop up' when something goes wrong, so this is called when an event get's handled that has been sent from java-code in another class.
This message pop-up get's called, but the code within the Platform.runLater() isn't executed, actually freezing the GUI.
There's one distinction I've found that seems to cause this and that is that a Platform.isFxApplicationThread() that I call right before the Platform.runLater() returns false in this message pop-up where it returns true when one of the other pop-ups get called from a button-click.
As I've also tried one of those pop-ups that's normally called from a button-click and that also doesn't work when it's called from the code that get's executed because of the incoming event, I'm pretty sure this is the problem, but Platform.runLater states "This method, which may be called from any thread, will post the Runnable to an event queue and then return immediately to the caller." and that seems not true for me, so I'm kinda puzzled if this actually is the problem ...
Has anyone encountered this before and / or does anyone know what I'm doing wrong?
This works fine:
#FXML
private void btnCashClicked(ActionEvent event) {
screensController.getCashTransactionController().addCashTransactionListener(this);
labelToPay = new Label(eurosToPay + " euro");
sealbagTextField = new SealbagTextField();
PopupUtils.showCashPaymentPopup(btnSealbag, btnCashOk, labelPaid, labelSealbag, labelToPay, lblExchange,
labelExchange, labelReturnValue, eurosToPay, btnCash, this, sealbagTextField);
screensController.getMainController().startTransaction(amountInCents, PaymentType.Asap);
}
This code in the same controller class doesn't show a pop-up:
#Override
public void showErrorOnScreen(String message) {
// temporary usage of label and textfield
labelToPay = new Label(eurosToPay + " euro");
sealbagTextField = new SealbagTextField();
PopupUtils.showCashPaymentPopup(btnSealbag, btnCashOk, labelPaid, labelSealbag, labelToPay, lblExchange,
labelExchange, labelReturnValue, eurosToPay, btnCash, this, sealbagTextField);
//PopupUtils.showMessagePopup("Error", message, "Close", 374, 250, btnCancel);
}
I'm on Windows and using jre1.8.0_60
The code of the cashPopup:
public static int showCashPaymentPopup(Button btnSealbag, Button btnCashOk, Label labelPaid, Label labelSealbag, Label labelToPay, Label lblExchange, Label labelExchange, Label labelReturnAmount, int amount, Node node, PayScreen parent, SealbagTextField sealbagTextField) {
int paid = 0;
logger.debug("cashPopup is on GUI thread: " + Platform.isFxApplicationThread());
Platform.runLater(new Runnable() {
#Override
public void run() {
cashPopup.getContent().clear();
Rectangle rectangle = new Rectangle();
rectangle.setArcHeight(20);
rectangle.setArcWidth(20);
rectangle.setFill(Color.LIGHTBLUE);
rectangle.setWidth(466);
rectangle.setHeight(311);
rectangle.setStroke(Color.DARKBLUE);
rectangle.setStrokeType(StrokeType.INSIDE);
...
cashPopup.getContent().addAll(rectangle, textArea, headerLabel, lblDesc, lblAmount, labelAmount, lblPaid, labelPaid, lblToPay, labelToPay, btnCashOk, lblSealbag, labelSealbag, lblExchange, labelExchange, labelReturnAmount, btnSealbag, btnCancel);
cashPopup.show(node, 150, 164);
}
});
return paid;
}
And the showMessagePopup:
public static void showMessagePopup(String title, String text, String buttonText, int posX, int posY, Node parent) {
logger.debug("messagePopup is on GUI thread: " + Platform.isFxApplicationThread());
Platform.runLater(new Runnable() {
#Override
public void run() {
logger.debug("0");
messagePopup.getContent().clear();
Rectangle rectangle = new Rectangle();
rectangle.setArcHeight(20);
rectangle.setArcWidth(20);
rectangle.setFill(Color.LIGHTBLUE);
rectangle.setWidth(500);
rectangle.setHeight(300);
rectangle.setStroke(Color.DARKBLUE);
rectangle.setStrokeType(StrokeType.INSIDE);
Label headerLabel = new Label(title);
headerLabel.setStyle("-fx-font-size: 18; -fx-font-family: Arial;");
headerLabel.setLayoutX(15);
headerLabel.setLayoutY(10);
TextArea textArea = new TextArea();
textArea.setStyle("-fx-font-size: 14; -fx-font-family: Arial;");
textArea.setLayoutX(10);
textArea.setLayoutY(35);
textArea.setMaxWidth(480);
textArea.setMinHeight(190);
textArea.setMaxHeight(190);
textArea.setEditable(false);
textArea.setWrapText(true);
textArea.setText(text);
Button btnClose = new Button(buttonText);
btnClose.setLayoutX(180);
btnClose.setLayoutY(235);
btnClose.setPrefSize(120, 54);
btnClose.setStyle("-fx-font-size: 18; -fx-font-family: Arial; -fx-text-fill:white; -fx-background-color: linear-gradient(#8b9aa1, #456e84), linear-gradient(#c5dde7, #639fba), linear-gradient(#79abc1, #639fba); -fx-background-insets: 0,1,2; -fx-background-radius: 6,5,4;");
btnClose.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
messagePopup.hide();
}
});
messagePopup.getContent().addAll(rectangle, headerLabel, btnClose, textArea);
messagePopup.show(parent, posX, posY);
}
});
}
logger.debug("0") isn't even executed ...
Found it, by running in debug mode and suspending the Java FX thread to see what it is doing.
There's this 'other thread' that gets started from the main program and which needs to get started before the process can continue. This other thread looks like this:
pinPadAsSlaveThread = new Thread(pinPadAsSlave);
pinPadAsSlaveThread.start();
while (!pinPadAsSlave.isRunning()) {
// wait for pinPadAsSlave to be running
try {
Thread.sleep(10);
} catch(InterruptedException ie) {
// ignore
}
}
Normally this takes about 50 ms, but as the pin pad is unavailable on the network this becomes an infinite loop. That on itself should be handled of course, by letting this loop only try it for 50 times or so.
But the real problem is that this thread that is put to sleep for 10 ms all the time is the Java FX thread. I don't know why the Java FX thread is doing the setting up of the communication, as it shouldn't (and I didn't ask for that by putting it inside a platform.runLater or something alike), but the fact is: it is ...
I am coding a javafx program and i need to create and use my own Stage based (Javafx.Stage) dialog box for showing messages and confirmations. I have written all the necessary code by now but i have a problem:
A dialog box must stop execution of rest of the code until a respond is given like "yes" or "no" or "retry". When i use my dialog box like "DialogBox.ShowMessage", a stage appears with message and buttons. But, as you may think, the rest of the code continues to execute. How can i get around this? When i create the stage, it must stop the other threads or the thread that it depends on. I have searched through internet and here, but i can not find exact solution. One idea is using "javafx.event.EventDispatcher" or "javafx.event.EventDispatchChain" but i couldn't figure out how to use them. And another idea is using "java.awt.EventQueue". And here is somthing that can help: I have a control of stage show and hide events and showing or hiding eventhandlers. I think som sort of thread queue can be used in one of these spesific sections.
I hope i clarified the situation enough. Briefly, ı need to manage threads while using another stage with my own code.
Thank you.
About execution suspending there is a Jira issue for it http://javafx-jira.kenai.com/browse/RT-19783.
As a workaround, I have no idea how to use EventDispatcher and EventDispatchChain to overcome this problem but you can send the EventHandlers as parameter. For instance,
public static void ShowMessage(final EventHandler<ActionEvent> okAction, final EventHandler<ActionEvent> cancelAction){
// Define and add buttons to the "view" and show message
btnOk.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
okAction.handle(null);
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
cancelAction.handle(null);
}
});
}
and use it as,
DialogBox.ShowMessage(
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent arg0) {
// Do stuff when "ok" clicked.
},
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent arg0) {
// Do stuff when "cancel" clicked.
});
I agree with this is a kind of "winding" way however.
Siteye hoş geldin ve kolay gelsin.
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.
A modal dialog with top most property set to true, doesn't appear as top most when shown within a new thread. Example code:
Thread thread = new Thread(KickOffForm);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
private void KickOffForm(object state)
{
Thread.Sleep(5000); // Mimics logic that takes place before form is shown
var form = new Form2();
form.ShowDialog();
}
The modal dialog appears as top most if the form is instantiated at the beginning of the thread. Example code:
Thread thread = new Thread(KickOffForm);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
private void KickOffForm(object state)
{
var form = new Form2();
Thread.Sleep(5000); // Mimics logic that takes place before form is shown
form.ShowDialog();
}
The above code is executed within a class that is instantiated when exe starts.
Why would the form appear as top most when instantiated at the beginning of the thread and not if instantiated later on?
Forms can only be modal to the thread they are created and owned by.
If you want to display a modal dialog that stops interaction with your main form, you must create the dialog on the main UI thread.
This must be so, because each thread runs it's own message loop. One thread knows nothing about any message loop in another thread.
Maybe you could invoke the dialog window in a correct thread:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click( object sender, EventArgs e )
{
Thread thread = new Thread( KickOffForm );
thread.SetApartmentState( ApartmentState.STA );
thread.Start();
}
private void KickOffForm( object state )
{
var form = new Form2();
Thread.Sleep( 5000 ); // Mimics logic that takes place before form is shown
this.Invoke( (Action)(() => { form.ShowDialog(); }) );
}
}