Skip to main content

centered text in a box

7 replies [Last post]
mbien
Offline
Joined: 2007-04-29

Hello,
I would like to render text inside a box. The box should resize to the bounds of the text and the text should be centered to the middle of the box.

Since almost all sample applications i found use absolute coordinates and sizes they circumvent most issues of real world aps. If it would be really that easy everyone would use images for gui;)

I tried to reimplement something small i did recently in java to see how javafx feels but i stuck here.

laying out the box using bind works fine but i can't figure out how to convince the text to stay in the middle without stackoverflowexceptions ;)

any hints appreciated (my first jfx app...)

here the code:

<br />
Stage {<br />
    width: 250<br />
    height: 250<br />
    scene: Scene {<br />
        content: [<br />
            Group{<br />
                var node:Group = Group {</p>
<p>                    var text:Text = Text {<br />
                        content: "test test..."<br />
                        textAlignment: TextAlignment.CENTER<br />
                        textOrigin: TextOrigin.TOP<br />
                        font: Font { size: 20 }<br />
                        fill: Color.WHITE<br />
        //need something like: x: bind (this.parent.width+this.width)/2<br />
                    }</p>
<p>                    var rect = Rectangle {<br />
                        width: bind text.boundsInLocal.width + 15<br />
                        height: bind text.boundsInLocal.height + 15<br />
                        fill: Color.BLACK<br />
                        strokeWidth: 2<br />
                        stroke: Color.BLUE<br />
                        arcWidth: 20 arcHeight: 30<br />
                        effect: DropShadow {<br />
                            radius: 10<br />
                        }<br />
                    }</p>
<p>                    content: [<br />
                        rect,<br />
                        text<br />
                    ]<br />
                }<br />
                content: node<br />
                effect: Reflection {fraction: 0.3 topOpacity: 0.2 topOffset: -10.0}</p>
<p>                var drag = DragBehavior { target: node }<br />
            }<br />
        ]</p>
<p>    }<br />
}<br />

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
stitzl
Offline
Joined: 2006-02-09

> here is how i solved it, it centers everything around
> a point and sizes the rect properly. You only have to
> think the other way around as in swing ;)

Actually, you didn't manage to center the text in the box. You just positioned the box. However, this "solution" fails when you need all boxes to have the same width.

I still have to find a way to center text wrt it's parent node.

bouye
Offline
Joined: 2008-06-17

I've discovered quite fast that it was a bad idea to try to bind the x and y attributes of a Text to its width and height to have it centered but that I could actually bind it's translateX attribute to achieve the same effect.

Here is a code I use to center a Text under an icon (a JLabel):

[code]
var label:Text = Text {
fill: bind fill;
font: bind font;
content: text
textAlignment: TextAlignment.CENTER;
translateX: bind (icon.boundsInLocal.width - label.boundsInLocal.width) / 2;
translateY: 12;
}
return Group {
content: [ VBox {
content: [icon, label]
}]
}
[/code]

However I miss calculating the translateY value as I do not know how to get the pixel height of a piece of text for a given font in JavaFX yet (and doing it in Java2D would require a Graphics and many type conversions).

Message was edited by: bouye

Message was edited by: bouye

mbien
Offline
Joined: 2007-04-29

hi bouye,

here is how i solved it, it centers everything around a point and sizes the rect properly. You only have to think the other way around as in swing ;)

[code]
Stage {
width: 500
height: 500
scene: Scene {
content: [
Group{
var node1 = MyNode{name:"Hello"}
var node2 = MyNode{name:"World"}
content: [node1, node2]
}
]

}
}
[/code]

[code]
public class MyNode extends CustomNode {

public var name:String;

public override function create(): Node {

// margin between text and border
var margin = 20;

var text:Text = Text {
content: name

textAlignment: TextAlignment.CENTER
textOrigin: TextOrigin.TOP

font: Font {
size: 20
}
fill: Color.WHITE
}

var rect = Rectangle {

width:bind text.boundsInLocal.width + margin
height:bind text.boundsInLocal.height + margin

x:bind text.x - margin/2
y:bind text.y - margin/2

fill: Color.BLACK

stroke: Color.BLUE
strokeWidth: 2

arcWidth: 20
arcHeight: 30

effect: DropShadow {
radius: 10
}
}

var node:Group = Group {
content: [
rect,
text
]
effect: Reflection {fraction: 0.3 topOpacity: 0.2 topOffset: -10.0}
}
return node
}

}
[/code]

bouye
Offline
Joined: 2008-06-17

Ah I see, textOrigin is the key to have the property origin on the Y axis for alignment. Thanks for the tip.

mambobanda
Offline
Joined: 2009-01-21

Hi
Just finished working on a similar problem. It's a button, the width is determined by the length of the text. To center it I took in account the the arcHeight and arcWidth. Here is the code, sorry for the lack of indentation, still can't figure out the code tags.

code:
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.text.*;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.scene.effect.*;
import javafx.geometry.*;

public class Button extends CustomNode
{
public var bgColor = Color.BLACK;
public var bgOpacity:Number;
public var arc:Number;
public var text:String = "Label";
public var reflection = false;

public var glowLevel:Number = 0.5;

public var label = Text
{
cache:true
translateY:17
translateX:10
content: bind text
fill:Color.WHITE
font:Font{size:14}
};

public var width:Number = bind label.layoutBounds.width + 20;
public var height:Number = 25;

var bg = Rectangle
{
cache:true
x:0
y:0
width:bind width
height:bind height
opacity:0.7
fill:bind bgColor

arcWidth:25
arcHeight:25

}

var gloss = Rectangle
{
x: 3
y: 2
cache:true
width:width - 6
height:12

opacity:0.2
fill:Color.WHITE
arcWidth:20
arcHeight:27
}

init
{

}

public override function create(): Node
{
if(not reflection)
{
return
Group
{

effect:DropShadow{}
content:[bg, label, gloss]
//[label]
};
}
else
{
return Group
{
effect:Reflection{fraction:0.5 topOpacity: 0.3}
content:[bg, label, gloss]
}

}
}

}

mbien
Offline
Joined: 2007-04-29

thank you mambobanda ;)

you are using a similar approach like i do and you have hardcoded the x/y of the text too. What i try is to automatically lay out the text and the box withoude hardcoding x/y or width/height.

equivalent code in java:
SGNode node = createBorder(createTextNodeComponent(name));

btw regarding the code tags:
["code"] ["/code"] (without quotes)

mambobanda
Offline
Joined: 2009-01-21

Interesting, didn't know there was a createBorder(). Thanks for the tags.