Qt Quick 导航类视图

 Qt Quick
时间:

ScrollView

ScrollView对应着C++中的QScrollView,既带有滚动条的视图。ScrollView中只能包含一个组件,这个组件会隐式地充满整个视图。

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Window 2.1

ApplicationWindow {
    width: 200; height: 200
    ScrollView {
        anchors.fill: parent
        Image { source: "screen.png" }
    }
}

SplitView

SplitView对应着C++中的QSplitter,可以将多个组件水平或垂直排列起来,相邻组件由可被拖动的分隔块分隔。SplitView通常要与布局管理器结合使用。虽然SplitView可以完全不使用布局管理器,但是如果要对SplitView的每一部分进行详细地设置,就要借助布局管理器地功能。

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1

ApplicationWindow {
    width: 400; height: 200
    SplitView {
        anchors.fill: parent
        orientation: Qt.Horizontal

        Rectangle {
            width: 200; color: "gray"
            Layout.maximumWidth:  300
        }

        Rectangle {
            id: centerItem; color: "darkgray"
            Layout.minimumWidth: 50
            Layout.fillWidth: true
        }

        Rectangle {
            width: 200; color: "gray"
        }
    }
}

StackView

StackView对应着C++中设置了QStackedLayout的Qwidget.这是一种基于栈的导航模型,可以将一系列相关联的视图页面添加到这个栈中。这个栈遵循“先进后出”的操作方式:视图被压入栈中,只有最上面的才会被显示;当单击“后退”按钮后,顶层的视图会被弹出。可以将StackView直接添加到ApplicationWindow中。通常,StackView都会充满整个窗口,除了窗口最上方和最下方可能要留出状态栏和其他界面组件的范围。

StackView提供了一系列用于实现导航的函数,比如push,pop和clear等。供StackView显示的第一个视图会被赋值给initialItem属性。被压入栈中的视图会获得3个Stack附加属性:

  • Stack.index: 保存该视图在StackView的索引;
  • Stack.view: 保存该视图所在的StackView对象;
  • Stack.status: 保存该视图的状态,这个状态有下面几个有效值:
    1. Stack.Inactive: 该视图不可见;
    2. Stack.Activating: 该视图正在变成可见状态;
    3. Stack.Active: 该视图可见,即处于栈中;
    4. Stack.Deactivating: 该视图正在变成不可见状态。
  1. 基本操作
    StackView最常用的3个操作是压入(push),弹出(pop)和替换(replace).这些操作同栈数据结构的定义相同: 压入会把一个视图添加到栈顶;弹出会把一个视图从栈顶移除;替换先进行弹出操作,然后进行压入操作,其效果是将一个视图从栈顶移除,然后再将另外一个视图添加到栈顶。栈顶的视图是在屏幕可见的视图。这意味着,压入操作相当于将导航前进一步;弹出操作相当于将导航后退一步;替换操作相当于更换当前视图。在界面进行切换时,StackView会添加过渡画。需要注意的是,如果栈本来是空的,那么第一次压入操作不会有动画出现。另外,如果栈只有一个或没有视图,弹出操作也不会起作用,这意味着弹出操作不会将栈清空。如果需要彻底清除栈,需要使用专门的清空(clear)操作。
    有时候,程序后退多步,例如退回主界面等。这种情况下,可以给弹出操作一个参数。这种操作称为“展开”,相当于将该元素上面的所有视图全部弹出,直到该视图显示到屏幕。如果找不到指定视图,StackView会将除最下面一个视图之外的所有视图全部弹出。如果希望直接显示最底层视图,可以使用pop(null)语句。

举例:
假如StackView已有三个视图,栈中的内容是[A, B, C],那么,我们对其进行操作:

  • push(D) => [A,B,C,D],压入的过渡动画将出现在C,D之间。
  • pop() =>[A,B],弹出的过渡动画将出现在C,B之间。
  • push(D, replace) => [A, B, D], 替换的过渡动画将出现在C,D之间。
  • pop(A) => [A],弹出的过渡动画将出现在C,A之间。

除了针对单个视图进行的操作,StackView还支持对视图数组进行压入,弹出等操作。这种操作被称为“深链接(deep linking)”.深链接API与前面介绍的基本API非常相似。压入一个视图数组,会将数组中所有视图压入栈中,但是,过渡动画只出现在原栈顶视图与数组最后一个视图之间。并且,只有需要显示的视图会被加载,其余视图会依照”懒加载”的要求,在显示时才会被加载。
下面按照上面的例子举例说明。假设StackView已有3个视图,栈中的内容是[A,B,C],那么。我们对其进行操作:

  • push([D,E,F])=>[A,B,C,D,E,F],压入的过渡动画将出现在C,F之间。
  • push([D,E,F], replace)=>[A,B,D,E,F],替换的过渡动画将出现在C,F之间。
  • clear(); push([D,E,F])=>[D,E,F],没有过渡动画。这个操作其实相当于替换整个栈的内容。
import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Window 2.3

ApplicationWindow {
    width: 800; height: 600
    MouseArea {
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
                         | Qt.MiddleButton

        onClicked: {
            if(mouse.button == Qt.LeftButton) {
                stackView.push([blueView,greenView,yellowView]);
            } else if(mouse.button == Qt.RightButton) {
                stackView.pop();
            } else {
                stackView.push({ item: orangeView, replace: true});
            }
        }
    }

    Rectangle { id: blueView; color: "blue" }
    Rectangle { id: greenView; color: "green" }
    Rectangle { id: yellowView; color: "yellow" }
    Rectangle { id: orangeView; color: "orange" }

    StackView {
        id: stackView; anchors.fill: parent
        initialItem: Item {
            id: redView
            Rectangle { anchors.fill: parent; color: "red" }
        }
    }

}

上面的代码在ApplicationWindow中添加了一个充满整个窗口的StackView对象。StackView的initialItem属性设置了在窗口显示时就加载的最初的控件。这里设置了一个红色的矩形,并且让这个矩形充满整个StackView。除此之外,ApplicationWindow还有几个子控件:blueView,greenView,yellowView和orangeView。这几个子控件都没有设置大小,因此都不会显示在界面上。
进行压入操作时,可以设置被压入视图的几个属性:

  • item: 必填属性,即被压入的视图。
  • properties: 一个属性列表,列表中所有属性都会压入操作中赋值给被压入视图。这些属性会在加载时或显示时赋值给被压入视图。
  • immediate:当该属性设置为true时,可以跳过过渡动画。如果压入一个视图数组,只需要设置数组中第一个元素的属性即可。
  • replace: 当该属性设置为true时,会使用设置了该属性的视图替换栈顶视图。如果压入一个视图数组,可以将其设置到数组第一个视图,那么,栈原有的与数组视图个数相同的数个视图都会被替换。
  • destroyOnPop: 当该属性设置为true时,StackView会在弹出后销毁被弹出的视图。默认情况下,StackView会销毁压入的组件(component)视图或由URL加载的视图。那些没有被销毁的视图将恢复在入栈之前的parent属性,并且隐藏。如果需要设置该属性,需要格外小心内存泄漏。

查找视图
除了前面提到的基本操作,查找也是必要的操作。例如,为了展开到某一视图,需要先查找是不是存在这个视图。查找操作通过StackView的find()函数实现。find()函数接受一个回调函数作为参数。这个回调函数会依照栈中视图从上向下的顺序,针对每一个视图调用。如果函数返回true,说明找到了特定视图,find函数返回找到的视图。若果始终没有找到视图,find函数返回null。

例子:
下面的代码片段目的展开到name为order_id的视图。注意,如果栈中没有这样的视图,find函数返回null。

stackView.pop(stackView.find(function(item) {
return item.name == "order_id";
}));

也可以使用get(index)函数获取特定索引的视图。这个函数适用于查找具有前后关系的视图,比如要找到特定视图view前面的一个视图,就可以使用下面的代码:

previousItem = stackView.get(view.Stack.index - 1);

TabView

TabView对应着C++中的QTabWidget,用于显示带有标签页的控件。TabView的count属性返回该视图中共有几个标签页;currentIndex属性返回当前显示的标签页的索引;tabPosition属性设置标签栏的显示位置,可选值为Qt.TopEdge或Qt.BottomEdge,其中Qt.TopEdge是默认值;如果暂时不想显示标签栏,可以设置tabsVisible属性;如果不想显示边框,可以设置frameVisible属性。TabView还提供了用于维护标签页的几个函数,比如addTab(),insertTab(),moveTab()或removeTab()等。

import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Window 2.3

ApplicationWindow {
    width: 300; height: 200
    TabView {
        anchors.fill: parent
        Tab { title: "Home" }
        Tab { title: "Edit" }
        Tab { title: "View" }
        Tab { title: "Help" }
    }
}

TabView需要添加Tab控件作为子视图。Tab控件继承自Loader,可以动态加载其他QML文档。

TableView

TableView类似C++中的QTableView,增加了滚动条,选择和可改变大小的列头。TableView使用数据模型为表格的每一行提供数据。

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Window 2.1

ApplicationWindow {
    width: 300; height: 200
    ListModel {
        id: libraryModel
        ListElement { title: "A Masterpiece"; author: "Gabriel" }
        ListElement { title: "Brilliance"; author: "Jens" }
        ListElement { title: "Outsanding"; author: "Frederik" }
    }

    TableView {
        anchors.fill: parent; model: libraryModel
        TableViewColumn { role: "title"; title: "Title"; width: 100 }
        TableViewColumn { role: "author"; title: "Author"; width: 200 }
    }
}

TableView可以通过itemDelegate属性,使用委托来绘制指定单元格。它与TableViewColumn的delegate效果相同。另外还可以通过rowDelegate和headerDelegate来使用委托绘制行或列头。TableView类型还提供了一些常用的函数,比如addColumn(),getColumn(),insertColumn(),removeCOlumn(),rowAt(x,y)等,进行相关操作。另外,当行被点击后会发射clicked()或doubleClick()信号。下面修改前面的例子:

import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Window 2.1

ApplicationWindow {
    width: 300; height: 200
    ListModel {
        id: libraryModel
        ListElement { title: "A Masterpiece"; author: "Gabriel" }
        ListElement { title: "Brilliance"; author: "Jens" }
        ListElement { title: "Outsanding"; author: "Frederik" }
    }

    TableView {
        anchors.fill: parent; model: libraryModel
        TableViewColumn { role: "title"; title: "Title"; width: 100 }
        TableViewColumn { role: "author"; title: "Author"; width: 200 }
        itemDelegate: Item {
            Text {
                anchors.horizontalCenter: parent.horizontalCenter
                color: styleData.selected ? "red" : "blue"
                font.pointSize: 10
                text: styleData.row == 2 ? "myrow" : styleData.value
            }
        }

        onClicked: console.debug(row)
    }
}


0 评论