Qt widget app - different layouts based on orientation - qt

I have a qt widgets app that needs to rearrange itself if the screen orientation is portrait vs landscape or if the window is resized to be taller than it is wide. The app has all the same widgets and functionality in both modes, just laid out differently.
I realize you can move widgets around in layouts at runtime based on resize events, but this alone is not ideal because you can't see what it will look like beforehand in the designer. I also found this example in the archives: https://doc.qt.io/archives/qt-4.8/qt-widgets-orientation-example.html where they have two separate UIs can choose which to show when the screen resizes, but in this case every single UI change, slot connection, etc. must be done to both UIs which is also extremely cumbersome, not scalable, and error prone.
Is there a clean way to handle this situation? Or at least visualize both modes without running the app? Qt version is 5.12+

You could - theoretically - create 2 files or objects. One would be myLandscapeWidget and other myPortraitWidget. Surround them with a Loader and could do a
Loader {
id: myLoader
anchors.fill: parent
sourceComponent: Screen.orientation === Qt.LandscapeOrientation ? land : port
Component {
id: land
myLandscapeWidget {
width: 500
height: 100
}
}
Component {
id: port
myPortraitWidget {
width: 100
height: 500
visible: Screen.orientation !== Qt.LandscapeOrientation
}
}
}
Well, atleast thats the gist of it...
Some links:
Loader , Screen

Related

How to scroll with arrow keys in a Kirigami ScrollablePage?

The Qt QML based mobile/desktop convergent UI framework Kirigami provides a QML type ScrollablePage to support scrolling through content. Placing any visual QML item into it automatically makes it scrollable if it's larger than the ScrollablePage itself:
ScrollablePage is a Page that holds scrollable content, such as ListViews.
Scrolling and scrolling indicators will be automatically managed.
Kirigami.ScrollablePage {
id: root
//The rectangle will automatically be scrollable
Rectangle {
width: root.width
height: 99999
}
}
(source)
This provides scrollbars and allows scrolling with the mouse wheel, two-finger-scrolling with the touchpad and flicking ("click and throw") scrolling as we're used to from touchscreen devices.
However, it does not allow scrolling with any keyboard keys (Arrow Up / Down, Page Up / Down). How can I make that possible? The usual approach of doing Keys.onUpPressed: scrollBar.decrease() does not work because the ScrollablePage's scrollbar is not accessible as part of its public API.
Instructions
Use a Flickable to wrap the content items you put into your ScrollablePage. Then evaluate key press events in the Flickable and in response execute flick() to scroll the view. Example (combining examples from the Kirigami manual and from the Qt manual):
Kirigami.ScrollablePage {
id: root
Flickable {
focus: true
topMargin: 20; leftMargin: 20; bottomMargin: 20; rightMargin: 20
Keys.onUpPressed: flick(0, 800)
Keys.onDownPressed: flick(0, -800)
Rectangle {
width: root.width
height: 5000
}
}
}
Details and Explanation
While you can't access the scrollbar, you can access what the scrollbar uses to move the view: a Flickable instance. You just have to wrap it around the page's content. If you don't, ScrollablePage internally uses ScrollView to wrap your page's content in a Flickable anyway, but then you don't have a reference on it to execute flick().
Executing flick() does the same as when the user flicks the element, so the scrollbar position etc. will be updated alright.
If it still does not work, then (1) maybe you give too small pixel/second values to Flickable::flick() for scrolling to be visible or (2) maybe the initial Flickable::flickDeceleration values on your platform are messed up. These values are platform specific, so it can require some experimentation. On some platforms, setting them to zero during a flick() will help, while under Linux this is exactly the value preventing any scroll movement.
It is not necessary to enable ScrollablePage::keyboardNavigationEnabled for the above solution to work, since that is only for moving the currentItem of suitable content with the arrow keys (see below), and not for scrolling in general. It will even prevent ordinary scrolling in case your page content is an item view (ListView, GridView etc.).
Alternative solution for item views
If the content of your ScrollablePage is an item view (any QML object that has a currentItem property, such as ListView or GridView), then instead of wrapping that content in a Flickable just enable ScrollablePage::keyboardNavigationEnabled. It will allow you to move the currentItem with the Arrow Up and Arrow Down keys. That's what one usually wants for these views, even though it's not scrolling but rather keyboard navigation.

How to implement a master-details view Qt/QML on an Android tablet?

I am porting an iOS app to Qt/QML targeting an Android tablet.
I would like to keep the app's behavior similar to the original iOS version, which is based on a UISplitViewController.
In other words, I need to build a master-details view using the tablet in landscape mode.
In order to achieve this, I was thinking of using ListView backed by a ListModel as the master view so that whenever an item is selected in the ListView, a details view is dynamically displayed.
At the moment I am struggling to get even the basics right. Forgive me in advance if my questions seem too broad but here are a couple of stumbling blocks I am facing right away:
Most examples I have seen in QML seem to "hardcode" the device's screen size. For example, a typical skeleton project in Qt Creator will consist of the following code:
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Page1 {
}
}
As illustrated above the width and height properties of the window are hard-coded. In practice I need to set these values dynamically depending on the screen size of the physical device. How can I achieve this?
I also need to size my application screen in order to leave some space for the status bar area at the top of the screen (the area where the battery charge level is displayed).
Any code snippets to as well as pointers to online docs illustrating how to achieve this will be very appreciated!
Edit: Here is an updated main.qml, which sets the size of the application window using the device's screen size:
ApplicationWindow {
id: appWindow
visible: true
width: Screen.width
height: Screen.height
title: qsTr("Hello World")
Page1 {
}
}
The width, height and position of the application window can be further adapted to not overlap on the status bar area of the device.
However I am still stuck with the layout orientation, which defaults to portrait. How do I change the orientation of the layout to landscape?
Here is what I use:
// in the main window
property bool desktop: {
switch (Qt.platform.os) {
case "android":
case "ios":
case "winphone":
case "winrt":
return false
default: return true
}
}
visibility: desktop ? Window.AutomaticVisibility : Window.Maximized
As for forcing landscape orientation, add the following to the AndroidManifest.xml file in your project folder / android (not the one in the build directory) in the manifest -> application -> activity properties section:
android:screenOrientation="landscape"

What is best way to load either Rectangle(drawn by code) or Image in Qml?

I have a Qml file with one 'Rectangle' and an 'Image'. I want to load either one based on the property set in my.cpp file.
Please help me to find a best way to do this.
Actually I could think two possible ways to do the same:
1) First approach is to have both the element (the image and rectangle), defined in the respective QML, and to control their visibility from my.cpp file. I can have a property, this property can control the visibility of either of the two. Drawback in this approach is that even though only one element has to be displayed, two will be created.
2) Second approach is that we can have two components and load either one using "Loader" depending on the property set from the my.cpp.
Ex:
'
Component
{
id:img
Image
{
id: myImage
source:currentdir + "/img_production/Separator/myImage.png"
width: 10
height: 79
}
}
Component
{
id:rect
Rectangle
{
id:re
height: 82
width: 10
color: "#FFFFFF"
}
}
Loader
{
id: itemDisplay
sourceComponent: style.flag? rect : img
anchors.fill: parent.fill
}
'
Looking for some expert suggestions.
PS: style.flag is property set by my.cpp to Qml.
In this case, where both items are simple base types, I would go for the visibility change.
Having both elements instantiated directly makes it easier to refer to them in bindings or bind to their properties.
It also means their allocation only happens once, reducing the chance of memory fragmentation
If you are worried about the image consuming too much memory while the rectangle is shown you could still make the image`s source property depend in the visiblity value, i.e. unload the image when not showing the Image element.

Loader size dependent on source

I'm working on a little system of message dialog windows in QML. For this I'm using a container with a Loader to load the different messages (these are not just text but text and graphical symbols layouted hence loading a QML file for each individual message). By default these message windows have the same size, so I have my size information directly in the container. But some messages can be longer, therefore I'm looking for a way to use the height of my loaded component if it exceeds the default value.
The way I see it my problem can be split into three parts:
How to have a container sized by the dimensions of its children?
How to access the size information of the loaded component through my Loader object?
How to selectively use the larger size?
Any suggestions?
You can access loaded object using item keyword.
Example if your loader id is idLoader, then the created item is idLoader.item, you have 2 solutions to do what you want:
1:How to access the size information of the loaded component through my loader object?
Loader{
id:idLoader
width: (item !== null && typeof(item)!== 'undefined')? item.width : 0
height: (item !== null && typeof(item)!== 'undefined')? item.height: 0
}
2: How to have a container sized by the dimensions of its children? & How to selectivly use the larger size?
Loader{
id:idLoader
width: childrenRect.width
height : childrenRect.height
}
Here's an idea, untested. Take the max of the child's preferred height or a hard-coded minimum, whichever is larger.
Loader {
height: Math.max(item ? item.implicitHeight : 0, 200)
}

Resize mobile QML app

I'm working on a program to run Harmattan (N9) apps on Fremantle (N900). One of the problems is the resolution difference.
N900 has 800x480 screen and N9 854x480. Because of this part of the screen is cut off.
Can I fool (something) so that it thinks that the 800px screen contains 854px and paints all the elements (all the elements are painted as if 854px were availabe). I know that the shapes will be unnatural due to resizing one dimension, but it's better than a cut-off layout.
This has to be done without recompilation, as I can't access source code of every application for N9. I can't edit the qml files as they're built-in into qrc
Thanks in advance
marmistrz
If you code for different sizes of screens, you had better not use the raw values of screen dimensions. What you can do is saying that "this item with fill pw% of the width and ph% of the height". It will be automatically resized with the property binding. In your QML code, you can write something like this :
MyItem {
id: my_item
width: (pw / 100) * screen_width
height: (ph / 100) * screen_height
// ...
}

Resources