Directly update button state JavaFX - eclipse

I have a GUI that uploads a bunch of settings via serial once the 'upload' button is pressed.
This upload takes some time and has some Thread.sleep's in it, so during upload the GUI freezes but still allows the user to press the upload button some more, which results in even more freezing.
What would be the best way to directly disable the upload button, upload in the background, and enable the button when finished?

Thanks for the reply.
To answer my own question, I already found a simple solution by creating a task:
public class uploadTask extends Task<String> {
#Override
protected String call() throws Exception {
}
}

I would recommend using RxJavaFx.
import java.util.concurrent.TimeUnit;
import io.reactivex.Observable;
import io.reactivex.rxjavafx.observables.JavaFxObservable;
import io.reactivex.rxjavafx.schedulers.JavaFxScheduler;
import io.reactivex.schedulers.Schedulers;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class BackgroundTaskButtonApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
Button button = new Button("Run!");
StackPane stackPane = new StackPane(button);
Scene scene = new Scene(stackPane, 400, 400);
stage.setScene(scene);
stage.show();
JavaFxObservable.actionEventsOf(button)
.doOnNext(event -> button.setDisable(true))
.switchMap(event -> Observable.just(event).observeOn(Schedulers.single()).doOnNext(e -> runLongTask()))
.observeOn(JavaFxScheduler.platform())
.doOnNext(event -> button.setDisable(false))
.subscribe();
}
private void runLongTask() {
System.out.println(Thread.currentThread().getName() + " runLongTask()");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

Related

How to save the current state of switches in Android Studio?

I know very little about programming. I downloaded Android Studio and started tinkering with it. I tried to make the app that they put on the tutorial and it worked. However I tried to add more functionality to it and I've failed so far. Excuse me if you see unnecessary junk on my code, I'm just kinda trying everything at first and I do feel a little misguided.
Anyways, onto the question. I have a Switch (id:toggle_text) with an OnClick action (change_font). When the switch is toggled it should change the font size of a different activity through intent1. Currently not only does it not send the font size variable (the variable keeps the default value you put on getIntExtra), but now that I tried to add the ability to save the current state it just shows errors. Here's the code:
package com.example.myfirstapp;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;
import android.widget.TextView;
import static com.example.myfirstapp.R.id.toggle_text;
import static com.example.myfirstapp.R.string.change_font;
public class ShowAnOption extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_an_option);
SharedPreferences sharedPrefs = getSharedPreferences("com.example.xyz", MODE_PRIVATE);
toggle.setChecked(sharedPrefs.getBoolean("NameOfThingToSave", true));
}
public void change_font(View v) {
int fssize;
if (toggle.isChecked())
{
SharedPreferences.Editor editor = getSharedPreferences("com.example.xyz", MODE_PRIVATE).edit();
editor.putBoolean("NameOfThingToSave", true);
editor.commit();
fssize=20;
}
else
{
SharedPreferences.Editor editor = getSharedPreferences("com.example.xyz", MODE_PRIVATE).edit();
editor.putBoolean("NameOfThingToSave", false);
editor.commit();
fssize=40;
}
Intent intent1 = new Intent (getBaseContext(), DisplayMessageActivity.class);
intent1.putExtra("Font_Size", fssize);
}
}
It says "cannot resolve symbol toggle" on toggle.setChecked() and the if statement. What can I do to fix this? Also, why does it not get sent to the other activity? Here's the code on the other activity:
package com.example.myfirstapp;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.TextView;
public class DisplayMessageActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
Intent intent = getIntent();
Intent intent1 = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
int Font_Size = intent1.getIntExtra("Font_Size",50);
TextView textView = new TextView(this);
textView.setTextSize(Font_Size);
textView.setText(message);
ViewGroup layout = (ViewGroup) findViewById(R.id.activity_display_message);
layout.addView(textView);
}
}
Thanks and sorry for the long read. If there's anything else that needs to be known let me know and I'll gladly show.
We did not try to change the font size but here is how to use the switch widget.
Our design is two activities MainActivity and SwitchActivity we changed a CheckBox from unchecked to checked The switch is on the MainActivity code below
setOnCheckedChangeListener();
private void setOnCheckedChangeListener() {
swAll.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
Toast.makeText(MainActivity.this, "Switch On", Toast.LENGTH_SHORT).show();
Intent intentSP = new Intent(MainActivity.this, SwitchActivity.class );
Bundle extras = new Bundle();
extras.putString("FONT","true" );
intentSP.putExtras(extras);
startActivity( intentSP );
} else {
Toast.makeText(MainActivity.this, "Switch Off", Toast.LENGTH_SHORT).show();
}
}
});
}
Now in the SwitchAcvity we capture the value from the intent and fire the method
doWhat()
Intent intentSP = getIntent();
Bundle bundle = intentSP.getExtras();
tORf = bundle.getString("FONT");
doWhat(null);
And here is the doWhat method
public void doWhat(View view){
if(tORf.equals("true")){
chkBoxOne.setChecked(true);
}else {
Toast.makeText( SwitchActivity.this, "NOT TRUE", Toast.LENGTH_LONG ).show();
}
}

EventFilter consume() does not prevent SpaceChars in TextField

I have a JavaFX GUI where I wish to intercept the pressing of the SpaceBar and use it to call a method. I wrote an EventFilter that seems to do the trick. It includes the command event.consume() which I believe is supposed to keep the KeyEvent from propagating to the various controls.
My issue is that when I added a TextField, and this field has the focus, the Spacebar presses are not being consumed as I thought they would. The " " are captured by the TextField. I would like to intercept and prevent the " " from being added to the TextField.
What am I leaving out in the code below in order to keep " " from reaching the TextField? The api, if I am reading it correctly, says that filters registered with a parent control can intercept an event before it reaches the children nodes. But even when putting the filter directly on the TextField, I am still having " " chars appear in the TextField.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE)
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
The text field is probably listening for KEY_TYPED events. As is well-documented, getCode() returns KeyCode.UNDEFINED for a KEY_TYPED event. Thus you do not catch this case.
You can check for the character variable as well as the code variable to handle all cases:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE || " ".equals(event.getCharacter()))
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
A simple solution i can think,which although doesn't blocks the space from being added to the TextField,but it replaces it after it has been added almost instantly is adding a changeListener to the TextProperty of the TextField:
textField.textProperty().addListener((observable,oldValue,newValue)->{
textField.setText(textField.getText().replace(" ", ""));
});
This may also be helpfull http://fxexperience.com/2012/02/restricting-input-on-a-textfield/

Close event in Java FX when close button is pressed

Is there any event handler present in Java FX, if i close a window directly bt pressing [X] button on Top right side.
Which events gets fire in this case ?
Nothing is working so far , neither setOnHiding not setOnCloseRequest()
Please help.
Try this one
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Main extends Application {
#Override
public void start(Stage stage) {
Text text = new Text("!");
text.setFont(new Font(40));
VBox box = new VBox();
box.getChildren().add(text);
final Scene scene = new Scene(box,300, 250);
scene.setFill(null);
stage.setScene(scene);
stage.show();
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
System.out.println("Stage is closing");
}
});
stage.close();
}
public static void main(String[] args) {
launch(args);
}
}
Source Stage close event : Stage « JavaFX « Java

Eclipse 4 RCP - application does not have active window

I want to have some helper functions for manipulating UI.
I don't want to pass to them any parameters except what is necessary by my domain model (i don't want to pass EModelService, EPartService etc.)
Question: The problem is i am getting exception application does not have active window.
I found where the problem is.
It happend because i am manipulating parts via EPartService accessed from the application context IWorkbench.getApplication().getContext().get(EPartService.class).
THIS IS IMPORTANT: Currently i am getting that exception when i am trying to modify my UI AFTER i read inputs from dialog. Pleas note that the error does not happened when i am trying to modify the UI just BEFORE i
opened the dialog. Look at the code, i added some comments.
NewFromDirectoryDialog.java
package cz.vutbr.fit.xhriba01.bc.handlers;
import javax.inject.Named;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import cz.vutbr.fit.xhriba01.bc.BcModel;
import cz.vutbr.fit.xhriba01.bc.resolvers.filesystem.FileSystemResolver;
import cz.vutbr.fit.xhriba01.bc.ui.dialogs.NewFromDirectoryDialog;
import cz.vutbr.fit.xhriba01.bc.ui.UI;
public class NewFromDirectoryHandler {
#Execute
public void execute(MApplication application, EPartService partService, #Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
FileSystemResolver fsr = new FileSystemResolver("/home/jara/git/cz.vutbr.fit.xhriba01.bc/bc/src",
"/home/jara/git/cz.vutbr.fit.xhriba01.bc/bc/bin");
BcModel.setResolver(fsr);
// THIS CALL IS OK AND EVERYTHING WORKS
UI.changeExplorerView("bc.partdescriptor.filesystemview", fsr);
NewFromDirectoryDialog dialog = new NewFromDirectoryDialog(shell);
dialog.create();
if (dialog.open() == Window.OK) {
String sourceDir = dialog.getSourceDir();
String classDir = dialog.getClassDir();
FileSystemResolver fsr = new FileSystemResolver(classDir, sourceDir);
//THIS CALL LEADS TO EXCEPTION: application does not have active window
UI.changeExplorerView("bc.partdescriptor.filesystemview", fsr);
}
}
}
That EPartService from application context is based on org.eclipse.e4.ui.internal.workbench.ApplicationPartServiceImpl
and not on org.eclipse.e4.ui.internal.workbench.PartServiceImpl
as EPartService instance you get when injected to #PostConstruct annotated method on Part's view.
org.eclipse.e4.ui.internal.workbench.ApplicationPartServiceImpl (not entire source code)
You can see that the error probably happened because at the time ApplicationPartServiceImpl.createPart is called in my UI.changeExplorerView, the Eclipse runtime does not know what window
is currently active.
package org.eclipse.e4.ui.internal.workbench;
import java.util.Collection;
import javax.inject.Inject;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.advanced.MPlaceholder;
import org.eclipse.e4.ui.model.application.ui.basic.MInputPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.IPartListener;
public class ApplicationPartServiceImpl implements EPartService {
private MApplication application;
#Inject
ApplicationPartServiceImpl(MApplication application) {
this.application = application;
}
private EPartService getActiveWindowService() {
IEclipseContext activeWindowContext = application.getContext().getActiveChild();
if (activeWindowContext == null) {
throw new IllegalStateException("Application does not have an active window"); //$NON-NLS-1$
}
EPartService activeWindowPartService = activeWindowContext.get(EPartService.class);
if (activeWindowPartService == null) {
throw new IllegalStateException("Active window context is invalid"); //$NON-NLS-1$
}
if (activeWindowPartService == this) {
throw new IllegalStateException("Application does not have an active window"); //$NON-NLS-1$
}
return activeWindowPartService;
}
#Override
public MPart createPart(String id) {
return getActiveWindowService().createPart(id);
}
}
LifeCycleManager.java (how i initialize the UI helper class)
You can see i am injecting IWorkbench to my UI class.
IWorkbench allows me to access MApplication, so that is all i should
need to modify app UI.
package cz.vutbr.fit.xhriba01.bc;
import javax.inject.Inject;
import org.eclipse.e4.core.contexts.ContextInjectionFactory;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.ui.di.UIEventTopic;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.e4.ui.workbench.UIEvents;
import cz.vutbr.fit.xhriba01.bc.ui.UI;
public class LifeCycleManager {
#Inject
#Optional
private void appCompleted(#UIEventTopic(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) Object event, IWorkbench workbench) {
ContextInjectionFactory.inject(UI.getDefault(), workbench.getApplication().getContext());
}
}
UI.java
package cz.vutbr.fit.xhriba01.bc.ui;
import javax.inject.Inject;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack;
import org.eclipse.e4.ui.workbench.IWorkbench;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.e4.ui.workbench.modeling.EPartService;
import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState;
import org.eclipse.jface.text.IDocument;
import cz.vutbr.fit.xhriba01.bc.BcModel;
import cz.vutbr.fit.xhriba01.bc.resolvers.ISourceAndClassResolver;
public class UI {
public static final String PART_EXPLORER_ID = "bc.part.inspector";
public static final String PART_EXPLORER_CONTAINER_ID = "bc.partstack.explorer_stack";
public static final String PART_JAVA_SOURCE_VIEWER_ID = "bc.part.javasourceview";
private static UI fInstance = new UI();
#Inject
private IWorkbench fWorkbench;
private UI() {
}
public static void changeExplorerView(String partDescriptorId, ISourceAndClassResolver resolver) {
EModelService modelService = fInstance.fWorkbench.getApplication().getContext().get(EModelService.class);
EPartService partService = fInstance.fWorkbench.getApplication().getContext().get(EPartService.class);
MApplication application = fInstance.fWorkbench.getApplication();
MPart part = partService.createPart(partDescriptorId);
MPart oldPart = partService.findPart(UI.PART_EXPLORER_ID);
MPartStack partStack = (MPartStack) modelService.find(UI.PART_EXPLORER_CONTAINER_ID, application);
partStack.setVisible(true);
if (oldPart != null) {
partService.hidePart(oldPart);
}
part.setElementId(UI.PART_EXPLORER_ID);
partStack.getChildren().add(part);
BcModel.setResolver(resolver);
partService.showPart(part, PartState.VISIBLE);
}
public static UI getDefault() {
return fInstance;
}
public static void setJavaSourceLabel(String label, EPartService partService) {
MPart part = partService.findPart(UI.PART_JAVA_SOURCE_VIEWER_ID);
if (part != null) {
part.setLabel(label);
}
}
public static void setJavaSourceText(String source) {
IDocument document = BcModel.getJavaDocument();
if (document != null) {
document.set(source);
}
}
}
I think the problem is when i open the dialog, the activeChild changes somehow to that new opened dialog and when i close it and try immediately change my UI, it does not work because the activeChild is still not properly setup back. Otherweise i don't know why it works fine just before i opened the dialog and doesn't work just after the dialog is closed.
Does anyone know if it is bug?

How to create a javafx 2.0 application MDI

How to implement something kinda internal frame in JavaFx 2.0 specifically?
My attempt is as so..
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
ConnectDb connection;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
final Stage stage1 = new Stage();
StackPane pane = new StackPane();
Button btn = new Button("Click Me");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
connection = new ConnectDb();
try {
connection.start(stage1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Fire some thing..");
}
});
pane.getChildren().add(btn);
stage.setScene(new Scene(pane ,200, 300));
stage.show();
}
}
ConnectDb.java
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ConnectDb extends Application {
#Override
public void start(Stage stage) throws Exception {
StackPane pane = new StackPane();
Button btn = new Button("Click On Button which is me");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Something here..");
}
});
pane.getChildren().add(btn);
stage.setScene(new Scene(pane ,200, 300));
stage.show();
}
}
First of all, for your approach, you don't really need to (and therefore should not) extend ConnectDb from Application as you just use the start method to create new stages. You just need one Application class (in your case Main). You could just as well create the new stage/scene in your first event handler.
Secondly, there is no real MDI support in JavaFX 2.1. Right now, you can just have multiple Stages (which is the equivalent to having multiple windows/frames). But you cannot have something like an internal frame in a desktop pane.
I guess you could take the following actions:
Just use multiple Stages (windows) with the drawback that they will float quite uninspiredly on your desktop
Use Swing as a container (with JDesktopPane and JInternalFrame) and integrate JavaFX (here's a nice How-To)
Implement your own framework that emulates MDI behavior
Find a framework that provides MDI behavior
Wait for a future release of JavaFX that hopefully provides MDI support (as far as I know, there's a change request pending...)
Create parent AncorPane.
Add several children AnchorPanes to it. They will serve as internal frames. Add different content to these.
Set children AnchorPanes invisible.
Add buttons to hide, resize or close children AnchorPanes. When needed, call function to set all children AnchorPanes invisible, except for one.