QML : Navigation between qml pages from design perception - c++

We need to develop a QtQuick project, where we have about 100 screens.
I had tried to make a demo project for the navigation which has three screens on button click. I had used the concepts of 'States' in the navigation between the pages. Initially I tried the same using 'Loader' but loader was not able to retain the previous state of page, it was re-loading the entire page during the navigation.
Below is the code snippet of main.qml
// import QtQuick 1.0 // to target S60 5th Edition or Maemo 5
import QtQuick 1.1
Rectangle {
id:main_rectangle
width: 360
height: 640
Page1{
id:page1
}
Page2{
id:page2
}
Page3{
id:page3
}
states: [
State {
name: "page2"
PropertyChanges { target: page3; visible:false; }
PropertyChanges { target: page1; visible:false; }
PropertyChanges { target: page2; visible:true; }
},
State {
name: "page1"
PropertyChanges { target: page3; visible:false; }
PropertyChanges { target: page2; visible:false; }
PropertyChanges { target: page1; visible:true; }
},
State {
name: "page3"
PropertyChanges { target: page1; visible:false; }
PropertyChanges { target: page2; visible:false; }
PropertyChanges { target: page3; visible:true; }
}
]
}
This runs well with the small POC with three screens, but its not feasible to define states for 100 screens.
From designing aspect we concluded to make a C++ controller we controls the states, visibility of various pages.
Need suggestions how to implement the 'State' logic in C++.

Here is the simplest solution in plain QML, using a configurable page list (like a model) + a Repeater + Loader items to not load everything at startup (lazy instanciation) and not destroy a page after hiding it (to not have to reload it if we come back to it) :
import QtQuick 1.1
Rectangle {
id: main_rectangle;
width: 360;
height: 640;
// Put the name of the QML files containing your pages (without the '.qml')
property variant pagesList : [
"Page1",
"Page2",
"Page3",
"Page4",
"Page5"
];
// Set this property to another file name to change page
property string currentPage : "Page1";
Repeater {
model: pagesList;
delegate: Loader {
active: false;
asynchronous: true;
anchors.fill: parent;
visible: (currentPage === modelData);
source: "%1.qml".arg(modelData)
onVisibleChanged: { loadIfNotLoaded(); }
Component.onCompleted: { loadIfNotLoaded(); }
function loadIfNotLoaded () {
// to load the file at first show
if (visible && !active) {
active = true;
}
}
}
}
}
Hope it helps !

I suggest to use StackView from Qt Quick Components. Here is its documentation.

Related

Black screen after existing FullScreen mode

I am trying to make a such thing:
I have a main window with a single button.
After pressing this button two semi transparent windows appear on all screens. They are in a FullScreen mode.
After 4 seconds screens dissapear.
Everything is ok. But when I cklick one of the screens, during process of disappearing, it becomes totaly black. How can I fix it?
// main.qml
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.Controls 2.2
Window {
id: main
visible: true
width: 100
height: 50
title: "Hello Splash World"
Button {
anchors.fill: parent
text: "Show splash"
onClicked: {
for (var i = 0; i < Qt.application.screens.length; ++i) {
var component = Qt.createComponent("SplashScreen.qml");
var window = component.createObject(main, {screen: Qt.application.screens[i]});
window.height = Qt.application.screens[i].height
window.width = Qt.application.screens[i].width
window.showSplash()
}
}
}
}
// SplashScreen.qml
import QtQuick 2.10
import QtQuick.Controls 2.2
ApplicationWindow {
id: splash
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground
color: "transparent"
Timer {
running: true
interval: 4000
onTriggered: hideSplash()
}
function showSplash() {
appearAnimation.start()
}
function hideSplash() {
disappearAnumation.start()
}
background: Rectangle {
id: bg
color: "black"
opacity: 0.8
}
SequentialAnimation {
id: appearAnimation
PropertyAction { target: splash; property: "visibility"; value: ApplicationWindow.FullScreen }
NumberAnimation { target: bg; property: "opacity"; duration: 1000; to: 0.8 }
}
SequentialAnimation {
id: disappearAnumation
NumberAnimation { target: bg; property: "opacity"; duration: 2000; to: 0 }
PropertyAction { target: splash; property: "visibility"; value: ApplicationWindow.Hidden }
}
}
I've come across some strange problems with repainting during further development of my program. For example, changing the size of the main form led to black form to. The solution I've found is to use OpenGL for rendering. You can do it by inserting this code:
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
Denis Popov answer is correct, but in this mode my application was a bit laggy. Problem wasn't occuring if mode was set to:
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
From the other hand this time I was getting following warning in the output everytime I was creating window:
DXGI WARNING: IDXGIFactory::CreateSwapChain: Blt-model swap effects (DXGI_SWAP_EFFECT_DISCARD and DXGI_SWAP_EFFECT_SEQUENTIAL) are legacy swap effects that are predominantly superceded by their flip-model counterparts (DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL and DXGI_SWAP_EFFECT_FLIP_DISCARD). Please consider updating your application to leverage flip-model swap effects to benefit from modern presentation enhancements. More information is available at http://aka.ms/dxgiflipmodel. [ MISCELLANEOUS WARNING #294: ]
Best solution I come up with so far is to run application in debug mode with one flag and in release/deployment with another:
#ifdef QT_DEBUG
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
#else
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif

Return from child qml to main one

I have several QML files, main one is the one that opens the ApplicationWindow when ever I try to get back from child QML to main, new window is opened again!
how can I prevent of doing this?
I thought that enabling a flag in child QML, but there may be other ways!
I tried stackview in QML
Is there any way to prevent from opening new page when I get back to main QML?
create a loader in main window and call every page into that loader when ever you need to change page just change loader's source
Window {
Loader{
id:myLoader
anchors.fill: parent
source: "LoginPage.qml"
}
Connections{
target: myLoader.item
onBack_clicked:{
loginid = ""
myLoader.source = "LoginPage.qml"
}
onSetting_clicked:{
myLoader.source = "Setting.qml"
}
}
}
and for child qml files : (for me Setting.qml)
Item {
signal back_clicked()
Button {
id: button1
anchors.right: parent.right
anchors.rightMargin: 15
onClicked: {
back_clicked()
}
}
}
but if you want to not destroy old page use SwipeView Or StackView:
SwipeView {
id: swipeView
clip: true
currentIndex: 0
Item{
id:firstPage
clip:true
//your page
}
Item{
id:secondPage
clip:true
//your page
}
}
and to change pages just change currentIndex
swipeView.currentIndex = 1
UPDATE:
StackView {
id: stackView
initialItem: one
}
Component {
id: one
Item{//your first page }
}
Component {
id: two
Item{//your second page }
}
and to push your pages :
stackView.push({ item: two})
//or
stackView.push("MySecondView.qml")
to get back to old or main page just pop it :
stackView.pop()

How to prevent recreation of page in a loader?

I am developing a Qt app on Win/Android. My question is very simple.
When my app starts, first a login page welcomes you.
If you want to configure server settings, ServerInfo.qml is opened in a loader. The login page and ServerInfo are loaded in the same loader.
My problem is that when I close ServerInfo.qml, then load loginpage.qml to loader, the loader creates a new instance of loginpage.qml. I don't want the page to be created again.
Here is my Qml code :
ApplicationWindow {
id:mainwindow
visible: true
width: 600
height: 800
x: Screen.width / 2 - width / 2
y: Screen.height / 2 - height / 2
menuBar:MenuBar{
Menu {
title:"Edit"
MenuItem {
text:"Sunucu Ayarları"
onTriggered: {
loader.source="ServerConfig.qml"
loader.anchors.centerIn=main
}
}
MenuItem {
text:"Çıkış"
onTriggered: {
Qt.quit();
}
}
}
}
Connections {
ignoreUnknownSignals: true
target: process
onProcessstart: {
busyrec.visible=true;
busyloader.item.busytext=text;
busyloader.item.busyrunnig=true;
}
onProcessstop: {
busyloader.item.busytext=text;
busyloader.item.busyrunnig=false;
busyloader.item.busytextcolor="blue"
}
Component.onCompleted: {
// process.onSuccesLogin();
//TaskResultm.taskresult.Malzemeler.push
console.log(TaskResultm.taskresult.serilaze());
}
}
Column {
anchors.fill: parent
Rectangle {
id:busyrec
width: parent.width
height: (parent.height/10)
visible:true
color:"green"
Loader {
id:busyloader
source:"BusyIndicator.qml"
anchors.fill: parent
}
Connections {
ignoreUnknownSignals: true
}
}
Rectangle {
id: main
// anchors.fill: parent
width: parent.width
height: (parent.height/10)*9
Loader {
id:loader
source: "LoginPage.qml"
anchors.centerIn:parent
focus:true
property bool valid: item !== null
}
Connections {
ignoreUnknownSignals: true
target: loader.valid? loader.item : null
onDirecttomainpage:{
// process.getWorkOrderList();
busyloader.item.switenabled=true;
busyloader.item.switopacity=1;
loader.anchors.fill=main;
loader.source="TaskNavigationMainScreen.qml";
}
onServerinfopageclose: {
loader.source="LoginPage.qml";
loader.anchors.centerIn=main;
}
}
}
}
onClosing: {
if(Qt.platform.os=="android") {
if(loader.item!==null)
{
if(loader.item.objectName==="tasknavigationmain")
if(loader.item.zemin===0)
close.accepted=true;
else
close.accepted=false;
}
}
else if (Qt.platform.os=="windows")
{
Qt.quit();
//if(loader.item!==null)
// if(loader.item.objectName==="tasknavigationmain")
// console.log(loader.item.stackViewItem.depth);
}
}
}
Just use a StackView instead of a Loader, it will keep previous "forms" alive as you push new ones on top, and you can always go back and forth.
A loader will load a single element, if you load another, the old one will be destroyed, there is no way around that.

Implementing the back button on bb10

I have one navigation pane and I disabled the back button in the main.qml, however I want to display the back button again to some part of the app. How do i implement this? here's my cpp
pane = qml->createRootObject<NavigationPane>();
// Set created root object as the application scene
app->setScene(pane);
qml->setContextProperty("cppObj", this);
}
void ApplicationUI::onLoginClicked() {
// create scene document from buttonclicked.qml asset
// set parent to created document to ensure it exists for the whole application lifetime
QmlDocument *qml = QmlDocument::create("asset:///projects.qml").parent(this);
qml->setContextProperty("cppObj", this);
Page* root = qml->createRootObject<Page>();
pane->push(root);
}
void ApplicationUI::onAddClicked() {
// create scene document from buttonclicked.qml asset
// set parent to created document to ensure it exists for the whole application lifetime
QmlDocument *qml = QmlDocument::create("asset:///addprojects.qml").parent(this);
Page* root = qml->createRootObject<Page>();
pane->push(root);
}
and here's my main where I disabled the back button
NavigationPane {
backButtonsVisible: false }
How do i make the back button active to some section of the app?
Let's say you have the following code:
StartPage
import bb.cascades 1.0
NavigationPane {
id: navPane
Page {
Container {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
layout: DockLayout {
}
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: "Next Page"
onClicked: {
var nextPage = page.createObject();
navPane.push(nextPage);
}
}
}
}
attachedObjects: [
ComponentDefinition {
id: page
source: "NextPage.qml"
}
]
}
NextPage:
import bb.cascades 1.0
Page {
// disables backButton (not peeking)
paneProperties: NavigationPaneProperties {
backButton: ActionItem {
enabled: false
}
}
// [0]
Container {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Fill
layout: DockLayout {
}
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
text: "Prev page"
onClicked: {
var page = navPane.pop();
if (page)
page.destroy();
}
}
} // [0]
// hides navigation bar
onCreationCompleted: {
navPane.backButtonsVisible = false;
}
}
Then you can completely disable backButton with this code in NextPage.qml
onCreationCompleted: {
navPane.backButtonsVisible = false;
}
Alternatively, if you want to have navigation pane visible but just Back Button disabled, use following in the same NextPage.qml file:
paneProperties: NavigationPaneProperties {
backButton: ActionItem {
enabled: false
}
}
Also, don't forget about peekEnabled property. Using peek BB10 feature user can move between sibling pages using sliding finger movement not touching any buttons on the screen.
It could be done in similar way:
onCreationCompleted: {
navPane.peekEnabled = false;
}
Hope it helps.

Autocomplete and suggesstion in QML textInput element

I have a QML textInput element like this:
TextBox.qml
FocusScope {
id: focusScope
property int fontSize: focusScope.height -30
property int textBoxWidth: parent.width * 0.8
property int textBoxHeight: 45
property string placeHolder: 'Type something...'
property bool isUserInTheMiddleOfEntringText: false
width: textBoxWidth
height: textBoxHeight
Rectangle {
width: parent.width
height: parent.height
border.color:'blue'
border.width: 3
radius: 0
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
Text {
id: typeSomething
anchors.fill: parent; anchors.rightMargin: 8
verticalAlignment: Text.AlignVCenter
text: placeHolder
color: 'red'
font.italic: true
font.pointSize: fontSize
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
focusScope.focus = true
textInput.openSoftwareInputPanel()
}
}
TextInput {
id: textInput
anchors {
right: parent.right
rightMargin: 8
left: clear.right
leftMargin: 8
verticalCenter: parent.verticalCenter
}
focus: true
selectByMouse: true
font.pointSize: fontSize
}
Text {
id: clear
text: '\u2717'
color: 'yellow'
font.pointSize: 25
opacity: 0
visible: readOnlyTextBox ? false : true
anchors {
left: parent.left
leftMargin: 8
verticalCenter: parent.verticalCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
textInput.text = ''
focusScope.focus = true;
textInput.openSoftwareInputPanel()
}
}
}
states: State {
name: 'hasText'; when: textInput.text != ''
PropertyChanges {
target: typeSomething
opacity: 0
}
PropertyChanges {
target: clear
opacity: 0.5
}
}
transitions: [
Transition {
from: ''; to: 'hasText'
NumberAnimation {
exclude: typeSomething
properties: 'opacity'
}
},
Transition {
from: 'hasText'; to: ''
NumberAnimation {
properties: 'opacity'
}
}
]
}
I want to add autocomplete and suggestions like google search to this text box. Autocomple get data from database and database return a list of dictionaries by a pyside SLOT.(or c++ slot)
How I can do this work?
Take a look at this code: https://github.com/jturcotte/liquid/blob/master/qml/content/SuggestionBox.qml
I bet it will do the job.
Edit:
Code that linked above is somewhat complicated and requires C++ backend, so I simplified it and made pure Qml example application, that you can play with, edit a little and apply to your needs. Sources can be found here. Most important things there are:
This implementation of SuggestionBox that uses some sort of model as it's source for completing/suggesting something
Its signal itemSelected(item) will be emitted every time user clicks on item
Main component of application that binds its LineEdit component to SuggestionBox
Note that code is quite rough and written for a sake of example.
I was looking for something very similar: a QML autocomplete component built around QML TextField, rather than the lower-level, more flexible but also more work intensive TextInput as in the question.
Since I could not find that, I implemented it. If anyone wants to use it: it's licensed under MIT and available as part of an application I am developing. You find the component in src/qml/AutoComplete.qml, and the application may serve as usage example. Features:
highlighting of autocompleted characters in bold, as in Google Search
Key bindings (navigating with arrow keys, Return / Enter, Esc to close completion box, Esc Esc to unfocus)
uses a simple QStringList as model for now, with the application showing how to update the model with live SQL database queries when the next key is pressed
heavily documented code, so it should be easy enough to adapt
Let me know if this is useful, I might then package it as a Qt QPM package or even try to make it mature enough to be added to the QML UI library KDE Kirigami.