Skip to main content

Tracking window preferences

6 replies [Last post]
cdouglass
Offline
Joined: 2005-08-24
Points: 0

Following up on my earlier post on "Initialization Concepts" I've tried to build something that will track the main frame x/y location and size.

I apologize for the length of this.

<br />
public class PrefsModel {</p>
<p>    private attribute logger = Logger.getLogger("JFXNav");</p>
<p>    private attribute file: File = new File("JFXNav.properties");<br />
    private attribute props: Properties = new Properties();<br />
    private attribute propsIn = new FileInputStream(file);</p>
<p>    public attribute frameX: Integer on replace oldFrameX {<br />
        if (oldFrameX == 0) {<br />
            props.load(propsIn);<br />
            frameX = java.lang.Integer.parseInt(props.getProperty("frameX", "100"));<br />
        }<br />
        else {<br />
            props.setProperty("frameX", "{frameX}");<br />
        }<br />
    };<br />
    public attribute frameY: Integer on replace oldFrameY {<br />
        if (oldFrameY == 0) {<br />
            frameY = java.lang.Integer.parseInt(props.getProperty("frameY", "100"));<br />
        }<br />
        else {<br />
            props.setProperty("frameY", "{frameY}");<br />
        }<br />
    };<br />
    public attribute frameWidth: Integer on replace oldFrameWidth {<br />
        if (oldFrameWidth == 0) {<br />
            frameWidth = java.lang.Integer.parseInt(props.getProperty("frameWidth", "500"));<br />
        }<br />
        else {<br />
            props.setProperty("frameWidth", "{frameWidth}");<br />
        }<br />
    };<br />
    public attribute frameHeight: Integer on replace oldFrameHeight {<br />
        if (oldFrameHeight == 0) {<br />
            frameHeight = java.lang.Integer.parseInt(props.getProperty("frameHeight", "300"));<br />
        }<br />
        else {<br />
            props.setProperty("frameHeight", "{frameHeight}");<br />
        }<br />
    };</p>
<p>    public function save():Void {<br />
        var propsOut = new FileOutputStream(file);<br />
        props.store(propsOut, "JFXNav runtime properties");<br />
    }<br />
}<br />

In my main frame I have code like this:

<br />
    visible: true<br />
    x: bind prefs.frameX with inverse;<br />
    y: bind prefs.frameY with inverse;<br />
    width: bind prefs.frameWidth with inverse;<br />
    height: bind prefs.frameHeight with inverse;<br />

Problems I have with this are:

1) It relies on the order of the functions to load the props the first time.

2) My attempts to initialize to a default value like:

<br />
    public attribute frameX: Integer = -1 on replace oldFrameX {<br />
        if (oldFrameX == -1) {<br />

never works -- the value seems to be constantly reset to -1. Therefore if the window is actually moved to screen location 0,0 it jumps to 100, 100.

3) It relies on hooking two different exits to call the "save()" function -- the "closeAction" of the frame, and the menu action to exit.

Can anyone suggest a more appropriate way of doing all of this? Or suggest improvements that address my concerns?

Thanks.

Chas Douglass

Added main frame "bind" code

Message was edited by: cdouglass

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
cdouglass
Offline
Joined: 2005-08-24
Points: 0

With the latest version of the SDK, this now works:

[code]
public class PrefsModel {

private attribute file: File = new File("JFXNav.properties");
private attribute props: Properties = new Properties();
private attribute propsIn = new FileInputStream(file);

public attribute frameX: Integer on replace oldFrameX {
props.setProperty("frameX", "{frameX}");
};
public attribute frameY: Integer on replace oldFrameY {
props.setProperty("frameY", "{frameY}");
};
public attribute frameWidth: Integer on replace oldFrameWidth {
props.setProperty("frameWidth", "{frameWidth}");
};
public attribute frameHeight: Integer on replace oldFrameHeight {
props.setProperty("frameHeight", "{frameHeight}");
};

public function save():Void {
var propsOut = new FileOutputStream(file);
props.store(propsOut, "JFXNav runtime properties");
}

postinit {
props.load(propsIn);
frameX = java.lang.Integer.parseInt(props.getProperty("frameX", "100"));
frameY = java.lang.Integer.parseInt(props.getProperty("frameY", "100"));
frameWidth = java.lang.Integer.parseInt(props.getProperty("frameWidth", "500"));
frameHeight = java.lang.Integer.parseInt(props.getProperty("frameHeight", "300"));
}

}
[/code]

My only remaining reservation is that I have to hook at least two different shutdown points where I call the save() method. It would be nice if there were only one.

Thanks!

Chas Douglass

shagus
Offline
Joined: 2007-05-10
Points: 0

Hi, please try the following. I slightly changed the save function. It seems to work.

[code]
import javafx.application.*;
import java.io.*;
import java.util.*;
public class PrefsModel {

private attribute file: File = new File("JFXNav.PROPERTIES");
private attribute props: Properties = new Properties();
private attribute propsIn = new FileInputStream(file);

public attribute frameX: Integer on replace oldFrameX {
props.setProperty("frameX", "{frameX}");
};
public attribute frameY: Integer on replace oldFrameY {
props.setProperty("frameY", "{frameY}");
};
public attribute frameWidth: Integer on replace oldFrameWidth {
props.setProperty("frameWidth", "{frameWidth}");
};
public attribute frameHeight: Integer on replace oldFrameHeight {
props.setProperty("frameHeight", "{frameHeight}");
};

public function save():Void {
var propsOut = new FileOutputStream(file);
props.store(propsOut, "JFXNav runtime properties");
java.lang.System.exit(0);
}

postinit {
props.load(propsIn);
frameX = java.lang.Integer.parseInt(props.getProperty("frameX", "100"));
frameY = java.lang.Integer.parseInt(props.getProperty("frameY", "100"));
frameWidth = java.lang.Integer.parseInt(props.getProperty("frameWidth", "500"));
frameHeight = java.lang.Integer.parseInt(props.getProperty("frameHeight", "300"));
}

}

var prefs = PrefsModel {};
Frame {
visible: true
x: bind prefs.frameX with inverse;
y: bind prefs.frameY with inverse;
width: bind prefs.frameWidth with inverse;
height: bind prefs.frameHeight with inverse;
closeAction :prefs.save

}
[/code]

cdouglass
Offline
Joined: 2005-08-24
Points: 0

Sorry, I didn't thoroughly re-test this with the latest SDK and I find it now works.

Earlier I had to hook Application.onExit() to catch the frame closing when using the "x" button. With the current SDK the "closeAction" seems to get all possible exits.

As a side note, I prefer to keep the exit visible in the frame, rather than a side-effect of saving the prefs, so I have it coded as:

[code]
var prefs = PrefsModel {};
Frame {
visible: true
x: bind prefs.frameX with inverse;
y: bind prefs.frameY with inverse;
width: bind prefs.frameWidth with inverse;
height: bind prefs.frameHeight with inverse;
closeAction : function() {
prefs.save;
System.exit(0);
}
}
[/code]

Chas Douglass

michael_heinrichs
Offline
Joined: 2007-11-15
Points: 0

Triggers are not meant to be used to initialize attributes. So first of all, I would move the initialization to postinit. Also this would make handling of IO-Exceptions in probs.load() easier.

[code]
postinit {
props.load(propsIn);
frameX = java.lang.Integer.parseInt(props.getProperty("frameX", "100"));
...
}
[/code]

I am not sure, if it is really necessary to store the properties immediately in probs. Maybe you can put all of that in the save-function. These changes would allow to change file, probs, probsIn to local variables and you are able to close and release them immediately after usage.

cdouglass
Offline
Joined: 2005-08-24
Points: 0

I should have mentioned I tried that, and ran into some extremely odd behaviour.

It seems the "replace" action is called when a value is assigned within "postinit". Perhaps that's a bug.

Since I need both "postinit" and "replace" semantics, the only way I could get it to work was to put the initialization in the "replace" function.

Chas Douglass

michael_heinrichs
Offline
Joined: 2007-11-15
Points: 0

I see. It's an open issue in JavaFX to make the triggers able to distinguish between changes during initialization and changes after that. Sometimes you need to react on changes during initialization as well, therefore the current state of firing after all changes.

The UI-library team had the same problem. They introduced a flag "initialized", which was set to true after initialization. The triggers check the state of that flag and react accordingly.