JavaFX detect if shape has been assigned to a Region/Parent/Node - javafx

as the title inquires is it possible?
eg. suppose i have a custom class that extends Shape
private class CR extends Rectangle{
public CR(){}
}
CR cr = new CR(); //normal rectangle
Pane pane = new Pane();// my node who extends region
pane.setPrefSize(100.0,100.0);
pane.setShape(cr); // here is what i am interested in
i want to know when cr has been set to a Node, is there any bindings, or any way i can be notified?
to summarise i have two questions
is there a way to detect either with bindings or some logic when your custom Shape class is being set to a Region. ?
can i get a reference to the Node/Region/Parent ?
Edit:
i am not suppose/ i do not have - access to the pane or Node that is going to set its shape as the custom shape -(implementing my Shape), something like my class is a library/wrapper.
also my custom Shape is not extending Rectangle but just for sample sake but i am extending Path with extends Shape to draw a complex Shape
if its possible i will put a bounty of 300 as gift

I'm not entirely clear what you're asking, but does:
cr.parentProperty().addListener((obs, oldParent, newParent) -> {
System.out.println("Parent changed from "+oldParent+" to "+newParent);
if (newParent != null) {
// do whatever you need here...
}
});
do what you need?

boolean check = pane.contains(cr .getX(),cr .getY());

Related

javafx - easiest way of changing the caret color

I would like to set the caret color for all JavaFX text inputs (e.g. TextField, TextArea, the ones in ComboBox:editable, DatePicker, etc...)
I found this Stackoverflow answer: How to change the caret color in JavaFX 2.0?
... and an example on GitHub.
The first one does change the text and the caret color which is not good. The second one extends the TextFieldSkin class, which is already better, but how can I use it in CSS?
Any help is appreciated.
UPDATE 1:
I found the following CSS style property for JavaFX controls: -fx-skin.
This would theoretically allow me to set a custom skin class (-fx-skin: "package.MySkin";), however, the skin class just isn't used!
The class looks like the following:
package gui;
…
public class MyTextFieldSkin extends TextFieldSkin
{
public MyTextFieldSkin(TextField tf) {
super(tf);
System.out.println("MyTextFieldSkin constructor called!");
ReadOnlyObjectWrapper<Color> farbe = new ReadOnlyObjectWrapper<>(Color.green);
caretPath.strokeProperty().bind(farbe);
caretPath.setStrokeWidth(1.5);
}
}
… and is set in CSS like that:
.text-field {
-fx-skin: "gui.MyTextFieldSkin";
}
What am I doing wrong? I looked at the source code of AquaFX, and they are doing it the same way as me!
After a bit of try & error, I solved the problem in the following way:
I gathered all TextFields and controls that have TextFields in them (like ComboBox, DatePicker and so on) inside a container recursively (in deference of TitledPane, ScrollPane, SplitPane and TabPane, because they don't publish their children in getChildren(), so one has to call the getContent() method of the individual classes and scan through it).
After I had all the TextField controls, I looped over them and changed their Skin with the following code:
public class MyTextFieldSkin extends TextFieldSkin {
public MyTextFieldSkin(TextField tf)
{
super(tf);
ReadOnlyObjectWrapper<Color> color = new ReadOnlyObjectWrapper<>(Color.RED);
caretPath.strokeProperty().bind(color);
}
}
Then I just had to call
textfield.setSkin(new MyTextFieldSkin(textfield));
and that was about it.
Cheers

How to center/wrap/truncate Text to fit within Rectangle in JavaFX 2.1?

I need to dynamically create Rectangles over Pane in JavaFX 2.1. Next I need to center/wrap/truncate Text over the Rectangle. The text has to fit within the rectangle. I am able to center and wrap the text with the following code, however, if the text length is too long, it will appear out of the rectangle. I want to create the behavior like Label within StackPane, essentially if the Rectangle grows, the Text will grow with it but always remain in the center of the Rectangle and if the Text cannot fit within the Rectangle, it will be truncated accordingly.
Rectangle r;
Text t;
...
//center and wrap text within rectangle
t.wrappingWidthProperty().bind(rect.widthProperty().multiply(0.9);
t.xProperty().bind(rect.xProperty().add(rect.widthProperty().subtract(t.boundsInLocalProperty().getValue().getWidth().divide(2)));
t.yProperty().bind(rect.yProperty().add(rect.heightProperty().divide(2)));
t.setTextAlignment(TextAlignment.CENTER);
t.setTextOrigin(VPos.CENTER);
What properties can I use to achieve that or is there a better way of doing this?
Here is a sample alternate implementation.
It uses a subclass of Group with a layoutChildren implementation rather than the binding api.
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.geometry.VPos;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.*;
import javafx.stage.Stage;
public class TextInRectangle extends Application {
public static void main(String[] args) throws Exception { launch(args); }
public void start(final Stage stage) throws Exception {
TextBox text = new TextBox("All roads lead to Rome", 100, 100);
text.setLayoutX(30);
text.setLayoutY(20);
final Scene scene = new Scene(text, 160, 140, Color.CORNSILK);
stage.setScene(scene);
stage.show();
}
class TextBox extends Group {
private Text text;
private Rectangle rectangle;
private Rectangle clip;
public StringProperty textProperty() { return text.textProperty(); }
TextBox(String string, double width, double height) {
this.text = new Text(string);
text.setTextAlignment(TextAlignment.CENTER);
text.setFill(Color.FORESTGREEN);
text.setTextOrigin(VPos.CENTER);
text.setFont(Font.font("Comic Sans MS", 25));
text.setFontSmoothingType(FontSmoothingType.LCD);
this.rectangle = new Rectangle(width, height);
rectangle.setFill(Color.BLACK);
this.clip = new Rectangle(width, height);
text.setClip(clip);
this.getChildren().addAll(rectangle, text);
}
#Override protected void layoutChildren() {
final double w = rectangle.getWidth();
final double h = rectangle.getHeight();
clip.setWidth(w);
clip.setHeight(h);
clip.setLayoutX(0);
clip.setLayoutY(-h/2);
text.setWrappingWidth(w * 0.9);
text.setLayoutX(w / 2 - text.getLayoutBounds().getWidth() / 2);
text.setLayoutY(h / 2);
}
}
}
Sample output of the sample app:
A couple of notes:
It is usually best to use a Label rather than trying to recreate part of a Label's functionality.
The layout in layoutChildren approach is a similar to that used by the JavaFX team in implementing the JavaFX control library. There are probably reasons they use layoutChildren rather than binding for layout, but I am not aware of what all of those reasons are.
I find for simple layouts, using the pre-built controls and layout managers from the JavaFX library is best (for instance the above control could have been implemented using just a Label or Text in StackPane). Where I can't quite get the layout I need from the built-in layouts, then I will supplement their usage with bindings, which I find also very easy to work with. I don't run into the need to use layoutChildren that much. It's probably just a question of scaling up to lay out complex node groups - most likely doing the calculations in the layoutChildren method performs better and may be easier to work with and debug when applied to complex node groups.
Rather than truncating Text by calculating a text size and eliding extra characters from a String as a Label does, the code instead calls setClip on the text node to visually clip it to the rectangle's size. If instead you would like to truncate Text more like a Label, then you could look at the code for the JavaFX utility class which does the computation of clipped text.
The sample code in the question does not compile because it is missing a bracket on the wrappingWidthProperty expression and it uses getValue and getWidth methods inside a bind expression, which is not possible - instead it needs to use a listener on the boundsInLocalProperty.
Also, created a small sample app demoing adding text placed in a Label with a rectangular background to a Pane with precise control over the x,y position of the labeled rectangle via binding.

Trying to draw a Rectangle to a Custom Container in Flex4/AS3

So below is the code I have so far. For now I simply want to make it draw a square and have it show up. Right now when I click the area defined in MXML as <components:PaintArea width="100%" height="100%" id="paint-a"></PaintArea> it shows nothing; however, the actionlistener is getting triggered and an element is being added to the group. Not sure exactly what is going on... perhaps for some reason it doesn't think the element is drawable? Anyways thanks for the help!
public class PaintArea extends SkinnableContainer
{
private var canvas:Group;
public function PaintArea()
{
super();
canvas = new Group();
canvas.clipAndEnableScrolling = true;
canvas.percentHeight = 100;
canvas.percentWidth = 100;
canvas.addEventListener(MouseEvent.MOUSE_UP,drawRectangle);
this.addElement(canvas);
}
private function drawRectangle(e:MouseEvent):void{
var r:Rect = new Rect();
r.fill = new SolidColor(0x00ff00,.5);
canvas.addElement(r);
}
}
You should probably set the width and height of the rectangle r.
You could also use a BorderContainer (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/spark/components/BorderContainer.html) - its a SkinnableContainer with a styleable border and fill

Flex: Label.addChild() not working?

I want to make a label that has a tiny title above it, for example so the label say $1,000 with a small retail price or our price above it. I am trying to add the title label to the display list of the main label. I get no error but the title does not show up. I also considered rawChildren but apparently Label has no rawChildren property.
Here is my code:
package
{
import mx.controls.Label;
public class PriceLabel extends StrikeThroughLabel //<-- exntension of label to add strike
{
private var _title:Label;
public function PriceLabel()
{
super();
}
[Bindable]
public function set title(s:String):void
{
if(_title == null)
{
_title = new Label();
addChild(_title);
this.alpha = .2;
}
_title.text = s;
}
public function get title():String
{
var s:String
if(_title != null)
{
s = _title.text;
}
return s;
}
}
}
If you add children to a Flex component that is not a container, then you have to manually manage sizing and positioning of those children. Containers do a lot of that work for you.
Here's what you should do:
Move the creation of your child Label into an override of the createChildren() function.
Set the text property of the child label in an override of the commitProperties() function. Your title getter and setter should save the value in a _title variable to be used later for the assignment in commitProperties(). This is actually important for performance.
Override the measure() function and update measuredWidth and measuredHeight to be the maximum width and height values of the main label and it's child.
Override updateDisplayList() and use setActualSize() on the child Label to set it to the required width and height.
That may seem like a lot of work, but in terms of best practices, that's the way you're supposed to build custom components. The Flex Team at Adobe spent a lot of time maximizing performance, and that's why things happen in several steps like that.
That's how to do it based on what you asked. Personally, I would make a subclass of UIComponent with two Labels or UITextFields as children, each with their own separate property.
By the way, the rawChildren property is only available on containers. It exists so that you can add "chrome" to a container that isn't part of the container's child layout algorithm. For example, Panel has a title bar and a border that aren't affected by the vertical/horizontal/absolute layout options.
Why not create a custom component that contains both labels as its children, instead of trying to throw a child on the Label? That feels cleaner to me, as adding children to build-in components like that doesn't seem right.

How can I change the size of icons in the Tree control in Flex?

I embed SVG graphics in my Flex application using
package MyUI
{
public class Assets
{
[Embed(source="/assets/pic.svg"]
[Bindable]
public static var svgPic:Class;
}
}
and then extending the Tree class with some of my own code, setting the icon upon adding a node to the data provider:
public class MyTree extends Tree
{
public function MyTree()
{
// ...
this.iconField = "svgIcon";
// ...
this.dataProvider = new ArrayCollection;
this.dataProvider.addItem({ /* ... */ svgIcon: MyUI.Assets.svgPic /* ... */ });
// ...
}
}
Now I have two things I want to do:
use the SVG graphics in multiple places in the app, scaling them to the appropriate size for each appearance, i. e. scale them to a proper icon size when using them in the tree
change the size of the icon at runtime, e. g. display a slightly larger icon for selected items or let an icon "pulse" as a response to some event
I read the Flex documentation on the 9-slice scaling properties in the Embed tag, but I think that's not what I want.
Edit:
I unsuccessfully checked the "similar questions" suggested by SO, among others this one:
Flex: Modify an embedded icon and use it in a button?
Subclass mx.controls.treeClasses.TreeItemRenderer and make it resize the icon to your desired dimensions, or create your own item renderer implementation by using the same interfaces as TreeItemRenderer. Set a custom item renderer with the itemRenderer property:
exampleTree.itemRenderer = new ClassFactory( ExampleCustomItemRendererClass );
The answer to this question might point you in the right direction, without knowing more about the trouble you're having:
Flex: Modify an embedded icon and use it in a button?
Hope it helps!

Resources