QML TabView in ColumnLayout - qml

I am trying to modify Gallery example. I want to add Button under TabView. So, I put TabView and Button into ColumnLayout, here is code:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Window 2.0
Window {
visible: true
title: "settings"
width: 600
height: 400
ColumnLayout{
anchors.fill: parent
TabView {
anchors.right: parent.right
anchors.left: parent.left
Tab {
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
Controls { }
}
Tab {
title: "Styles"
Controls { }
}
Tab {
title: "Layouts"
Controls { }
}
}
RowLayout{
anchors.right: parent.right
anchors.left: parent.left
Button{
text: "ok"
}
}
}
}
However, when I resize window okButton stands under tab controls. How should I fix code?

When you have defined a Layout, each element added has access to specific properties related to the layout itself. These properties are useful to position the element inside the space covered from the layout. Confront what is described here.
Hence, you should modify the ColumnLayout like this:
ColumnLayout {
anchors.fill: parent
TabView {
id:frame
enabled: enabledCheck.checked
tabPosition: controlPage.item ? controlPage.item.tabPosition : Qt.TopEdge
Layout.fillHeight: true // fill the available space vertically
Layout.fillWidth: true // fill the available space horizontally
Layout.row: 0 // item in the first row of the column
anchors.margins: Qt.platform.os === "osx" ? 12 : 2
Tab {
id: controlPage
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
ModelView { }
}
Tab {
title: "Styles"
Styles { anchors.fill: parent }
}
Tab {
title: "Layouts"
Layouts { anchors.fill:parent }
}
}
Button {
text: "ok"
Layout.row: 1 // item in the second row of the column
Layout.alignment: Qt.AlignCenter // simple center the button in its spatial slot
}
}
You don't need a RowLayout for the button. It should be placed in the second row of the ColumnLayout you have defined, since it is a simple component. A sub-layout could be useful in case of multiple elements on the same row, e.g. two or more buttons.
Note also that anchoring is just used for the ColumnLayout to "stretch" and fit the window. All the other operations are executed via the layout properties. For general rules take a look at this other article.

Related

SplitView inside ScrollView

Putting SplitView inside ScrollView breaks its work: for some reason it stops responding to mouse events and therefore resizing its children by dragging the splitter becomes impossible.
import QtQuick 2.7
import QtQuick.Controls 2.15
ScrollView {
width: 800
SplitView {
anchors {
top: parent.top
right: parent.right
left: parent.left
}
orientation: Qt.Vertical
Repeater {
model: 3
Rectangle {
SplitView.fillWidth: true
SplitView.minimumHeight: 150
color: "lightsteelblue"
Text {
anchors.centerIn: parent
text: "Row " + index
}
}
}
}
}
Is this a bug or am I missing something?

Reusable confirmation prompt in QML

I need a confirmation or alert dialog when user presses a button. Based on if they choose 'yes' or 'no', different actions are triggered. The challenge is that I have two buttons which pops such a dialog and it's not quite straightforward how to do that in QML. Here is the code (my demo application):
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
function areYouSure()
{
prompt.visible = true
}
MainForm {
anchors.fill: parent
Button {
id: buttonA
anchors.left: parent.left
anchors.top: parent.top
text: "Button A"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
Button {
id: buttonB
anchors.right: parent.right
anchors.top: parent.top
text: "Button B"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
}
Prompt {
anchors.fill: parent
id: prompt
visible: false
onCancelled: {
console.log("Cancel was pressed")
// but how can I tell which button's cancel as pressed?
}
onAccepted: {
console.log("Accept was pressed")
// same for which button's Ok?
}
}
}
Prompt.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Rectangle
{
id: root
width: parent.width
property string message: "Are you Sure?"
signal cancelled;
signal accepted;
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
cancelled()
}
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
accepted()
}
}
}
}
In traditional programming, an individual dialog pops up which respond exactly to that question and than we respond to its cancelled() or accepted() signals. In QML we can't really do that, right? What is the best way to know which button was pressed? The irony is that even the right signals are emitted, we just can't seem to act on them.
Well, first and foremost you should really have a look at Dialogs module since it provides what would be a ready made solution for you, i.e. MessageDialog.
That said, you can achieve a customisation in different ways, including redefining the handlers or passing the ids. If the action to perform are simple (e.g. a function call) you can dynamically create even the dialog and bind the signals with the desired behaviour. Customisation can obviously go further, changing title and text.
Here is a simple example which follows the last approach and prints different texts depending on the pressed button. Once the dialog is set to not visible it is destroyed via the destroy function.
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
ApplicationWindow {
id: win
title: qsTr("MultiDialog")
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
onClicked: {
var d1 = compDialog.createObject(win)
// change "title" & "text"?
d1.accepted.connect(function(){
console.info("accepted: " + text)
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
})
d1.visible = true
}
}
Button {
text: "Button 2"
onClicked: {
var d2 = compDialog.createObject(win)
// change "title" & "text"?
d2.accepted.connect(function(){
console.info("accepted: " + text)
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
})
d2.visible = true
}
}
}
Component {
id: compDialog
MessageDialog {
title: "May I have your attention please"
text: "It's so cool that you are using Qt Quick."
onVisibleChanged: if(!visible) destroy(1)
standardButtons: StandardButton.Cancel | StandardButton.Ok
}
}
}
If you want to use Rectangle or are forced to use it, then you can still use this approach. Dynamic creation of objects is NOT related to the usage of MessageDialog and can be used (and should be used) to reduce the number of objects kept instanced throughout application lifetime. Have a look here for more details about that.
The following example uses the very same dialog component you defined (with some small modifications. As you can see the code is almost identical. I've just moved the destruction of the object at the end of the signal handlers. In this case I've also changed the value of the unique property defined in the component, i.e. message, to show you complete customization.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component {
id: prompt
Rectangle {
id: root
anchors.fill: parent
property string message: "Are you Sure?"
signal rejected()
signal accepted()
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: rejected()
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: accepted()
}
}
}
}
}
If your component is not inlined as I did with Component but it's kept in another file you can use createComponent as depicted in the link provided above. The code of your main window would look like this:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
property var prompt
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component.onCompleted: prompt = Qt.createComponent("Prompt.qml");
}
You should always check that component creation is correcly carried out (I didn't do it for the sake of brevity). That said, the code is identical to the previous one.
Last but not least, I've noticed an error in your code: signals must always be declared with parenthesis, even when no parameter is emitted. It should be signal accepted(), not signal accepted, same goes for the other signal and any other signal declaration.

How to hide a QML Window when opening a other QML Window

I need to hide The QML Window when opening the another QML Window while clicking the button,I use Loader to open the another QML Window and its only hide the QML form components not QML Window,but I currently use window component to opens the QML Window
Here is my code :
Button {
id: button2
x: 19
y: 54
width: 114
height: 25
text: qsTr("DIFF-R")
style: ButtonStyle {
background: Rectangle {
implicitWidth: 10
implicitHeight: 25
border.width: control.activeFocus ? 2 : 1
border.color: "#555"
radius: 10
gradient: Gradient {
GradientStop { position: 0 ; color: control.pressed ? "#ddd" : "#fff" }
GradientStop { position: 1 ; color: control.pressed ? "#8ad993" : "#528dc8" }
}
}
}
onClicked:{
/*pagesource.source="screen2.qml"
button1.visible="false"
button2.visible="false"
text1.visible="false"
text2.visible="false"
text3.visible="false"
text4.visible="false"
textField1.visible="false"
textField2.visible="false"
textField3.visible="false"
image1.visible="false"*/
var component = Qt.createComponent("screen2.qml")
var window = component.createObject(root)
window.show("screen2.qml") }
The above code only navigates the QML Window while the Button is clicked whereas I need to Hide the QML Window.
I see no code when you hide main window. Please, read this article since your code say nothing about the problem.
This is small example when main window hides when popup shows. May be it can be useful for you.
Window {
id: mainWindow
title: "Main window"
width: 600
height: 600
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Component {
id: popupWindow
Window {
title: "Popup window"
width: 400
height: 400
visible: true
flags: Qt.Dialog
modality: Qt.ApplicationModal
Text {
anchors.centerIn: parent
text: "Close me to show main window"
}
}
}
Button {
anchors.centerIn: parent
text: "Show popup window"
onClicked: {
var window = popupWindow.createObject(mainWindow);
mainWindow.hide();
conn.target = window;
}
}
Connections {
id: conn
onVisibleChanged: {
mainWindow.show();
}
}
}

How to make TableView Items draggable

I’ve a TableView and have implemented my own item delegate for it. I want to be able to drag it out and place it somewhere else. How do I do it
itemDelegate: Text {
id: objMainText
anchors.horizontalCenter: parent.horizontalCenter
elide: styleData.elideMode
color: "yellow"
text: styleData.value.get(0).content //assume this is correct
MouseArea {
id: objDragArea
anchors.fill: parent
drag.target: objDragableText
drag.axis: Drag.XAndYAxis
hoverEnabled: true
onEntered: {
console.log("Hover Captured") //This gets printed
}
onClicked: {
console.log("Detected") //This NEVER gets printed
}
Text {
id: objDragableText
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.active: objDragArea.drag.active
opacity: Drag.active / 2
text: objMainText.text
color: objMainText.color
states: State {
when: { objDragArea.drag.active }
AnchorChanges {
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
}
}
}
Don’t mind if there are a few brackets less here and there. Those I’m taking care of ofcourse. But why can’t I drag objDragableText and how do i do it?
Also, onClicked is captured as in the comments above but not onPressed. How do I also do this?
{Qt 5.1 RC 1 - Win7 - MinGw 4.8}

Hide the highlight of a ListView while scrolling

I am building a Qt5 application based on Qt-Quick 2 for the UI. I have an issue while displaying a ListView with an highlight component. When I scroll the ListView the highlight rectangle is visible outside of the ListView and I can't find a way to avoid it.
Here is an example of the issue with a minimal QML file:
import QtQuick 2.0
Rectangle {
width: 360; height: 600
ListView {
width: 350; height: 200
anchors.centerIn: parent
id: myList
model: myModel
highlight: highlightBar
delegate: Item {
width: 400; height: 20
Text { text: name }
MouseArea {
id: mArea
anchors.fill: parent
onClicked: { myList.currentIndex = index; }
}
}
}
Component {
id: highlightBar
Rectangle {
width: parent.width; height: 20
color: "#FFFF88"
}
}
ListModel {
id: myModel
}
/* Fill the model with default values on startup */
Component.onCompleted: {
for(var i = 0; i < 100; i++) {
myModel.append({ name: "Big Animal : " + i});
}
}
}
Is there a way to "limit" a component to its parent borders or to hide the highlight component while scrolling?
As reported by the documentation:
Note: Views do not enable clip automatically. If the view is not clipped by another item or the screen, it will be necessary to set clip: true in order to have the out of view items clipped nicely.
Hence, what you are experiencing is a common behaviour and you should either 1) clip the view via other Items (e.g. a header Rectangle and a footer Rectangle with z:infinite or simply set the clip property to true, i.e.
ListView{
//...
clip:true
//...
}
Clipping has some perfomance disavantages which can greatly affect the application as it grows. Hence, its usage, especially outside the views scenario, should be evaluated carefully.