I am trying to create a "custom widget" (extends HBox) which renders 3D graphics.
The problem is that all the examples I see for setting the camera, show how to do it on the main "scene", which belongs to the main window.
I don't want any relation to the main Window, I want it to be an independent widget.
Is it anyway possible to do that?
I'll be glad if you can share some code example, as I feel pretty lost with it...
I am not quite sure if I understood you correctly, but if you want the camera to be transformable, you can insert it into the Scene Graph where ever you want. You can add it to a group node like this:
Group someGroup = new Group();
PerspectiveCamera camera = new PerspectiveCamera();
someGroup.getChildren().add(camera);
Scene s = new Scene(someGroup);
s.setCamera(camera);
When you now move the Group node the camera moves as well. You can add the camera to any Group node you want, but I am not sure what happens when you put it into a Group node that uses LayoutManagement like HBox.
The important thing is you always have to add the camera to the Scene that it is in.
Related
A stage in javafx requires exactly one scene, and a scene requires exactly one root node.
So I want to know what's the main role of the scene? It seems like a scene connects two sides that can be connected directly without an intermediate.
I want juste to understand the logic.
Thank you.
Stage represents a native system window. Scene is the content of this window with JavaFX controls, nodes, stylesheets, etc.
You can change Scenes inside a Stage during your UI workflow without a need to create a new system window each time.
I'm learning basic JavaFX right now, and I don't understand this statement from the book I'm reading: "No, a node such as a text field can be added to only one pane and once. Adding a node to a pane multiple times or to different panes will cause a runtime error." I can see from the UML diagram the book provides that it is a composition, but I don't understand why (library class code implementation) that is.
For instance, why does this result in a compile error? Isn't a new text field instantiated within the pane since it's a composition?
FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf);
Also, why does the following run but not show the text field placed in pane?
FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane2.getChildren().add(tf);
primaryStage.setScene(new Scene(pane));
primaryStage.show();
This is basically a (deliberate) consequence of the way the API is designed. Each Node has a collection of properties, including a parent property (the - one and only one - parent of the node in the scene graph), along with properties such as layoutX and layoutY which are the coordinates of the node in relation to its parent. Consequently, a node can only belong to one parent, and can only be added to a parent once (as it can only have one location in the parent). Organizing things this way enables a very efficient layout process.
Another way to think of this: suppose your first code block did what you wanted; so the text field tf appeared twice in the flow pane. What result would you expect to get from tf.getBoundsInParent()? Since tf appears twice in the parent, the API would not be able to give a sensible value for this call.
There are a couple of inaccuracies in statements you make in your question:
For instance, why does this result in a compile error? Isn't a new
text field instantiated within the pane since it's a composition?
First, technically, this is aggregation, not composition; though I'm not sure understanding the difference will aid your understanding of what is happening at this point.
Second, there is no compile error here; you get an error at runtime (the pane detects that the same node has been added twice; the complier has no way to check this).
Third, parents do not instantiate copies of the nodes you add to them. If so, you wouldn't be able to change the properties of nodes that were displayed. For example, if the FlowPane in your example instantiated a new TextField when you called pane.getChildren().add(tf);, and then displayed that new text field, then if you subsequently called tf.setText("new text"), it would have no effect, as it would not be changing the text of the text field that pane was displaying.
When you call pane.getChildren().add(...) you pass a reference to the node you want to be added; it is that node that is then displayed as a child of the pane. Any other implementation would produce pretty counter-intuitive behavior.
In your second code block:
pane.getChildren().add(tf);
pane2.getChildren().add(tf);
the second call implicitly sets the parent property of tf to pane2; consequently tf is no longer a child of pane. So this code has the effect of removing tf from the first parent, pane. As far as I am aware, this side-effect is not documented, so you probably should avoid writing code like this.
Try this:
TextField tf = new TextField();
TextField tf2 = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf2);
The reason you cannot add the same node twice is that only one node with the same specifications and dimensions can be viewable in the gui. It would be like copying an identical blue circle onto an original blue circle. To the user it looks the same, but it takes up more memory.
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.
I'm working on a PyQt project. I have a map with points on it (The map is a QGraphicsScene and my points are QGraphicsEllipseItem).
I would like to display some informations on the points when they receive a hover event.
The information will be: a picture, some text and a treeview fill with data.
I don't want to open a new window, I want it to float over the map exactly how a tooltip will do.
I don't know how to do it, I can't find any widget who fill my needs.
Thank you for any help !
Create a new widget/window with windowflag Qt::ToolTip. According to the docs Qt's tooltips are nothing else. http://doc.qt.io/qt-5/qt.html#WindowType-enum
In a Qt 4.7.1 Windows app, a slot that's connected to QGraphicsScene::changed() is fired as expected but the dirty region count is always 1 and the rect size I get is always the same as my app window. I tried calling QGraphicsView::setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); but that didn't help.
Is there a way to tell Qt to only give me the area(s) of the page that changed?
An update in a QGRaphicsView is different from the one in a QGraphicsScene. Update in the view is caused by the need to repaint the view. With or without changing the scene. This typical is from window (resize) and view changes (scroll). An change in the scene will also trigger an update to the view.
A change in a scene is the change of the content of the scene. Like adding or removing a item, scaling or translating of the transformation. This will emit the changed() signal. All views displaying that scene will also update themselves for the display.
For example. Scrolling a view around will not generate any scene update since nothing in the scene changed. The paint() function of items in the scene will be called to repaint. But no changed() signal will be emitted from the scene.
If you changed the scale of the scene for instance, the whole scene changed. In addition to the whole repaint, the scene will emit changed() signal and indicates the whole scene changed. But if you add a new item to the scene, changed() should indicate only the rect of the new item.
If you want to know what part of the scene need to be repainted, in addition to calling QGraphicsView::setViewportUpdateMode(), you need to install a event filter to the view and check for QEvent::Paint. Note that the region and rect in QPaintEvent is in local coordinate of the view, which can be different from the scene. But QGraphicsView has many mapping functions to do the conversion.