I have this code which inserts Image into the center of a borderpane:
private static final ImageView iv;
static {
iv = new ImageView(StartPanel.class.getResource("/com/dx57dc/images/6.jpg").toExternalForm());
}
bpi.setCenter(iv);
And now I have this problem. I have this insert text as a label at the center of the image.
Text inftx = new Text("Infrastructure");
How I can do this?
You can use a StackPane to performed the desired image overlap. The following code can be used on your example:
private static final ImageView iv;
static {
iv = new ImageView(StartPanel.class.getResource("/com/dx57dc/images/6.jpg").toExternalForm());
Text inftx = new Text("Infrastructure");
StackPane pane = new StackPane();
pane.getChildren().add(iv);
pane.getChildren().add(inftx);
pane.setAlignment(Pos.CENTER);
}
As informed on StackPane tutorial:
The StackPane layout pane places all of the nodes within a single stack with each new node added on top of the previous node. This layout model provides an easy way to overlay text on a shape or image or to overlap common shapes to create a complex shape.
Related
Trying to create a linear layout programmatically and setting its width and height by layout params. But it seems layout params isn't working.
this is the code:
// CREATING A NEW LINEAR LAYOUT PROGRAMMATICALLY
LinearLayout linearLayout = new LinearLayout(getActivity());
ViewGroup.LayoutParams layoutParams = new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
linearLayout.setLayoutParams(layoutParams);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
// CREATING CHILDDRENS (TEXT VIEWS)
TextView name = new TextView(getContext(), null, 0, R.style.item_layout_style);
name.setText("Pine");
TextView qty = new TextView(getContext(), null, 0, R.style.item_layout_style);
qty.setText("10");
TextView cost = new TextView(getContext(), null, 0, R.style.item_layout_style);
cost.setText("785");
TextView tCost = new TextView(getContext(), null, 0, R.style.item_layout_style);
tCost.setText("1000");
// SET TEXT VIEW TO LINEAR LAYOUT
linearLayout.addView(name);
linearLayout.addView(qty);
linearLayout.addView(cost);
linearLayout.addView(tCost);
// SET LINEAR LAYOUT TO PINE LAYOUT
LinearLayout daddy= (LinearLayout) view.findViewById(R.id.layout);
daddy.addView(linearLayout, 2);
// Return the view
return view;
I have root layout (daddy) which has many linear layouts (vertically oriented), but I need to create a linear layout programmatically and add that to "daddy". But the text views are sticked together, they aren't getting the entire space horizontally.
Do help me!
Everything is fine with the code. It is the style that I tried to give to text views, they weren't getting layout weight, width and height. How did I find this out? Well I set the linear layout's background-color to black to see if it's really not getting width and height set by LayoutParams. And I wasn't wrong! Width was set to match parent. So what I did was create a new layout param for text views and set it to them.
My ImageView is matching screen size on x-axis and is using remaining space on y-axis in my layout. I want to create bitmap into this ImageView with exactly the same size as the ImageView is. How to make it please? Can it be done by some automatic setting, should I call some measure function?
I tried SetAdjustViewBounds() but it didn't work for me.
Creating Bitmap big enough (I don't like much such a memory wasting) and setting SetScaleType(ImageView.ScaleType.Matrix) works, but still when I'm making drawing operations on canvas, I don't know real size of area I should paint into, both canvas and bitmap height are equal to yScreen while imgWeekView height is pretending to be 0, even though it paints whole desired area with gray color.
imgWeekView = new ImageView(context);
//imgWeekView.SetAdjustViewBounds(true);
imgWeekView.SetScaleType(ImageView.ScaleType.Matrix);
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent,1f);
layoutParams.Height = 0;
imgWeekView.LayoutParameters = layoutParams;
Bitmap bitmap = Bitmap.CreateBitmap((int)xScreen, (int)yScreen, Bitmap.Config.Argb8888);
cnvWeekView = new Canvas(bitmap);
imgWeekView.SetImageBitmap(bitmap);
linearLayout.AddView(imgWeekView); //whole activity layout
//Test
cnvWeekView.DrawColor(new Color(128, 128, 128));
Paint paint = new Paint(PaintFlags.AntiAlias);
paint.Color = new Color(255, 255,0);
cnvWeekView.DrawCircle(50, 50, 40, paint);
Finally I found a way how to measure my ImageView and here I will post my answer.
I believed that there should be much easier solution, but maybe there isn't. From this question I took most of the important data:
How to get the width and height of an android.widget.ImageView?
Things look however a little different in my android application and I'm not experienced enough to tell why. I had to change things a little. I had to learn a bit about interfaces and this question helped too.
Implementing the View.IOnTouchListener interface
Here is how I combined things. First I created class that will do the measure.
public class MyPredrawListener : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener
{
ImageView imageView;
public MyPredrawListener(ImageView img)
{
imageView = img;
}
public bool OnPreDraw()
{
imageView.ViewTreeObserver.RemoveOnPreDrawListener(this);
int finalHeight = imageView.MeasuredHeight;
int finalWidth = imageView.MeasuredWidth;
Bitmap bitmap = Bitmap.CreateBitmap(finalWidth, finalHeight, Bitmap.Config.Argb8888);
imageView.SetImageBitmap(bitmap);
//Test to see result
Canvas cnv = new Canvas(bitmap);
Paint paint = new Paint();
paint.Color = new Color(255, 255, 0);
cnv.DrawColor(new Color(128, 128, 128));
cnv.DrawCircle(finalWidth-50, finalHeight-50, 50, paint);
return true;
}
}
And in code where I create my imageView I set the listener like this.
imgWeekView = new ImageView(context);
MyPredrawListener listener=new MyPredrawListener(imgWeekView);
imgWeekView.ViewTreeObserver.AddOnPreDrawListener(listener);
In OnPreDraw function I put test code to see the result graphically, clearing bitmap to gray color and painting yellow circle to bottom right of a view.
Is there any way to make fullscreen(and if possible resizing too) to instead of rearranging everything (actually what it does is to rearrange the elements like resizing but to the whole screen) to make an actual fullscreen mode? (like games that what usually do is change screen resolution), so that buttons and text grows accordingly to the size of the screen/window
Also how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?
EDIT: use this way to make resizeable
#Override public void start(Stage stage) throws Exception{
final int initWidth = 720; //initial width
final int initHeight = 1080; //initial height
final Pane root = new Pane(); //necessary evil
Pane controller = new CtrlMainMenu(); //initial view
controller.setPrefWidth(initWidth); //if not initialized
controller.setPrefHeight(initHeight); //if not initialized
root.getChildren().add(controller); //necessary evil
Scale scale = new Scale(1, 1, 0, 0);
scale.xProperty().bind(root.widthProperty().divide(initWidth)); //must match with the one in the controller
scale.yProperty().bind(root.heightProperty().divide(initHeight)); //must match with the one in the controller
root.getTransforms().add(scale);
final Scene scene = new Scene(root, initWidth, initHeight);
stage.setScene(scene);
stage.setResizable(true);
stage.show();
//add listener for the use of scene.setRoot()
scene.rootProperty().addListener(new ChangeListener<Parent>(){
#Override public void changed(ObservableValue<? extends Parent> arg0, Parent oldValue, Parent newValue){
scene.rootProperty().removeListener(this);
scene.setRoot(root);
((Region)newValue).setPrefWidth(initWidth); //make sure is a Region!
((Region)newValue).setPrefHeight(initHeight); //make sure is a Region!
root.getChildren().clear();
root.getChildren().add(newValue);
scene.rootProperty().addListener(this);
}
});
}
There are a couple of ways to resize your UI.
Scale by Font Size
You can scale all controls by setting -fx-font-size in the .root of your scene's style sheet.
For example, if you apply the following stylesheet to your scene, then all controls will be doubled in size (because the default font size is 13px).
.root {
-fx-font-size: 26px;
}
The above will work to scale controls, which is fine for things which are completely control based, but not so good for things which are graphic and shape based.
Scale by Transform
Apply a Scale transform pivoted at (0,0) to your scene's root node.
Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
scene.getRoot().getTransforms().setAll(scale);
To scale a game I developed which includes graphics and various shapes, I used a letter boxing technique which sized the game window to a constant aspect ratio, (similar to the letter boxing you see when you watch a 4:3 tv show on a 16:9 screen).
The SceneSizeChangeListener in the code below listens for changes to the scene size and scales the content of the scene appropriate to the available scene size.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
import org.jewelsea.games.supersnake.layout.LayoutController;
import java.io.IOException;
import java.util.ResourceBundle;
/* Main JavaFX application class */
public class SuperSnake extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(final Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("layout/layout.fxml"),
ResourceBundle.getBundle("org.jewelsea.games.supersnake.layout.text")
);
Pane root = (Pane) loader.load();
GameManager.instance().setLayoutController(loader.<LayoutController>getController());
Scene scene = new Scene(new Group(root));
stage.setScene(scene);
stage.show();
GameManager.instance().showMenu();
letterbox(scene, root);
stage.setFullScreen(true);
}
private void letterbox(final Scene scene, final Pane contentPane) {
final double initWidth = scene.getWidth();
final double initHeight = scene.getHeight();
final double ratio = initWidth / initHeight;
SceneSizeChangeListener sizeListener = new SceneSizeChangeListener(scene, ratio, initHeight, initWidth, contentPane);
scene.widthProperty().addListener(sizeListener);
scene.heightProperty().addListener(sizeListener);
}
private static class SceneSizeChangeListener implements ChangeListener<Number> {
private final Scene scene;
private final double ratio;
private final double initHeight;
private final double initWidth;
private final Pane contentPane;
public SceneSizeChangeListener(Scene scene, double ratio, double initHeight, double initWidth, Pane contentPane) {
this.scene = scene;
this.ratio = ratio;
this.initHeight = initHeight;
this.initWidth = initWidth;
this.contentPane = contentPane;
}
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
final double newWidth = scene.getWidth();
final double newHeight = scene.getHeight();
double scaleFactor =
newWidth / newHeight > ratio
? newHeight / initHeight
: newWidth / initWidth;
if (scaleFactor >= 1) {
Scale scale = new Scale(scaleFactor, scaleFactor);
scale.setPivotX(0);
scale.setPivotY(0);
scene.getRoot().getTransforms().setAll(scale);
contentPane.setPrefWidth (newWidth / scaleFactor);
contentPane.setPrefHeight(newHeight / scaleFactor);
} else {
contentPane.setPrefWidth (Math.max(initWidth, newWidth));
contentPane.setPrefHeight(Math.max(initHeight, newHeight));
}
}
}
}
Here is a screenshot where you can see the letterboxing and scaling taking effect. The green grass in the middle is the main game content screen and scales up and down to fit the available screen area. The wood texture around the outside provides a flexibly sized border which fills in the area where the black letterbox bars would normally be if you were watching a tv program at a different aspect ratio to your screen. Note that the background in the screenshot below is blurry at the title page because I make it so, when the game starts, the blur effect is removed and the view is crisp regardless of the size.
Windowed version:
Scaled full screen version:
You might think that the scaling method above might make everything go all blocky and pixelated, but it doesn't. All font's and controls scale smoothly. All standard drawing and graphic commands and css based styles scale smoothly as they are all vector based. Even bitmapped images scale well because JavaFX uses fairly high quality filters when scaling the images.
One trick to get good scaling on images is to provide high resolution images, so that when the screen scales up, the JavaFX system has more raw data to work from. For example, if the preferred window size for an app is quarter of the screen size and it contains a 64x64 icon, instead use a 128x128 icon, so that when the app is put in full screen and all elements scaled, the scaler has more raw pixel data samples to use for interpolating values.
The scaling is also fast as it is hardware accelerated.
how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?
It's not possible to remove the full screen exit message in JavaFX 2.2, it will be possible in JavaFX 8:
RT-15314 Allow trusted apps to disable the fullscreen overlay warning and disable the "Exit on ESC" behavior
It will be nice when that is done, because then my games won't have that "look at me - I look like a beta" feel about them.
"Also how can I remove the message and the effect on click the "esc" key to exit the fullscreen mode?"
Use this code :
stage.setFullScreenExitHint("");
It will change the string message "Press Esc to quit Fullscreen mode" into empty string so it will not show up.
You may copy this into JavaFXApplication
Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
double width = resolution.getWidth();
double height = resolution.getHeight();
double w = width/1280; // your window width
double h = height/720; // your window height
Scale scale = new Scale(w, h, 0, 0);
root.getTransforms().add(scale);
First of all, I'm a long time Java/Swing developer. I recently installed JavaFX 2.2 to play around with.
I'm creating a fairly simple app, whose main window has a toolbar on top and content in the rest of the window. The obvious way to accomplish this is to use a BorderPane, and stick a ToolBar into the top section. So far, so good. However, I would like some of the controls in the toolbar to be at the left edge of the window, and some at the right edge. I can find no way to do this. I can put an invisible spacer object into the toolbar, but I only know how to give it a fixed width; it doesn't resize when the window is resized.
So I thought that instead of using a ToolBar object, I'll just use an HBox; it should be equivalent to a horizontally-oriented Swing Box object, right? And the Swing Box class has a createHorizontalGlue() method that inserts an auto-sizing spacer. Well, I can't find an equivalent in the JavaFX HBox class. Is there no simple way to do this?
I figured out how to do it using an HBox instead of a ToolBar to hold the controls; the key is the HBox.setHgrow() method, which allows you to set a spacer object to grow to fill the available space. I still don't know if it's possible to do this with an actual ToolBar instance.
/**
* Creates and populates the Node that serves as the window toolbar.
*
* #return a newly constructed and populated toolbar component
*/
private Node makeToolbar() {
// Auto-sizing spacer
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
// Horizontal box containing toolbar controls
HBox box = new HBox();
box.setPadding(new Insets(8));
box.setAlignment(Pos.CENTER);
box.getChildren().addAll(openButton, spacer, resizeSlider);
// Colored background panel with drop shadow
Pane bgRect = new Pane();
bgRect.setStyle("-fx-background-color: #e0e0e0;");
bgRect.setEffect(DropShadowBuilder.create().width(1).build());
// StackPane to hold box and rectangle
StackPane stack = new StackPane();
stack.getChildren().addAll(bgRect, box);
return stack;
}
i do it this way:
private Node makeFooter(Node left, Node right) {
ToolBar footer = new ToolBar();
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
spacer.setMinWidth(Region.USE_PREF_SIZE);
footer.getItems().addAll(left, spacer, right);
return footer;
}
hope i could help someone
I have been trying to set the scene's width and height outside of the constructor and it's been to no avail. After looking through the Scene API I saw a method that lets you get the height and width respectively but not one to set the method.. :s (design flaw maybe).
After further research I came across the SceneBuilder and found methods that could modify the height and width. However, I do not know how to apply it to a scene object already created or how to create a SceneBuilder object that could be used in place of the scene object.
Once you created Scene and assigned it to the Stage you can use Stage.setWidth and Stage.setHeight to change both stage and scene sizes simultaneously.
SceneBuilder can't be applied to an already created object, it can only be used for the scene creation.
It seems not possible to set the size of the Scene after it has been created.
Setting the size of the Stage means to set the size of the window, which includes the size of the decoration. So the Scene is smaller in size, unless the Stage is undecorated.
My solution is to compute the size of the decoration while initialization and add it to the size of the Stage when resizing:
private Stage stage;
private double decorationWidth;
private double decorationHeight;
public void start(Stage stage) throws Exception {
this.stage = stage;
final double initialSceneWidth = 720;
final double initialSceneHeight = 640;
final Parent root = createRoot();
final Scene scene = new Scene(root, initialSceneWidth, initialSceneHeight);
this.stage.setScene(scene);
this.stage.show();
this.decorationWidth = initialSceneWidth - scene.getWidth();
this.decorationHeight = initialSceneHeight - scene.getHeight();
}
public void resizeScene(double width, double height) {
this.stage.setWidth(width + this.decorationWidth);
this.stage.setHeight(height + this.decorationHeight);
}
I just wanted to post another answer for those who might have had a similar problem as mine.
http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Scene.html
There is no setWidth() or setHeight(), and the property is ReadOnly, but if you look at
Constructors
Scene(Parent root)
Creates a Scene for a specific root Node.
Scene(Parent root, double width, double height)
Creates a Scene for a specific root Node with a specific size.
Scene(Parent root, double width, double height, boolean depthBuffer)
Constructs a scene consisting of a root, with a dimension of width and height, and specifies whether a depth buffer is created for this scene.
Scene(Parent root, double width, double height, boolean depthBuffer, SceneAntialiasing antiAliasing)
Constructs a scene consisting of a root, with a dimension of width and height, specifies whether a depth buffer is created for this scene and specifies whether scene anti-aliasing is requested.
Scene(Parent root, double width, double height, Paint fill)
Creates a Scene for a specific root Node with a specific size and fill.
Scene(Parent root, Paint fill)
Creates a Scene for a specific root Node with a fill.
As you can see, this is where you can set the height and width if you need to.
For me, I am using SceneBuilder, just as you described you were doing, and needed the width and height of that. I am creating custom controls, so it was weird that it didn't do it automatically, so this is how to do it if you need to.
I could have used setWidth() / setHeight() from the Stage as well.
I had an similar challenge when I wanted to switch between different size scenes in JavaFX.
I did my scene switching by changing the Parent resource of a Scene. The new resource would have larger dimensions than the previous resource so the entire Scene wasn't visible.
Like user2229691's answer stated - my issue turned out to be the Window not matching the Scene's dimensions.
Although I'm not able to comment about decorations - I was able to solve my issue by using:
sceneName.getWindow().sizeToScene();
It works when downsizing and upsizing from my own testing.
Here's some example code so you can better understand what I did:
public void start(Stage stage) throws IOException {
// Height of 300, width of 300
Parent scene1 = FXMLLoader.load(getClass().getResource("scene1.fxml"));
// Height of 400, width of 400
Parent scene2 = FXMLLoader.load(getClass().getResource("scene2.fxml"));
// Starting off in the smaller scene
Scene mainScene = new Scene(scene1); // Scene & Window are 300x300
stage.setScene(mainScene);
stage.show();
// Switching to the larger scene resource, that doesn't fit in the window
mainScene.setRoot(scene2); // Scene is 400x400 but can only see 300x300
// Resizing the window so the larger scene fits
mainScene.getWindow().sizeToScene(); // Window is now 400x400 & everything is visible
}
I hope this helps someone.
Source:
https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Window.html#sizeToScene--