Qt:环境20.04.1-Ubuntu,Qt5.14.2
1.创建项目:
创建CM项目文件夹,创建下面文件和文件夹
├── cm-lib
│ ├── cm-lib.pro //库项目
│ └── source
│ ├── cm-lib_global.h
│ └── models
│ ├── client.cpp
│ └── client.h
├── CM.pro
├── cm-tests
│ ├── cm-tests.pro //TEST
│ └── source
│ └── models
│ └── client-tests.cpp
└── cm-ui
├── cm-ui.pro //UI
├── source
│ └── main.cpp
└── views
CM.pro:
TEMPLATE = subdirs
SUBDIRS += \ #包含的子目录
cm-ui \
cm-lib \
cm-tests
message(cm project dir: $${PWD})
cm-lib.pro:
QT -= gui #由于这是一个库项目,我们不需要加载默认的 GUI 模块
TARGET = cm-lib #输出的库名字
TEMPLATE = lib #指定生成库
CONFIG += c++14
DEFINES += CMLIB_LIBRARY
INCLUDEPATH += source
SOURCES += source/models/client.cpp
HEADERS += source/cm-lib_global.h \
source/models/client.h
cm-ui.pro
QT += qml quick
TEMPLATE = app
CONFIG += c++14
INCLUDEPATH += source
SOURCES += source/main.cpp
QML_IMPORT_PATH = $$PWD
cm-test:pro:
QT += testlib
QT -= gui #我们不需要GUI模块
TARGET = client-tests
TEMPLATE = app
CONFIG += c++14
CONFIG += console #控制台程序
CONFIG -= app_bundle
INCLUDEPATH += source
SOURCES += source/models/client-tests.cpp
CM/cm-lib/source/cm-lib_global.h:
#ifndef CMLIB_GLOBAL_H
#define CMLIB_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(CMLIB_LIBRARY)
# define CMLIBSHARED_EXPORT Q_DECL_EXPORT
#else
# define CMLIBSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // CMLIB_GLOBAL_H
CM/cm-lib/source/models/client.h:
#ifndef CLIENT_H
#define CLIENT_H
#include "cm-lib_global.h"
class CMLIBSHARED_EXPORT Client
{
public:
Client();
};
#endif // CLIENT_H
CM/cm-lib/source/models/client.cpp:
#include "client.h"
Client::Client()
{
}
CM/cm-tests/source/models/client-tests.cpp:
#include <QString>
#include <QtTest>
class ClientTests : public QObject
{
Q_OBJECT
public:
ClientTests();
private Q_SLOTS:
void testCase1();
};
ClientTests::ClientTests()
{
}
void ClientTests::testCase1()
{
QVERIFY2(true, "Failure");
}
QTEST_APPLESS_MAIN(ClientTests)
#include "client-tests.moc"
CM/cm-ui/source/main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
return app.exec();
}
代码day1
2.掌握MVC:
在cm-ui下添加views.qrc views.qrc下添加MasterView.qml 保存CM/cm-ui/views目录
修改views.qrc为:
<RCC>
<qresource prefix="/views">
<file alias="MasterView.qml">views/MasterView.qml</file>
</qresource>
</RCC>
MasterView.qml:
import QtQuick 2.9
import QtQuick.Window 2.2
Window
{
visible: true
width: 640
height: 480
title: qsTr("Client Management")
Text
{
text: qsTr("学习Qt")
}
}
main.cpp 里面添加
engine.load(QUrl(QStringLiteral("qrc:/views/MasterView.qml")));//用于加载qml
运行cm-ui:
cm-lib 中创建MasterController类 保存/CM/cm-lib/source/controllers目录
MasterController.h:
#ifndef MASTERCONTROLLER_H
#define MASTERCONTROLLER_H
#include <QObject>
#include <cm-lib_global.h>> //包含导出宏的头文件
//添加命名空间
namespace cm
{
namespace controllers //
{
class CMLIBSHARED_EXPORT MasterController : public QObject
{
Q_OBJECT
public:
explicit MasterController(QObject *parent = nullptr);
signals:
};
}
}
#endif // MASTERCONTROLLER_H
MasterController.h:
#ifndef MASTERCONTROLLER_H
#define MASTERCONTROLLER_H
#include <QObject>
#include <cm-lib_global.h>> //包含导出宏的头文件
//添加命名空间
namespace cm
{
namespace controllers //
{
class CMLIBSHARED_EXPORT MasterController : public QObject
{
Q_OBJECT
public:
explicit MasterController(QObject *parent = nullptr);
signals:
};
}
}
#endif // MASTERCONTROLLER_H
MasterController.h:
#ifndef MASTERCONTROLLER_H
#define MASTERCONTROLLER_H
#include <QObject>
#include <cm-lib_global.h>> //包含导出宏的头文件
//添加命名空间
namespace cm
{
namespace controllers //
{
class CMLIBSHARED_EXPORT MasterController : public QObject
{
Q_OBJECT
public:
explicit MasterController(QObject *parent = nullptr);
signals:
};
}
}
#endif // MASTERCONTROLLER_H
MasterController.h:
#ifndef MASTERCONTROLLER_H
#define MASTERCONTROLLER_H
#include <QObject>
#include <cm-lib_global.h>> //包含导出宏的头文件
//添加命名空间
namespace cm
{
namespace controllers //
{
class CMLIBSHARED_EXPORT MasterController : public QObject
{
Q_OBJECT
public:
explicit MasterController(QObject *parent = nullptr);
signals:
};
}
}
#endif // MASTERCONTROLLER_H
master-controller.cpp:
#include "MasterController.h"
namespace cm
{
namespace controllers
{
MasterController::MasterController(QObject *parent) : QObject(parent)
{
}
}
}
cm-ui的main.cpp要访问cm-lib的头文件需要cm-ui.pro添加
INCLUDEPATH += source
../cm-lib/source
cm-ui.pro :添加链接库
LIBS += -L$$PWD/../../build-CM-Desktop_Qt_5_14_2_GCC_64bit-Debug/cm-lib/ -lcm-lib
我们在这里所做的是向 QML 引擎注册类型,然后,我们实例化 MasterController 的一个实例并将其注入到根 QML 上下文中,添加下面代码。
qmlRegisterType<cm::controllers::MasterController>("CM", 1, 0, "MasterController");
cm::controllers::MasterController masterController;/
engine.rootContext()->setContextProperty("masterController",&masterController);
现在可以测试qml读取CM-LIB的成员变量
为了能够从 QML 访问这个成员,我们需要配置一个新属性。 在 Q_OBJECT 宏之后但在第一个公共访问修饰符之前,添加以下内容
在这里,我们正在创建 QML 可以访问的 QString 类型的新属性
QML 将该属性称为 ui_welcomeMessage,并且在调用时,将获取(或设置)名为welcomeMessage 的 MEMBER 变量中的值
//属性
Q_PROPERTY( QString ui_welcomeMessage MEMBER welcomeMessage CONSTANT )
//公有成员
QString welcomeMessage = "学习Qt";
回到 MasterView.qml,我们将使用这个属性。 将 Text 组件的 text 属性改为如下
text: masterController.ui_welcomeMessage
ex2
3.UX
导航栏 (1) 将永远存在并包含将用户导航到应用程序内关键区域的按钮。默认情况下,栏会变窄,与按钮关联的命令将由图标表示;但是,按下切换按钮将扩展栏以显示每个按钮的随附描述性文本。
内容窗格 (2) 将是一堆子视图。导航到应用程序的不同区域将通过替换内容窗格中的子视图来实现。例如,如果我们在导航栏上添加一个 New Client 按钮并按下它,我们会将 New Client View 推送到内容框架堆栈上。
命令栏 (3) 是一个可选元素,用于向用户显示更多命令按钮。导航栏的主要区别在于这些命令将与当前视图相关的上下文敏感。例如,在创建新客户端时,我们需要一个保存按钮,但是当我们搜索客户端时,保存按钮没有意义。每个子视图将可选地显示自己的命令栏。命令将通过图标显示,下方带有简短说明。
在 cm-ui 中,右键单击 views.qrc 并选择添加新QML文件:
在 cm-ui/ui/views 中创建 SplashView.qml 文件,重复此过程,创建以下所有文件:
File | Purpose |
---|
SplashView.qml | 加载 UI 时显示的占位符视图。 | DashboardView.qml | The central “home” view. | CreateClientView.qml | 查看以输入新客户的详细信息 | EditClientView.qml | 查看以读取/更新现有客户端详细信息 | FindClientView.qml | 用于搜索现有客户的视图 |
把
改为
4.StackView
堆栈视图
子视图将通过 StackView 组件呈现,该组件提供了一个带有内置历史记录的基于堆栈的导航模型。
新视图(在此上下文中的视图意味着几乎所有 QML)在要显示时被push到堆栈,并且可以从堆栈中弹出以返回到前一个视图。我们不需要使用历史功能,但它们是一个非常有用的功能。
要访问该组件,我们首先需要引用该模块,因此将导入添加到 MasterView.qml
import QtQuick.Controls 2.14
完成后,让我们用 StackView 替换 Text 元素:
StackView
{
id: contentFrame
initialItem: "qrc:/views/SplashView.qml"
}
我们为组件分配了一个唯一标识符 contentFrame 以便我们可以在QML的其他地方引用它,并且我们指定我们默认要加载的子视图——SplashView
接下来,编辑 SplashView将QtQuick模块版本更新为 2.9,使其与MasterView匹配,(如果没有明确说明,请对所有其他 QML 文件执行此操作).这不是绝对必要的,但这是避免视图间不一致的做法.引用不同 QtQuick 版本的两个视图上的相同代码可能会表现出不同的行为.
在SplashView.qml是制作一个 400 像素宽 x 200 像素高的矩形:
import QtQuick 2.9
Rectangle
{
width: 400
height: 200
color: "#f4c842"
}
可以像我们在这里所做的那样使用十六进制 RGB 值指定颜色.或者命名为 SVG 颜色.
如果您将光标悬停在 Qt Creator 中的十六进制字符串上,您将获得一个非常有用的小弹出色样.
5.Anchors
锚点
SplashView 的一个小问题是它实际上并没有填满窗口,当然,我们可以将 400 x 200 尺寸更改为 1024 x 768 以使其与 MasterView 匹配,但是如果用户调整窗口大小会发生什么?现代 UI 都是关于响应式设计的——动态内容可以适应它所呈现的显示,因此仅适用于一个平台的硬编码属性并不理想。
将 anchors.fill: parent 添加到 StackView 组件
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.14
import CM 1.0
Window
{
visible: true
width: 640
height: 480
title: qsTr("Client Management")
StackView
{
id: contentFrame
anchors.fill: parent
initialItem: "qrc:/views/SplashView.qml"
}
}
将 anchors.fill: parent 添加到 SplashView.qml
import QtQuick 2.9
Rectangle
{
anchors.fill: parent
color: "#f4c842"
}
StackView 现在将填充它的父窗口,我们明确给出了 1024 x 768 的固定大小。再次运行应用程序,你现在应该有一个橙黄色 SplashView,它充满了屏幕,如果你调整它的大小.它会很自动地调整自己的大小。
6.Navigation
向 SplashView.qml 添加文本框
import QtQuick 2.9
Rectangle
{
anchors.fill: parent
color: "#f4c842"
Text
{
anchors.centerIn: parent
text: "Splash View"
}
}
把SplashView.qml的内容分别拷贝到FindClientView.qml text: “FindClient View”,EditClientView.qml ,text: “EditClient View”,DashboardView.qml,text: “Dashboard View” CreateClientView.qml,text: “Create Client View”。
在MasterView.qml中添加:
Component.onCompleted: contentFrame.replace("qrc:/views/DashboardView.qml");
现在,当您构建和运行时,一旦 MasterView 完成加载,它就会将子视图切换到 DashboardView,这可能发生得如此之快
以至于您甚至不再看到 SplashView,但它仍然存在。如果您的应用程序需要进行大量初始化,并且您不能真正拥有非阻塞 UI,那么拥有这样的启动视图是很好的,这是放置公司徽标和“网状样条…”加载消息的方便位置。
StackView 就像网络浏览器中的历史记录。如果您访问 www.google.com 然后访问 www.packtpub.com,那么您将 www.packtpub.com 推入堆栈。如果您在浏览器上单击“返回”,则会返回 www.google.com。此历史记录可以由多个页面(或视图)组成,您可以在其中前后导航。有时您不需要历史记录,有时您主动不希望用户能够返回。我们可以他调用replace() 方法,将一个新视图推入堆栈并清除所有历史记录。
|