文章目錄
- 1. TabBar的工具列/目錄
- 1.1 演示
- 1.2 關鍵控制元件
- 1.3 原始碼
- 2 MenuBar 選單
- 2.1 演示
- 2.2 關鍵控制元件
- 2.3 原始碼
- 3 ToolBar 工具列/目錄
- 3.1 演示
- 3.2 關鍵控制元件
- 3.3 原始碼
- 4. 基于Button定制的工具列/目錄
- 4.1 演示
- 4.2 關鍵控制元件
- 4.3 原始碼
- 5. 基于Listview的側邊目錄/工具列
- 5.1 演示
- 5.2 控制元件
- 5.3 核心原始碼
- 5.4 原始碼
- 6. 基于Repeater的目錄/工具列
- 6.1 演示
- 6.2 關鍵控制元件
- 6.3 關鍵原始碼
- 6.4 原始碼
- 7. 總結
1. TabBar的工具列/目錄
1.1 演示

1.2 關鍵控制元件
TabBar 提供了一個tab-based的導航模型,由TabButton來填充內容,
TabButton 與Button相似,都是從AbstractButton繼承它的API,一般用在TabBar中,
SwipeView :使用一組頁面填充,一次只能看到一個頁面,用戶可以通過橫向滑動在頁面之間導航,
PageIndicator :SwipeView本身完全是非可視的,與PageIndicator結合使用后,給用戶一個有多個頁面的視覺提示,
1.3 原始碼
如下為TabBar、TabButton放入header中的實體:
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 480
height: 360
title: qsTr("TabBar工具列")
///--1. ApplicationWindow 中才有 header
///--2. QtQuick.Controls 2.0 版本后才有header
///--3. TabBar不一定要用在header中
header: TabBar {
id: tabBar
TabButton { text: qsTr("我是目錄1") }
TabButton { text: qsTr("我是目錄2") }
TabButton { text: qsTr("我是目錄3") }
}
SwipeView {
id: view
currentIndex: tabBar.currentIndex
anchors.fill: parent
onCurrentIndexChanged: {
tabBar.currentIndex = currentIndex
indicator.currentIndex = currentIndex
}
//第一頁
Image {
id: firstPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/code"
}
//第二頁
Image {
id: secondPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/working"
}
//第三頁
Image {
id: thirdPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/focus"
}
}
PageIndicator {
id: indicator
count: view.count
anchors.bottom: view.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
2 MenuBar 選單
2.1 演示
在上述中增加一個MenuBar選單條:

2.2 關鍵控制元件
MenuBar 選單欄由下拉選單組成,通常位于視窗的頂部邊緣,
Menu 選單有兩個主要用例,其一為文本選單; 桌面右鍵單擊后顯示的選單,推薦的打開選單的方法是呼叫popup();其二為彈出選單,例如,在頂部選單欄中,單擊按鈕后顯示的選單,
Action 表示一個抽象的用戶界面操作,該操作可以具有快捷鍵,也可以分配給選單項和工具列按鈕,
MenuItem 與Button相似,都是從AbstractButton繼承它的API,一般用在Menu選單中,
MenuSeparator 是通過用一行線來分隔選單中的不同項
2.3 原始碼
在TabBar的導航模型中加入以下代碼即可,以下都未系結觸發事件
//不用 "menuBar:" 就不會固定在header的上方
menuBar: MenuBar {
Menu {
title: qsTr("&File")
Action { text: qsTr("&New...") }
Action { text: qsTr("&Open...") }
Action { text: qsTr("&Save") }
Action { text: qsTr("Save &As...") }
MenuSeparator { }
Action { text: qsTr("&Quit") }
}
Menu {
title: qsTr("&Edit")
MenuItem {
text: "Cut"
//快捷鍵,QtQuick.Controls 2.0后沒有了,當然可以用其他方式實作
// shortcut: "Ctrl+X"
onTriggered: {}
}
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}
Menu {
title: qsTr("&Help")
Action { text: qsTr("&About") }
}
}
3 ToolBar 工具列/目錄
3.1 演示
與TabBar 相似:

3.2 關鍵控制元件
ToolBar :常用在頁眉或頁腳作導航按鈕和搜索欄位,它通常要與布局,一起使用,如通過創建RowLayout,
ToolButton :繼承于Button按鈕,但是提供了更適合在工具列中使用的外觀,
RowLayout :能自動調整的橫向排列,
3.3 原始碼
ToolBar 與 TabBar相似,ToolBar 主要沒有tabBar.currentIndex屬性,需要自定義,在上述代碼中作如下修改,其一替換了"header" ,其二為修改控制元件之間的觸發邏輯,(可搜索 “[ToolBar修改]” )
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 480
height: 360
title: qsTr("3.ToolBar工具列")
//[ToolBar修改]1: 替換header
/* ///--1 TabBar工具列
header: TabBar {
id: tabBar
TabButton { text: qsTr("我是目錄1") }
TabButton { text: qsTr("我是目錄2") }
TabButton { text: qsTr("我是目錄3") }
}
*/
///--2.ToolBar
header: ToolBar {
id: toolBar
RowLayout {
id: rowLayout
anchors.fill: parent
ToolButton {
text: qsTr("目錄0")
onClicked: view.currentIndex = 0
}
ToolButton {
text: qsTr("目錄1")
onClicked: view.currentIndex = 1
}
ToolButton {
text: qsTr("目錄2")
onClicked: view.currentIndex = 2
}
}
}
SwipeView {
id: view
anchors.fill: parent
//[ToolBar修改]2: 修改控制元件之間的觸發邏輯
//currentIndex: tabBar.currentIndex
onCurrentIndexChanged: {
//tabBar.currentIndex = currentIndex
for (var i=0; i<rowLayout.children.length; i++) {
rowLayout.children[i].checked = false
}
rowLayout.children[currentIndex].checked = true
indicator.currentIndex = currentIndex
}
//第一頁
Image {
id: firstPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/code"
}
//第二頁
Image {
id: secondPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/working"
}
//第三頁
Image {
id: thirdPage
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/focus"
}
}
PageIndicator {
id: indicator
count: view.count
anchors.bottom: view.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
}
4. 基于Button定制的工具列/目錄
4.1 演示

4.2 關鍵控制元件
MyButton :在 “Button” 上的定制,包括背景、內部的文字,圖片等,
ColoredImage :彩色圖片,之前的文章已經講過,對普通的 “image” 加一層 “ColorOverlay” 顏色覆寫即可,后續不再講述, QML 影像顏色漸變和顏色覆寫
Loader :加載器,動態的加載QML檔案,也可以根據需要創建QML,此處為最簡單的Loader的加載,
4.3 原始碼
main.qml:
import QtQuick 2.12
import QtQuick.Window 2.3
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 480
height: 360
title: qsTr("4. 定制Button")
minimumWidth: 450
minimumHeight: 240
property int index: 1
header: ToolBar {
id: tabBar
RowLayout {
id: rowLayout
anchors.fill: parent
spacing: 10
//head
ColoredImage {
id: innerImage
width: 30
height: width
source: "/images/menu"
color: "black"
}
//first Button
MyButton {
id: firstButton
text: qsTr("我是目錄1")
icon.source: "/images/1"
onClicked: {
clearAllChecks()
checked = true
index = 1
}
}
//second Button
MyButton {
text: qsTr("我是目錄2")
icon.source: "/images/2"
onClicked: {
clearAllChecks()
checked = true
index = 2
}
}
//third Button
MyButton {
text: qsTr("我是目錄3")
icon.source: "/images/3"
onClicked: {
clearAllChecks()
checked = true
index = 3
}
}
}
}
Component.onCompleted: {
firstButton.checked = true
}
function clearAllChecks() {
for (var i=0; i<rowLayout.children.length; i++) {
if (rowLayout.children[i].toString().startsWith("MyButton"))
rowLayout.children[i].checked = false
}
}
//界面的顯示的形式有多種多樣的,這里不做多說明,如前三個用的SwipeView,
Loader {
id: firstPage
anchors.fill: parent
visible: index==1
source: "TestPage1.qml"
}
Loader {
id: secondPage
anchors.fill: parent
visible: index==2
source: "TestPage2.qml"
}
TestPage3 {
id: thirdPage
anchors.fill: parent
visible: index==3
}
}
MyButton.qml:
import QtQuick 2.9
import QtQuick.Controls 2.5
Button {
id: button
height: 20
leftPadding: 4
rightPadding: 4
checkable: false
property alias labelColor: _label.color
onCheckedChanged: checkable = false
background: Rectangle {
anchors.fill: parent
color: button.checked ? "#FFDC35" : Qt.rgba(0,0,0,0)
}
contentItem: Row { //可修改為Column
spacing: 10
anchors.verticalCenter: button.verticalCenter
ColoredImage {
id: innerImage
width: 20
height: width
source: button.icon.source
color: button.checked ? "#007979" : "black"
}
Text {
id: _label
visible: text !== ""
text: button.text
anchors.verticalCenter: parent.verticalCenter
color: button.checked ? "#007979" : "black"
font.bold: true
font.pointSize: 15
}
}
}
ColoredImage.qml 就不貼出了,具體見原始碼,
5. 基于Listview的側邊目錄/工具列
5.1 演示

5.2 控制元件
ListView :ListView有一個模型(model)和一個委托(delegate),前者定義要顯示的資料,后者定義資料應該如何顯示,串列視圖中的專案可以水平放置,也可以垂直放置,此處ListView放與左側且垂直排列,
MouseArea 滑鼠區域是一個不可見的項,通常與可見項一起使用,以便為該項提供滑鼠處理,
Connections :信號連接器,其它文章也已講過,此處為連接根目錄的listIndex信號,
5.3 核心原始碼
整體結構是通過ListView來確定的,通過點擊事件,觸發每一個modelData的listIndex信號,來改變checked的值,來確認是否點擊,還可以確保其它model的互斥,主要邏輯如下:
property alias listModel: leftListView.model
signal listIndex(int idx);
ListView{
id: leftListView
...
delegate: listDelegate
}
Component{
id: listDelegate
Rectangle{
property bool checked: false
...
Connections{
target: _leftMenu
onListIndex: listItem.checked = (idx===index);
}
...
MouseArea {
...
onClicked: {
listIndex(index)
}
}
}
}
5.4 原始碼
main.qml: (省去部分非關鍵代碼)
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.12
Window {
id: root
visible: true
width: 480
height: 360
minimumWidth: 450
minimumHeight: 240
title: qsTr("ListView選單/工具列")
property int pageIndex: 0
property bool fullMenuShow: false
property real menuWidthShort: 40
//三個圖片界面:
Item {
id: page
height: parent.height
anchors.left: parent.left
anchors.leftMargin: 40
anchors.right: parent.right
//firstPage
Image {
id: firstPage
anchors.fill: parent
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/code"
visible: pageIndex == 0
}
//secondPage
Image {
id: secondPage
...
source: "/images/working"
visible: pageIndex == 1
}
//thirdPage
Image {
id: thirdPage
...
source: "/images/focus"
visible: pageIndex == 2
}
}
//左側工具列/目錄的外框
Rectangle {
id: rectMenu
width: fullMenuShow ? 40*4 : 40
height: parent.height
anchors.left: parent.left
anchors.top: parent.top
color: "gray"
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: fullMenuShow = true
onExited: fullMenuShow = false
}
// Behavior on width {
// NumberAnimation { duration: 200 }
// }
}
//左側工具列/目錄
ListviewMenu {
id: listViewMenu
width: rectMenu.width
listViewIndex: 0;
color: "gray"
listModel: [
{
name: qsTr("我是目錄1"),
iconSource: "/images/1.png",
},
{
name: qsTr("我是目錄2"),
iconSource: "/images/2.png",
},
{
name: qsTr("我是目錄3"),
iconSource: "/images/3.png",
}
]
onListIndex: { //使用信號連接器都可以
pageIndex = idx;
}
}
}
ListviewMenu.qml: (省去部分非關鍵代碼)
import QtQuick 2.7
import QtQuick.Controls 1.2
import QtGraphicalEffects 1.0
Item {
id: _leftMenu
visible: true
height: leftMunu.height;
property alias color: leftMunu.color
property alias listViewIndex: leftListView.currentIndex;
property alias listModel: leftListView.model
property bool bMenuShown: false
property real listItemHeight: 30
signal listIndex(int idx);
Component.onCompleted: {
listIndex(0)
}
Rectangle {
id: leftMunu
height: rectHeader.height + leftItem.anchors.margins + leftItem.height
width: parent.width
///--header
Rectangle {
id: rectHeader
height: 35
width: parent.width
color: "#5D478B" //紫色
Row {
id: _rowHeader
...
Image {
id: innerImageHeader
source: "/images/menu.png"
...
}
Label {
id: innerTextHeader
...
text: qsTr("目 錄")
visible: root.fullMenuShow ? true : false
}
}
Image {
id: dottedlineHeader
...
source: "/images/line.png"
visible: root.fullMenuShow ? true : false
}
}
///--list view
Item {
id: leftItem
height: listItemHeight * leftListView.count
width: parent.width
anchors.top: rectHeader.bottom
ListView{
id: leftListView
anchors.fill: parent
delegate: listDelegate
}
}
}
Component{
id: listDelegate
Rectangle{
id: listItem
property bool checked: false
color: _leftMenu.color
width: parent.width
height: listItemHeight
Connections{
target: _leftMenu
onListIndex: listItem.checked = (idx===index);
}
Row {
id: _row
anchors.centerIn: parent
height: parent.height * 0.6
width: parent.width
spacing: 6
ColoredImage {
id: innerImage
width: menuWidthShort
height: parent.height
source: modelData.iconSource
color: listItem.checked? "yellow" : "white"
}
Text {
id: innerText
text: modelData.name
color: listItem.checked? "yellow" : "white" //"#5DB6EA"
font.family: "Microsoft Yahei" //友情提醒:商業用途會收費的
font.pointSize: 15
anchors.verticalCenter: parent.verticalCenter
visible: root.fullMenuShow ? true : false
}
}
Image {
id: dottedline
...
fillMode: Image.Stretch
source: "/images/line.png"
visible: root.fullMenuShow ? true : false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
root.fullMenuShow = true
color = "green"
}
onExited: {
root.fullMenuShow = false
color = _leftMenu.color
}
onClicked: {
listIndex(index)
}
}
}
}
}
6. 基于Repeater的目錄/工具列
6.1 演示

6.2 關鍵控制元件
Repeater Repeater型別用于創建大量類似的項,與上文中ListView一樣,Repeater有一個模型(model)和一個委托(delegate):前者定義要顯示的資料,后者定義資料應該如何顯示,
LinearGradient :彩色漸變圖片,之前的文章已經講過,使用它也是對其它知識點的學習, QML 影像顏色漸變和顏色覆寫
6.3 關鍵原始碼
結構與ListView相似,邏輯上也基本一樣,多了一個當前項自身的互斥(ListView也可以實作的),配合Column等排列,使用是來更加靈活,其主要結構和邏輯代碼如下:
Column { //改為Row RowLoyout等都行
...
Repeater {
...
delegate: listDelegate
}
}
Component{
id: listDelegate
Rectangle {
property bool checked: false
property bool oldChecked: false
Connections{
target: menu
onGetListIndex: {
//idx: click item ---- index: every item
if(idx === index ) {
//與前一次互斥事件, 大部分目錄都是此邏輯
if(idx!==3) {
if(!listItem.oldChecked) {
listItem.checked = true
pageSig(idx)
}
else {
listItem.checked = false
pageSig(9) //關閉此目錄(回到主頁)/工具
}
}
//可添加:連續點擊事件 (工具列中,需要此邏輯,如放大縮小)
else {
listItem.checked = true
pageSig(idx)
}
}
//所有的子Item互斥
else {
listItem.checked = false
}
listItem.oldChecked = listItem.checked
}
}
...
MouseArea {
...
onClicked: {
getListIndex(index)
}
}
6.4 原始碼
main.qml(洗掉不必要檔案)
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.12
//import "qrc:/qml/slider/SlidierMain.qml"
Window {
visible: true
width: 480
height: 360
title: qsTr("Repeater選單/工具列")
minimumWidth: 450
minimumHeight: 240
property int pageIndex: 3
//三個圖片界面 + 主界面:
Item {
id: page
height: parent.height
anchors.left: parent.left
anchors.leftMargin: 40
anchors.right: parent.right
//miantPage
Text {
id: mainPage
anchors.centerIn: parent
text: "我是主頁"
font.pointSize: 30
font.bold: true
visible: (pageIndex != 0) || (pageIndex != 1) || (pageIndex != 2)
}
//firstPage
Image {
id: firstPage
anchors.fill: parent
smooth: true
mipmap: true
antialiasing: true
fillMode: Image.PreserveAspectFit
sourceSize.height: height
source: "/images/code"
visible: pageIndex == 0
}
//secondPage
Image {
id: secondPage
...
source: "/images/working"
visible: pageIndex == 1
}
//thirdPage
Image {
id: thirdPage
...
source: "/images/focus"
visible: pageIndex == 2
}
}
Rectangle {
id: rectMenu
width: 40
height: parent.height
anchors.left: parent.left
anchors.top: parent.top
color: "gray"
border.color: "black"
border.width: 2
}
RepeaterMenu {
id: repeaterMenu
anchors.fill: rectMenu
maxWidth: rectMenu.width
maxHeight: rectMenu.height
listMode: [
{
name: qsTr("我是目錄1"),
iconSource: "/images/1.png",
},
{
name: qsTr("我是目錄2"),
iconSource: "/images/2.png",
},
{
name: qsTr("我是目錄3"),
iconSource: "/images/3.png",
}
]
///--信號連接器
Connections {
target: repeaterMenu
onPageSig : {
pageIndex = idx //idx為pageSig信號的輸入引數
}
}
}
}
RepeaterMenu.qml(洗掉不重要代碼)
import QtQuick.Layouts 1.2
import QtPositioning 5.2
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtGraphicalEffects 1.2
Item {
id: menu
visible: true
property real maxHeight ///< Maximum height for control, determines whether text is hidden to make control shorter
property real maxWidth
property alias listMode: _repeater.model
signal getListIndex(int idx);
signal pageSig(int idx);
Column { //改為Row RowLoyout等都行
id: rowItem
...
spacing: 20
Repeater {
id: _repeater
anchors.left: parent.left
delegate: listDelegate
}
}
Component{
id: listDelegate
Rectangle {
id: listItem
property bool checked: false
property bool oldChecked: false
property int clickCnt: 0
width: innerImage.width
height: innerImage.height
color: Qt.rgba(0,0,0,0) //無色
opacity: 0.8 //透明度
Connections{
target: menu
onGetListIndex: {
//idx: click item ---- index: every item
if(idx === index ) {
//與前一次互斥事件, 大部分目錄都是此邏輯
if(idx!==3) {
if(!listItem.oldChecked) {
listItem.checked = true
pageSig(idx)
}
else {
listItem.checked = false
pageSig(9) //關閉此目錄(回到主頁)/工具
}
}
//可添加:連續點擊事件 (工具列中,需要此邏輯,如放大縮小)
else {
listItem.checked = true
pageSig(idx)
}
}
//所有的子Item互斥
else {
listItem.checked = false
}
listItem.oldChecked = listItem.checked
}
}
//水平線性漸變
LinearGradient
{
id: innerImage
...
source: Image {
source: modelData.iconSource
}
gradient: Gradient {
...
}
Rectangle {
id: innerRect
...
color: "green"//Qt.rgba(0,0,0,0)
border.color: "black"
Text {
id: _label
...
text: modelData.name
font.family: "Microsoft Yahei" //友情提醒:商業用途會收費的
font.pointSize: 15
color: "blue"
}
}
MouseArea {
anchors.fill: innerImage
hoverEnabled: true
onEntered: {
innerRect.visible = true
}
onExited: {
innerRect.visible = false
}
onClicked: {
getListIndex(index)
}
}
}
}
}
7. 總結
本文一共介紹了六種選單/目錄/工具列,各有優缺點,越是集成高的如TabBar、ToolBar ,就更方便使用,但不靈活,這個時候就可以考慮控制元件的定制呢, 上述對自己所使用過的目錄的總結,也是對使用過的控制元件的一些歸納,顏色配色還不夠舒服,原始碼稍長,還請見諒~
原始碼請點擊這里,如果沒有積分,各位小伙伴們關注后,可以在留個郵箱,看到的話會第一時間發過來哦!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/210429.html
標籤:其他
