I try to make a cell editable using a tableview in qt. I have found a few examples and came up with the following:
TableView {
id: tableView
objectName: "tableView"
horizontalScrollBarPolicy: -1
selectionMode: SelectionMode.SingleSelection
Layout.minimumWidth: 300
Layout.fillHeight: true
Layout.fillWidth: true
model: trackableInfoModel
itemDelegate: Rectangle {
Text {
anchors.verticalCenter: parent.verticalCenter
text: styleData.value
}
MouseArea {
id: cellMouseArea
anchors.fill: parent
onClicked: {
if(styleData.column === 2){
//do something
}
}
}
}
From what I found it looks like I need an itemDelegate to paint each cell. Then I add a MouseArea to the cell and check which cell was selected. In my case I only need to react on the cells in column 2.
The thing is when I use the code shown above I get the error that:
JavaScipt blocks are not supported in a QT Quick UI form. (M223)
Because of that I tried to register a property alias for cellMouseArea like this:
property alias cellMouseArea : cellMouseArea
However that leads to this error:
qrc:/EditPageForm.ui.qml:24 Invalid alias reference. Unable to find id "cellMouseArea"
Overlay cell with TextInput on click.
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TableView {
id: tableView
objectName: "tableView"
horizontalScrollBarPolicy: -1
selectionMode: SelectionMode.SingleSelection
anchors.fill: parent
TableViewColumn {
id: titleColumn
title: "Title"
role: "title"
movable: false
resizable: false
width: tableView.viewport.width - authorColumn.width
}
TableViewColumn {
id: authorColumn
title: "Author"
role: "author"
movable: false
resizable: false
width: tableView.viewport.width / 3
}
model: ListModel {
id: libraryModel
ListElement {
title: "A Masterpiece"
author: "Gabriel"
}
ListElement {
title: "Brilliance"
author: "Jens"
}
ListElement {
title: "Outstanding"
author: "Frederik"
}
}
itemDelegate: Rectangle {
Text {
anchors { verticalCenter: parent.verticalCenter; left: parent.left }
color: "black"
text: styleData.value
}
MouseArea {
id: cellMouseArea
anchors.fill: parent
onClicked: {
// Column index are zero based
if(styleData.column === 1){
loader.visible = true
loader.item.forceActiveFocus()
}
}
}
Loader {
id: loader
anchors { verticalCenter: parent.verticalCenter; left: parent.left}
height: parent.height
width: parent.width
visible: false
sourceComponent: visible ? input : undefined
Component {
id: input
TextField {
anchors { fill: parent }
text: ""
onAccepted:{
// DO STUFF
loader.visible = false
}
onActiveFocusChanged: {
if (!activeFocus) {
loader.visible = false
}
}
}
}
}
}
}
}
Related
I am using Qt/QML. on my touch screen, I have a side drawer that enables when user touches the menu button and it brings a side panel to the screen. My ListView holds a list model which has 7 ListElement in it. Which further bring users to separate setting pages.
I want one of the List Element be visible based on a bool value. In short I like to make the visibility conditional for that List Element. How can I do it?
model: ListModel {
ListElement { title: "abcd"; iconsource: "qrc:/qml/images/abcd.png"; source: "qrc:/qml/abcd.qml"; ftoption: 243; visible: true}
ListElement { title: "xyz"; iconsource: "qrc:/qml/images/xyz.png"; source: "qrc:/qml/xyz.qml"; ftoption: 243; visible: true}
ListElement { title: "pqr"; iconsource: "qrc:/qml/images/pqr.png"; source: "qrc:/qml/pqr.qml"; ftoption: 243; visible: true}
}
delegate: ItemDelegate {
id: menu_item
width: parent.width
height: Style.footerHeight
visible: (model.title === "pqr") ? menuVisibility : true
Timer {
interval: 5000; running: true; repeat: true
onTriggered: {(model.title === "pqr") ? model.visible = menuVisibility : model.visible = true}
}
Just add visible (can be other name though) role in your model.
Simple example:
(You can drop the Timer it is just for illustration)
import QtQuick 2.15
import QtQuick.Controls 2.15
Rectangle {
anchors.fill: parent;
Grid {
spacing: 10
anchors.centerIn: parent;
Repeater {
anchors.fill: parent;
model: ListModel {
ListElement {
visible: true
}
ListElement {
visible: false
}
ListElement {
visible: true
}
ListElement {
visible: false
}
ListElement {
visible: true
}
ListElement {
visible: false
}
}
delegate:
Rectangle {
width: 100; height: 100;
visible: model.visible
color: "red"
Timer {
interval: 500; running: true; repeat: true
onTriggered: {if (!visible) visible = true; else visible= Qt.binding(function(){return model.visible})}
}
}
}
}
}
What I want to do is create a new object inside a component, which can be done with the Component component of qml, but as an argument I want to pass another component which will be in a different .qmlfile.
I'm going to illustrate what I'm trying to do.
I have a tab bar accordion component I've done:
When I click on the button I want a new tab to be created which will have its own contents!
I provide the code I've used below:
import QtQuick 2.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Window 2.3
ApplicationWindow {
visible: true
width: 640
height: 500
title: qsTr("Tabbars")
Button{
id: button
text: "add new tab dynamically"
onClicked: item.createPanelItem()
anchors.top:parent.top
anchors.left:parent.left
height: 20
width: parent.width
}
Item{
id:item
//anchors.fill:parent
anchors.top: button.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
ScrollView{
anchors.fill:parent
Column {
id: column
width:item.width
property int currentItem: 0
PanelItem {
id:panel1
index:0
title: "Panel 1"
width:parent.width
content: Item {
property string title: "teste"
height: configContent.implicitHeight
width: configContent.implicitWidth
ColumnLayout{
id:configContent
anchors.topMargin: 10
anchors.bottomMargin: 10
anchors.fill:parent
TextField {
id: companyNameText1
placeholderText: qsTr("Company name")
Layout.fillWidth: true
selectByMouse: true
}
ComboBox {
id: languagesComboBox1
textRole: "text"
objectName: "language"
Layout.fillWidth: true
model: ListModel {
ListElement {text: QT_TR_NOOP("English"); oid: 0}
ListElement {text: QT_TR_NOOP("Portuguese"); oid: 1}
ListElement {text: QT_TR_NOOP("Spanish"); oid: 2}
ListElement {text: QT_TR_NOOP("Italian"); oid: 3}
ListElement {text: QT_TR_NOOP("French"); oid: 4}
ListElement {text: QT_TR_NOOP("Portuguese(Brasil)"); oid: 5}
}
}
ComboBox {
id: devSndrModeComboBox1
textRole: "text"
objectName: "test_dev_sndr_mode"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("None"), oid: 0 })
append({ text: QT_TR_NOOP("Subpanel"), oid: 1 })
append({ text: QT_TR_NOOP("All"), oid: 2 })
}
}
}
}
}
// onResetOtherPanels: function(indexClicked){
// if()
// }
}
PanelItem {
id:panel2
index:1
title: "Panel 2"
width:parent.width
content: Item {
property string title: "teste"
height: configContent2.implicitHeight
width: configContent2.implicitWidth
ColumnLayout{
id:configContent2
anchors.fill:parent
ComboBox {
id: sndrModeComboBox1
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
//resetOtherAccordions.connect(panel1.resetHeight)
console.log("panel 2 height "+panel2.height)
}
}
PanelItem {
id:panel3
index:2
title: "Panel 3"
width:parent.width
content: Item {
property string title: "teste"
height: configContent3.implicitHeight
width: configContent3.implicitWidth
ColumnLayout{
id:configContent3
anchors.fill:parent
ComboBox {
id: sndrModeComboBox2
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
console.log("panel 3 height "+panel2.height)
}
}
}
}
function createPanelItem(){
panelItem.createObject(column,{title:qsTr("newTest"),index:4 /*,content: Item{}*/ })
}
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
}
}
}
}
PanelItem.qml:
import QtQuick 2.7
import QtQuick.Layouts 1.2
Item {
id: root
property Component content
property string title: "panel"
property bool isSelected: false
property int index: 0
function toggleSelected() {
root.isSelected = !root.isSelected
if(root.isSelected){
parent.currentItem = index
for(var i = 0;i<parent.children.length;i++)
{
if(parent.children[i].index !== parent.currentItem && parent.children[i].isSelected)
{
parent.children[i].toggleSelected()
}
}
}
}
clip: true
height: container.height + bar.height
Rectangle{
id: bar
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: 30
color: root.isSelected ? "#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.isSelected ? "180" : 0
}
MouseArea {
id:panelAreaClick
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: function(){
toggleSelected()
}
}
}
Rectangle{
id: container
anchors.top: bar.bottom
anchors.left: parent.left
anchors.right: parent.right
height: loader.item && isSelected ? loader.item.height : 0
Loader {
id: loader
visible: isSelected
sourceComponent: content
anchors.top: container.top
}
Behavior on height {
PropertyAnimation { duration: 1000 }
}
}
}
My big problem here, is I can't find a way to provide something to content in the createObject function.
I know that I can pass dynamically content to content doing something like:
"content": "import QtQuick 2.0; Rectangle{}"
but this is not I want to do, because I will have a component created on a file something like panellog.qml that is what I want to pass to the contentargument of the new tab that will be created.
It would be easiest to simply specify that in your inline component:
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
content: Item {}
}
}
Or you can set the type of content to be Component so you can pass some other inline component to it, which ... is pretty much the same thing really. This might seem a bit too laborious, but is actually quite handy to customize stuff in a way that also gives you access to the current component scope.
The problem here is that Qt has a two way limitation that is kinda impeding:
you cannot use declarative component syntax in imperative (JS) code
you cannot declaratively instantiate inline components
Which means that:
if you want to reference a declarative object, you have to do so using its id or a property - it will only work with an identifier, not with an object literal/instance
if you want to decalratively create an object, it has to be in a dedicated qml file
I want to make a ToolTip for a delegate Component in a TableView. It works fine, if I use an ItemDelegate, however, I cannot use an ItemDelegate as it destroys the selection mode of TableView. If I try to define the ToolTip in my delegate component I get the error
qrc:/FileSystem.qml:34 Invalid component body specification
How can I use a ToolTip for a Component?
Here is my code:
TreeView {
id: view
anchors.fill: parent
sortIndicatorVisible: true
model: fileSystemModel
rootIndex: rootPathIndex
selection: sel
selectionMode: 2
Component {
id: mycomp
Row{
id: myrow
CheckBox{
id: cbox
anchors.baseline: ctext.baseline
}
Text{
id: ctext
text: styleData.value
color: styleData.textColor
width: namecolumn.width-cbox.width-myrow.x
elide: Text.ElideRight
}
}
NC.ToolTip {
parent: mycomp
visible: hovered
delay: 1000
text: qsTr(styleData.value)
}
}
TableViewColumn {
id: namecolumn
title: "Name"
role: "fileName"
resizable: true
width: parent.width-sizeWidth-dateWidth-scrollBarWidth
delegate: mycomp
}
A component must consist of exactly one "child". So you could try to wrap the contents of the component into an Item, something like this:
Component {
Item {
width: parent.width
height: myrow.height
Row{
id: myrow
CheckBox{
id: cbox
anchors.baseline: ctext.baseline
}
Text{
id: ctext
text: styleData.value
color: styleData.textColor
width: namecolumn.width-cbox.width-myrow.x
elide: Text.ElideRight
}
}
MouseArea {
id: mouseArea
anchors.fill: true
hoverEnabled: true
}
NC.ToolTip {
visible: mouseArea.containsMouse
delay: 1000
text: qsTr(styleData.value)
}
}
}
I am working on qml, found found an error during moving mouse wheel scrolling i.e.
"TypeError: Cannot read property 'name' of undefined".
It only appear when either mouse wheel scrolling or close the application while during execution and beginning of the application didn't show this error.
One more thing, I am getting accurate data/result whatever I want but due to this error the performance of application get affected.
Please let me know how can I get rid of this issue?
also find below example to see error.
My code is..
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
TableView {
anchors.fill: parent
visible: true
backgroundVisible: false
alternatingRowColors: false
sortIndicatorVisible: true
clip: true
highlightOnFocus: false
width: parent.width
height: parent.height
TableViewColumn{ role: "code" ; title: "cde" ; width: 200;
delegate: Component {
id: codeDelegate
Item{
Text {
color: "lightgray"
elide: styleData.elideMode
text: styleData.value //modelSettingData.get(styleData.row).name
font.family: "Arial"
font.pixelSize: 18
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Text {
id: metaData
color: "red"
width: parent.width
// height: 20
anchors.bottom: parent.bottom
anchors.bottomMargin: -parent.height/1.5
font.weight: Font.ExtraLight
//elide: Text.ElideMiddle
text: "Time: " + modelSettingData.get(styleData.row).name //Error comes when this part added but I need to use it with the same form
}
}
}
}
}
TableViewColumn{ role: "name" ; title: "nme" ; width: 200
delegate: Component {
id: nameDelegate
Text {
color: "yellow"
elide: styleData.elideMode
text: styleData.value
font.family: "Arial"
font.pixelSize: 18
}
}
}
model: ListModel {
id: modelSettingData
ListElement {
name: "aaaaaaaaaa"
code: "3042666666666"
}
ListElement {
name: "bbbbbb"
code: "32235"
}
ListElement {
name: "ccccccc"
code: "32638"
}
ListElement {
name: "ddddddddddd"
code: "00000000000"
}
ListElement {
name: "eeeeeeeeeeee"
code: "111111111111"
}
ListElement {
name: "ffffffffffff"
code: "222222222222"
}
ListElement {
name: "ggggggggggggg"
code: "3333333333333"
}
ListElement {
name: "hhhhhhhhhhhhh"
code: "4444444444444"
}
ListElement {
name: "iiiiiiiiiiiii"
code: "5555555555555"
}
}
rowDelegate: Rectangle {
property bool selected : styleData.selected
width: parent.width-2
height: 100
color: styleData.selected? "black" : "black"
Rectangle {
width: parent.width
height: 1
anchors.bottom: parent.bottom
visible: parent.selected
color: "yellow"
}
}
}
}
I am trying to create a component in QML as shown in the attached screenshot
AFAIK, TableView is the component that I should use to create something like this using QML. Looking at the example here it seems that it can support multiple columns and the style is configurable. However, I am not sure how to add the checkbox control and an image element in the columns.
You can start from here:
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Window {
visible: true
width:1000; height: 500
ListModel {
id: mymodel
ListElement {
title: "my_name.mp4"
check: true
img: "1450465860217s.jpg" //your own img url here
filesize: "1.5GB"
lenght: "20:00"
lastMod: "12/02/2014"
}
ListElement {
title: "my_nam2.mp4"
check: false
img: "1450465860217s.jpg" //your own img url here
filesize: "400MB"
lenght: "8:00"
lastMod: "01/01/2015"
}
ListElement {
title: "my_nam2.mp4"
check: false
img: "1450465860217s.jpg" //your own img url here
filesize: "1.5GB"
lenght: "1:20:00"
lastMod: "12/13/2016"
}
}
TableView {
width: 1000; height: 500
anchors.centerIn: parent
TableViewColumn {
role: "title"
title: "Title"
width: 200
}
TableViewColumn {
role: "filesize"
title: "FileSize"
}
TableViewColumn {
role: "lenght"
title: "Lenght"
}
TableViewColumn {
role: "lastMod"
title: "Last Modified"
}
model: mymodel
rowDelegate: Rectangle{
color: "white"
height: 40
}
itemDelegate: RowLayout {
width: parent == null? 0 : parent.width
Loader{
sourceComponent: styleData.column == 0 ?
things : null
}
Component {
id: things
RowLayout{
height: 30
CheckBox{
id: itemCheckBox
checked: mymodel.get(styleData.row).check
}
Image{
Layout.preferredWidth: 80
Layout.preferredHeight: 40
source: mymodel.get(styleData.row).img
}
}
}
Text {
//anchors.centerIn: parent
text: styleData.value
}
}
}
}
You'll need to code your model in c++ and polish the interface, but its a good starting point.