JavaFX nodes - How to make them resizable by the end user? - javafx

I am developing a JavaFX application where a class I have developed (extended from javafx.scene.Parent) is created on-the-fly based on what entry the user has clicked in a ListView control.
Just to be clear about this node, it is not created using a layout tool like SceneBuilder, it is created at runtime based on the user's actions.
The constructor for my custom node class creates a VBox and a Label and uses passed coordinates (X,Y) in the constructor method to set its own Layout coords. I then use a custom utility class to make the node draggable. This new node is then added to the main application Pane.
However, I have failed to find out how I can make these nodes resizable by the user. That is, allow the user to mouse over the corner of the node, hold and drag to resize. An operation that all users are used to, no matter what the OS.
Has anyone done anything like this in JavaFX? (My searches on the subject only seem to pull up subjects on the automatic resizing that a parent node does with its child nodes.)
Many thanks,
Ian.

As you can see on the documentation of VBox you can only define minimum, prefered and maximum range, there's not really a way to make it manually resizable.
The only proper solution to solve your problem is to develop your own class to do it, because what you want seems very specific, with your problem description, I don't think use some layouts or panels will do what you exactly want.
I found something that you can use : Dragging to resize a JavaFX Region
This allows you to resize a region, all you have to do after is to put you VBox in this region, but notice in this article that :
Only height resizing is currently implemented.
This code won't work in JavaFX8, you'll have to check the comment to see how it worls in JavaFX8
Hope this helps.

Related

Check if QML Item is being drawn

I have a set of QML items distributed all over my UI. They display data from a remote device and their content needs to be updated regularly. The Items are spread on several tabs and hidden in nested ListView instances, so most of them won't be visible to the user all the time.
In order to keep the bandwidth low I want to update only those items that are currently visible to the user.
I am looking for the right hook to get the information which of these Items is currently displayed from within the Item, without relying on information from the parents. If they were all placed in ListView delegates I could use the delegate's Components onCompleted and onDestroyed signals. Since this is not the case I am stuck at finding out how to get this information.
Am I missing something here? Is there an onPaintFinished signal or something similar? My workaround would be to add that logic to the parent containers, but that would be tedious, since there are several kinds of container that can contains these display Items.
Instances that are on delegates of a ListView will not exist until they would be in the visible range or the cache range around the visual area of the list view. If the delegate moves outside of that range, it is destroyed. So, no need to worry about instances hidden there.
Furthermore, items are currently not visible are also not drawn. They are not entered into the scene graph, and hence, not rendered. So, instances of your items appearing on tabs that are currently not current will also not be drawn. However, these items do still exist of course.
Figuring out if an item is effectively visible or not is quite a hard problem though. QML delegates part of that to OpenGL (clipping for instance). There is not feedback on the result of that. You could in theory lift that information out of the renderer, but that would require customizing that and that is very hard. You could take a look at the heuristics that GammaRay uses to warn about items not being visible. Perhaps you can take some inspiration from that.

JavaFX Secondary Screen "Always on Top" of All Applications

I've read about using a JDialog to wrap a JFXPanel in order to use JDialog's alwaysOnTop method. It works, but I'm having a small issue with this hack.
Since I'm using this technique to make secondary windows to my main application (popups etc), I need to set them on top of the main window. If I use the wrapper hack to do this, the top panel is "always on top" of everything (including other applications).
Is there a way to put the secondary screen only on top of my application? I don't like the fact that another application can be dragged in between the main window and secondary window of my application.
I suggest not using JDialog and JFXPanel, but only using JavaFX Stages.
Make your secondary screen a Stage and invoke secondaryStage.initOwner(primaryStage) before you show the secondary stage.
From the Stage documentation:
A stage can optionally have an owner Window. When a window is a stage's owner, it is said to be the parent of that stage . . . A stage will always be on top of its parent window.
I believe setting the owner of the secondary stage, correctly fulfills your requirement of "secondary screen only on top of my application".
Update: answers to additional questions from comments
I don't want there to be any interaction with the main stage once the secondary is open (the secondary window must be closed to allow interaction again).
To block input to the primary stage, Before showing the secondary stage, call: secondaryStage.initModality(Modality.WINDOW_MODAL).
You could use APPLICATION_MODAL instead of WINDOW_MODAL if you preferred to block all input to any other of your application windows - which one to use depends on the user experience you want.
There's nothing obvious in the api that would center the secondary screen on the main screen. It just always centers on the monitor, no matter where the main screen is.
This part of the question is a duplicate of Center location of stage. The answer to the duplicate has sample code for performing the centering of the child window.
That's right, there is nothing in the public api around positioning child windows relative to parent windows. I've filed a feature request for this functionality Add helper methods for positioning popups relative to nodes, but the feature request has not yet been implemented as of JavaFX 2.2.
There is a sample project I created to do relative positioning of child dialogs, which might be useful.
Just for centering within the parent, you are probably best off querying the stage location and width before displaying the child and then setting the x and y co-ordinates of the child appropriately when you display it. All of this can be done based on x, y and width properties of windows.
There is also a dialog project in the JavaFX UI controls sandbox which might provides some of the functionality you require so that you don't need to code it yourself.
In time all of the functionality you are requesting will probably end up in the JavaFX core platform, but I don't think it's all quite there yet for JavaFX 2.2.
I agree with jewelsea, but if you need to use JDialog and JavaFX stages (like it was my case), then you can't set your primaryStage's parent or modality.
The only solution i found is to use a little "hack":
I use JNA, Java Native Access API to do my own setAlwaysOnTop() method using User32.INSTANCE.setWindowPos(...) with HWND_TOPMOST parameter.
edit: see microsoft doc
and jna doc

How to completely initialise a component but not add it to the display? Flex

I need to completely initialize a custom component in my Flex app (i.e. I should be able to access it from action script and get its properties and its children etc), But I do not want to add it to the display or make it visible.
I have tried to add it to my visible component, but keep it visible, but often many of its properties are set only when it is drawn, so i don't get what i need.
Is there a way to add a custom component to some sort of 'Virtual' display, that is not visible to the user?
You could add the component to an invisible Sprite - that way the component itself could both be on the stage and have its own visible property set to true.
Did you try using initialize()? After a view is added to the display list, the initialization stage begins. Calling initialize() before addChild() should let you initialize the view without needing to first add it to the stage.
For more info visit:
http://flexscript.wordpress.com/2008/10/24/flex-component-lifecycle-and-flex-component-framework/
http://blog.deadinkvinyl.com/2008/10/05/flex-3-addchild-and-initialize/
Not sure if possible without adding it to the display list, although I'd wish it were to some extent.
I once had to make custom drag proxy, which didn't work with the real component, because of some weird skinning issues. So instead I had PopupMananger add a box as a popup, added my component to the box, called validateNow on the component, drew it in a bitmap data, removed the popup, and used the bitmap data as the proxy.
So what you were trying was missing a call to validateNow most likely.

How to update a QLayout and get the new dimensions before returning?

This is driving me nuts. I have a custom menu class that, when set visible, shows a list of items located in a particular folder. When a hardware button is pressed, my application gets the latest list of items, populates the menu with them, and returns.
The menu displaying these items uses a QListWidget filled with custom widgets. Each of the widgets contains one or more QLabels in a horizontal layout, and is created at the time the menu is shown. In order to adjust the text displayed based on the menu width available, I need to get the size of the QLabel AFTER it has been resized according to the layout, but before the menu becomes visible to the user. The problem is, my layout does not get updated until all of the functions constructing my list return.
I have tried QApplication::ProcessEvents() and the layout update functions, but none of them have updated the values of my QLabels before returning. I can set a QTimer when the button is initially pressed, and have it show the menu, update the items, and stop itself, but that seems like a terrible solution.
Any help would really be appreciated! I've spent most of a day on this.
Marlon
I had this exact problem and could not find an answer anywhere on the Internet. Calling Layout.update(), Layout.activate(), or widget.adjustSize() (all suggested in various places) all did not work.
I had a widget with a vertical layout that I wanted to add a QLabel to and then immediately use the size of the QLabel.
The only thing that worked reliably was
layout->addWidget(myLabel);
myLabel->show();
size = myLabel->size();
It would seem that layouts will just not recalculate until you either return from a function and allow the Qt event loop to progress or manually call show() yourself.
How to update a QLayout and get the new dimensions before returning?
Don't. You're not meant to do that. It'll drive you "nuts" because you're doing it backwards. Layout updates are handled asynchronously from the event loop. Instead of getting layout dimensions right away, set yourself up to be part of the system. Some options are:
Implement a custom widget that will interact properly with the layout, growing to fill the available width of the layout. Perhaps all you need is a size policy and a way to elide text?
Make a custom layout that takes the special properties of your use case into account.
You want to call QWidget::adjustSize() on your parent widget. This will force the layout recalculations.
Have you tried using layout()->update(); ?
I've tried many but nothing works for me on Qt 5.15.
Only invented little patch - create timer and get size after 20 msec:
QTimer::singleShot(20, this, [this]
{
const auto height = myLayout->contentsRect().height();
// ...
});

Simple AddChild question

I am checking this guy's code...
http://www.codingcolor.com/as3/as3-youtube-chromless-api/
I have download the source code...but I couldn't figure out how he add the play, pause and stop button in the stage. I know in his VideoPlayerControl.as, he has
playbackControl = new PlayPauseButton();
playbackControl.addEventListener(Event.CHANGE,setPlaybackState);
addChild(playbackControl);
in his PlayPauseButton.as. there is not code for the location of the button(x,y)..
I am not sure how he place the control buttons....
Also...Are there anyways to give the button location with object oriented way instead of specify it with static number???
I appreciate any help...
Without reviewing his code...
it sounds like you need to read up on the Flex Component Lifecycle.
In normal cases, the PlayPauseButton will be created and added in createChildren().
the updateDisplayList() method will position and size the elements. Additionally, many components implement a measure() method that will determine the ideal size for it. And many containers have code to automatically lay out the children. If the PlayPauseButton has a measure method and it is added to a container (such as an HBox of VBox) he won't need code to position or size the button as that wrk is already done in the code that he inherits from the Flex framework.

Resources