I have a question regarding the "Qt 3D: Multi Viewport QML Example" Link
Is there a possibility to add a single view (one of the four in the example) into a separate widget. I tried to change the example but I only could add all four views to one widget.
The following code creates a camera which should be displayed in a separate Widget. see Picture
I am not sure if it is possible and how i can solve it.
SimpleCamera {
id: camera4
lens: cameraLens3
position: Qt.vector3d(100.0, 0.0, -6.0)
viewCenter: Qt.vector3d(0.0, 0.0, -6.0)
}
In the example, the four views are created using the classes Viewport and CameraSelector.
The Viewport class
The class Viewport defines the portion of the screen that the branch of the framegraph (that the Viewport node is part of) is rendered to. The portion is defined as (x, y, width, height). The coordinates of the whole screen are (0, 0, 1, 1).
If you have a look at the QuadViewportFrameGraph class that is part of the example, you'll see four viewports defined - one for each camera. The top left camera renders to the rectangle (0, 0, 0.5, 0.5) of the screen. The top right camera on the other hand renders to (0.5, 0, 0.5, 0.5), i.e. it uses half of the screen size as its x offset.
The CameraSelector class
This class defines which camera the branch of the framegraph uses to render content. If you look into the example you'll see a CameraSelector { id: someCamera } within each Viewport instance. This way, each Viewport gets its own camera.
Conclusion
If you only want one view, remove the four Viewports within the main Viewport and add one camera selector as the child of it. So your QuadViewportFrameGraph should look like this (without import statements):
RenderSettings {
id: quadViewportFrameGraph
property alias camera: cameraSelector.camera;
property alias window: surfaceSelector.surface
activeFrameGraph: RenderSurfaceSelector {
id: surfaceSelector
Viewport {
id: mainViewport
normalizedRect: Qt.rect(0, 0, 1, 1)
ClearBuffers {
buffers: ClearBuffers.ColorDepthBuffer
clearColor: Qt.rgba(0.6, 0.6, 0.6, 1.0)
CameraSelector { id: cameraSelector }
}
}
}
}
Of course you also have to adjust the code where you instantiate the QuadViewportFrameGraph and only set the one camera. If you now want all four views displayed in separate widgets you need to create four 3D windows and window containers and such a framegraph for each (with different cameras of course).
But be warned that the performance might be crappy if you create for distinct 3D windows. As far as I know, there are no other solutions to obtain 3D widgets.
Related
I want to display a large amount of content, for example, a grid of multiple images inside a window that is smaller than the content, similar to a geographical map but instead of a map, I want my own components as the "map". For this minimal working example, let's take for the content a grid of images with a total size of 1000x1000 with a window into this content of only 300x300.
I have tried 2 different approaches, but I will only go into detail of the first approach as that is the one that got me closest to my desired result:
I have tried the Flickable component but the content cannot be moved outside the predefined bounds, making the user unable to move the view in order to display all the parts of the content. So the simplest solution that I'm thinking about now is if I could remove these bounds from the Flickable component, but how?
I have also tried the Map component but it requires a "plugin" and I was unable to figure out how to use this component with my own content of an image grid.
The content that I want to show is something this
Grid {
columns: 5
spacing: 2
Repeater {
model: ListModel {
ListElement {
path: 'test1'
}
ListElement {
path: 'test2'
}
// ...
ListElement {
path: 'test25'
}
}
Rectangle {
width: 200
height: 200
Image {
anchors.fill: parent
source: 'file:' + path
}
}
}
}
I tried, putting this inside the Flickable like this
Flickable {
anchors.centerIn: parent
width: 300
height: 300
contentWidth: 1000
contentHeight: 1000
clip: true
// INSERT CUSTOM GRID COMPONENT HERE
}
This results in a 300x300 view inside the content as expected, but once you start to flick through the content to view different parts of it, you are stopped by the bounds preventing you from seeing anything outside these bounds. You can see it while dragging but once you release the view of the content is reset to these bounds.
So how do I remove these bounds? (Or is there a different component more suitable for my application?)
Here is a gif that shows how the content can be dragged passed the bounds, but once released it will only go up to the bounds and not further
I found the issue, I set the contentWidth and contentHeight of the Flickable incorrectly, this example works fine. The contentWidth and contentHeight determine the bounds in which you can flick.
In my QML application I am drawing a triangle manually using "Canvas" object. The problem is I cannot figure out how to change the drawn object size each time I resize the main window.
Preferably, it would be convenient If I could simply redraw the triangle each time a window resize occurs. But I don't know how could this be done in QML. In bare QT, I guess I would subscribe to window size changed signal. What is the proper way of doing this in QML?
Edit: The program is described here: Change polygon color dynamically
In my main window there is a rectangle called rectMain. It is always the same size as the window. Then inside that rectangle there is another one, called rectTemp. In that rectangle I draw the canvas.
Edit 2: So far I have figure out how to react manually on window size changes:
property int lastWindowWidth: 0
property int lastWindowHeight: 0
function windowSizeChanged()
{
if ((lastWindowWidth == width) && (lastWindowHeight == height))
return;
console.log("New height: ", height, " New width: ", width);
lastWindowWidth = width
lastWindowHeight = height
}
onHeightChanged: windowSizeChanged();
onWidthChanged: windowSizeChanged();
What is the difference between width/height and implicitWidth/Height in QML? When should one set the implicit dimensions instead of the regular? When should one ask the implicit dimensions instead of the regular from a component/item?
Generally, usage of implicitHeight/Width only makes sense within reusable components.
It gives a hint, of the natural size of the Item without enforcing this size.
Let's take a Image as an example. The natural size of the image would map one pixel from the image file to one pixel on the screen. But it allows us to stretch it, so the size is not enforced and can be overridden.
Let's say now, we want to have a gallery with pictures of unknown dimension, and we don't want to grow but only shrink them if necessary. So we need to store the natural size of the image. That is, where the implicit height comes into play.
Image {
width: Math.max(150, implicitWidth)
height: Math.max(150, implicitHeight)
}
In custom components, you have a choice on how to define the sizes.
The one choice is, to have all dimensions relative to the components root-node, maybe like this:
Item {
id: root
Rectangle {
width: root.width * 0.2
height: root.height * 0.2
color: 'red'
}
Rectangle {
x: 0.2 * root.width
y: 0.2 * root.height
width: root.width * 0.8
height: root.height * 0.8
color: 'green'
}
}
In this case, there is no natural size of the object. Everything works out perfectly for each size you set for the component.
On the other hand, you might have an object, that has a natural size - that happens, e.g. if you have absolute values in it
Item {
id: root
property alias model: repeater.model
Repeater {
id: repeater
delegate: Rectangle {
width: 100
height: 100
x: 102 * index
y: 102 * index
}
}
}
In this example you should provide the user with information about the natural size, where the content does not protude the item. The user might still decide to set a smaller size and deal with the protrusion, e.g. by clipping it, but he needs the information about the natural size to make his decision.
In many cases, childrenRect.height/width is a good measure for the implcitHeight/Width, but there are examples, where this is not a good idea. - e.g. when the content of the item has x: -500.
A real life example is the Flickable that is specifically designed to contain larger objects than its own size. Having the size of the Flickable to be equal to the content would not be natural.
Also be careful, when using scale in custom components, as the childrenRect will not know about the scaling.
Item {
id: root
implicitWidth: child.width * child.scale
implicitHeight: child.height * child.scale
Rectangle {
id: child
width: 100
height: 100
scale: 3
color: 'red'
}
}
And to your comment: I just don't understand why it is better to set implicitWidth/Height instead of setting width/height of a component's root dimension.
implicitWidht/Height are not a necessety - QtQuick could do without them. They exist for convenience and shall be convention.
Rule of Thumb
When you want to set dimension of a root node of a reusable component, set implicitWidth/Height.
In some cases, set it for non-root-nodes, if the nodes are exposed as a property.
Do so only, if you have a reason for it (many official components come without any).
When you use a component, set width/height.
I don't have the definitive answer but I can tell you what I found out. First, from the documentation:
implicitWidth : real
Defines the natural width or height of the Item if no width or height
is specified.
The default implicit size for most items is 0x0, however some items
have an inherent implicit size which cannot be overridden, for
example, Image and Text.
but less informative for width:
width
Defines the item's position and size.
The width and height reflect the actual size of the item in the scene. The implicit size is some kind of inherent property of the item itself.1
I use them as follows: When I create a new item and it can be resized, I set an implicit size inside the object2. When I'm using the object, I often set the real size explicitly from the outside.
The implicit size of an object can be overridden by setting height and width.
an example: TextWithBackground.qml
Item {
implicitWidth: text.implicitWidth
implicitHeight: text.implicitHeight
// the rectangle will expand to the real size of the item
Rectangle { anchors.fill: parent; color: "yellow" }
Text { id: text; text: "Lorem ipsum dolor..." }
}
an example: MyWindow.qml
Item {
width: 400
height: 300
TextWithBackground {
// half of the scene, but never smaller than its implicitWidth
width: Math.max(parent.width / 2, implicitWidth)
// the height of the element is equal to implicitHeight
// because height is not explicitly set
}
}
1) For some elements, like Text, the implicit height depends on the (not-implicit) width.
2) The implicit size usually depends on the implicit size of its children.
Implicit size is supposed to be used when calculating size of an item based on its contents. Whereas setting width or height on a parent item may affect the size of its children it should never be a case, when you set implicit size.
Rule of thumb
Implicit size should only "bubble up", i.e. children should never
lookup for implicit size of their parent to calculate their own
implicit size, neither parent should try to force implicit size of its
children.
If you would try to set width on a component similar to layout, that initially calculates its width from the width (rather than implicitWidth) of its child item and that child is affected by the size of a parent, you would end up with a binding loop.
This is why the property exists - to break cyclic dependencies when calculating size of an item based on its contents.
I am creating a simple 'tooltip' subclass that is a rounded rectangle and a small triangle that will be 'anchored' to another view.
I created a UILabel subclass and am overriding 'drawRect' to shrink the main label area and draw a triangle.
The 'roundRect' represents the rounded rectangle portion that should contain the full text.
This all works great, except that I am having trouble getting the full text to be shown within the 'roundRect'. It appears that the text just doesn't show up for the last line (i.e. where the triangle now occupies).
One other thing to note, I am using auto layout and have setup the constraints for the 'tooltipLabel' to fill the screen as needed. This works as expected, as reducing/adding more text shows the appropriate sized tooltip. But it seems like I need to somehow inform the 'tooltip' or 'auto layout' that the text should be fitted into the 'roundRect' portion of the 'tooltipLabel'.
Screenshot #1 uses this 'drawTextInRect' method and you can see that the full text is being shown, but overlaps into the 'triangle' area (plus it has no insets, which is not the desired look):
override public func drawTextInRect(rect: CGRect) {
super.drawTextInRect(rect)
// super.drawTextInRect(UIEdgeInsetsInsetRect(rect, UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)))
}
Screenshot #2 uses this 'drawTextInRect' method with the desired insets (also adds the triangleHeight so that space is not written into with text) and you can see that it cuts off the 2nd and 3rd lines of text, as they don't 'fit' within the 'roundRect' bounds:
override public func drawTextInRect(rect: CGRect) {
// super.drawTextInRect(rect)
super.drawTextInRect(UIEdgeInsetsInsetRect(self.roundRect, UIEdgeInsets(top: 10, left: 10, bottom: 10+self.triangleHeight, right: 10)))
}
Here is the 'drawRect' override:
override public func drawRect(rect: CGRect) {
self.roundRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height-self.triangleHeight)
self.triangleBezier.moveToPoint(CGPoint(x: self.roundRect.midX-self.triangleWidth/2, y: self.roundRect.maxY))
self.triangleBezier.addLineToPoint(CGPoint(x: rect.midX, y: rect.maxY))
self.triangleBezier.addLineToPoint(CGPoint(x: self.roundRect.midX+self.triangleWidth/2, y: self.roundRect.maxY))
self.triangleBezier.closePath()
self.roundRectBezier = UIBezierPath(roundedRect: self.roundRect, cornerRadius: 5.0)
self.roundRectBezier.appendPath(self.triangleBezier)
self.tooltipColor.setFill()
self.roundRectBezier.fill()
super.drawRect(rect)
}
I would actually not be subclassing UILabel for this, and make your own tooltip class composed of the outer view and the internal label with auto layout constraints. The internal label determines the whole height of the view.
Something like this with appropriately rounded off corners/triangle:
Alternatively, use UITextView instead if you want to assign padding: Adding space/padding to a UILabel
I have imported several 3D meshes from blender to form a human figure and I want to rotate the arm-meshes about a specific origin point so that it will look like the normal movement of an arm. In order to display the mesh, it needs to be included in the Entity class although I can not use the Rotation property inside the entity class which has a property of origin in itself. If there is a way to rotate meshes about specific point?
Below is my code. I have to rotate the shoulder mesh, but it does not rotate about a specific origin point so its rotation does not match up with normal body movement
Entity{
Mesh {
id: rightShoulder
source: "objects/RightShoulder2.obj"
}
Transform {
id: RightShoulderTransform
Scale { scale3D: Qt.vector3d(1.5, 1, 1.5) }
Rotate {
id:RightShoulderRotation
angle: headSlider.value
axis: Qt.vector3d(0, 1, 0)
}
Entity {
id: headEntity
components: [rightShoulder, material, RightShoulderTransform]
}
}
}
I found the way to solve it.
Center of Blender editor space is "origin" point of your object.
Like this:"origin"
Green point in mesh is origin point of selected object