I'm using a indicator progress set to -1.0 to show some loading while loginprocess is running.
But when I press the Enter button and start my executor with the loginProcess, my interface stays freezed even if I use Plataform.runLater to set visible my ProgressIndicator.
My button event:
public void initManager(final LoginManager loginManager) {
btnEntrar.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String email = loginTxtField.getText().trim();
String token = tokenTxtField.getText().trim();
if (email.equals("")) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", "Digite o e-mail");
}
});
return;
}
try {
Future future = loginProcess(email, token);
showLoginLoading(future);
future.get();
if (!loginGatewayFailed && !loginTargetAppFailed) {
Login loginTargetApp = new Login(email, null, null);
loginManager.autheticated(loginTargetApp, loginGateway, gateway, file);
} else {
if (loginTargetAppFailed) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", loginTargetAppFailedCause);
}
});
} else {
if (loginGatewayFailed) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", loginGatewayFailedCause);
}
});
}
}
}
} catch (final Exception ex) {
Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, ex.getMessage());
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", ex.getMessage());
}
});
}
}
});
}
My loginProcess:
public Future<?> loginProcess(String email, String token) throws Exception {
// MY PROCESS
return Executors.newSingleThreadExecutor().submit(new LoginTask(this, email, token));
} catch (Exception e) {
Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, e.getMessage());
throw e;
}
}
method showLoginLoading:
private void showLoginLoading(Future future) {
while (!future.isDone()) {
Platform.runLater(new Runnable() {
#Override
public void run() {
progressInd.setVisible(true);
// progressInd.setProgress(-1.0);
}
});
}
}
The problem was in thread management. I was trying to execute the login instructions in the same thread that the main FX view runs.
I figured it out using the Platform.isFxApplicationThread(); It returns true if the calling thread is the JavaFX Application Thread.
To fix my problem i just needed to create a new thread to run all my login instructions as you can see in bellow example:
public void initManager(final LoginManager loginManager) {
btnEntrar.setOnAction(new EventHandler<ActionEvent>() {
boolean mainThread = Platform.isFxApplicationThread();
System.out.println("This is the main Thread: " + mainThread);
Platform.runLater(new Runnable() {
#Override
public void run() {
progressInd.setVisible(true);
}
});
new Thread() {
public void run() {
boolean mainThread = Platform.isFxApplicationThread();
System.out.println("This is the main Thread: " + mainThread);
String email = loginTxtField.getText().trim();
String token = tokenTxtField.getText().trim();
if (email.equals("")) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", "Digite o e-mail");
}
});
return;
}
try {
Future future = loginProcess(email, token);
// showLoginLoading(future);
future.get();
if (!loginGatewayFailed && !loginTargetAppFailed) {
Login loginTargetApp = new Login(email, null, null);
loginManager.autheticated(loginTargetApp, loginGateway, gateway, file);
} else {
if (loginTargetAppFailed) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", loginTargetAppFailedCause);
}
});
} else {
if (loginGatewayFailed) {
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", loginGatewayFailedCause);
}
});
}
}
}
} catch (final Exception ex) {
Logger.getLogger(LoginController.class.getName()).log(Level.SEVERE, ex.getMessage());
Platform.runLater(new Runnable() {
public void run() {
Dialog.showError("Erro", ex.getMessage());
}
});
}
}
}.start();
});
}
Related
Trying to create two independent forma that could run code in separate threads. Code below creates two forms , but if I press button on one of them I can't do the same with another. It simply not executes code. How to make two simple forms that could run non blocking each other?
public class MnemonicEx1 extends JFrame
{
public JeasiHandler jh = null;
private Log log = Log.getLog();
public MnemonicEx1()
{
initUI();
}
private void initUI()
{
JButton btnAuth = new JButton("1");
btnAuth.addActionListener(new ActionListener()
{
// #Override
public void actionPerformed(ActionEvent e)
{
System.out.println("starting");
for (int i = 0; i < 1000; i++)
{
try
{
Thread.sleep(100);
System.out.println(Integer.toString(i));
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
System.out.println("finishing");
}
});
btnAuth.setMnemonic(KeyEvent.VK_B);
//createLayout(btnAuth);
createLayout(btnAuth);
setTitle("****");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void createLayout(JComponent authButn)
{
Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
int i = 0;
gl.setHorizontalGroup(
gl.createSequentialGroup()
.addComponent(authButn)
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(authButn)
);
pack();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
});
EventQueue.invokeLater(new Runnable()
{
public void run()
{
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
});
}
}
UPD
Changed main() by creating separate threads , but got the same result
public static void main(String[] args)
{
new Thread (new Runnable()
{
public void run()
{
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
}).start();
new Thread(new Runnable()
{
public void run()
{
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
}).start();
}
#Nadir is more or less right.
You are launching both windows in the same thread represented by EventQueue.
I think swing programmers prefer to use SwingUtilities for opening new frame applications but you can achieve your goal changing your method actionPerformed
// #Override
public void actionPerformed(ActionEvent e) {
new Thread() {
#Override
public void run() {
System.out.println("starting");
for (int i = 0; i < 1000; i++)
{
try
{
Thread.sleep(100);
System.out.println(Integer.toString(i));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println("finishing");
}
}.start();
That way you'll have two different threads. In your original version you only had one thread.
UPDATED: Change also your main method
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
});
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
MnemonicEx1 ex = new MnemonicEx1();
ex.setVisible(true);
}
});
}
I've been trying to make a button visible when the counter == 7 but it just keeps crashing whenever I add a method showButton().
This is the method that makes the button visible:
public void showButton() {
b.getHandler().post(new Runnable() {
public void run() {
b.setVisibility(View.VISIBLE);
}
});
}
While this is where the thread starts and animates, tho it keeps crashing whenever the counter reaches 7.
void animateFace() {
Runnable r = new Runnable() {
public void run() {
while (true) {
counter++;
if (counter > 8)
counter = 0;
if (counter == 1)
facedest8 = facedest1;
if (counter == 2)
facedest9 = facedest2;
if (counter == 3)
facedest10 = facedest3;
if (counter == 4)
facedest11 = facedest4;
if (counter == 5)
facedest12 = facedest5;
if (counter == 6)
facedest13 = facedest6;
if (counter == 7)
facedest14 = facedest7;
showButton();
SystemClock.sleep(1000);
}
}
};
Thread t = new Thread(r);
t.start();
}
UI updates should be done on the main thread. Try this:
public void showButton() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
b.setVisibility(View.VISIBLE);
}
});
}
To display the button after an 8 sec delay, you can do this:
public void animateFace() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
b.setVisibility(View.VISIBLE)
}
}, 8000);
// No need to call showButton() anywhere in this case
}
if showButton() is part of activity, then,
public void showButton() {
runOnUiThread(new Runnable() {
#Override
public void run() {
b.setVisibility(View.VISIBLE);
}
});
}
if showButton() is outside activity then pass reference of activity to showButton(),
public void showButton(Activity context) {
context.runOnUiThread(new Runnable() {
#Override
public void run() {
b.setVisibility(View.VISIBLE);
}
});
}
My goal is to implement blue coloring of keywords written by user into JTextPane. This is how my code look like:
private class DocumentHandler implements DocumentListener {
#Override
public void changedUpdate(DocumentEvent ev) {
}
#Override
public void insertUpdate(DocumentEvent ev) {
highlight();
}
#Override
public void removeUpdate(DocumentEvent ev) {
highlight();
}
private void highlight() {
String code = codePane.getText();
SimpleAttributeSet defSet = new SimpleAttributeSet();
StyleConstants.setForeground(defSet, Color.BLACK);
doc.setCharacterAttributes(0, code.length(), defSet, true);
SimpleAttributeSet set = new SimpleAttributeSet();
StyleConstants.setForeground(set, Color.BLUE);
for (String keyword : keywords) {
Pattern pattern = Pattern.compile(keyword + "(\\[\\])*");
Matcher matcher = pattern.matcher(code);
while (matcher.find()) {
//Just for test
System.out.print("Start index: " + matcher.start());
System.out.print(" End index: " + matcher.end());
System.out.println(" Found: " + matcher.group());
doc.setCharacterAttributes(matcher.start(), keyword.length(), set, true);
}
}
}
}
After typing anything into pane I get:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338)
at javax.swing.text.DefaultStyledDocument.setCharacterAttributes(DefaultStyledDocument.java:500)
at jnotepad.MainPanel$DocumentHandler.highlight(MainPanel.java:121)
at jnotepad.MainPanel$DocumentHandler.insertUpdate(MainPanel.java:108)
at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:202)
at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749)
How to solve my problem? Maybe I should use something other than DocumentListener?
You need to invoke changes to the document from the Event Dispatcher Thread.
Try this:
private void highlight() {
Runnable doHighlight = new Runnable() {
#Override
public void run() {
// your highlight code
}
};
SwingUtilities.invokeLater(doHighlight);
}
I had the same problem, I solved it by using this:
expiration_timeTF.getDocument().addDocumentListener(
new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
System.out.println("remove");
}
private void assistDateText() {
Runnable doAssist = new Runnable() {
#Override
public void run() {
// when input "2013",will add to "2013-";when
// input "2013-10",will add to "2013-10-"
String input = expiration_timeTF.getText();
if (input.matches("^[0-9]{4}")) {
expiration_timeTF.setText(input + "-");
} else if (input.matches("^[0-9]{4}-[0-9]{2}")) {
expiration_timeTF.setText(input + "-");
}
}
};
SwingUtilities.invokeLater(doAssist);
}
#Override
public void insertUpdate(DocumentEvent e) {
// System.out.println("insert");
assistDateText();
}
#Override
public void changedUpdate(DocumentEvent e) {
// System.out.println("change");
}
});
I want to make dialog box to be shown while I load some data from the web service
I'm using the LWUIT,
The following is the code
public class LoaderAnimation extends Container implements Runnable {
private Thread t;
private boolean running = false;
public LoaderAnimation() {
}
public void start() {
running = true;
t = new Thread(this);
t.start();
}
public void run() {
while (running) {
// do something
t.sleep(150);
}
}
public void stop() {
running = false;
}
}
what happens now that it runs but the code of calling the web service has stop working
that is the calling of it
public static void showLoaderScreen ()
{
dialog = new Dialog();
dialog.setLayout(new BorderLayout());
canvas = new LoaderAnimation();
dialog.addComponent(BorderLayout.CENTER , canvas);
canvas.start();
dialog.show();
}
public static void dismissLoaderScreen ()
{
canvas.stop();
dialog.dispose();
}
try this piece of code.
private void startLoader() {
Dialog d = new Dialog();
d.getStyle().setBgColor(0xffffff);
d.getStyle().setBgTransparency(255);
d.show(100, 250, 90, 150, true, false);
d.setAutoDispose(true);
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
d.dispose();
new Timer().schedule(new TimerTask() {
public void run() {
new Loader().start();
}
}, 30);
}
Loader class we can write parsing stuff or web service handling etc.
class Loader extends Thread
{ public void run() {
try {
ServiceTypesScreen st = new ServiceTypesScreen();
st.init();
} catch (Exception e) {
e.printStackTrace();
}
}
}
How can i use the callme(input); to get launched with a new thread?
/* We send username and password for register and load a heavy load */
public class button3 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String input = output.getText();
if (input.length()<=0)
{
JOptionPane.showMessageDialog(null, "Empty....");
} else {
callme(input);
}
}
}
public static String callme() { //heavy loads... starts, which freezed the button
return "Did you called me?";
}
Try 1: but getting failed (output1 does not get the returned text results):
/* We send username and password for register and nat mapping */
public class button3 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String input = output.getText();
if (input.length()<=0)
{
JOptionPane.showMessageDialog(null, "Empty....");
} else {
new Thread(new Runnable() {
public void run() {
try {
output1.setText( callme(output.getText()) );
} catch(Exception t) {
}
}
}).start();
}
}
}
Try 2: Also tried this, did not returns output1 = callme();
new Thread(new Runnable() {
public void run() {
final String result = callme(output.getText());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
output1.setText( result );
} catch(Exception t) {
}
}
});
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
callme(input);
} catch(Exception t) {
// appropriate error reporting here
}
}
}).start();
Note that input must be declared as final.
Also, consider using invokeLater(Runnable) from Swing Utilities
Try this:
public class button3 implements ActionListener {
public void actionPerformed(ActionEvent e) {
final String input = output.getText();
if ( input.length() <= 0 ) {
JOptionPane.showMessageDialog(null, "Empty....");
}
else {
Thread t = new Thread(new Runnable() {
public void run() {
callme(input);
}
});
t.start();
}
}
public static String callme(String input) {}
}
If you modify swing controls inside your method you should use
new Thread(new Runnable() {
#Override
public void run() {
final String result = callme(input);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
output1.setText( result );
} catch(Exception t) {
}
}
});
}
}).start();
If you need the return value, you should really be using a Callable with an ExecutorService which will give you back a Future that you can use the retrieve the value later on.
See:
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html