I am new in java.
I am trying to build a three bead game.
I am having problems to place 6 movable objects inside a jpg file.
I have tried using JPanel but the objects doesn't show.
Not sure if I understood you correctly, but I suppose you want to display background (a JPG image) and then programatically move three beads on it. If that's the case, there's Simple tutorial on how to work with images in JavaFX. To just display image, you need to do the following:
public void start(Stage stage) throws FileNotFoundException {
//Creating an image
Image image = new Image(new FileInputStream("file path"));
//Setting the image view 1
ImageView imageView1 = new ImageView(image);
//Creating a Group object
Group root = new Group(imageView1);
//Creating a scene object
Scene scene = new Scene(root, 600, 400);
//Adding scene to the stage
stage.setScene(scene);
//Displaying the contents of the stage
stage.show();
}
To move beads, you need to keep their state in your application and re-draw it periodically. The tutorial I've mentioned describes basics of pixel manipulation so you may want to check that too.
Related
I've been working in JavaFX for the first time to try to make an app which I can use to demonstrate a simple animation with button controls. To do this I've used a BoarderPane for the primary stage, with both the left,right, and bottom using Gridpanes.
However, for the center I need to be able to draw a sphere with a line within it which I can rotate for different views while simultaneously being able to animated, or at the very least snap-move, the line within.
I've tried using a Pane for the center which doesn't work. I've tried making it it's own scene and sub scene which doesn't work. And I can't use a canvas as that is only for 2D animation.
Is there a way I can animate the line or rotate the camera while maintaining the BoarderPane layout I've created?
I've tried looking at the following before to understand what I could do but most just seem incompatible with the BoarderPane:
JavaFX Rotating Camera Around a Pivot
JavaFX Canvas rotate image with fixed center (and without bouncing)
Whenever you want to mix 2D and 3D (and camera) you have to use a SubScene container for the 3D content:
SubScene provides separation of different parts of a scene, each of which can be rendered with a different camera, depth buffer, or scene anti-aliasing. A SubScene is embedded into the main scene or another sub-scene.
If you have a BorderPane container, you can perfectly add the subScene to its center.
For a similar use case, you can check the Qubit3D class from here, which is mainly a group that holds a sub scene with an Sphere and a cylinder (both from the FXyz 3D library).
You can add this group easily to your 2D scene:
private final Rotate rotate = new Rotate(0, 0, 0, 0, javafx.geometry.Point3D.ZERO.add(1, 1, 1));
#Override
public void start(Stage primaryStage) throws Exception {
final Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(10),
new KeyValue(rotate.angleProperty(), 360)));
final Qubit3D qubit = new Qubit3D();
final BorderPane root = new BorderPane(qubit);
final Button buttonAnimate = new Button("Animate");
buttonAnimate.setOnAction(e -> {
rotate.setAngle(0);
timeline.playFromStart();
});
root.setLeft(new StackPane(buttonAnimate));
final Button buttonStop = new Button("Stop");
buttonStop.setOnAction(e -> timeline.stop());
root.setRight(new StackPane(buttonStop));
Scene scene = new Scene(root, 600, 400, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.BISQUE);
primaryStage.setScene(scene);
primaryStage.setTitle("Qubit3D Sample");
primaryStage.show();
qubit.rotateRod(rotate);
}
The only modification I've added to Qubit3D is:
public void rotateRod(Rotate rotate) {
rodSphere.getTransforms().setAll(rotate);
}
If you run it:
Note that you can interact with the sphere (via mouse dragged events), while you can also start/stop a full rotation of sphere and rod.
I have a titled pane, and I'm displaying an image in this pane, but the image is very big so I resize it, to fit the pane. Since the image becomes smaller, the user might want to view it in original size, so I implemented a method on mouse click opening the original image in new bigger window.
imgViewPicture.setFitWidth(titledPanePicture.getPrefWidth());
imgViewPicture.setPreserveRatio(true);
imgViewPicture.setSmooth(true);
imgViewPicture.setCache(true);
titledPanePicture.setContent(imgViewPicture);
The problem is, when I click on titledPanePicture the small image disappears, its content is cleared. Why? For the solution I added a reloading of the content on mouseclick event. But I dont like it, I think the content should stay the same for titledPanePicture.
Here is my mouseclick event:
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
Group root = new Group();
Scene scene = new Scene(root);
scene.setFill(Color.BLACK);
HBox box = new HBox();
imgViewPicture.setFitWidth(0);
box.getChildren().add(imgViewPicture);
root.getChildren().add(box); // before tPane
stage.setTitle("Picture Original Size");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
reloadContentofTitledPane(); // This line is the fix but I find it unnecessary
Tips would be appreciated.
You seem to use the same ImageView in both scenes. However a Node can only be placed at a single place in a single scene graph.
Create a new node for your new Scene.
ImageView newImageView = new ImageView(imgViewPicture.getImage());
...
box.getChildren().add(newImageView);
So
I am trying to let the user set a path to a picture and then display it but I am not able to display it.
Currently, I am using Eclipse and Scene Builder to accomplish my goals
Code so far:
#FXML
public void choseFile() {
fc = new FileChooser();
File tmp = fc.showOpenDialog(dialogStage);
Image img = new Image(tmp.getAbsolutePath);
image1 = new ImageView();
image1.setImage(img);
}
image1 is set to an ImageView in the SceneBuilder and the choseFile() method is set to a button that is next to that picture
Thanks in advance
As James_D mentioned, you need to add ImageView in your code.
Import javax.scene.image.ImageView.
According to the documentation,
The ImageView is a Node used for painting images loaded with Image class. This class allows resizing the displayed image (with or without preserving the original aspect ratio) and specifying a viewport into the source image fro restricting the pixels displayed by this ImageView.
Sample code from the document :
public class HelloMenu extends Application {
#Override public void start(Stage stage) {
// load the image
Image image = new Image("flower.png");
// simple displays ImageView the image as is
ImageView iv1 = new ImageView();
iv1.setImage(image);
// resizes the image to have width of 100 while preserving the ratio and using
// higher quality filtering method; this ImageView is also cached to
// improve performance
ImageView iv2 = new ImageView();
iv2.setImage(image);
iv2.setFitWidth(100);
iv2.setPreserveRatio(true);
iv2.setSmooth(true);
iv2.setCache(true);
// defines a viewport into the source image (achieving a "zoom" effect) and
// displays it rotated
ImageView iv3 = new ImageView();
iv3.setImage(image);
Rectangle2D viewportRect = new Rectangle2D(40, 35, 110, 110);
iv3.setViewport(viewportRect);
iv3.setRotate(90);
Group root = new Group();
Scene scene = new Scene(root);
scene.setFill(Color.BLACK);
HBox box = new HBox();
box.getChildren().add(iv1);
box.getChildren().add(iv2);
box.getChildren().add(iv3);
root.getChildren().add(box);
stage.setTitle("ImageView");
stage.setWidth(415);
stage.setHeight(200);
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
There is plenty of online resource on how to add a graphic to a JavaFX button.
However I would like to know if there is a way to add a second (or any number, but more than 2 images probably woudn't make much sense in most situations) image.
My use case : i have a button with a square icon on the left, followed by a text label. The image is a representation of some real-life concept that button is linked with (could e.g. a car or a person). I would like to add a small icon to the right of some buttons, a "right chevron" to indicate the nature of the interaction.
I was thinking maybe to use a HBox with the full width as the graphic node of the button, and add the 2 images to it, but I don't think it is possible to put the text on top of the graphic node.
Any idea ?
Create your own custom node with icons and text and set it as graphic. Of course you don't show the button text because it's already in your custom graphic node.
Here's a simple example. You need to provide the files icon1.png and icon2.png.
public class ButtonWithMultipleIcons extends Application {
#Override
public void start(Stage primaryStage) {
try {
Group group = new Group();
Button button = new Button();
button.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
HBox hBox = new HBox();
ImageView icon1 = new ImageView( getClass().getResource( "icon1.png").toExternalForm());
ImageView icon2 = new ImageView( getClass().getResource( "icon2.png").toExternalForm());
Label label = new Label("Text");
//make the button grow if you want the right icon to always be on the right of the button :
label.setMaxWidth(Long.MAX_VALUE);
HBox.setHgrow(label, Priority.ALWAYS);
hBox.getChildren().addAll( icon1, label, icon2);
button.setGraphic(hBox);
group.getChildren().add( button);
Scene scene = new Scene(group,400,400);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
You can try using html formatting in your button and adding an image with the tag before and after your text.
You can find more information about it in here:http://docs.oracle.com/javase/tutorial/uiswing/components/html.html
I had the same thing to get along with. You describing the solution with using a HBox. I think this would also be the best way.
Do the following:
Create a new CustomButton with your own specific layout maybe using a HBox and extending Button class from JavaFX. Style it your way you need it and you can add as many images you want to have in your custom button. Maybe it can look like this:
public class CustomButton extends Button
{
private HBox hbox;
private ImageView image1;
private ImageView image2;
public CustomButton()
{
super();
// Here add your specific images to global or local variables and then add all the children (images) to your HBox layout and this one to the button.
}
}
The problem ist, that JavaFX provides normal buttons and not such deeply customized components. If you want to style it, you can use CSS anyway.
I would like to embedd a video in my JavaFx 2.x scene and also resize it and relocate it to my needs. The problem I'm having is following. If I build a MediaView component and then translate X or Y coordinate, then the whole view is being properly moved like so:
MediaView mv = (...)
mv.setTranslateX(200);
mv.setTranslateY(200);
I could do a similar transformation with scaling property:
MediaView mv = (...)
mv.setScaleX(2);
mv.setScaleY(2);
which will properly scale mv instance two times in dimension.
However, the problem is when I combine those two translations. The mv instance is being scaled but it always ends up in screen coordinates (0,0). This is of course incorrect behavior from my perspective.
I have also tried to wrap my MediaView component within some wrapper node, like Group and perform translations on this element. The behavior is the same.
How can I properly move and scale MediaView component at the same time?
Edit:
Here is my code, although I'm using here ImageView. This is irrelevant, however. After running this code, image will be placed at (0,0) instead of (100,100).
#Override
public void start(Stage stage) throws Exception {
Group root = new Group();
// Img's dimension is 200x200
javafx.scene.image.Image img = new javafx.scene.image.Image("/home/bachman/projects/cs-player/src/main/resources/content.png");
ImageView iv = new ImageView(img);
root.getChildren().add(iv);
// Move Image View
iv.setTranslateX(100);
iv.setTranslateY(100);
// Scale Image View
iv.setScaleX(2.0);
iv.setScaleY(2.0);
Scene scene = new Scene(root);
stage.setWidth(600);
stage.setHeight(600);
stage.setScene(scene);
stage.show();
}
When you use setScaleX, setScaleY, scaling occurs from the center of the node.
If you want to translate by an amount in addition to scaling, you need to take the scaling expansion into account when you set the required translation values. For example, if the node doubles in size (and you want to translate the node to a position relative to the upper left corner of the unscaled node), you need to translate by an additional half the node width and height.
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.media.*;
import javafx.scene.transform.*;
import javafx.stage.Stage;
public class TransformedVideo extends Application {
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
final MediaPlayer oracleVid = new MediaPlayer(new Media("http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv"));
final MediaView mediaView = new MediaView(oracleVid);
mediaView.setFitWidth(320); mediaView.setFitHeight(240); mediaView.setPreserveRatio(false);
mediaView.setTranslateX(mediaView.getFitWidth() / 2 + 200);
mediaView.setTranslateY(mediaView.getFitHeight() / 2 + 200);
mediaView.setScaleX(2); mediaView.setScaleY(2);
// alternative method of scaling and translating.
// mediaView.getTransforms().addAll(
// new Translate(200, 200),
// new Scale(2, 2)
// );
Group group = new Group(mediaView);
stage.setScene(new Scene(group, 1250, 800));
stage.show();
oracleVid.play();
System.out.println(group.getBoundsInParent());
}
}
When performing multiple transforms on a node, rather than using the setScale/setTransform/setRotate methods, it is often easier to just supply a list of transforms to the getTransforms() method.