I got a ScrollPane containing focusable Nodes.
The current default behaviour is:
Shift + ←, ↑, →, ↓ moves the focus
←, ↑, →, ↓ scrolls the view
I want it the other way around.
How can I accomplish this or where should I start?
[EDIT] Well, there is another fragile approach.
Instead of messing around with the events, one could mess around with the KeyBindings.
scrollPane.skinProperty().addListener(new ChangeListener<Skin<?>>() {
#Override
public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) {
ScrollPaneSkin scrollPaneSkin = (ScrollPaneSkin) scrollPane.getSkin();
ScrollPaneBehavior scrollPaneBehavior = scrollPaneSkin.getBehavior();
try {
Field keyBindingsField = BehaviorBase.class.getDeclaredField("keyBindings");
keyBindingsField.setAccessible(true);
List<KeyBinding> keyBindings = (List<KeyBinding>) keyBindingsField.get(scrollPaneBehavior);
List<KeyBinding> newKeyBindings = new ArrayList<>();
for (KeyBinding keyBinding : keyBindings) {
KeyCode code = keyBinding.getCode();
newKeyBindings.add(code == KeyCode.LEFT || code == KeyCode.RIGHT || code == KeyCode.UP || code == KeyCode.DOWN ? keyBinding.shift() : keyBinding);
}
keyBindingsField.set(scrollPaneBehavior, newKeyBindings);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
LOGGER.warn("private api changed.", e);
}
}
});
I think, that could be the cleaner way, if KeyBindings were more non-static, modifyable and public.
Use an event filter to capture the relevant key events and remap them to different key events before the events start to bubble.
Re-mapping default keys is a tricky thing which:
Can confuse the user.
May have unexpected side effects (e.g. TextFields may no longer work as you expect).
So use with care:
import javafx.application.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.TilePane;
import javafx.stage.Stage;
import java.util.*;
public class ScrollInterceptor extends Application {
#Override
public void start(Stage stage) {
ScrollPane scrollPane = new ScrollPane(
createScrollableContent()
);
Scene scene = new Scene(
scrollPane,
300, 200
);
remapArrowKeys(scrollPane);
stage.setScene(scene);
stage.show();
hackToScrollToTopLeftCorner(scrollPane);
}
private void remapArrowKeys(ScrollPane scrollPane) {
List<KeyEvent> mappedEvents = new ArrayList<>();
scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (mappedEvents.remove(event))
return;
switch (event.getCode()) {
case UP:
case DOWN:
case LEFT:
case RIGHT:
KeyEvent newEvent = remap(event);
mappedEvents.add(newEvent);
event.consume();
Event.fireEvent(event.getTarget(), newEvent);
}
}
private KeyEvent remap(KeyEvent event) {
KeyEvent newEvent = new KeyEvent(
event.getEventType(),
event.getCharacter(),
event.getText(),
event.getCode(),
!event.isShiftDown(),
event.isControlDown(),
event.isAltDown(),
event.isMetaDown()
);
return newEvent.copyFor(event.getSource(), event.getTarget());
}
});
}
private TilePane createScrollableContent() {
TilePane tiles = new TilePane();
tiles.setPrefColumns(10);
tiles.setHgap(5);
tiles.setVgap(5);
for (int i = 0; i < 100; i++) {
Button button = new Button(i + "");
button.setMaxWidth(Double.MAX_VALUE);
button.setMaxHeight(Double.MAX_VALUE);
tiles.getChildren().add(button);
}
return tiles;
}
private void hackToScrollToTopLeftCorner(final ScrollPane scrollPane) {
Platform.runLater(new Runnable() {
#Override
public void run() {
scrollPane.setHvalue(scrollPane.getHmin());
scrollPane.setVvalue(0);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
Related
I'm a bit confused about JavaFx 8 and the listener memory leak problem. The official doc says:
The ObservableValue stores a strong reference to the listener which will prevent the listener from being garbage collected and may result in a memory leak.
I would like to have an example where the usage of ObservableValue<T> addListener method create a memory leak.
For example, if I have a class like this:
public class ConfigurationPane extends AnchorPane {
#FXML
private Label titleLabel;
public ConfigurationPane () {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("view/ConfigurationPane .fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void initialize() {
titleLabel.sceneProperty().addListener(new MyListener());
}
}
Can I get memory leaks? When a ConfigurationPane object is garbage collected, the MyListener object is garbage collected too? I'm not able to see a scenario where
a strong reference to the listener will prevent the listener from being garbage collected
P.S. I see other S.O. questions about this but none of these helped me to understand the problem.
Thanks.
It means that map which store your listener is not using weak references, and you have to remove listeners youself to avoid memory leaks.
In the example below LeakingListener objects will never be freed although corresponding TextFields being removed from scene:
public class LeakListener extends Application {
private static class LeakingListener implements InvalidationListener {
private final TextField tf;
private final int[] placeHolder = new int[50000]; // to simplify monitoring
public LeakingListener(TextField tf) {
this.tf = tf;
}
public void invalidated(Observable i) {
tf.setText(tf.getText() + ".");
}
}
#Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);
final Button btnType = new Button("Type in all");
Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
// memory leaking listener which never gets cleaned
btnType.armedProperty().addListener(new LeakingListener(tf));
});
Button btnRemove = new Button("Remove");
btnRemove.setOnAction((ActionEvent e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});
Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e) -> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});
root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}
If ObservableValue stores weak reference to a listener, you wouldn't have a problem. It can be mimicked by next example:
public class LeakListener extends Application {
private static class NonLeakingListener implements InvalidationListener {
// we need listener to don't hold reference on TextField as well
private final WeakReference<TextField> wtf;
private final int[] placeHolder = new int[10000];
public NonLeakingListener(TextField tf) {
this.wtf = new WeakReference<>(tf);
}
public void invalidated(Observable i) {
if (wtf.get() != null) {
wtf.get().setText(wtf.get().getText() + ".");
}
}
}
#Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);
final Button btnType = new Button("Type in all");
// Here is rough weak listeners list implementation
WeakHashMap<TextField, NonLeakingListener > m = new WeakHashMap<>();
btnType.armedProperty().addListener((e)-> {
for (TextField tf : m.keySet()) {
m.get(tf).invalidated(null);
}
});
Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
m.put(tf, new NonLeakingListener(tf));
});
Button btnRemove = new Button("Remove");
btnRemove.setOnAction((e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});
Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e)-> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});
root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}
In following project here is example
I'm using with .notifyDataSetChanged(); this method .post(new Runnable(){ to scroll down after adding new item
private void addItemsToList() {
int randomVal = MIN + (int) (Math.random() * ((MAX - MIN) + 1));
mItems.add(String.valueOf(randomVal));
mListAdapter.notifyDataSetChanged();
mCompleteListView.post(new Runnable(){
public void run() {
mCompleteListView.setSelection(mCompleteListView.getCount() - 1);
}});
}
public class ReceiverThread extends Thread {
String line;
String name;
ReceiverThread(String name, String line){
this.line=line;
this.name=name;
}
public void run() {
OpenStream.this.runOnUiThread(new Runnable() {
public void run() {
addItemsToList();}}}}
BUT when I want scroll up by using finger, new programmatically added item scrolls listview to down.
How I can set off .post(new Runnable() when I touch the screen and using finger to scroll? or what can I do to don't let listview scroll down when I touch the screen?
I've added this code, and now when I touch listview there is no scrolling to down
mCompleteListView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
flag = true;
Log.e(MainActivity.tag,"onTouch "+flag);
}else{
flag = false;
Log.e(MainActivity.tag,"onTouch "+flag);
}
return false;
}
});
I have a problem using the JavaFX WebView. What I want to achieve is pre-fetching a web page in the background and visualiszing it only when the page is totally loaded.
I have made a simple exmaple program to reproduce the problem. After the page is loaded I enable a button. A Click on this button then makes the WebView visible.
The problem I have is, that if I click on the button when it gets enabled, the web page is not visible directly. Instead the following happens: At first there is a totally white panel and then after a short time the web page is visible. I don't understand why the page is not visible directly. How can I achieve it, that the web page is directly visible?
The following link points to an animated gif which shows the behaviour:
http://tinypic.com/view.php?pic=oh66bl&s=5#.Ujmv1RddWKk
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class WebViewTest extends javax.swing.JPanel {
private static JFXPanel browserFxPanel;
private WebView webView;
private WebEngine eng;
/**
* Creates new form WebViewTest
*/
public WebViewTest() {
initComponents();
Platform.setImplicitExit(false);
browserFxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
webView = createBrowser();
Scene scene = new Scene(webView);
scene.setFill(null);
browserFxPanel.setScene(
scene);
}
});
}
/**
* This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
* content of this method is always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
pnlMain = new javax.swing.JPanel();
showWebpageButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
pnlMain.setLayout(new java.awt.BorderLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(pnlMain, gridBagConstraints);
showWebpageButton.setText("show web page");
showWebpageButton.setEnabled(false);
showWebpageButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showWebpageButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
add(showWebpageButton, gridBagConstraints);
}// </editor-fold>
private void showWebpageButtonActionPerformed(java.awt.event.ActionEvent evt) {
pnlMain.removeAll();
pnlMain.add(browserFxPanel, BorderLayout.CENTER);
WebViewTest.this.invalidate();
WebViewTest.this.revalidate();
}
// Variables declaration - do not modify
private javax.swing.JPanel pnlMain;
private javax.swing.JButton showWebpageButton;
// End of variables declaration
private WebView createBrowser() {
Double widthDouble = pnlMain.getSize().getWidth();
Double heightDouble = pnlMain.getSize().getHeight();
final WebView view = new WebView();
view.setMinSize(widthDouble, heightDouble);
view.setPrefSize(widthDouble, heightDouble);
eng = view.getEngine();
eng.load("http://todomvc.com/architecture-examples/angularjs/#/");
eng.getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() {
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
final double workDone = eng.getLoadWorker().getWorkDone();
final double totalWork = eng.getLoadWorker().getTotalWork();
if (workDone == totalWork) {
showWebpageButton.setEnabled(true);
}
}
});
return view;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame f = new JFrame("Navigator Dummy");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(new Dimension(1024, 800));
final WebViewTest navDummy = new WebViewTest();
f.getContentPane().add(navDummy);
f.setVisible(true);
}
});
}
}
JFX needs a "stage" to show up its face. Modify your codes as following and it will work perfectly
/**
* Creates new form WebViewTest
*/
private Stage stage; // insert this line
public WebViewTest() {
initComponents();
Platform.setImplicitExit(false);
browserFxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
webView = createBrowser();
Scene scene = new Scene(webView);
scene.setFill(null);
stage = new Stage(); // <<<
stage.setScene(scene); // <<<
browserFxPanel.setScene(scene);
}
});
}
...
private void showWebpageButtonActionPerformed(java.awt.event.ActionEvent evt) {
pnlMain.removeAll();
pnlMain.add(browserFxPanel, BorderLayout.CENTER);
WebViewTest.this.invalidate();
WebViewTest.this.revalidate();
stage.show(); // <<< afer click Button
}
I have this code:
package javafxapplication9;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
public class JavaFXApplication9 extends Application {
StackPane pane;
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
Polygon triangle = createStartingTriangle();
pane=new StackPane();
Group root = new Group();
root.getChildren().add(triangle);
root.getChildren().addAll(createControlAnchorsFor(triangle.getPoints()));
pane.getChildren().add(root);
pane.setPrefWidth(600);
pane.setPrefHeight(600);
stage.setTitle("Triangle Manipulation Sample");
stage.setScene(
new Scene(
pane,
400, 400, Color.ALICEBLUE
)
);
stage.show();
}
// creates a triangle.
private Polygon createStartingTriangle() {
Polygon triangle = new Polygon();
triangle.getPoints().setAll(
100d, 100d,
150d, 50d,
250d, 150d
);
triangle.setStroke(Color.FORESTGREEN);
triangle.setStrokeWidth(4);
triangle.setStrokeLineCap(StrokeLineCap.ROUND);
triangle.setFill(Color.CORNSILK.deriveColor(0, 1.2, 1, 0.6));
return triangle;
}
private ObservableList<Anchor> createControlAnchorsFor(final ObservableList<Double> points) {
ObservableList<Anchor> anchors = FXCollections.observableArrayList();
for (int i = 0; i < points.size(); i+=2) {
final int idx = i;
DoubleProperty xProperty = new SimpleDoubleProperty(points.get(i));
DoubleProperty yProperty = new SimpleDoubleProperty(points.get(i + 1));
xProperty.addListener(new ChangeListener<Number>() {
#Override public void changed(ObservableValue<? extends Number> ov, Number oldX, Number x) {
points.set(idx, (double) x);
}
});
yProperty.addListener(new ChangeListener<Number>() {
#Override public void changed(ObservableValue<? extends Number> ov, Number oldY, Number y) {
points.set(idx + 1, (double) y);
}
});
Anchor an=new Anchor(Color.GOLD, xProperty, yProperty,pane);
anchors.add(an);
}
return anchors;
}
class Anchor extends Circle {
Anchor(Color color, DoubleProperty x, DoubleProperty y,StackPane pane) {
super(x.get(), y.get(), 10);
setFill(color.deriveColor(1, 1, 1, 0.5));
setStroke(color);
setStrokeWidth(2);
setStrokeType(StrokeType.OUTSIDE);
x.bind(centerXProperty());
y.bind(centerYProperty());
enableDrag();
}
// make a node movable by dragging it around with the mouse.
private void enableDrag() {
final Delta dragDelta = new Delta();
setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = getCenterX() - mouseEvent.getX();
dragDelta.y = getCenterY() - mouseEvent.getY();
pane.setCursor(Cursor.MOVE);
}
});
setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
pane.setCursor(Cursor.HAND);
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
double newX = mouseEvent.getX() + dragDelta.x;
if (newX > 0 && newX < pane.getWidth()) {
setCenterX(newX);
}
double newY = mouseEvent.getY() + dragDelta.y;
if (newY > 0 && newY < pane.getHeight()) {
setCenterY(newY);
}
}
});
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
pane.setCursor(Cursor.HAND);
}
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
pane.setCursor(Cursor.DEFAULT);
}
}
});
}
// records relative x and y co-ordinates.
private class Delta { double x, y; }
}
}
The problem is that I can't move the edges of the triangle all the way to the top of the scene.
If I don't use a stackPane,only a scene it works well but I need the Stack Pane because the next thing I want to do is to save the triangle as an image and use the image as background.Every time I will save a new triangle,it;s image will overlap with the others.Any sugestion is welcomed.Thank you.
At First I wantet to say NICE PROGRAM ;-)
And now to your problem, this problem is easy to fix. ;-)
Just use an AnchorPane and not a Group.
Here is the code:
#Override
public void start(final Stage stage) throws Exception {
Polygon triangle = createStartingTriangle();
pane = new StackPane();
//Use an AnchorPane instead of a Group ;)
AnchorPane ap = new AnchorPane();
ap.getChildren().add(triangle);
ap.getChildren().addAll(createControlAnchorsFor(triangle.getPoints()));
pane.getChildren().add(ap);
pane.setPrefWidth(600);
pane.setPrefHeight(600);
stage.setTitle("Triangle Manipulation Sample");
stage.setScene(
new Scene(
pane,
400, 400, Color.ALICEBLUE));
stage.show();
}
I am trying to download xml files from server when my application starts. So i want to show splash screen until am done with downloading and then show next screen. below is my code:
Here, i want to show My splash screen when getTopNotDoc() method is under execution. and after completion of that method show next screen.
//get _topics and notification document<br>
_getDoc = new ServerConnectivity(this);
public class ServerConnectivity {
private Document _questionDoc;
private Document _topics;
private Document _notifications;
public ServerConnectivity(ApplicationSession appSession){
//getTopNotDoc();
_this = this;
_appSession = appSession;
new Thread(new Runnable(){
public void run(){
getTopNotDoc();
}
}).start();
}
}
private void getTopNotDoc(){
InputStream inputStream = null ;
try{
// Build a document based on the XML file.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
inputStream = getClass().getResourceAsStream("topics.xml");
_topics = builder.parse( inputStream );
inputStream = getClass().getResourceAsStream("notification.xml");
_notifications = builder.parse( inputStream );
if(_topics == null || _notifications == null){
Dialog.alert("Unable to connect to internet");
}
}
catch ( Exception e ){
System.out.println( e.toString() );
}
finally{
if(inputStream != null){
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
Usually when I do this, I create a loading screen, then I just extend the Thread class.
So I would create a loading screen like this:
public class LoadingScreen extends MainScreen {
public LoadingScreen() {
super();
this.setTitle("loading...");
// add a spinning animated gif or whatever here
final Screen me = this;
new Thread(new Runnable(){
public void run(){
// do something that takes a long time
try { Thread.sleep(1000);} catch (Exception e) {}
}
}){
public void run() {
super.run();
synchronized (UiApplication.getEventLock()) {
UiApplication.getUiApplication().popScreen(me);
}
}
}.start();
}
}
Then I push this screen, it will perform the long task, and then pop itself when its done.
(you may or may not want to disable the back button and menus on this screen)
I made the Runnable as an anonymous inner class just to compact the code, but you probably have this code already in a class somewhere else, so you would pass it in instead.
To add some flexibility and keep your classes loosely coupled together, you could make some modifications to your ServerConnectivity class so your calls could go something like the following:
// push your splash screen on to the stack
//
final SplashScreen splashScreen = new SplashScreen();
UiApplication.getUiApplication().pushScreen(splashScreen);
_getDoc = new ServerConnectivity(this, new ServerConnectivityListener() {
public void onCompleted(ServerConnectivity sender) {
// display next screen
//
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
splashScreen.close();
UiApplication.getUiApplication().pushScreen(new NextScreen());
}
});
}
public void onError(ServerConnectivity sender) {
splashScreen.close();
// display error message, retry, etc...
}
});
For this to work, you need an interface with the following definition:
public interface ServerConnectivityListener {
void onCompleted(ServerConnectivity sender);
void onError(ServerConnectivity sender);
}
So, your ServerConnectivity class maintains a reference to some object that implements the interface called ServerConnectivityListener This allows you to maintain loose coupling between the subject class and any observers that need to listen for events.
Within ServerConnectivity, you would make calls to the listener's methods something like this:
// begin excerpt from above...
//
if(_topics == null || _notifications == null) {
_listener.onError(this);
} else {
_listener.onCompleted(this);
}
catch ( Exception e ){
System.out.println( e.toString() );
_listener.onError(this);
//
// end excerpt from above...
Here is code for splash screen in java........after and call that view.........
http://www.randelshofer.ch/oop/javasplash/javasplash.html
import java.awt.*;
import java.awt.event.*;
public class SplashTest extends Frame implements ActionListener {
static void renderSplashFrame(Graphics2D g, int frame) {
final String[] comps = {"foo", "bar", "baz"};
g.setComposite(AlphaComposite.Clear);
g.fillRect(130,250,280,40);
g.setPaintMode();
g.setColor(Color.BLACK);
g.drawString("Loading "+comps[(frame/5)%3]+"...", 130, 260);
g.fillRect(130,270,(frame*10)%280,20);
}
public SplashTest() {
super("SplashScreen demo");
setSize(500, 300);
setLayout(new BorderLayout());
Menu m1 = new Menu("File");
MenuItem mi1 = new MenuItem("Exit");
m1.add(mi1);
mi1.addActionListener(this);
MenuBar mb = new MenuBar();
setMenuBar(mb);
mb.add(m1);
final SplashScreen splash = SplashScreen.getSplashScreen();
if (splash == null) {
System.out.println("SplashScreen.getSplashScreen() returned null");
return;
}
Graphics2D g = (Graphics2D)splash.createGraphics();
if (g == null) {
System.out.println("g is null");
return;
}
for(int i=0; i<100; i++) {
renderSplashFrame(g, i);
splash.update();
try {
Thread.sleep(200);
}
catch(InterruptedException e) {
}
}
splash.close();
setVisible(true);
toFront();
}
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
public static void main (String args[]) {
SplashTest test = new SplashTest();
}
}
Since,it is a thread based one,We cannot do it the normal way.So Check the following link
http://supportforums.blackberry.com/t5/Java-Development/What-is-the-Event-Thread/ta-p/446865
and Check whether parsing is done,Until that have the same screen,Check the condition of whehter it is downloaded or not ,and then push the screen