I am using Vaadin 7.1
I have 2 layuots:
| header |
| main |
and popup window.
When I maximize the window I want it to be opened in "main" but not in whole screen.
is it possible?
When I try to do this directly I get:
java.lang.IllegalArgumentException: A Window can only be added to a UI
using UI.addWindow(Window window)
Regards,
Oleksandr.
I think you need some javascript and custom logic for this.
First of all, you have to set the main layout id:
mainLayout.setId("xyz");
And here is the extended window:
public class MyWindow extends Window {
private static final long serialVersionUID = 1L;
private int top;
private int left;
private int bottom;
private int right;
public MyWindow() {
setResizable(false);
setData(WindowMode.NORMAL);
String sourceURL = "javascript:com.xyz.foo.myfunc(" +
"document.getElementById('xyz').getBoundingClientRect().top," +
"document.getElementById('xyz').getBoundingClientRect().left," +
"document.getElementById('xyz').getBoundingClientRect().bottom," +
"document.getElementById('xyz').getBoundingClientRect().right)";
final Link link = new Link("maximization", new ExternalResource(sourceURL));
// set link icon if needed
JavaScript.getCurrent().addFunction("com.xyz.foo.myfunc", new JavaScriptFunction() {
private static final long serialVersionUID = 1L;
#Override
public void call(JSONArray arg) throws JSONException {
if (MyWindow.this.getData() == WindowMode.NORMAL) {
saveCurrentPos();
setPos(arg.getInt(0), arg.getInt(1), arg.getInt(2), arg.getInt(3));
link.setCaption("normalization"); // or set icon
MyWindow.this.setData(WindowMode.MAXIMIZED);
} else {
setPos(top, left, bottom, right);
link.setCaption("maximization"); // or set icon
MyWindow.this.setData(WindowMode.NORMAL);
}
}
});
VerticalLayout vLayout = new VerticalLayout(link);
vLayout.setComponentAlignment(link, Alignment.TOP_RIGHT);
setContent(vLayout);
// demo settings
setWidth("200px");
setHeight("150px");
center();
}
private void saveCurrentPos() {
left = getPositionX();
top = getPositionY();
right = left + (int) getWidth();
bottom = top + (int) getHeight();
}
private void setPos(int top, int left, int bottom, int right) {
setPositionX(left);
setPositionY(top);
setWidth(right - left, Unit.PIXELS);
setHeight(bottom - top, Unit.PIXELS);
}
}
I suggest that you write your own header with caption and closing button.
Related
I have a simple HBOX control which uses USE_COMPUTED_SIZE in Pref-Height, hence the size is all calculated and adjusted by the controls inside, which are a couple VBOX.
The issue comes when I try to add a new Pane as a children to the HBOX and draw a vertical line from top to bottom of the HBOX, so I write my line:
int startX = 5;
int startY = 0;
int endX = 5;
Line line = new Line(startX,startY,endX,hbox.getHeight());
Here, I need the hbox.getHeight(), but surprise: it is =-1, because it is using USE_COMPUTED_SIZE. So, how can I get the real (computed) value of hbox.getHeight()?
Not tested, but I think you can do something like:
public class HBoxWithLine extends HBox {
// Example of configurable property:
private final DoubleProperty lineOffset = new SimpleDoubleProperty(5);
public DoubleProperty lineOffsetProperty() {
return lineOffset ;
}
public final double getLineOffset() {
return lineOffsetProperty().get();
}
public final void setLineOffset(double lineOffset) {
lineOffsetProperty().set(lineOffset);
}
private final Line line = new Line();
public HBoxWithLine() {
getChildren().add(line);
// request layout when offset is invalidated:
lineOffset.addListener(obs -> requestLayout());
}
#Override
protected void layoutChildren() {
line.setStartX(getLineOffset());
line.setEndX(getLineOffset());
line.setStartY(0);
line.setEndY(getHeight());
super.layoutChildren();
}
}
Now you can just create a HBoxWithLine and add (additional) child nodes to it, set it's pref width and height to either fixed values, or Region.USE_COMPUTED_SIZE, etc., and it should just work.
I've created MainGameTab which extends TabSheet.
In constructor I create layouts and add them as tabs. I wanted to add right click event to the layout
mainLayout.addLayoutClickListener(new LayoutClickListener() {
private static final long serialVersionUID = 1871942396979048283L;
#Override
public void layoutClick(LayoutClickEvent event) {
if (event.getButton() == MouseButton.RIGHT) {
TextQuestUi.getCurrent().addWindow(new CharacterSheet(c));
}
}
});
this.addTab(mainLayout, "Game");
CharacterSheet is a class, that extends Window
public class CharacterSheet extends Window {
But when I click on tab - I've got basic right click items for browser instead of new window.
What's the problem?
My MainGameTab looks like this
public MainGameTab() {
final Player c = new Player();
c.setName("Hero");
c.setLevel(100);
Skill skill = new Skill();
skill.setName("Help from heaven");
skill.setEffect("Full recover health");
c.addSkill(skill);
Stat stat = new Stat();
stat.setName("Attack");
stat.setValue(50);
c.addStat(stat);
HorizontalLayout mainLayout = new HorizontalLayout();
mainLayout.addLayoutClickListener(new LayoutClickListener() {
private static final long serialVersionUID = 1871942396979048283L;
#Override
public void layoutClick(LayoutClickEvent event) {
if (event.getButton() == MouseButton.RIGHT) {
TextQuestUi.getCurrent().addWindow(new CharacterSheet(c));
}
}
});
this.addTab(mainLayout, "Game");
HorizontalLayout logLayout = new HorizontalLayout();
this.addTab(logLayout, "Log");
}
And I add it in UI
#Override
protected void init(VaadinRequest request) {
this.setContent(new MainGameTab());
}
I'll suggest you to use one of the existing Vaadin addons. See here
Or, I am assuming that you're probably looking for getButton() in ItemClickEvent - something like this:
t.addListener(new ItemClickListener() {
public void itemClick(ItemClickEvent event) {
if (event.getButton()==ItemClickEvent.BUTTON_RIGHT) {
// Right mouse button clicked, do greatThings!
}
}
});
The text button draws normally (no errors or warnings) but it doesn't respond to mouse clicks. The situation is the same on Desktop and Android build. I've read and followed every topic about it with no results. What am I doing wrong?
Maybe I need to set something in stage object?
Here's my MenuScreen class code:
public class MenuScreen implements Screen {
private OrthographicCamera camera;
private BitmapFont font;
private TextureAtlas menuGraphics;
Stage stage;
TextButton button;
TextButtonStyle buttonStyle;
Skin skin;
public MenuScreen(Game game)
{
//create satage object
stage = new Stage();
//create font object
font = new BitmapFont(Gdx.files.internal("data/arial-15.fnt"),false);
font.setColor(Color.RED);
//load buttons texture atlas and create Skin object
menuGraphics = new TextureAtlas( Gdx.files.internal( "buttons/buttons.pack" ) );
skin = new Skin();
skin.addRegions(menuGraphics);
// Store the default libgdx font under the name "defaultFont".
skin.add("defaultFont",font);
//Set button style
buttonStyle = new TextButtonStyle();
buttonStyle.up = skin.newDrawable("yellow");
buttonStyle.down = skin.newDrawable("orange");
buttonStyle.checked = skin.newDrawable("orange");
buttonStyle.over = skin.newDrawable("orange");
buttonStyle.font = skin.getFont("defaultFont");
skin.add("default", buttonStyle);
//assign button style
button=new TextButton("PLAY",buttonStyle);
button.setPosition(200, 200);
button.setSize(200,200);
//add button to stage
stage.addActor(button);
//add click listener to the button
button.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
button.setText("Starting new game");
Gdx.app.log("MenuScreen", "clicked button");
}
});
Gdx.app.log("MenuScreen", "create");
}
#Override
public void resize(int width, int height )
{
float aspectRatio = (float) width / (float) height;
camera = new OrthographicCamera(640, 360);
camera.translate(320,180);
camera.update();
stage.setViewport(new FillViewport(640, 360, camera));
stage.getViewport().setCamera(camera);
Gdx.app.log( "MenuScreen", "Resizing screen to: " + width + " x " + height );
}
#Override
public void show() {
Gdx.input.setInputProcessor(stage);
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
resize((int)w,(int)h);
Gdx.app.log( "MenuScreen", "Show screen code" );
}
#Override
public void render(float delta)
{
Gdx.gl.glClearColor( 0f, 1f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
stage.act( delta );
// draw the actors
stage.draw();
}
#Override
public void dispose()
{
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
}
I Finally solved it!
Additional line in resize function did the trick:
stage.getViewport().update(width, height);
I realized that the problem was caused by setting the Camera and Viewport in the resize function. When I removed that code (an adjusted the button position to be visible with standard stage viewport) the button started working.
But I wanted to use camera and viewport. Reading about stage resizing in LibGDX documantation (https://github.com/libgdx/libgdx/wiki/Scene2d) I found out that after setting camera, the viewport needs to be updated, otherwise the actor boundries are not recalculated. So I added the viewport update line in resize function and it started working!
The new resize function looks like that:
#Override
public void resize(int width, int height )
{
float aspectRatio = (float) width / (float) height;
camera = new OrthographicCamera(640, 360);
camera.translate(320,180);
camera.update();
stage.setViewport(new FillViewport(640, 360, camera));
stage.getViewport().setCamera(camera);
stage.getViewport().update(width, height);
Gdx.app.log( "MenuScreen", "Resizing screen to: " + width + " x " + height );
}
add implements ApplicationListener to your class
public MenuScreen implements ApplicationListener
hope this helps.
I have a problem with centering my dialog boxes (that are basically AnchorPanes that have caption in them) in their parent node (that is also AnchorPane, but I beleive this is irrelevant).
Code goes as follows:
public void showDialog(final Dialog dialog) {
dialogStack.add(dialog);
dialogCanvas.toFront();
dialog.toFront();
dialogCanvas.setVisible(true);
dialog.setVisible(true);
getChildren().add(dialog);
dialog.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if(newValue.doubleValue() > 0) {
centerDialog(dialog);
}
}
});
}
public void centerDialog(final Dialog dialog) {
double width = getWidth();
double height = getHeight();
dialog.setLayoutX(width / 2 - dialog.getWidth() / 2);
dialog.setLayoutY(height / 2 - dialog.getHeight() / 2);
}
I use the widthProperty change listener because you can only center the node when it gets rendered and only then it gets the width/height set.
When I debug the code at point when I have set the dialog's layout x/y the values are calculated fine but the dialog node at the end gets positioned at top/left corner (X:0/Y:0).
Why???
Can I somehow trigger the redraw of a parent node so that the element gets positioned righty? What am I doing wrong?
Kind regards,
Stjepan
Your options:
Continue using AnchorPane as a parent but center the child by using anchor constraints as
AnchorPane.setTopAnchor(dialog, height / 2 - dialog.getHeight() / 2);
AnchorPane.setLeftAnchor(dialog, width / 2 - dialog.getWidth() / 2);
on every change of width and height values of parent pane. You need add event listener for both width and height properties if you want the child pane to stay centered on window resizing.
Use Pane instead of AnchorPane as parent and center the child pane by setLayoutX() / setLayoutY(), on every change of parent's width and height values (again using event listeners). The Pane, in opposite to AnchorPane, will not layout its children other than resizing them to their preferred sizes.
Use StackPane instead of AnchorPane as parent and no need to center the child pane since StackPane will do it for you automatically.
Use the ControlsFX Dialogs.
A demo code for the first option:
public class AnchorDemo extends Application {
private final AnchorPane anchorPaneParent = new AnchorPane();
private final AnchorPane anchorPaneChild = new AnchorPane(new Label("TEXT TEXT TEXT TEXT TEXT"));
#Override
public void start(Stage primaryStage) {
anchorPaneParent.setStyle("-fx-border-color:red");
anchorPaneChild.setStyle("-fx-border-color:green");
anchorPaneParent.getChildren().add(anchorPaneChild);
anchorPaneParent.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> arg0, Bounds oldBound, Bounds newBound) {
System.out.println("oldBound = " + oldBound);
System.out.println("newBound = " + newBound);
System.out.println("");
if (oldBound.getHeight() != newBound.getHeight() || oldBound.getWidth() != newBound.getWidth()) {
updateChildAnchorConstraint();
}
}
});
Scene scene = new Scene(anchorPaneParent, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
updateChildAnchorConstraint();
}
private void updateChildAnchorConstraint() {
AnchorPane.setTopAnchor(anchorPaneChild, anchorPaneParent.getHeight() / 2 - anchorPaneChild.getHeight() / 2);
AnchorPane.setLeftAnchor(anchorPaneChild, anchorPaneParent.getWidth() / 2 - anchorPaneChild.getWidth() / 2);
}
public static void main(String[] args) {
launch(args);
}
}
The problem was that this was all done in the single thread and the information about layout was not yet known... But using the Platform.runLater(...) I was able to solve the problem.
At the end it is pretty elegant when you know how to solve it...
public void showDialog(final Dialog dialog) {
dialogStack.add(dialog);
dialogCanvas.toFront();
dialog.toFront();
dialogCanvas.setVisible(true);
dialog.setVisible(true);
getChildren().add(dialog);
dialog.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if(newValue.doubleValue() > 0) {
centerDialog(dialog);
}
}
});
}
public void centerDialog(final Dialog dialog) {
Platform.runLater(new Runnable() {
#Override
public void run() {
double width = getWidth();
double height = getHeight();
dialog.setLayoutX(width / 2 - dialog.getWidth() / 2);
dialog.setLayoutY(height / 2 - dialog.getHeight() / 2);
}
});
}
I want to change the colors of background button and the color of text onfocus
How can I make it?
class RoundedRectField extends Field {
// Layout values
private static final int CURVE_X = 12; // X-axis inset of curve
private static final int CURVE_Y = 12; // Y-axis inset of curve
private static final int MARGIN = 2; // Space within component boundary
// Static colors
private static final int TEXT_COLOR = 0xFFFFFF; // White
private static final int BORDER_COLOR = 0xFF8000; // dark gray
private static final int BACKGROUND_COLOR = 0xFFFFFF; // White
private static final int TEXT_COLOR_selected = 0xFF6DB6;
private static final int BORDER_COLOR_selected = 0xFF8000;
private static final int BACKGROUND_COLOR_selected = 0xCCCCCC;
boolean _focus = false;
private static String text_button;
// Point types array for rounded rectangle. Each point type
// corresponds to one of the colors in the colors array. The
// space marks the division between points on the top half of
// the rectangle and those on the bottom.
private static final byte[] PATH_POINT_TYPES = {
Graphics.CURVEDPATH_END_POINT,
Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT,
Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_END_POINT,
Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT,
Graphics.CURVEDPATH_END_POINT,
Graphics.CURVEDPATH_END_POINT,
Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT,
Graphics.CURVEDPATH_END_POINT, Graphics.CURVEDPATH_END_POINT,
Graphics.CURVEDPATH_QUADRATIC_BEZIER_CONTROL_POINT,
Graphics.CURVEDPATH_END_POINT, };
// Colors array for rounded rectangle gradient. Each color corresponds
// to one of the points in the point types array. Top light, bottom black.
private static final int[] PATH_GRADIENT = { 0xFF8000, 0xFF8000, 0xFF8000,
0xFF8000, 0xFF8000, 0xFF8000,
0xFC0500, 0xFC0500, 0xFC0500, 0xFC0500, 0xFC0500, 0xFC0500 };
// Center our readonly field in the space we're given.
public RoundedRectField(String text_button) {
super(FIELD_HCENTER | FIELD_VCENTER | READONLY);
this.text_button = text_button;
}
// This field in this demo has a fixed height.
public int getPreferredHeight() {
return 70;
}
// This field in this demo has a fixed width.
public int getPreferredWidth() {
return 240;
}
// When layout is requested, return our height and width.
protected void layout(int width, int height) {
setExtent(getPreferredWidth(), getPreferredHeight());
}
// When painting is requested, do it ourselves.
protected void paint(Graphics g) {
// Clear this area to white background, fully opaque.
g.clear();
g.setGlobalAlpha(255);
g.setBackgroundColor(BACKGROUND_COLOR);
// Drawing within our margin.
int width = getPreferredWidth() - (MARGIN * 2);
int height = getPreferredHeight() - (MARGIN * 2);
// Compute paths for the rounded rectangle. The 1st point (0) is on
// the left
// side, right where the curve in the top left corner starts. So the
// top left
// corner is point 1. These points correspond to our static arrays.
int[] xPts = { 0, 0, CURVE_X, width - CURVE_X, width, width, width,
width, width - CURVE_X, CURVE_X, 0, 0 };
int[] yPts = { CURVE_Y, 0, 0, 0, 0, CURVE_Y, height - CURVE_Y,
height, height, height, height, height - CURVE_Y };
// Draw the gradient fill.
g.drawShadedFilledPath(xPts, yPts, PATH_POINT_TYPES, PATH_GRADIENT,
null);
// Draw a rounded rectangle for the outline.
// I think that drawRoundRect looks better than drawPathOutline.
g.setColor(BORDER_COLOR);
g.drawRoundRect(0, 0, width, height, CURVE_X * 2, CURVE_Y * 2);
// Place some text in the center.
Font font = Font.getDefault().derive(Font.PLAIN, 9, Ui.UNITS_pt);
int textWidth = font.getAdvance(text_button);
int textHeight = font.getHeight();
g.setColor(TEXT_COLOR);
g.setFont(font);
g.drawText(text_button, (width / 2) - (textWidth / 2) - MARGIN,
(height / 2) - (textHeight / 2) - MARGIN);
}
protected void onFocus(int direction) {
_focus = true;
Dialog.alert("dcd");
invalidate();
super.onFocus(direction);
}
protected void onUnfocus() {
_focus = false;
invalidate();
super.onUnfocus();
}
}
You can do it several ways. One popular way is to provide custom focus drawing in the paint() method, which you already override.
You should be able to do this (I'm assuming you declared the _selected colors for the focused state):
if (isFocus()) {
g.setBackgroundColor(BACKGROUND_COLOR_selected);
else {
g.setBackgroundColor(BACKGROUND_COLOR);
}
...
if (isFocus()) {
g.setColor(TEXT_COLOR_selected);
} else {
g.setColor(TEXT_COLOR);
}
Those lines go in paint(), right where you are currently calling g.setBackgroundColor and g.setColor(TEXT_COLOR).
Then, you would override drawFocus() and do nothing, since your focus drawing is handled in paint():
protected void drawFocus(Graphics graphics, boolean on) {
// override superclass implementation and do nothing
}
Finally, you need to make your Field focusable, in order to ever receive focus. You can do so like this:
public RoundedRectField(String text_button) {
super(FIELD_HCENTER | FIELD_VCENTER | FOCUSABLE);
this.text_button = text_button;
}
If you need the field to be dynamically focusable (sometimes focusable, or sometimes not focusable), then you could implement this method:
public boolean isFocusable() {
But, if the field is always focusable, then using the FOCUSABLE flag in your constructor will work. I tested this out, and I saw the text color change with focus (on a OS 5.0 9550).