FluentUI系列 - 1 - 介绍&第一个窗口

介绍一个QML的UI库,国人编写,作者也耍知乎。这个UI库确实好用,但是教程基本等于无,个人在使用中顺便记录一下学习内容。这玩意儿也有Pyside6的版本,有需要的可以查看PySide6-FluentUI-QML

FluentUI库地址​github.com/zhuzichu520/FluentUI

预览程序,可以在上面查看大部分组件

安装

浏览项目的Github页,注意有如下前置需求。

有缺少的可以在Qt目录下的MaintenanceTool.exe里进行安装。

  • Qt Core, Qt Quick, Qt QML, Qt ShaderTool, Qt 5 Compatibility Module. (必备)
  • Qt LinguistTool (optional,for translations)
    • Tips: 在 Qt安装目录\版本\编译环境类型\bin 里
    • 例如:F:\Qt\6.5.2\mingw_64\bin
  • Qt Svg (optional, however essential for Qt 5)

确认前置条件满足后,开始安装,具体步骤参考:

FluentUI:如何在新项目中使用?_哔哩哔哩_bilibili​www.bilibili.com/video/BV1ek4y1N7r8/​编辑

这里要注意git clone有些坑,作者的库里有引用别的库的,clone过程使用如下

cd source
git clone --recursive https://github.com/zhuzichu520/FluentUI.git
cd FluentUI

完成后的FluentUI源码目录

注意检查完成后的framelesshelper与zxing-cpp可能是空的。我写这篇文章的时候,作者的引用的framelesshelper仍然处于NotFound状态, 可能需要直接去clone再放进此目录下。

删除framelesshelper与zxing-cpp文件夹,直接clone:

git clone --recursive https://github.com/zhuzichu520/framelesshelper.git
git clone https://github.com/zhuzichu520/zxing-cpp.git

完成安装后,Qt目录下会有QML模块生成的。路径类似F:\Qt\6.5.2\mingw_64\qml\FluentUI

路径中的版本和编译环境类型来源于图中

第一个程序

  1. 新建一个Qt Quick Application,为了方便可以命名为Tutorial1-FirstWindow

2. 选择前面用来编译FluentUI的Qt版本

3. 如果有选择项,构建方式选cmake而不是qmake或者qbs

新建项目完成后

4. 把之前的FluentUI文件夹丢到项目根目录下

5. 修改CMakeLists.txt, 改完之后类似上面的构建视频的cmakelist

cmake_minimum_required(VERSION 3.16)

# Tutorial1-FirstWindow是项目名, 修改为自己的项目名
project(Tutorial1-FirstWindow VERSION 0.1 LANGUAGES CXX)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(FLUENTUI_BUILD_EXAMPLES OFF)
set(FLUENTUI_BUILD_FRAMELESSHEPLER OFF)
find_package(FluentUI)
find_package(Qt6 6.4 REQUIRED COMPONENTS Quick)

qt_standard_project_setup()

qt_add_executable(appTutorial1-FirstWindow
    main.cpp
)

qt_add_qml_module(appTutorial1-FirstWindow
    URI Tutorial1-FirstWindow
    VERSION 1.0
    QML_FILES Main.qml
)

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appTutorial1-FirstWindow PROPERTIES
#    MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appTutorial1-FirstWindow
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

target_link_libraries(appTutorial1-FirstWindow
    PRIVATE Qt6::Quick
)

include(GNUInstallDirs)
install(TARGETS appTutorial1-FirstWindow
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

6. 修改Main.qml代码:

import QtQuick
import QtQuick.Window
// 注意这里,如果报错的话可能是前面构建FluentUI失败。检查这种路径F:\Qt\6.5.2\mingw_64\qml\FluentUI
import FluentUI

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    FluFilledButton {
        width: 100
        height: 50
        anchors.centerIn: parent
        text: "HelloWorld"
    }

}

FluFilledButton

使用FluApp与FluWindow

  1. QtCreator右键项目选择添加新文件->Qt Resource File->命名resource
  2. 在项目根目录下新建文件夹qml
  3. qml文件夹内新建文件AppMainWindow.qml
  4. 修改AppMainWindow.qml
import QtQuick 2.15
import FluentUI

FluWindow {

    id: mainWindow

    // 避免双屏情景下的宽度溢出
    minimumWidth: Screen.width * 0.8
    minimumHeight: Screen.desktopAvailableHeight * 0.8
    visible: true
    title: "Helloworld"
    //appBar: undefined

}
  1. 右键resource.qrc->添加现有文件->AppMainWindow.qml

创建完成后的项目

5. 右键resource.qrc下的AppMainWindow-> Copy URL "qrc:/qml/AppMainWindow.qml"

6. 修改Main.qml

import QtQuick
import QtQuick.Window
import FluentUI

Window {

    id: app
    flags: Qt.SplashScreen
    // 一定要是false
    visible: false

    Component.onCompleted: {
        // 初始化FluApp,实质是记录了app这个根组件实例用以获取QQmlEngine
        // 然后从engine中以initialRoute文本找到用户定义的组件.qml(在这里是AppMainWindow.qml)
        // 实例化AppMainWindow,在窗口实例表中对照是否已有相同窗口存在,若存在则会判断launchMode
        // 所以AppMainWindow要继承自FluWindow, 否则必须自行添加Property: _pageRegister 、 argument、 _route、 launchMode
        FluApp.init(app)
        // 相关枚举大部分都在Def.h里
        FluTheme.darkMode = FluThemeType.Light
        // 开启动画
        FluTheme.enableAnimation = true
        // 开启文本本地渲染
        FluTheme.nativeText = true
        // 切换主题色
        // FluTheme.primaryColor = FluColors.Orange
        // 路由表
        FluApp.routes = {
            "/": "qrc:/qml/AppMainWindow.qml"
        }
        // 初始化路径
        FluApp.initialRoute = "/"
        FluApp.run()
    }
}

Ctrl+R运行

FluWindow

图中的FluWindow拥有一个默认的FluAppBar,这个玩意儿是使用Loader动态载入的Component。我遇到过一个bug就是因为window的appbar还没有载入完成,我的canvas组件就依据appBar进行paint导致页面错误。所以可以自定义一个appBar。

这个appBar其实是有与FramelessHelper联动的,我的工作机上FramelessHelper时好时坏,就不无人子弟了。

刚刚AppMainWindow.qml里,取消这一行的注释:

appBar: undefined

后面再加上新的AppBar,整个文件内容:

import QtQuick 2.15
import FluentUI

FluWindow {

    id: mainWindow

    // 避免双屏情景下的宽度溢出
    minimumWidth: Screen.width * 0.8
    minimumHeight: Screen.desktopAvailableHeight * 0.8
    visible: true
    title: "Tutorial1-FirstWindow"
    appBar: undefined

    // 窗口标题栏
    FluAppBar {
        id: title_bar
        title: mainWindow.title
        // 可以在resource.qrc中添加ico,把url复制过来,程序左上角就有图标了
        // icon:"qrc:/example/res/image/favicon.ico"
        anchors {
            top: parent.top
            left: parent.left
            right: parent.right
        }
        showDark: true
        darkText: "Dark Mode"
    }
}

这里点了右上角的dark mode会切换黑/白模式

关闭窗口提示

在AppMainWindow.qml中添加代码

    // 退出软件确认提示框
    FluContentDialog {
        id: dialog_close
        title: "退出"
        message: "确定要退出程序吗?"
        negativeText: "最小化"
        buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.NeutralButton
                     | FluContentDialogType.PositiveButton
        onNegativeClicked: {
            mainWindow.hide()
        }
        positiveText: "退出"
        neutralText: "取消"
        onPositiveClicked: {
            FluApp.exit()
        }
    }

onPositiveClicked这里,如果是1.6.0版本之前的FluentUI,需要写成

            mainWindow.deleteWindow()
            FluApp.closeApp()

现在Ctrl+R运行程序,点击右上角关闭窗口,发现并没有什么不一样

我们查看FluWindow的代码里有:

    Connections{
        target: window
        function onClosing(event){closeListener(event)}
    }
    property var closeListener: function(event){
        if(closeDestory){
            destoryOnClose()
        }else{
            visible = false
            event.accepted = false
        }
    }

我们查看QML的Window 文档会发现

closing(CloseEvent close)

This signal is emitted when the user tries to close the window.
This signal includes a close parameter. The close.accepted property is true by default so that the window is allowed to close; but you can implement an onClosing handler and set close.accepted = false if you need to do something else before the window can be closed.

所以FluWindow的onClosing已经被监听了,会调用closeListener, 我们直接用closeListener就行。

    closeListener:function(event){
        // 打开关闭确认 弹窗
        dialog_close.open()
        // 取消关闭先
        event.accepted = false
    }

完整代码

import QtQuick 2.15
import FluentUI

FluWindow {

    id: mainWindow

    // 避免双屏情景下的宽度溢出
    minimumWidth: Screen.width * 0.8
    minimumHeight: Screen.desktopAvailableHeight * 0.8
    visible: true
    title: "Tutorial1-FirstWindow"
    appBar: undefined

    closeListener: function (event) {
        dialog_close.open()
        // 取消窗口关闭
        event.accepted = false
    }

    // 窗口标题栏
    FluAppBar {
        id: title_bar
        title: mainWindow.title
        // icon:"qrc:/example/res/image/favicon.ico"
        anchors {
            top: parent.top
            left: parent.left
            right: parent.right
        }
        showDark: true
        darkText: "Dark Mode"
    }

    // 退出软件确认提示框
    FluContentDialog {
        id: dialog_close
        title: "退出"
        message: "确定要退出程序吗?"
        negativeText: "最小化"
        buttonFlags: FluContentDialogType.NegativeButton | FluContentDialogType.NeutralButton
                     | FluContentDialogType.PositiveButton
        onNegativeClicked: {
            mainWindow.hide()
        }
        positiveText: "退出"
        neutralText: "取消"
        onPositiveClicked: {
            FluApp.exit()
        }
    }
}

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-04-13 07:54:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-13 07:54:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-13 07:54:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-13 07:54:01       20 阅读

热门阅读

  1. HiveSQL基础Day04

    2024-04-13 07:54:01       14 阅读
  2. SQL Server的索引选择

    2024-04-13 07:54:01       13 阅读
  3. 神经网络和反向传播算法快速入门

    2024-04-13 07:54:01       14 阅读
  4. 基于ethers.js连接小狐狸快速开发

    2024-04-13 07:54:01       15 阅读
  5. CentOS 7下Vim常用工作模式详解

    2024-04-13 07:54:01       19 阅读
  6. Android OpenCV 概述、优缺点及应用场景分析

    2024-04-13 07:54:01       14 阅读
  7. Linux Zookeeper 安装

    2024-04-13 07:54:01       18 阅读