问题
In the context of a dual-pane file manager, I have two TabView
items side by side, each contains multiple tabs of course, and each Tab
loads a TableView
showing the content of a specific directory using FolderListModel
.
SplitView
TabView
Tab
Tab
TabView
Tab
My current task is to implement a toolbar button to toggle the showHidden
property of the FolderListModel
instance shown in the active tab. Therefore, I need a way to find out what the currently active tab is.
Next, once I get the active Tab
, I need to change Tab.item.some_property
, in particular, the property of interest is show_hidden
, which is an alias to the showHidden
property of the underlying FolderListModel
. For example, a hard-coded scenario would be:
ToolButton {
onClicked: {
tab1.item.show_hidden = false;
tab1.destroy(); // need "refresh" instead
}
}
First I need to get tab1
based on whether it is active, and second, after I change show_hidden
, the view doesn't refresh by itself, so I need to call some kind of reload function, but which? Or maybe reload isn't the best way to do it? Is it possible to do it using a custom signal handler? (Again I can only think conceptually without knowing how to implement it.)
As suggested I'm posting a running example below:
/* main.qml */
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 1280
height: 700
toolBar: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
onClicked: { // TODO toggle folderModel.showHidden property
tab1A.item.show_hidden = false;
// tab1A.destroy(); // fixme how to refresh the view?
}
}
}
}
Item {
anchors.fill: parent
SplitView {
id: splitView
anchors.fill: parent
TabView {
id: tabView1
width: splitView.width / 2
Tab {
id: tab1A
title: qsTr("Home")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///tmp";
}
}
Tab {
title: qsTr("Folder")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///home";
}
}
}
TabView {
id: tabView2
Tab {
title: qsTr("Home")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///home";
}
}
}
}
}
}
/* dirview.qml */
import QtQuick 2.4
import QtQuick.Controls 1.4
import Qt.labs.folderlistmodel 2.1
TableView {
property alias folder_url: folderModel.folder
property alias show_hidden: folderModel.showHidden
id: tableView
anchors.fill: parent
TableViewColumn {
role: "fileName"
title: qsTr("Name")
width: tableView.width * 0.7
}
TableViewColumn {
role: "fileSize"
title: qsTr("Size")
width: tableView.width * 0.2
}
FolderListModel {
id: folderModel
nameFilters: ["*"]
showHidden: true
showDirsFirst: true
showDotAndDotDot: true
}
model: folderModel
}
Thank you.
Noticed something weird: Tab.item.folder_url
has the right info, however, Tab.item.show_hidden
is always false
, even if I remove the line where I manually set it to false
. This is hard to understand as I initially set FolderListModel.showHidden
to true
in dirview.qml
.
ToolButton {
onClicked: { // TODO toggle folderModel.showHidden property
var cur_tab_idx = tabView1.currentIndex;
console.log(tabView1.getTab(cur_tab_idx).item.folder_url);
console.log(tabView1.getTab(cur_tab_idx).item.show_hidden);
}
}
回答1:
Here is an explanation of how I have got it to work.
I solved first problem using focus
flag. When current Tab
in TabView
changes one Tab
gains focus and the other one looses. So by using onFocusChanged()
signal you can know exactly when one Tab
becomes active or inactive.
The focus of Tab
does not change when focus of whole TabView
changes. Because of this I created an Array
(named tabs in code) containing references to every TabView
and Tab
it contains. With this when TabView
becomes inactive I can set focus
of its Tab
objects to false
using simple for
.
Second problem was more tricky. I see no other option of turning showHidden
flag off than destroying and creating a new FolderListModel
. We cannot (or I could not :) ) provide model
to TableView
dynamically so I made a ListModel
. Advantage of regular ListModel
compared to FolderListModel
is that it can be cleared and refilled with data. Every time folder_url
or show_hidden
changes I destroy current FolderListModel
and create a new one. After it is created I rewrite its data to the ListModel
.
Here is the working code.
main.qml
/* main.qml */
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 1280
height: 700
property var tabs: [
[tabView1, [tab1A, tab1B]],
[tabView2, [tab2A]]
]
toolBar: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
onClicked: { // TODO toggle folderModel.showHidden property
tab1A.item.show_hidden = false;
// tab1A.destroy(); // fixme how to refresh the view?
}
}
}
}
Item {
anchors.fill: parent
SplitView {
id: splitView
anchors.fill: parent
TabView {
id: tabView1
width: splitView.width / 2
Tab {
id: tab1A
title: qsTr("Home")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///tmp";
}
onFocusChanged: {
item.show_hidden = focus
}
}
onFocusChanged: {
if (!focus)
for (var i = 0 ; i < tabs[0][1].length ; i++)
tabs[0][1][i].focus = false
}
Tab {
id: tab1B
title: qsTr("Folder")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///home";
}
onFocusChanged: {
item.show_hidden = focus
}
}
}
TabView {
id: tabView2
Tab {
id: tab2A
title: qsTr("Home")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///tmp";
}
onFocusChanged: {
item.show_hidden = focus
}
}
onFocusChanged: {
if (!focus)
for (var i = 0 ; i < tabs[1][1].length ; i++)
tabs[1][1][i].focus = false
}
}
}
}
}
dirview.qml
/* dirview.qml */
import QtQuick 2.4
import QtQuick.Controls 1.4
import Qt.labs.folderlistmodel 2.1
TableView {
property string folder_url
property bool show_hidden
id: tableView
anchors.fill: parent
TableViewColumn {
role: "fileName"
title: qsTr("Name")
width: tableView.width * 0.7
}
TableViewColumn {
role: "fileSize"
title: qsTr("Size")
width: tableView.width * 0.2
}
ListModel {
id: secondListModel
}
property var fm
property int folderModelCount
onFolder_urlChanged: {
reloadFolderModel()
}
onShow_hiddenChanged: {
reloadFolderModel()
}
onFolderModelCountChanged: {
resetSecondListModel()
}
function reloadFolderModel() {
folderModelCount = 0
if (typeof(fm) !== "undefined")
fm.destroy()
var component = Qt.createComponent("foldermodel.qml")
if (component.status === Component.Ready)
fm = component.createObject(
tableView, {"folder_url": folder_url, "show_hidden": show_hidden})
else
console.error(component.errorString())
folderModelCount =
Qt.binding(function(){return fm.folderModel.count})
}
function resetSecondListModel() {
secondListModel.clear()
for (var i = 0 ; i < folderModelCount ; i++) {
secondListModel.append({
"fileName": fm.folderModel.get(i, "fileName"),
"filePath": fm.folderModel.get(i, "filePath"),
"fileURL": fm.folderModel.get(i, "fileURL"),
"fileBaseName": fm.folderModel.get(i, "fileBaseName"),
"fileSuffix": fm.folderModel.get(i, "fileSuffix"),
"fileSize": fm.folderModel.get(i, "fileSize"),
"fileModified": fm.folderModel.get(i, "fileModified"),
"fileAccessed": fm.folderModel.get(i, "fileAccessed"),
"fileIsDir": fm.folderModel.get(i, "fileIsDir")
})
}
}
model: secondListModel
}
foldermodel.qml (add this file)
import QtQuick 2.4
import QtQuick.Controls 1.4
import Qt.labs.folderlistmodel 2.1
Item {
property string folder_url
property bool show_hidden
property alias folderModel: folderModelObject
FolderListModel {
id: folderModelObject
nameFilters: ["*"]
folder: folder_url
showHidden: show_hidden
showDirsFirst: true
showDotAndDotDot: true
}
}
Now you understand why QML is not very flexible. :)
回答2:
Solution to finding the current Tab
in the active TabView
(pane): declare a property of SplitView
to store the TabView
that has activeFocus
.
A StatusBar
is added to demo the functionality.
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 1280
height: 700
toolBar: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
onClicked: { // TODO toggle folderModel.showHidden property
// Demo: get the current tab of the active pane
var active_pane = splitView.activePane;
var cur_tab_idx = active_pane.currentIndex;
var cur_tab_item = active_pane.getTab(cur_tab_idx).item;
testLabel.text = cur_tab_item.folder_url;
}
}
}
}
SplitView {
id: splitView
property TabView activePane: tabView1
anchors.fill: parent
TabView {
id: tabView1
width: splitView.width / 2
onActiveFocusChanged: {
if (activeFocus) {
splitView.activePane = tabView1;
}
}
Tab {
title: qsTr("tmp")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///tmp";
}
}
Tab {
title: qsTr("home")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///home";
}
}
}
TabView {
id: tabView2
onActiveFocusChanged: {
if (activeFocus) {
splitView.activePane = tabView2;
}
}
Tab {
title: qsTr("bin")
source: "dirview.qml"
onLoaded: {
item.folder_url = "file:///bin";
}
}
}
}
statusBar: StatusBar {
RowLayout {
Label {
text: (splitView.activePane === tabView1) ? "Pane 1" : "Pane 2"
}
Label {
id: testLabel
}
}
}
}
来源:https://stackoverflow.com/questions/33557271/get-active-tab-from-tabview-and-change-item-property