I have a problem with understanding the import of QML files into another QML file.
I use Visual Studio 2022 with the Qt Tools Extension.
The project has the following structure in the QML directory:
|--src
|-----qml
|-------display
|-----------Display.qml
|-------x86
|-----------Main.qml
The resource.qrc file looks like this:
<RCC>
<qresource prefix="/screens/display">
<file>qml/display/Bottom.qml</file>
<file>qml/display/Content.qml</file>
<file>qml/display/Display.qml</file>
<file>qml/display/Footer.qml</file>
<file>qml/display/FooterButton.qml</file>
<file>qml/display/Header.qml</file>
<file>qml/display/HeaderButton.qml</file>
<file>qml/display/Left.qml</file>
<file>qml/display/Right.qml</file>
</qresource>
<qresource prefix="/screens/x86">
<file>qml/x86/Button.qml</file>
<file>qml/x86/Encoder.qml</file>
<file>qml/x86/Main.qml</file>
</qresource>
</RCC>
Main.qml in x86 folder should use the Display.qml from display folder like this:
GridLayout {
id: grid
anchors.fill: parent
rows: 4
columns: 3
Rectangle { id: left; Layout.row: 0; Layout.column: 0; Layout.rowSpan: 4; Layout.fillWidth: true; Layout.fillHeight: true; Layout.preferredWidth: _leftSideWidth; color: "whitesmoke" }
Rectangle { id: top; Layout.row: 0; Layout.column: 1; Layout.fillWidth: true; Layout.fillHeight: true; Layout.preferredHeight: _headerHeight; Layout.preferredWidth: _baseWidth; color: "lightgray" }
Display { Layout.row: 1; Layout.column: 1; Layout.fillWidth: true; Layout.fillHeight: true; Layout.preferredHeight: _baseHeight }
Rectangle { id: buttons1; Layout.row: 2; Layout.column: 1; Layout.fillWidth: true; Layout.fillHeight: true; Layout.preferredHeight: root.buttons1Height; color: "lightgray"
RowLayout { anchors.centerIn: parent; spacing: 20
Button { id: button1; height: root.buttonHeight; icon: "abort"; onButtonClicked: { console.log("Button1 clicked") } }
Button { id: button2; height: root.buttonHeight; icon: "abort"; onButtonClicked: { console.log("Button x2 clicked") } }
I tried several variants of import statements in Main.qml and variants of engine.addImportPath() but without knowing exactly in which form this has to be done it is a matter of luck to get it running.
Currently I get an error
qrc:/screens/x86/qml/x86/Main.qml:35:9: Display is not a type
Your .qrc file shows a prefix that you have to add on to the path of the file. So your import should look like this:
import "qrc:/screens/display/qml/display"
Related
I'm trying to create accordion qml control like this.
First I thought that I can use combobox and customize it but now I think it is impossible.
Is there any standerd control that I can use? If not can you help me with controls structure?
Just playing with QML
PanelItem.qml
import QtQuick 2.7
import QtQuick.Layouts 1.2
Item {
default property var contentItem: null
property string title: "panel"
id: root
Layout.fillWidth: true
height: 30
Layout.fillHeight: current
property bool current: false
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: bar
Layout.fillWidth: true
height: 30
color: root.current ? "#81BEF7" : "#CEECF5"
Text {
anchors.fill: parent
anchors.margins: 10
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: root.title
}
Text {
anchors{
right: parent.right
top: parent.top
bottom: parent.bottom
margins: 10
}
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
text: "^"
rotation: root.current ? "180" : 0
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
root.current = !root.current;
if(root.parent.currentItem !== null)
root.parent.currentItem.current = false;
root.parent.currentItem = root;
}
}
}
Rectangle {
id: container
Layout.fillWidth: true
anchors.top: bar.bottom
implicitHeight: root.height - bar.height
clip: true
Behavior on implicitHeight {
PropertyAnimation { duration: 100 }
}
}
Component.onCompleted: {
if(root.contentItem !== null)
root.contentItem.parent = container;
}
}
}
usage:
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Window 2.0
Window {
visible: true
width: 400
height: 400
ColumnLayout {
anchors.fill: parent
spacing: 1
property var currentItem: null
PanelItem {
title: "Panel 1"
Rectangle {
color: "orange"
anchors.fill: parent
}
}
PanelItem {
title: "Panel 2"
Rectangle {
color: "lightgreen"
anchors.fill: parent
}
}
PanelItem {
title: "Panel 3"
Rectangle {
color: "lightblue"
anchors.fill: parent
}
}
PanelItem {
title: "Panel 4"
Rectangle {
color: "yellow"
anchors.fill: parent
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
What about using this open source component which I did here
Accordion component and used here Accordion component example.
You only need to initialize:
Components.Accordion {
id: acordion
anchors.fill: parent
anchors.margins: 10
}
And create the data dynamically like this:
propertyAcordion.model = [
{
'menuTitle': value,
'children': [
{
'menuTitle': value,
'children': [
...
Updating the MouseArea click part as below with some added condition. Thanks to folibis for this qml accordian menu.
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
root.current = !root.current;
if(root.parent.currentItem !== null) {
if(root.parent.currentItem !== root)
root.parent.currentItem.current = false;
}
root.parent.currentItem = root;
}
}
What i want to do here is to prevent the tab and enter to jump the focus to a specific control but go to the next.
So for example lets say i have 3 sequencial TextField
i'm focused on the first TextField now i press tab and instead of jumping to the second TextField the focus goes to the third TextField.
A full code example:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
title: "Stack"
visible: true
width: 1400
Page {
id: page
anchors.fill: parent
property int responsiveWidth: 1000
property int maximumWidth: 900
ScrollView {
id:configScroll
anchors.fill: parent
function scrollToY(y) {
configScroll.flickableItem.contentY = y-30
}
GridLayout {
columns: 2
Keys.onPressed: {
if(event.key==Qt.Key_Return)
for (var i = 0; i < children.length; ++i)
if (children[i].focus) {
children[i].nextItemInFocusChain().forceActiveFocus()
break
}
}
width: page.width > page.responsiveWidth ? page.maximumWidth : page.width
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: page.width > page.responsiveWidth ? (page.width - childrenRect.width)/2 : 10
anchors.rightMargin: page.width > page.responsiveWidth ? 0 : 10
Label {
text: "Company Name"
color: "red"
Layout.fillWidth: true
}
TextField {
objectName: "company_name"
font.bold: true
Layout.fillWidth: true
Layout.rightMargin: 10
onFocusChanged: if(focus) { configScroll.scrollToY(y); }
}
Label {
text: "tab or enter passes this TextField"
color: "red"
Layout.fillWidth: true
}
TextField {
objectName: "company_name2"
font.bold: true
Layout.fillWidth: true
Layout.rightMargin: 10
onFocusChanged: if(focus) { configScroll.scrollToY(y); }
}
Label {
text: "label"
color: "red"
Layout.fillWidth: true
}
TextField {
objectName: "company_name"
font.bold: true
Layout.fillWidth: true
Layout.rightMargin: 10
onFocusChanged: if(focus) { configScroll.scrollToY(y); }
}
}
}
}
}
You can use the QML Type KeyNavigation to setup custom navigation, take a look at the documentation: KeyNavigation QML Type
You can set the KeyNavigation.tab property to navigate to a specific id like this:
TextField {
id: field1
objectName: "company_name"
font.bold: true
Layout.fillWidth: true
Layout.rightMargin: 10
onFocusChanged: if(focus) { configScroll.scrollToY(y); }
KeyNavigation.tab: field3
}
For navigation with enter-key here is a solution for this specific situation:
children[i].nextItemInFocusChain().nextItemInFocusChain().forceActiveFocus()
I'm trying to avoid this annoying overlapping that both SideView and ListView seem to fancy. Here is an example which demonstrates the issue:
Note: Look at the green rectangle on the left when you swipe the SwipeView and also the tabs when you scroll down the ListView
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2
Window {
id: window
visible: true
width: 600
height: 480
title: "Demo"
RowLayout {
id: layoutTopLevel
anchors.fill: parent
spacing: 0
Rectangle {
id: sidebarView
Layout.preferredWidth: layoutTopLevel.width * .3
Layout.fillHeight: true
color: "#453"
border.width: 1
}
ColumnLayout {
id: sideViewLayout
spacing: 0
SwipeView {
id: sideView
currentIndex: sideViewPageIndicator.currentIndex
Layout.fillWidth: true
Layout.preferredHeight: layoutTopLevel.height * .9
Page {
id: page1
header: Text {
text: "Page 1"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
}
Page {
id: page2
header: Text {
text: "Page 2"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
TabView {
id: page2TabView
width: parent.width
height: parent.height
anchors.margins: 4
tabPosition: Qt.BottomEdge
Tab {
title: qsTr("Tab 1")
}
Tab {
title: qsTr("Tab 2")
ColumnLayout {
Text {
text: "Text 1"
Layout.alignment: Qt.AlignCenter
}
Text {
text: "Text 2"
Layout.alignment: Qt.AlignCenter
}
ListView {
width: parent.width
height: parent.height
model: ListModel {
ListElement {
name: "Element 1"
}
ListElement {
name: "Element 2"
}
ListElement {
name: "Element 3"
}
ListElement {
name: "Element 4"
}
ListElement {
name: "Element 5"
}
ListElement {
name: "Element 6"
}
}
delegate: Text {
text: name
}
}
}
}
style: TabViewStyle {
tabsAlignment: Qt.AlignHCenter
frameOverlap: 1
tab: Rectangle {
border.width: styleData.selected
implicitWidth: Math.max(text.width + 4, 80)
implicitHeight: 20
radius: 10
Text {
id: text
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "white" : "black"
}
color: styleData.selected ? "#654" : "white"
}
frame: Rectangle {
color: "white"
}
}
}
}
}
PageIndicator {
id: sideViewPageIndicator
count: sideView.count
interactive: true
anchors.bottom: sideView.bottom
anchors.bottomMargin: -45
anchors.horizontalCenter: parent.horizontalCenter
delegate: Rectangle {
height: 30
width: 30
antialiasing: true
color: "#654"
radius: 10
opacity: index === sideView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
Behavior on opacity {
OpacityAnimator {
duration: 100
}
}
}
}
}
}
}
Use clip: true
Which clips the content which goes out of its boundaries.
I accidentally came across an example of a ListView while looking into another problem I had and I saw the clip property there. I have completely missed it while looking into the docs of both SideView and ListView. Basically when you set it to true the view no longer covers other components and this is exactly what I want. See comment by #Mitch on why this is not enabled by default.
I have Rectangle filled with MouseArea which on onPressAndHold() handler reveals second Rectangle and transfers drag action to that Rectangle. The problem is that when I move that second Rectangle over DropArea it doesn't notify about any actions (onEntered, onExited, onDropped). I tried to do this in many combinations but it has never worked. Here is an example, am I missing something?
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
id: appDrawerRoot
visible: true
width: 360; height: 360
property bool isRectVisible: false
Rectangle{
id:rect
color: "blue"
x:50; y:50
width: 50; height: 50
MouseArea{
anchors.fill: parent
onPressed: {
cloneRect.x = rect.x
cloneRect.y = rect.y
}
onPressAndHold: {
isRectVisible = true
drag.target = cloneRect
}
onReleased: {
drag.target = undefined
isRectVisible = false
cloneRect.x = rect.x
cloneRect.y = rect.y +100
}
}
}
Item{
id: cloneRect
width: 50; height:50
visible: isRectVisible
MouseArea{
id: mouseArea
width:50; height:50
anchors.centerIn: parent
Rectangle{
id:tile
width: 50; height:50
color:"black"
opacity: 0.5
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.hotSpot.x: 25
Drag.hotSpot.y: 25
}
}
}
DropArea {
id:dropArea
x:153
y:158
z:-1
width:100; height: 100
Rectangle{
anchors.fill: parent
color: "Green"
}
onEntered: {
drag.source.opacity = 1
console.log("ENTERED")
}
onExited: {
drag.source.opacity = 0.5
console.log("EXITED")
}
onDropped:
{
console.log("DROPPED")
}
}
}
The main problem with your code is that you don't set the active property of the drag. Modify you code like this:
//..........................
Item{
id: cloneRect
width: 50; height:50
visible: isRectVisible
Drag.active: visible // Add this line of code
//.....................
For more information please refer to Qt examples. At Qt Creator's "Welcome" screen hit "Examples" button and search for "drag and drop qml".
I didn't found any good resource how to use this component and it still fails layout of my app (check that right properties inspector). What i did wrong?
without ScrollView
with ScrollView
scroll that code down please, the scrollview is defined last
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.1
ApplicationWindow {
title: qsTr("Hello World")
width: 1400
height: 800
color: "#414141"
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
ColumnLayout {
anchors.fill: parent
Rectangle {
color: "#414141"
Layout.fillWidth: true
Layout.preferredHeight: 50
MyLabel {
text: "Toolbar"
}
}
SplitView {
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Horizontal
handleDelegate: MyVSlider {}
SplitView {
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Vertical
handleDelegate: MyHSlider {}
SplitView {
handleDelegate: MyVSlider {}
Layout.fillHeight: true
Layout.fillWidth: true
orientation: Qt.Horizontal
Rectangle {
color: "#565656"
Layout.fillHeight: true
Layout.preferredWidth: 200
Layout.minimumWidth: 200
MyLabel {
text: "Tree view"
}
}
Rectangle {
color: "#565656"
Layout.fillHeight: true
Layout.fillWidth: true
Layout.minimumWidth: 500
Layout.preferredHeight: 300
MyLabel {
text: "Scene view"
}
}
}
Rectangle {
color: "#565656"
Layout.fillWidth: true
Layout.preferredHeight: 200
Layout.minimumHeight: 200
MyLabel {
text: "Console output"
}
}
}
Rectangle {
id: inspector
color: "#565656"
Layout.fillHeight: true
Layout.preferredWidth: 200
Layout.minimumWidth: 200
MyLabel {
text: "Properties inspector"
}
}
ScrollView {
contentItem: inspector
}
}
}
}
Are you trying to get your inspector element to be scrollable? You'll want to put the element to be scrolled within the the ScrollView.
i.e.
ScrollView {
Rectangle {
id: inspector
color: "#565656"
Layout.fillHeight: true
Layout.preferredWidth: 200
Layout.minimumWidth: 200
MyLabel {
text: "Properties inspector"
}
// Make the thing really big.
width: 1000
height: 1000
}
}
This will cause your inspector to show up with scroll bars if you set the width and height as I did above.