Put text in background of JavaFX node - javafx

This stackoverflow answer explains how to put a background image inside a TextField. However, I would like to know how to put arbitrary text as background, and do it without CSS, if possible. My first idea was to take a snapshot of Text node and use it as a background image, as follows (I am doing this inside a constructor of a class extending TextField):
Text text = new Text("TEST");
text.setFill(Color.RED);
WritableImage image = text.snapshot(new SnapshotParameters(), null);
this.setBackground(new Background(
new BackgroundImage(
image,
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
new BackgroundPosition(Side.LEFT, 3D, false, Side.TOP, 50, true),
new BackgroundSize(image.getWidth(), image.getHeight(), false, false, false, false))));
However, it doesn't work. Background gets completely grayed out, and even the border disappears. Any idea how to do this? CSS solution is also acceptable.

I figured it out. Sometimes it helps to just put the question here, it gets you thinking. :-)
There were three problems. First, I had to use existing background as a base for new background. Second, I used vertical position incorrectly, I thought if you set it to 50% it will center it vertically, but apparently not. And finally, you can't do this in constructor because background doesn't exist yet, so I had to wrap it inside Platform.runLater(). Here is the revised code.
Platform.runLater(new Runnable() {
#Override
public void run() {
Text text = new Text("TEST");
text.setFill(Color.RED);
WritableImage image = text.snapshot(new SnapshotParameters(), null);
double imageVPos = (getHeight() - image.getHeight()) / 2;
BackgroundImage backImage = new BackgroundImage(
image,
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
new BackgroundPosition(Side.LEFT, 7D, false, Side.TOP, imageVPos, false),
new BackgroundSize(image.getWidth(), image.getHeight(), false, false, false, false));
List<BackgroundImage> images = new ArrayList<BackgroundImage>();
images.add(backImage);
setBackground(new Background(getBackground().getFills(), images));
}
});

Related

How to set image to a scene background in JavaFX?

The title says it all, I guess.
How to set a .jpg (or any other supported image format) image to a Scene background?
I somewhat achieved this by using a HBox, an Image and an ImageView, like this:
String url = ...
HBox box= new HBox();
Image x = new Image(url);
ImageView iv = new ImageView(x);
box.getChildren().add(iv);
box.setVisible(true);
Then I add that box to the Scene first, and everything else afterwards.
I'm not complaining about that piece of code - it works for my purposes - but is there a proper way to set a background?
An ImagePattern can be used as fill of the Scene:
ImagePattern pattern = new ImagePattern(myImage);
scene.setFill(pattern);
Just call setBackground on the root node of the scene. For example:
Pane root = ... ; // probably some pane subclass...
String url = ... ;
Image img = new Image(url);
BackgroundImage bgImg = new BackgroundImage(img,
BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT,
BackgroundPosition.DEFAULT,
new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, false, false, true, false));
// put stuff in root as normal....
Scene scene = new Scene(root);
See the Javadocs for the parameters for the BackgroundImage constructor, etc.

Binding ColorPicker in JavaFX to Label Background property

Works well for foreground by simply:
ObjectProperty op = label.textFillProperty();
ColorPicker cp = new ColorPicker(Color.GRAY);
...
op.bind(cp.valueProperty());
How do I do it for Background - not even sure it is possible, due to the complexity of Background property
First, don't use raw types. The code you posted should be
ObjectProperty<Paint> op = label.textFillProperty();
ColorPicker cp = new ColorPicker(Color.GRAY);
...
op.bind(cp.valueProperty());
For the background you can use Bindings.createObjectBinding():
ObjectProperty<Background> background = label.backgroundProperty();
background.bind(Bindings.createObjectBinding(() -> {
BackgroundFill fill = new BackgroundFill(cp.getValue(), CornerRadii.EMPTY, Insets.EMPTY);
return new Background(fill);
}, cp.valueProperty());

How do I scroll an Editor that has been obscured by the keyboard into view?

I'm designing a UI in Xamarin.Forms to collect feedback from users about our application. There is an Editor control at the bottom of this page. On an iPhone 4S, and in many landscape orientations, the keyboard completely obscures this editor control. On Android, this is not a big deal because the OS automatically scrolls (though the sizing behavior is a little weird.) On iOS, the only things resembling solutions are very wonky.
In native iOS, the solution is simple: wrap your views in a UIScrollView, then when the keyboard appears add that much space to the content size and scroll appropriately. Xamarin doesn't expose anything to control the scroll position in ScrollView, and ContentSize is private, so that's out. A few posts (here and here) seem to indicate ScrollView is at least part of the solution. It does appear Xamarin has some automatic scrolling behavior, but it's... curious.
My layout is fairly simple:
At the top, a fixed navigation bar that I do not want to scroll out of view.
Beneath that, a 180px tall image that represents a screenshot of the application.
Beneath that, a label with information such as the timestamp. (2-3 lines of text).
Beneath that, the editor, filling the remaining available space.
I've included code for a layout I've tried at the bottom of my post. I created a StackLayout that contains the image, the label, and the editor. I put that inside a ScrollView. Then, I create a RelativeLayout and place the navigation bar at the top-left with the ScrollView beneath it.
What I want to happen when the Editor is tapped is for the keyboard to be displayed and, if it obscures the Editor, for the layout to be nudged upwards to make the Editor visible. What happens instead is it seems like Xamarin scrolls the layout upwards by the keyboard height plus some margin that looks suspiciously like the keyboard utility bar height. This shoves the Editor upwards so high it's obscured by the navigation bar.
I've tried a lot of different tweaks and I'm at a loss. I can't control enough of the ScrollView to get the behavior I need. I've seen suggestions that use a BoxView resized when the Editor gains focus, but to make it work really well I'd still have to hook into the iOS notifications to get the appropriate size and have a fairly intimate knowledge of where my Editor's bounds are. It feels wrong.
Does anyone else have a solution to this on Xamarin.Forms? Even if I have to dip into native, I'd like an answer.
(Here's an example layout that demonstrates the problem, there's a little bit of weird structure because I was debugging. The funky colors are also a relic of layout debugging.)
using System;
using Xamarin.Forms;
namespace TestScroll
{
public class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private ScrollView _scroller;
protected void InitializeComponent() {
var mainLayout = new RelativeLayout();
var navbar = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.White,
Text = "I am the Nav Bar",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand
};
var subLayout = new ScrollView() {
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scroller = subLayout;
var subStack = new StackLayout();
subStack.Spacing = 0;
subLayout.Content = subStack;
var image = new BoxView() {
Color = Color.Green,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Fill,
HeightRequest = 300
};
subStack.Children.Add(image);
var infoLabel = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.Black,
Text = "Timestamp!\r\nOther stuff!",
VerticalOptions = LayoutOptions.Start
};
subStack.Children.Add(infoLabel);
var editor = new Editor() {
VerticalOptions = LayoutOptions.FillAndExpand
};
subStack.Children.Add(editor);
mainLayout.Children.Add(navbar,
Constraint.Constant(0),
Constraint.Constant(20),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.Constant(70));
mainLayout.Children.Add(subLayout,
Constraint.Constant(0),
Constraint.RelativeToView(navbar, (parent, view) => navbar.Bounds.Bottom),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.RelativeToView(navbar, TestConstraint));
Content = mainLayout;
}
private double TestConstraint(RelativeLayout parent, View view) {
double result = parent.Height - view.Bounds.Height;
Console.WriteLine ("Lower stack height : {0}", result);
Console.WriteLine ("Scroll content size: {0}", _scroller.ContentSize);
return result;
}
}
}
One thing I notice is that you are adding a ScrollView (subLayout) to another ScrollView (_scroller).
Also, I ran into this same problem on iOS except all of my controls were within a Grid. Simply putting the Grid into a single ScrollView fixed the problem, without having to change content sizes or anything like that.
This question sat for a long time unanswered, here's what I did. I don't know that it's the 'answer', and I do appreciate hvaughan3's answer that's currently here and I will try it if I ever get the time.
My page behaved like I wanted on Android, so I didn't do anything specific for that.
So I wrote specific code for iOS that used the notifications UIKeyboardWillShow and UIKeyboardWillHide. These notifications provide information about the bounds the keyboard will take up. So when I get a 'show' notification, I manipulate my layout to allow room for an element of that size I place underneath the keyboard. When I get a 'hide' notification, I reset the layout.
It's janky and a little embarrassing, I hope to come back with news I tried another solution like hvaughan3's and it worked.

Set StackPane background image

I want to set background image autoresized with StackPane.
I tried this:
StackPane stackPane = new StackPane();
Image im = new Image(Dashboardpanel.class.getResource("/images/11.jpg").toExternalForm());
stackPane.setBackground(new Background(new BackgroundImage(im, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, BackgroundSize.DEFAULT)));
But the image is not auto-resized when I resize the StackPane. The image is repeated to fill the gap. How I can resize the image just as the Stackpane no matter how I extend the StackPane?
Don't use the default BackgroundSize, create a new BackgroundSize and use the contain and cover arguments of the BackgroundSize constructor.
For example (and I just wrote this by reading the javadoc, I didn't test it):
new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, false, false, false, true);
I advise using a CSS stylesheet for this kind of styling rather than coding the style in Java.

Silverlight 3 Button - Text + Image Alignment Problems

I'm trying to have a button contain both an image text. Ideally have the text left aligned, while the image is as far right as possible.
So i create a Grid, and add an Image and Textblock to it and set its alignment. For the life of me i cant get alignment to act as expected.
var gridPanel = new Grid();
gridPanel.ColumnDefinitions.Add(new ColumnDefinition());
var text = new TextBlock { Text = header, TextAlignment = TextAlignment.Left };
text.HorizontalAlignment = HorizontalAlignment.Left;
text.Margin = new Thickness(0);
text.SetValue(Grid.RowProperty, 0);
text.SetValue(Grid.ColumnProperty, 0);
var image = new Image();
image.Source = new BitmapImage(new Uri("../Images/Common/RedFlag.png", UriKind.Relative));
image.HorizontalAlignment = HorizontalAlignment.Right;
image.Height = 25;
image.Width = 25;
image.SetValue(Grid.RowProperty, 0);
image.SetValue(Grid.ColumnProperty, 1);
gridPanel.Children.Add(text);
gridPanel.Children.Add(image);
button.Content = gridPanel;
Both the Image and Text are center aligned for some reason...Is Grid the wrong way to go? I tried StackPanel and setting its orientation to Horizontal but it was the same thing..
by default the HorizontalContentAlignment of a button is set at "Center"... Just set it to "Stretch" like that :
button.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Stretch;
Change the HorizontalContentAlignment from Centre to Stretch, like-
<Button Name="button" HorizontalContentAlignment="Stretch"/>
Edit-
I was originally doing this in the button style as I didn't know about the HorizontalContentAlignment property

Resources