I am facing an issue with editor and its contents layout. Its following: there is an editor with print preview functionality, main part of the editor is taken by paper clips PrintPreview component, on the left side there is a composite with some buttons (see screenshot 1).
As you can see PrintPreview is located inside ScrolledComposite.
The problem is: when I am resizing window or views under editor, the bottom scrollbar moves under views and thus disappears. There is no way to scroll horizontally afterwards (no editor scrollbar appears). see screenshot2 (bottom scrollbar is getting hidden).
It starting to get hidden, when editor height is less then height of the right composite ( there are more widgets below the last button, I've just erased them)
If I am shrinking the window, then right composite never loses its width and always visible (see screenshot 3 - It does not allow to resize more than that).
The composites are created in the following way:
#Override
public void createPartControl(final Composite parent) {
GridLayout gridLayout = new GridLayout(2, false);
parent.setLayout(gridLayout);
// Scroll area for the print area
scroll = new ScrolledComposite(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
final GridData gridData = new GridData(GridData.FILL_BOTH);
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
gridData.widthHint = 1;
gridData.heightHint = 1;
scroll.setLayoutData(gridData);
scroll.setExpandHorizontal(true);
scroll.setExpandVertical(true);
// Button area
final Composite buttonArea = new Composite(parent, SWT.FLAT);
final GridData layoutData = new GridData(SWT.FILL, SWT.TOP, false, false);
buttonArea.setLayoutData(layoutData);
gridLayout = new GridLayout(1, false);
buttonArea.setLayout(gridLayout);
The question is: how not to prevent disappearing of the bottom scrollbar? Can I have the same behavior as width the width of the right composite - It not possible to resize less then right composite height? Or how can I show scrollbar on the whole editor if some minimum height limit is exceeded?
I've tried different things on different composites, like setting minimumHeight and heightHint, putting buttonsArea into the scrolledcomposite (just for fun) etc. But nothing have helped me.
Does anybody knows fast solution? Thank you.
See this SO post: Prevent SWT scrolledComposite from eating part of it's children
You need to listen for width changes on the content composite
(mParent), compute the minimum height again given the new content
width, and call setMinHeight() on the scrolled composite with new
height.
If the above post is not as useful as it seems then share some minimal compiling and executable code to replicate the problem. Also, mention the eclipse/swt version, OS and JDK version, it helps in analyzing the problem.
Demo code for resize event and output !!
Code :
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
public class ScrolledCompositeTest
{
public static void main (String [] args)
{
Display display = new Display ();
Shell shell = new Shell (display);
shell.setLayout(new FillLayout());
GridLayout layout = new GridLayout();
layout.numColumns = 4;
// set the minimum width and height of the scrolled content - method 2
final ScrolledComposite sc2 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc2.setExpandHorizontal(true);
sc2.setExpandVertical(true);
final Composite c2 = new Composite(sc2, SWT.NONE);
sc2.setContent(c2);
layout = new GridLayout();
layout.numColumns = 7;
c2.setLayout(layout);
Button b2 = new Button (c2, SWT.PUSH);
b2.setText("first button");
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
Button add = new Button (shell, SWT.PUSH);
add.setText("add children");
final int[] index = new int[]{0};
add.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
index[0]++;
Button button = new Button(c2, SWT.PUSH);
button.setText("button "+index[0]);
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
c2.layout();
}
});
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
Output:
Actual Size
Vertical Resize
Horizontal Resize
Related
How can I implement following design functionality with android standard component bottom sheet:
Image when Bottom sheet dialog fragment will appear:
Image when user scrolled to up to view bottom of content:
I will use ViewPager to scrolling header images and RecyclerView to showing descriptions and other informations. And parallax effect to ImageView(which are placed in ViewPager) when scrolling content vertically. Have a minimum height of the ImageView(and ViewPager), user can't collapse fully it (Look to second screenshot, which is user scrolled until the end of content).
I want stop scrolling ImageView when it will reach to minimum height(look to second one Screenshot), but the content of below ImageView should be continue scrolling
This can be done with an if statement in an on scroll view such as shown below:
ScrollView scrollView = findViewById(R.id.scrollView); //Adjust for your code
ImageView imageView = findViewById(R.id.imageView); //Adjust for your code
boolean imageIsHidden = false;
int threshold = 250;
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged() {
int scrollY = rootScrollView.getScrollY();
if(scrollY >= threshold){
imageIsHidden = true;
//Move image outside of scroll view so it doesn't scroll
}
else if(scrollY < threshold && imageIsHidden){
imageIsHidden = false;
//Move image inside of scroll view so it does scroll
}
}
});
What this does is has a boolean called imageIsHidden and an integer called threshold. Threshold is where you want it to make it disappear. You will need to play around with this value to find a sweet spot.
You will also need to implement moving the image inside and outside of the scroll view as well in the if and if else statement.
I want to add close button to top right corner of a dialog box.
I tried using setbounds with addactor and just add and setposition with setsize and addactor, but nothing works. I know that dialog works with table layout, it has a table for content and for buttons. I don't want to use this layout and put the button outside this layout like on the border of the dialog.
How can I do it?
This is how it should be:
The easiest solution I could come up with now, is to use negative padding for your button to move it "outside" of it's cell.
Button closeButton = new TextButton("X", skin, "default");
getTitleTable().add(closeButton).size(60, 40).padRight(-30).padTop(-20);
With this padding hack you have the problem, that the button will be outside of your Dialog, and by default, Window checks the bounds of your window when it performs Actor.hit(...) evaluation.
We need to disable clipping for that reason, but the rendering of the window depends on it. That's why we use another hack to enable it, just for the rendering:
#Override
public void draw(Batch batch, float parentAlpha) {
setClip(true);
super.draw(batch, parentAlpha);
setClip(false);
}
Do this:
private Stage stage;
private Window window;
private Table table;
#Override
public void show() {
table = new Table();
table.setSize(Gdx.graphics.getWidth() / 2
, Gdx.graphics.getHeight() / 5);
window = new Window("", skin);
window.setSize(table.getWidth(), table.getHeight());
Button btnWindow = new Button(skin, "close");
btnWindow.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
window.setVisible(false);
}
});
window.addActor(btnWindow);
btnWindow.setSize(50, 50);
btnWindow.setPosition(window.getWidth() - btnWindow.getWidth()
, window.getHeight() - btnWindow.getHeight());
table.addActor(window);
window.setModal(true);
table.setPosition(Gdx.graphics.getWidth() / 2 - window.getWidth() / 2
, Gdx.graphics.getHeight() / 2 - window.getHeight() / 2 +
100);
window.addAction(Actions.sequence(Actions.alpha(0)
, Actions.fadeIn(.1f)
, Actions.moveTo(+50, +50, 1)));
stage.addActor(table);
}
I had a similar problem. After a bit of searching this thread helped me.
Basically to tell the alignment of the actors inside a table, and to tell the alignment of the table itself are two separate things. Setting the alignment of the table top top-left would produce the desired behavior.
table = new Table();
table.setFillParent(true);
table.setSkin(usedSkin);
table.setDebug(true);
table.top().left();
stage.addActor(table);
table.add(exitBtn);
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 want to align the text in a TextArea to the right. I tried the following code:
Form form = new Form();
TextArea textArea = new TextArea("Some Arabic text ...");
textArea.setRTL(true);
textArea.setAlignment(RIGHT);
form.addComponent(textArea);
The result was just moving the scroll to left,
But the text is still not aligned RIGHT,
check the image below:
So how to align the content to the RIGHT ?
It may sound crazy for the first instance :) but setting the alignment to TextArea.LEFT solved the issue and now it's RIGHT aligned !
Form form = new Form();
TextArea textArea = new TextArea("Some Arabic text ...");
textArea.setRTL(true);
textArea.setAlignment(TextArea.LEFT);
form.addComponent(textArea);
Setting it to LEFT makes the displayed text RIGHT aligned !
Or by removing the textArea.setRTL(true) which is mirroring the display
Form form = new Form();
TextArea textArea = new TextArea("Some Arabic text ...");
textArea.setAlignment(TextArea.RIGHT);
form.addComponent(textArea);
For those who are interested in more complicated details when it's set to RTL:
the paint method of TextArea class is
public void paint(Graphics g) {
UIManager.getInstance().getLookAndFeel().drawTextArea(g, this);
}
And drawTextArea method in DefaultLookAndFeel is as follows:
int align = ta.getAbsoluteAlignment();
// remaining code is here in initial source
switch(align) {
case Component.RIGHT:
x = ta.getX() + ta.getWidth() - rightPadding - f.stringWidth(displayText);
break;
// remaining code is here in initial source
}
g.drawString(displayText, x, y);
Unfortunately TextArea.RIGHT value is 3
But when calling ta.getAbsoluteAlignment() it returns 1 (despite that the object's alignment is set by code to TextArea.RIGHT !!)
Meanwhile TextArea.Left value is 1
That's why it matched the value in the switch and was aligned to RIGHT
BTW, if you set
textArea.setAlignment(Component.RIGHT);
it will also be wrong, because Component.RIGHT outside the paint method has the value 3 not 1 !
You only have to write 'TextArea.RIGHT' instead of 'RIGHT'
textArea.setAlignment(TextArea.RIGHT);
You can use the following line:
TextArea textArea = new TextArea("Some Arabic text ...");
textArea.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);