How to redirect MouseEvent.MOUSE_PRESSED to a different Node? - javafx-2

I have a Region called 'R', and a Node called 'N'. N is the only child on R. Consider this behaviour:
the user presses the left-mouse button on some part of R
N (which is somewhere else on R) moves so that it is centered on the spot where the user pressed
the user releases the left-mouse button, then presses it again without moving the mouse
with the left-mouse button still pressed, the user drags the mouse, and N now follows the mouse cursor around as it is dragged.
I have no problems implementing the behaviour I've just described. I put a MOUSE_PRESSED handler on R that implements step 2. And I put a MOUSE_DRAGGED handler on N that implements step 4. JavaFX automatically directs the MouseEvents to these handlers on R and N for the presses in step 1 and 3 respectively.
The Problem:
I need to do this WITHOUT step 3. That is, the user should not have to press-release-press-drag, but rather should simply press-drag, and N should "jump" to the mouse location on the "press", and then start receiving MOUSE_DRAGGED events immediately.
Unfortunately, this doesn't happen. The release-click that I'm trying to omit seems to be necessary, otherwise the drag events all happen on R instead of N.
I'm thinking the solution will involve redispatching the initial MOUSE_PRESSED, or something along those lines. Does anyone know a way to do this (or a better way to solve my problem?)

Node has api to mark it as the target of drag gestures:
public void startFullDrag()
Starts a full press-drag-release gesture with this node as gesture
source. This method can be called only from a DRAG_DETECTED mouse
event handler. More detail about dragging gestures can be found in the
overview of MouseEvent and MouseDragEvent.
Assuming circle being your currently active node in a pane (borrowing code/names from James's answer), the collaborators are handlers on
mousePressed on pane that snaps the position of circle to the the current location
dragDetected on pane that calls startsFullDrag on circle
dragAny on circle that does the actual moving
In code:
pane.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
}
});
pane.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
circle.startFullDrag();
}
});
circle.addEventHandler(MouseDragEvent.ANY, new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
}
});

I chose the simplest node to work with for this, but I think this would work in general:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class ClickAndDragTest extends Application {
#Override
public void start(Stage primaryStage) {
final Pane pane = new Pane();
final Circle circle = new Circle(100, 100, 50, Color.CORNFLOWERBLUE);
pane.getChildren().add(circle);
pane.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
}
});
pane.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
}
});
final Scene scene = new Scene(pane, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Related

How can I make a TextArea stretch to fill the content, expanding the parent in the process?

So I have a TextArea and as the user pastes paragraphs into it, or just writes in it, I want it to expand vertically to reveal all the available text. I.e. not to use a scrollbar in the text field itself... much like what happens on many web pages. Many users, myself included, don't like to be forced to edit in a small window. Exactly how Facebook status updates box works.
I've tried
myTextArea.autoSize()
wrapped in an
myTextArea.textProperty().addListener(new ChangeListener()....);
but that doesn't work. I think it's happy autosizing to its current size.
The left, right & top anchors are set to it's parent AnchorPane. I've tried it with the bottom attached and not attached. Ideally I'd like to grow the anchor pane as the textarea grows.
I don't mind reading the TextProperty and calculating a trigger size which I set myself... but this seems a hacky approach IF there is already a best practise. The number of properties and sub objects of javafx is sufficiently daunting that it seems like a good point to ask the question here, rather than trying to figure out how many pixels the font/paragraphs etc are taking up.
Update:
So I thought maybe I was overthinking it, and all I needed to do was to switch the scrollbars off and the rest would happen. Alas, looking for available fields and methods for "scroll", "vertical", "vbar" comes up with nothing I can use. ScrollTopProperty looks like it's for something else.
The problem; the height of textArea is wanted to be grown or shrunk while its text is changing by either user's typing or copy-pasting. Here is another approach:
public class TextAreaDemo extends Application {
private Text textHolder = new Text();
private double oldHeight = 0;
#Override
public void start(Stage primaryStage) {
final TextArea textArea = new TextArea();
textArea.setPrefSize(200, 40);
textArea.setWrapText(true);
textHolder.textProperty().bind(textArea.textProperty());
textHolder.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
if (oldHeight != newValue.getHeight()) {
System.out.println("newValue = " + newValue.getHeight());
oldHeight = newValue.getHeight();
textArea.setPrefHeight(textHolder.getLayoutBounds().getHeight() + 20); // +20 is for paddings
}
}
});
Group root = new Group(textArea);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
// See the explanation below of the following line.
// textHolder.setWrappingWidth(textArea.getWidth() - 10); // -10 for left-right padding. Exact value can be obtained from caspian.css
}
public static void main(String[] args) {
launch(args);
}
}
But it has a drawback; the textarea's height is changing only if there are line breaks (ie Enter keys) between multiple lines, if the user types long enough the text gets wrapped to multiple line but the height is not changing.
To workaround this drawback I added this line
textHolder.setWrappingWidth(textArea.getWidth() - 10);
after primaryStage.show();. It works well for long typings where user does not linebreaks. However this generates another problem. This problem occurs when the user is deleting the text by hitting "backspace". The problem occurs exactly when the textHolder height is changed and where the textArea's height is set to new value. IMO it maybe a bug, didn't observe deeper.
In both case the copy-pasting is handling properly.
Awaiting a better, i use this hacky solution.
lookup the vertical scrollbar of the textarea.
make it transparent
listen to its visible property
when the scrollbar become visible i add a row to the textarea.
The code:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class GrowGrowTextArea extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
AnchorPane root = new AnchorPane();
root.setStyle("-fx-padding:20;-fx-background-color:dodgerblue;");
final TextArea textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 10.0);
AnchorPane.setLeftAnchor(textArea, 10.0);
AnchorPane.setRightAnchor(textArea, 10.0);
root.getChildren().add(textArea);
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
ScrollBar scrollBar = lookupVerticalScrollBar(textArea);
scrollBar.setOpacity(0.0);
scrollBar.visibleProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> source,
Boolean wasVisible,
Boolean isVisible) {
if (isVisible) {
textArea.setPrefRowCount(textArea.getPrefRowCount() + 1);
textArea.requestLayout();
}
}
});
}
private ScrollBar lookupVerticalScrollBar(Node node) {
if (node instanceof ScrollBar && ((ScrollBar)node).getOrientation() == Orientation.VERTICAL) {
return (ScrollBar) node;
}
if (node instanceof Parent) {
ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
for (Node child : children) {
ScrollBar scrollBar = lookupVerticalScrollBar(child);
if (scrollBar != null) {
return scrollBar;
}
}
}
return null;
}
}
I had a similar problem with creating expanding TextArea. I was creating TextArea that looks like TextField and expand vertically every time when there is no more space in line.
I have tested all solutions that I could find on this topic on stack and other sources available. I found few good solutions but neither was good enough.
After many hours of fighting, I figured out this approach.
I extended TextArea class, override layoutChildren() method and add a listener on text height.
#Override
protected void layoutChildren() {
super.layoutChildren();
setWrapText(true);
addListenerToTextHeight();
}
private void addListenerToTextHeight() {
ScrollPane scrollPane = (ScrollPane) lookup(".scroll-pane");
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
StackPane viewport = (StackPane) scrollPane.lookup(".viewport");
Region content = (Region) viewport.lookup(".content");
Text text = (Text) content.lookup(".text");
text.textProperty().addListener(textHeightListener(text));
}
private InvalidationListener textHeightListener(Text text) {
return (property) -> {
// + 1 for little margin
double textHeight = text.getBoundsInLocal().getHeight() + 1;
//To prevent that our TextArena will be smaller than our TextField
//I used DEFAULT_HEIGHT = 18.0
if (textHeight < DEFAULT_HEIGHT) {
textHeight = DEFAULT_HEIGHT;
}
setMinHeight(textHeight);
setPrefHeight(textHeight);
setMaxHeight(textHeight);
};
}
I used some of the code found in the previous answers.
The growTextAreaIfNecessary method will increase the height of textArea until the scrollbar is not visible (limited to 20 lines in this example).
The problem with this approach is that the window needs to be redrawn several times until the perfect height is found.
private ScrollBar lookupVerticalScrollBar(Node node) {
if (node instanceof ScrollBar && ((ScrollBar) node).getOrientation() == Orientation.VERTICAL) {
return (ScrollBar) node;
}
if (node instanceof Parent) {
ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
for (Node child : children) {
ScrollBar scrollBar = lookupVerticalScrollBar(child);
if (scrollBar != null) {
return scrollBar;
}
}
}
return null;
}
private void growTextAreaIfNecessary(TextArea textArea) {
Platform.runLater(() -> {
ScrollBar lookupVerticalScrollBar = lookupVerticalScrollBar(textArea);
int prefRowCount = textArea.getPrefRowCount();
if (lookupVerticalScrollBar.isVisible() && prefRowCount < 20) {
textArea.setPrefRowCount(prefRowCount + 1);
System.out.println("increasing height to: " + (prefRowCount + 1));
growTextAreaIfNecessary(textArea);
}
});
}
I have tried many hacks, most of them had jitters while typing, this to me was the perfect result:
textArea.textProperty().addListener((obs,old,niu)->{
Text t = new Text(old+niu);
t.setFont(textArea.getFont());
StackPane pane = new StackPane(t);
pane.layout();
double height = t.getLayoutBounds().getHeight();
double padding = 20 ;
textArea.setMinHeight(height+padding);
});

JavaFx 2.x : Stage within a TabPane

I need to display one or more stage(s) within a TabPane by clicking on a button, such as the picture below
My target is to have a situation similar to JInternalFrame in Swing: how to accomplish this?
I am not able to add stage as children to the tab pane.
If this is not possible, what could be other solutions? I would like to have SplitPanes on the stage.
Thanks
PS I am using Win7, NetBeans 7.4 Beta (Build 201307092200), SceneBuilder 1.1
Edit: here is how it looks after some VFXWindows css changes
There's one thing worth notice: I have had to add a node ( in my case an HBox with prefSize(0,0), otherwise I can't move o resize the first window plotted, only the first one.
As last, I can't find a way to set windows full screen (maximize).
Here I put an example of windows from jfxtras inside of Tabs, I just modify the example.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;
import jfxtras.labs.scene.control.window.CloseIcon;
import jfxtras.labs.scene.control.window.MinimizeIcon;
import jfxtras.labs.scene.control.window.Window;
public class WindowInTab extends Application {
private static int counter = 1;
private void init(Stage primaryStage) {
TabPane tabPane = new TabPane();
Tab tab = generateTab("Windows...");
Tab anotherTab = generateTab("More Windows");
tabPane.getTabs().addAll(tab, anotherTab);
primaryStage.setResizable(true);
primaryStage.setScene(new Scene(tabPane, 600, 500));
}
private Tab generateTab(String tabName) {
Tab tab = new Tab(tabName);
final Group root = new Group();
tab.setContent(root);
Button button = new Button("Add more windows");
root.getChildren().addAll(button);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
// create a window with title "My Window"
Window w = new Window("My Window#"+counter);
// set the window position to 10,10 (coordinates inside canvas)
w.setLayoutX(10);
w.setLayoutY(10);
// define the initial window size
w.setPrefSize(300, 200);
// either to the left
w.getLeftIcons().add(new CloseIcon(w));
// .. or to the right
w.getRightIcons().add(new MinimizeIcon(w));
// add some content
w.getContentPane().getChildren().add(new Label("Content... \nof the window#"+counter++));
// add the window to the canvas
root.getChildren().add(w);
}
});
return tab;
}
public double getSampleWidth() {return 600;}
public double getSampleHeight() {return 500;}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {launch(args);}
}
I don't know if this was exactly what you were looking for. Hope it helps!

Checking Collision of Shapes with JavaFX

I am trying to do some collision detection. For this test I am using simple rectangular Shape, and checking their Bound, to figure if they are colliding. Although the detection does not work as expected. I have tried using different ways to move the object(relocate, setLayoutX,Y) and also different bound checks (boundsInLocal,boundsInParrent etc) but I still cannot get this to work. As you can see the detection works only for one object, even when you have three objects only one detects collision. This is some working code demonstrating the problem:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
public class CollisionTester extends Application {
private ArrayList<Rectangle> rectangleArrayList;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("The test");
Group root = new Group();
Scene scene = new Scene(root, 400, 400);
rectangleArrayList = new ArrayList<Rectangle>();
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.GREEN));
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.RED));
rectangleArrayList.add(new Rectangle(30.0, 30.0, Color.CYAN));
for(Rectangle block : rectangleArrayList){
setDragListeners(block);
}
root.getChildren().addAll(rectangleArrayList);
primaryStage.setScene(scene);
primaryStage.show();
}
public void setDragListeners(final Rectangle block) {
final Delta dragDelta = new Delta();
block.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = block.getTranslateX() - mouseEvent.getSceneX();
dragDelta.y = block.getTranslateY() - mouseEvent.getSceneY();
block.setCursor(Cursor.NONE);
}
});
block.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
block.setCursor(Cursor.HAND);
}
});
block.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
block.setTranslateX(mouseEvent.getSceneX() + dragDelta.x);
block.setTranslateY(mouseEvent.getSceneY() + dragDelta.y);
checkBounds(block);
}
});
}
private void checkBounds(Rectangle block) {
for (Rectangle static_bloc : rectangleArrayList)
if (static_bloc != block) {
if (block.getBoundsInParent().intersects(static_bloc.getBoundsInParent())) {
block.setFill(Color.BLUE); //collision
} else {
block.setFill(Color.GREEN); //no collision
}
} else {
block.setFill(Color.GREEN); //no collision -same block
}
}
class Delta {
double x, y;
}
}
Looks like you have a slight logic error in your checkBounds routine - you are correctly detecting collisions (based on bounds) but are overwriting the fill of your block when you perform subsequent collision checks in the same routine.
Try something like this - it adds a flag so that the routine does not "forget" that a collision was detected:
private void checkBounds(Shape block) {
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
static_bloc.setFill(Color.GREEN);
if (block.getBoundsInParent().intersects(static_bloc.getBoundsInParent())) {
collisionDetected = true;
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.GREEN);
}
}
Note that the check you are doing (based on bounds in parent) will report intersections of the rectangle enclosing the visible bounds of nodes within the same parent group.
Alternate Implementation
In case you need it, I updated your original sample so that it is able to check based on the visual shape of the Node rather than the bounding box of the visual shape. This lets you to accurately detect collisions for non-rectangular shapes such as Circles. The key for this is the Shape.intersects(shape1, shape2) method.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.ArrayList;
import javafx.scene.shape.*;
public class CircleCollisionTester extends Application {
private ArrayList<Shape> nodes;
public static void main(String[] args) { launch(args); }
#Override public void start(Stage primaryStage) {
primaryStage.setTitle("Drag circles around to see collisions");
Group root = new Group();
Scene scene = new Scene(root, 400, 400);
nodes = new ArrayList<>();
nodes.add(new Circle(15, 15, 30));
nodes.add(new Circle(90, 60, 30));
nodes.add(new Circle(40, 200, 30));
for (Shape block : nodes) {
setDragListeners(block);
}
root.getChildren().addAll(nodes);
checkShapeIntersection(nodes.get(nodes.size() - 1));
primaryStage.setScene(scene);
primaryStage.show();
}
public void setDragListeners(final Shape block) {
final Delta dragDelta = new Delta();
block.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = block.getLayoutX() - mouseEvent.getSceneX();
dragDelta.y = block.getLayoutY() - mouseEvent.getSceneY();
block.setCursor(Cursor.NONE);
}
});
block.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
block.setCursor(Cursor.HAND);
}
});
block.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
block.setLayoutX(mouseEvent.getSceneX() + dragDelta.x);
block.setLayoutY(mouseEvent.getSceneY() + dragDelta.y);
checkShapeIntersection(block);
}
});
}
private void checkShapeIntersection(Shape block) {
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
static_bloc.setFill(Color.GREEN);
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.GREEN);
}
}
class Delta { double x, y; }
}
Sample program output. In the sample the circles have been dragged around and the user is currently dragging a circle which has been marked as colliding with another circle (by painting it blue) - for demonstration purposes only the circle currently being dragged has it's collision color marked.
Comments based on additional questions
The link I posted to an intersection demo application in a prior comment was to illustrate the use of various bounds types rather than as a specific type of collision detection sample. For your use case, you don't need the additional complexity of the change listener and checking on various different kinds of bounds types - just settling on one type will be enough. Most collision detection is only going to be interested in intersection of visual bounds rather than other JavaFX bounds types such as the layout bounds or local bounds of a node. So you can either:
Check for intersection of getBoundsInParent (as you did in your original question) which works on the smallest rectangular box which will encompass the visual extremities of the node OR
Use the Shape.intersect(shape1, shape2) routine if you need to check based on the visual shape of the Node rather than the bounding box of the visual shape.
Should I be using setLayoutX or translateX for the rectangle
The layoutX and layoutY properties are intended for positioning or laying out nodes. The translateX and translateY properties are intended for temporary changes to the visual location of a node (for example when the node is undergoing an animation). For your example, though either property will work, it is perhaps better form to use the layout properties than the translate ones, that way if you did want to run something like a TranslateTransition on the nodes, it will be more obvious what the start and end translate values should be as those values will be relative to the current layout position of the node rather than the position in the parent group.
Another way you could use these layout and translate co-ordinates in tandem in your sample is if you had something like an ESC to cancel during the course of a drag operation. You could set layoutX,Y to the initial location of your node, start a drag operation which sets translateX,Y values and if the user presses ESC, set translateX,Y back to 0 to cancel the drag operation or if the user releases the mouse set layoutX,Y to layoutX,Y+translateX,Y and set translateX,Y back to 0. The idea is that the translation is values are used for a temporary modification of the visual co-ordinates of the node from it's original layout position.
will the intersect work even though the circles are animated? I mean without dragging the circle by mouse, what will happen if I made them to move around randomly. Will the colour change in this case also?
To do this, just change where the collision detection function is called and the collision handler invoked. Rather than checking for intersections based upon a mouse drag event (like the example above), instead check for collisions within a change listener on each node's boundsInParentProperty().
block.boundsInParentProperty().addListener((observable, oldValue, newValue) ->
checkShapeIntersection(block)
);
Note: if you have lots of shapes being animated, then checking for collisions once per frame within a game loop will be more efficient than running a collision check whenever any node moves (as is done in the boundsInParentProperty change listener above).
Additional info for handling input on non-rectangular shapes
For input detection not collision detection, so not directly related to your question, look at the node.pickOnBounds setting if you need mouse or touch interaction with a non-rectangular node.

Lwuit touch screen strange behaviour

I am making an application using LWUIT.
There is a form
There is a list embedded on the form.
The list has 5 elements.
Initially, when I first load the app, if I choose the 1st element, 2nd gets chosen; when I choose the second the 3rd gets chose and and so on (Weird!)
I am not able to click any button on the screen either
next what I do is, shift to a different from using arrow keys (of the keyboard... I am running the app on a simulator btw)
Then I come back to the first form and now everything works as expected(no weird behaviour).
What could be the issue?
I am using Sun Java Micro Edition SDK 3.0 (default touch screen for testing)
My code is:
List dummy = new List();
dummy.addItem("wewerwer");
dummy.addItem("wewerdswer");
dummy.addItem("wewqweerwer");
dummy.addItem("dscxwewerwer");
dummy.addItem("jhgwewerwer");
mainListForm.setLayout(new BorderLayout());
mainListForm.addComponent(BorderLayout.CENTER,dummy);
mainListForm.show();
What could possible be going wrong here?
UPDATE 1
I think there is a bug here. I have attached the complete code below along with the screen shot
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
public class Demo extends MIDlet implements ActionListener {
private Form mForm;
List abc;
public void startApp() {
Display.init(this);
try {
Resources r = Resources.open("/Test.res");
UIManager.getInstance().setThemeProps(r.getTheme(
r.getThemeResourceNames()[0])
);
} catch (Exception e){
System.out.println(e.toString());
}
if (mForm == null) {
Button click = new Button("Press me!");
click.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("I have been pressed");
}
});
abc = new List();
abc.addItem("Str1");
abc.addItem("Str2");
abc.addItem("Str3");
abc.addItem("Str4");
abc.addItem("Str5");
abc.addItem("Str6");
Form f = new Form("Hello, LWUIT!");
abc.addActionListener(this);
f.addComponent(abc);
Command exitCommand = new Command("Exit");
f.addCommand(exitCommand);
f.addCommandListener(this);
f.addComponent(click);
f.show();
}
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void actionPerformed(ActionEvent ae) {
System.out.println(abc.getSelectedIndex());
}
}
So now when I click on 'Str1' of the list Str2 gets selected and so on.
IDE: Netbeans
Emulator: Default Touch screen phone
On the action event set the list to active again after the event by invoking setHandlesInput(true)
OK....so this is how you resolve it.
After the form is displayed remove the list from the form and again add it to the form and then repaint the form.
Earlier Code
1) form.addComponenet(BorderLayout.center,list);
2) form.show();
Word Around for the problem
1)form.addComponenet(BorderLayout.center,list);
2)form.show();
3)form.setScrollable(false);
I know its kind of strange, but this way the list index selection works smooth for touch screen phones.

How to play clean audio loops and one-shot sounds in parallel in JavaFX 2.0?

I'm trying to play background audio in a loop in a JavaFX 2.0 application using JavaFX SDK 2.0.1. I decided to use a MediaPlayer created by the following piece of code:
MediaPlayerBuilder
.create().media(BACKGROUND_MEDIA)
.cycleCount(MediaPlayer.INDEFINITE);
This basically works, but when a new cycle starts there is a tiny (latency?) gap between the end and the start of the audio. So it's not a working option for me since it's not playing a clean loop.
I decided to build a new MediaPlayer object and start playback everytime Media ends. This works fine so far. Additionally, I use a button playing a short AudioClip when clicked.
I discoverd that frequent and fast clicking this button leads to interrupts in the background audio. I created an example to reproduce this behaviour by inifinitely playing an AudioClip with volume 0 when the button is clicked once. The example is not self contained, since the required audio files are missing. It requires to place 2 audio files in the project's source directory:
click.wav (a really short click sound ~300ms)
background.wav (~5 seconds of audio)
How do I achieve playing a clean audio loop in background without these interrupts when other one-shot audio sounds are played? Is it just a performance issue?
Example:
package mediatest;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.media.AudioClip;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayerBuilder;
import javafx.stage.Stage;
public class MediaTest extends Application {
private static final AudioClip CLICK_AUDIOCLIP = new AudioClip(MediaTest.class.getResource("/click.wav").toString());
private static final Media BACKGROUND_MEDIA = new Media(MediaTest.class.getResource("/background.wav").toString());
private MediaPlayerBuilder builder;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
this.builder = MediaPlayerBuilder
.create()
.media(BACKGROUND_MEDIA)
.onEndOfMedia(new Runnable() {
public void run() {
MediaPlayer player = MediaTest.this.builder.build();
player.play();
}
});
MediaPlayer player = this.builder.build();
player.play();
Button btn = new Button();
btn.setText("Repeat playing short audio clip");
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
//Simulation of many button clicks
MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
MediaTest.CLICK_AUDIOCLIP.play(0);
}
});
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
}
have you looked into ExecutorService? You would then have a number of predefined threads like so:
ExecutorService service = Executors.newFixedThreadPool(4);
where 4 is the number of threads it makes.
It will improve performance because it uses already made threads rather than making a new one each time you want to run something.
You would create a Runnable and execute it with the service like so:
Runnable r = new Runnable() {
#Override
public void run() {
playSound();
}
};
service.execute(r);
Not only would this improve performance but it automatically assigns the job to a not-currently-busy thread in its thread pool.
Also look at this: Playing sound loops using javafx which I believe solves your small latency problem.
EDIT: damn sorry, I didn't know this post was that old. It was a top result in google.
Using another thread at
public void handle(ActionEvent event) {
Platform.runLater(new Runnable()
{
#Override
public void run()
{
//Simulation of many button clicks
MediaTest.CLICK_AUDIOCLIP.setCycleCount(AudioClip.INDEFINITE);
MediaTest.CLICK_AUDIOCLIP.play(0);
}
});
}
});
May solve the problem of the interruption

Resources