I'm using the radioButton in javaFX to set a parameter.
public class SelectCOM extends Application {
private int comNum ;
public int getComNum() {
return comNum;
}
public void setComNum() {
launch();
}
#Override
public void start(Stage primaryStage) {
//......
//OK BUTTON
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String str = tg.getSelectedToggle().toString();
int begin = str.indexOf("COM");
str = str.substring(begin+3, str.length()-1);
comNum = Integer.parseInt(str);
System.out.println(comNum);
primaryStage.close();
}
});
}
When I call setComNum, the variable comNum is changed to the number I want. But getComNum just return 0.
Here is my calling method:
SelectCOM selectCOM = new SelectCOM();
selectCOM.setComNum();//After clicking the OK BUTTON about 3s, a 0 printed.
int com = selectCOM.getComNum();
System.out.println(com);
The static launch() method in Application creates a new instance of your Application subclass, starts the JavaFX toolkit, and invokes start() on the instance it created. (The call to start() is made on the FX Application Thread.)
So you are setting the comNum value on the field in the instance created by the call to launch(), but you are calling getComNum() on the instance you created yourself (i.e. on a different object); hence you don't get the correct value.
Note also the launch() method, and consequently your setComNum() method, will not complete until the JavaFX Platform exits (by default this is when the user closes the last window).
Related
I am currently creating a text adventure game and am displaying the player stats through the Jtable. I want to use the Jtable repaint method in order to make it display the stats as they change however I don't want to have to write the repaint method after every time I change it. How could I run the repaint() method whenever a stat changes and then continue with the rest of the code.
Here is the script running the Table that the repaint listener must be added:
import javax.swing.*;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
public class mainSystem extends JFrame{
public static class Stats{
public static int x = 1;
public static int n = 0;
public static ArrayList<String> contacts = new ArrayList<>(n);
public static int karma;
public static int SPC;
public static int OPC;
public static int wisdom;
public static int billsProposed;
public static int billsPassed;
public static String party;
public static String currentBill;
}
public static JTable statsWindow;
public mainSystem() {
String[] columns = new String[] {"Stat", "Value"};
Object[][] data = new Object[][]{{"Karma", Stats.karma}, {"SPC", Stats.SPC}, {"OPC", Stats.OPC}, {"Wisdom", Stats.wisdom}, {"Bills Proposed", Stats.billsProposed}, {"Bills Passed", Stats.billsPassed}, {"Party", Stats.party}};
statsWindow = new JTable(data, columns);
this.add(new JScrollPane(statsWindow));
this.setTitle("Stat Window");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
public static void addToContacts(String name){
Stats.n = Stats.n + 1;
Stats.contacts.add(name);
}
public static void table(){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new mainSystem();
}
});
}
public static void main(String[] args) throws InterruptedException {
while (Stats.x == 1){
int karmaChange = Stats.karma; int SPCChange = Stats.SPC; int OPCChange = Stats.OPC; int wisdomChange = Stats.wisdom; int billsProposedChanged = Stats.billsProposed; int billsPassedChanged = Stats.billsPassed;
intro.Introduction();
Section1.section1();
break;
}
if (Stats.x != 1){
End.loose();
} else{
End.win();
}
}
}
What you are looking for is the observer pattern, and it is not automatic:
You must create a listener interface (see for example ActionListener or MouseListener) with a method to be called when the int property change (hint: you may use PropertyChangeListener).
You must be able to register listener to your observable object. You may look at addXXXListener from any JComponent object (for example: addPropertyChangeListener or DefaultListModel). Registering is basically adding listener to a list of listener to "warn".
When you change the int value, you have to fire the event, cycling through the listeners bounds to your object. You can read the code of DefaultListModel for an example.
As for your question title:
Is there a way in java to, while a method is running, detect an
integer change and run said method, then return to the same spot
Unless you are running in several thread, if all you are doing is done on the same thread, then you will return to the same spot. Then again, you are using Swing, and you have the main thread and the EventDispatchThread (EDT): you may need to use SwingUtilities.invokeAndWait (if you are not on the EDT) to return to the same spot.
I have a custom dialog that is added to the scene and then removed again. Doing profiling with VisualVM, I noticed that even after a GC run the instance of this dialog is still retained.
I know that this means that there must be a reference to that object somewhere so I had a look at the references:
As seen in the image there are a lot of references from this$ which means inner classes, in this case they are bindings or ChangeListeners. The change listener can be replaced with WeakChangeListener. I'm not quite sure how I should handle the Bindings however.
Furthermore there are some references that do not make much sense at first glance:
bean of type SimpleStringProperty or SimpleObjectProperty
oldParent and value of type Node$1
So here are the concrete questions:
How to get around these strong references, so the object can actually be garbage collected? Would the use of lambda expressions instead of anonymous inner classes have any effect in this respect? How to figure out where the object is references by bean, oldParent and value.
EDIT1:
The bean references of type SimpleStringProperty are used in the super class and therefore should not cause an issue here, I guess. One SimpleObjectProperty bean reference comes from a utility method that provides an EventHandler. How would I resolve that, is there something similar for EventHandler as for ChangeListeners?
EDIT2:
I tried to come up with a simple application to reproduce the same thing. I could manage it and saw that I have basically the same fields listed in the heap dump, but then noticed that I have retained a reference to the component that is removed from the scene in my application. Once I let go of that reference it was cleaned up. The only noticeable difference is in my small example there is no reference in an Object array.
EDIT3:
I did some digging and found two places in the code that when commented out or not used, will not cause the object become eligible for garbage collection. The first one is this ChangeListener:
sailorState.numberOfSailorsProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue,
Number oldValue, Number newValue) {
int inTavern = newValue.intValue()-sailorsAdditionalOnShip.get();
if (inTavern < 0) {
sailorsAdditionalOnShip.set(Math.max(sailorsAdditionalOnShip.get() + inTavern, 0));
inTavern = 0;
}
sailorsInTavern.set(inTavern);
}
});
The second one is a bit more complex. The component is a Dialog that has a close button. On pressing that one the dialog closes. This is the code of the button, I do not think that with this part is the problem, but for completeness sake:
public class OpenPatricianButton extends Control {
protected final StringProperty text;
protected final ReadOnlyObjectProperty<Font> currentFont;
protected final ObjectProperty<EventHandler<MouseEvent>> onAction;
public OpenPatricianButton(String text,
final Font font) {
super();
this.text = new SimpleStringProperty(this, "text", text);
this.currentFont = new ReadOnlyObjectPropertyBase<Font>() {
#Override
public Object getBean() {
return this;
}
#Override
public String getName() {
return "currentFont";
}
#Override
public Font get() {
return font;
}
};
this.onAction = new SimpleObjectProperty<EventHandler<MouseEvent>>(this, "onAction");
this.getStyleClass().add(this.getClass().getSimpleName());
}
#Override
public String getUserAgentStylesheet() {
URL cssURL = getClass().getResource("/ch/sahits/game/javafx/control/"+getClass().getSimpleName()+".css");
return cssURL.toExternalForm();
}
public StringProperty textProperty() {
return text;
}
public String getText() {
return text.get();
}
public void setText(String text) {
this.text.set(text);
}
public Font getFont() {
return currentFont.get();
}
public ObjectProperty<EventHandler<MouseEvent>> onActionProperty() {
return onAction;
}
public EventHandler<MouseEvent> getOnAction() {
return onAction.get();
}
public void setOnAction(EventHandler<MouseEvent> onAction) {
this.onAction.set(onAction);
}
}
public class OpenPatricianSmallWaxButton extends OpenPatricianButton {
public OpenPatricianSmallWaxButton(String text,
final Font font) {
super(text, font);
}
#Override
protected Skin<?> createDefaultSkin() {
return new OpenPatricianSmallWaxButtonSkin(this);
}
public OpenPatricianSmallWaxButton(String text) {
this(text, Font.getDefault());
}
}
public class OpenPatricianSmallWaxButtonSkin extends SkinBase<OpenPatricianSmallWaxButton> {
public OpenPatricianSmallWaxButtonSkin(final OpenPatricianSmallWaxButton button) {
super(button);
InputStream is = getClass().getResourceAsStream("sealingWaxFlattend.png");
Image img = new Image(is);
final ImageView imageView = new ImageView(img);
final Label label = new Label();
label.textProperty().bind(button.textProperty());
label.getStyleClass().add("OpenPatricianSmallWaxButtonLabeled");
label.setFont(button.getFont());
label.onMouseClickedProperty().bind(button.onActionProperty());
label.textProperty().bind(button.textProperty());
imageView.onMouseReleasedProperty().bind(button.onActionProperty());
StackPane stack = new StackPane();
stack.getChildren().addAll(imageView, label);
Group group = new Group(stack);
group.setManaged(false);
button.setPrefHeight(img.getHeight());
button.setPrefWidth(img.getWidth());
getChildren().add(group);
}
}
And here is the code fragment where the button is instantiated:
closeButton = new OpenPatricianSmallWaxButton("X", font);
closeButton.setLayoutX(WIDTH - CLOSE_BUTTON_WIDTH - CLOSE_BUTTON_PADDING);
closeButton.setLayoutY(CLOSE_BTN_Y_POS);
closeButton.setOnAction(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
executeOnCloseButtonClicked();
}
});
closeButton.getStyleClass().add("buttonLabel");
getContent().add(closeButton);
The call to remove the button is done through Guava AsyncEventBus. Therefore the code is a bit length. It starts in the Application thread and then gets posted to the event bus thread which then eventually has to call Platform.runLater:
protected void executeOnCloseButtonClicked() {
ViewChangeEvent event = new ViewChangeEvent(MainGameView.class, EViewChangeEvent.CLOSE_DIALOG);
clientEventBus.post(event);
}
public void handleViewChange(ViewChangeEvent event) {
if (event.getAddresse().equals(MainGameView.class)) {
if (event.getEventNotice() instanceof DialogTemplate) {
setNewDialog((DialogTemplate) event.getEventNotice());
} else {
sceneEventHandlerFactory.getSceneEventHandler().handleEvent(event.getEventNotice());
}
}
}
public void handleEvent(Object eventNotice) {
Preconditions.checkNotNull(dialogContoller, "Dialog controller must be initialized first");
if (eventNotice == EViewChangeEvent.CLOSE_DIALOG) {
dialogContoller.closeDialog();
}
....
public void closeDialog() {
if (Platform.isFxApplicationThread()) {
closeDialogUnwrapped();
} else {
Platform.runLater(() -> closeDialogUnwrapped());
}
}
private void closeDialogUnwrapped() {
if (dialog != null) {
new Exception("Close dialog").printStackTrace();
getChildren().remove(dialog);
dialog = null;
dialogScope.closeScope();
}
}
The really peculiar thing is that the dialog can be cleaned up by the GC (provided the first issue with the ChangeListener is commented out) when I call closeDialog from a timer. In other words this behaviour does only happen if I close the dialog with a mouse click.
I have a very strange problem with a java class in my android application.
I have some sub classes which extend my abstract class GameDialog
GameDialog class
public abstract class GameDialog extends Sprite
{
private static boolean gd_visible = false;
protected GameDialog(GameScene scene, Camera camera, VertexBufferObjectManager pSpriteVertexBufferObject){
...
}
public boolean display(){
if(!GameDialog.gd_visible) {
...
}
}
protected boolean hide(){
if(GameDialog.gd_visible){
...
}
}
}
PauseDialog class
public class PauseDialog extends GameDialog {
public PauseDialog(GameScene scene, Camera camera, VertexBufferObjectManager pSpriteVertexBufferObject) {
super(scene, camera, pSpriteVertexBufferObject);
...
final ButtonSprite play_button = new ButtonSprite(...);
play_button.setOnClickListener(setPlayButtonListener());
}
private OnClickListener setPlayButtonListener() {
return new OnClickListener() {
#Override
public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {
hide();
}
};
}
}
Each time I want to display a dialog, I write this line :
new PauseDialog(GameScene.this, camera, vbom).display();
The first time, it works well : the dialog is displayed, user make a choice and it's hidden.
But the 2nd time, the dialog is not hidden (after user's choice).
I used the debugger to see what's going on, and the conclusion is :
In the 2nd instance, it calls the hide() method of the first instance !
If some one can explain me what it is doing that ... Thank you.
It is because gd_visible is static. Delete the static keyword and it should work. Static fields doesn't belong to the instances but they belong to the class.
I'm working on a JavaFX application which will have several tab panes which I want to set to visible or hidden using check box which will send boolean flag to render or not to render the component.
Check box
final CheckMenuItem toolbarSubMenuNavigation = new CheckMenuItem("Navigation");
toolbarSubMenuNavigation.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
// call here the getter setter and send boolean flag
System.out.println("subsystem1 #1 Enabled!");
}
});
Tab pane which will listen for the boolean property:
public boolean renderTab;
public boolean isRenderTab()
{
return renderTab;
}
public void setRenderTab(boolean renderTab)
{
this.renderTab = renderTab;
}
tabPane.setVisible(renderTab);
The check box and the tab pane are isolated into different Java Classes. I need to send the value of the flag every time when I check or uncheck the flag. Can you tell me how I can send the flag using getter and setter?
EDIT
I tested this code:
final CheckMenuItem toolbarSubMenuNavigation = new CheckMenuItem("Navigation");
toolbarSubMenuNavigation.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
boolean dcd = toolbarSubMenuNavigation.isSelected();
DataTabs nn = new DataTabs();
nn.setRenderTab(dcd);
// call here the getter setter and send boolean flag
System.out.println("subsystem1 #1 Enabled!");
}
});
and
public boolean renderTab;
public boolean isRenderTab()
{
return renderTab;
}
public void setRenderTab(boolean renderTab)
{
this.renderTab = renderTab;
}
But it's not working when I switch the checkbox.
No.
Inorder to get that eithr you need to have a intance or you need to create new intance there.
If you create a new object there it will create a fresh intance,which doesnt helps you any more..
I guess the only way you have is to Make the renderTab as a static field and access there.
How can I pass the context and the name string as arguments to the new thread?
Errors in compilation:
Line
label = new TextView(this);
The constructor TextView(new Runnable(){}) is undefined
Line "label.setText(name);" :
Cannot refer to a non-final variable name inside an inner class defined in a different method
Code:
public void addObjectLabel (String name) {
mLayout.post(new Runnable() {
public void run() {
TextView label;
label = new TextView(this);
label.setText(name);
label.setWidth(label.getWidth()+100);
label.setTextSize(20);
label.setGravity(Gravity.BOTTOM);
label.setBackgroundColor(Color.BLACK);
panel.addView(label);
}
});
}
You need to declare name as final, otherwise you can't use it in an inner anonymous class.
Additionally, you need to declare which this you want to use; as it stands, you're using the Runnable object's this reference. What you need is something like this:
public class YourClassName extends Activity { // The name of your class would obviously be here; and I assume it's an Activity
public void addObjectLabel(final String name) { // This is where we declare "name" to be final
mLayout.post(new Runnable() {
public void run() {
TextView label;
label = new TextView(YourClassName.this); // This is the name of your class above
label.setText(name);
label.setWidth(label.getWidth()+100);
label.setTextSize(20);
label.setGravity(Gravity.BOTTOM);
label.setBackgroundColor(Color.BLACK);
panel.addView(label);
}
});
}
}
However, I'm not sure this is the best way to update the UI (you should probably be using runOnUiThread and AsyncTask). But the above should fix the errors you've encountered.