登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 31|回复: 0

Duilib入门教程02_制作一个简单的界面

[复制链接]

主题

0

回帖

0

积分

网站编辑

积分
0
发表于 2024-12-12 22:53:41 | 显示全部楼层 |阅读模式
本帖最后由 大理寺少卿 于 2024-12-12 22:55 编辑

在实现这个基本窗口之前,我们首先根据自己的习惯设置一下 DuiLib 编译后生成的文件路径和项目依赖的头文件目录。你不一定要按着我的修改,符合你自己的使用习惯即可。要修改的位置主要有一下几个。修改过程比较繁琐,主要还是因为 DuiLib 是从 VC6 升级上来的,很多属性需要删除和修改,也有些属性是 DuiLib 团队自己的目录结构风格,改与不改不影响使用。
  • 常规->输出路径
  • 常规->中间目录(DLL 和 LIB 不能有冲突)
  • 常规->输出文件名(32 位和 64 位不一样,Debug 和 Release 也不同)
  • C/C++->预编译头->预编译头输出文件
  • 连接器->常规 删除 DuiLib 项目原有的输出文件选项
  • 连接器->系统->子系统 设置子系统为窗口(负责构建过程中会有警告)
  • 连接器->高级->到入库 删除默认到入库
  • 常规->平台工具集 设置 EXE 的平台工具集与 DuiLib 一致为 VS2013(如果是 2017 需要改一些因新标准导致的编译错误)
  • VC++ 目录->包含目录 设置 EXE 依赖的头文件目录,如果使用静态库那么要设置附加库目录和附加库文件
  • C/C++->代码生成->运行库 设置 EXE 项目的C/C++代码生成->运行库为 /MTd 和 /MT 与 DuiLib 保持一致否则链接时报错
  • 连接器->输入 设置 EXE 项目依赖项
DuiLib 的具体结构这里我们先不说,目前我们仅需要了解,如何使用动态库或静态库来创建一个基于 DuiLib 的简单界面就可以了,然后再循序渐进的往深入去挖一挖。DuiLib 实现了一个窗口基类,我们自己的窗口只需要继承这个类,实现三个必须要实现的纯虚函数,然后设置一下窗口使用的配置文件、窗口配置文件的路径和窗口的名称就可以了。
  • 继承 WindowImplBase 类(DuiLib 窗口管理的一个基类)
  • 实现 GetWindowClassName 接口(描述窗口唯一名称的方法)
  • 实现 GetSkinFile 接口(描述窗口样式的 xml 文件名称方法)
  • 实现 GetSkinFolder 接口(描述窗口样式文件路径的方法)
  • 创建一个窗口描述配置文件(描述窗口的 xml 样式文件)
根据上面的方法,我们把向导自动生成的项目代码删一删,修改 duilib_tutoral.cpp 文件,仅留下一个 main 函数,如下所示:
  1. //duilib_tutorial.cpp: 定义应用程序的入口点。
  2. //

  3. #include "stdafx.h"
  4. #include "duilib_tutorial.h"

  5. int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
  6.                      _In_opt_ HINSTANCE hPrevInstance,
  7.                      _In_ LPWSTR    lpCmdLine,
  8.                      _In_ int       nCmdShow)
  9. {
  10.     UNREFERENCED_PARAMETER(hPrevInstance);
  11.     UNREFERENCED_PARAMETER(lpCmdLine);

  12.     return 0;
  13. }

复制代码
打开 stdafx.h 添加 ATL 依赖(创建项目时选择了 ATL 支持,但是没有导入 ATL 的库文件,可能是 VS2017 的 Bug),再添加上 DuiLib 的统一入口头文件和引入整个命名空间(因为是做示例,大型项目不建议引入整个命名空间)
然后我们在 duilib_tutoral.cpp 中创建一个自己的窗口,来继承 WindowImplBase,并实现 GetSkinFolder GetSkinFile GetWindowClassName 三个接口,代码如下:
  1. // stdafx.h : 标准系统包含文件的包含文件,
  2. // 或是经常使用但不常更改的
  3. // 特定于项目的包含文件
  4. //

  5. #pragma once

  6. #include "targetver.h"

  7. #define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
  8. // Windows 头文件:
  9. #include <windows.h>

  10. // C 运行时头文件
  11. #include <stdlib.h>
  12. #include <malloc.h>
  13. #include <memory.h>
  14. #include <tchar.h>

  15. // ATL
  16. #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
  17. #include <atlbase.h>
  18. #include <atlstr.h>

  19. // TODO: 在此处引用程序需要的其他头文件
  20. #include "UIlib.h"
  21. using namespace DuiLib;
复制代码
  1. class MainWndFrame : public WindowImplBase
  2. {
  3. protected:
  4.         virtual CDuiString GetSkinFolder() override;                                                        // 获取皮肤文件的目录,如果有多层目录这里可以设置
  5.         virtual CDuiString GetSkinFile() override;                                                                // 设置皮肤文件名字
  6.         virtual LPCTSTR GetWindowClassName(void) const override;        // 设置当前窗口的 class name

  7. public:
  8.         static const LPCTSTR kClassName;
  9.         static const LPCTSTR kMainWndFrame;
  10. };

  11. DuiLib::CDuiString MainWndFrame::GetSkinFolder()
  12. {
  13.         // GetInstancePath 接口返回默认的皮肤文件位置
  14.         // 在 main 函数中我们可以通过 SetResourcePath 来设置路径
  15.         return m_PaintManager.GetInstancePath();
  16. }

  17. DuiLib::CDuiString MainWndFrame::GetSkinFile()
  18. {
  19.         // 成员变量定义的皮肤文件名
  20.         return kMainWndFrame;
  21. }

  22. LPCTSTR MainWndFrame::GetWindowClassName(void) const
  23. {
  24.         // 成员变量定义的窗口 class name
  25.         return kClassName;
  26. }

  27. const LPCTSTR MainWndFrame::kClassName = _T("main_wnd_frame");
  28. const LPCTSTR MainWndFrame::kMainWndFrame = _T("main_wnd_frame.xml");
复制代码

仔细分析代码,我们可以看到我们指定了这个窗口的皮肤路径是默认路径(取决于我们如何设置,稍后就能看到),并指定了这个窗口的皮肤文件 main_wnd_frame.xml,最后还指定了一下窗口的类名。这样这个窗口就创建好了,我们还需要在 mian 函数中把这个窗口 new 出来,其次还需要创建一个 xml 文件来描述一下这个窗口的样子。先来写 main 函数。
  1. int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
  2.                      _In_opt_ HINSTANCE hPrevInstance,
  3.                      _In_ LPWSTR    lpCmdLine,
  4.                      _In_ int       nCmdShow)
  5. {
  6.         UNREFERENCED_PARAMETER(hPrevInstance);
  7.         UNREFERENCED_PARAMETER(lpCmdLine);

  8.         // 设置窗口关联的实例
  9.         CPaintManagerUI::SetInstance(hInstance);

  10.         // 设置皮肤的默认路径
  11.         CPaintManagerUI::SetCurrentPath(CPaintManagerUI::GetInstancePath());
  12.         CPaintManagerUI::SetResourcePath(_T("theme"));

  13.         // 创建窗口
  14.         MainWndFrame* pMainWndFrame = new MainWndFrame;
  15.         pMainWndFrame->Create(nullptr, MainWndFrame::kClassName, UI_WNDSTYLE_DIALOG, 0);
  16.         pMainWndFrame->CenterWindow();
  17.         pMainWndFrame->ShowWindow();

  18.         CPaintManagerUI::MessageLoop();

  19.         if (nullptr != pMainWndFrame)
  20.         {
  21.                 delete pMainWndFrame;
  22.         }

  23.         return 0;
  24. }
复制代码

Create(nullptr, MainWndFrame::kClassName, UI_WNDSTYLE_DIALOG, 0);        pMainWndFrame->CenterWindow();        pMainWndFrame->ShowWindow();        CPaintManagerUI::MessageLoop();        if (nullptr != pMainWndFrame)        {                delete pMainWndFrame;        }        return 0;}" tabindex="0" role="button" style="box-sizing: border-box; position: relative; line-height: 20px; vertical-align: middle; cursor: pointer; user-select: none; border: 0px; border-radius: 6px; appearance: none; box-shadow: none; transition: color 80ms cubic-bezier(0.33, 1, 0.68, 1), background-color, box-shadow, border-color; width: var(--control-small-size, 28px); height: var(--control-small-size, 28px); display: flex !important; justify-content: center !important; align-items: center !important; margin: var(--base-size-8, 8px) !important;">

通过 CPaintManagerUI 的一些静态设置了当前关联的窗口实例、皮肤文件的路径,接下来 new 了一个我们继承 WindowImplBase 所产生的窗口。调用 Create 方法创建了窗口,使用 CenterWindow 让窗口居中显示,再调用 ShowWindow 显示窗口。最后我们使用了 CPaintManagerUIMessageLoop 启动消息循环的监听,保证程序不被退出。并且在退出前我们要 delete 掉 new 出来的窗口。这样创建窗口的过程就完事儿了,但是现在还是不能运行的,我们还需要完善一下这个窗口的 xml 文件。
代码中设置了皮肤文件路径是 EXE 目录下的 theme 文件夹,所以要在 EXE 生成的文件夹创建一个 theme 文件夹,把 main_wnd_frame.xml 放到这个里面。
把如下代码添加到 xml 文件中(先暂时不需要关注 xml 的内容,后面会详细的讲解)
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Window size="640,480" caption="0,0,0,35">
  3.         <VerticalLayout>
  4.                 <HorizontalLayout bkcolor="#FFFFFFFF"/>
  5.                 <HorizontalLayout bkcolor="#FFFFFFFF">
  6.                         <Button text="Hello DuiLib" bkcolor="#FF1296DB"/>
  7.                 </HorizontalLayout>
  8.                 <HorizontalLayout bkcolor="#FFFFFFFF"/>
  9.         </VerticalLayout>
  10. </Window>
复制代码

<clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w" value="                                                                                                        " tabindex="0" role="button" style="box-sizing: border-box; position: relative; line-height: 20px; vertical-align: middle; cursor: pointer; user-select: none; border: 0px; border-radius: 6px; appearance: none; box-shadow: none; transition: color 80ms cubic-bezier(0.33, 1, 0.68, 1), background-color, box-shadow, border-color; width: var(--control-small-size, 28px); height: var(--control-small-size, 28px); display: flex !important; justify-content: center !important; align-items: center !important; margin: var(--base-size-8, 8px) !important;">

所有准备工作就绪,我们编译一下程序,但你会发现报了一大堆的错误,如下所示
很明显,程序不知道到哪里去找我们用到的这些函数,换句话说还没告诉程序要用 DuiLib 的动态库还是静态库,这个好解决。如果你想使用动态库,那么首先保证 EXE 目录下有动态库的文件,其次在项目的 属性->C/C++->预处理器 中增加 UILIB_EXPORTS 的预定义宏,这是告诉 DuiLib 你需要把我们用到的接口按动态库的方式导出。其实搜索一下 UILIB_EXPORTS 就可以看到具体的定义了。
如果你想使用静态库,同样,定义一个 UILIB_STATIC 的预定义宏然后在项目 属性->连接器->输入 中,输入附加依赖库的 lib 文件名字就可以啦(在之前我们已经在项目属性->VC++目录 设置中添加了附加库的目录,所以直接添加附加库就可以了 )。当你定义完预定义宏后再次编译就可以编译通过了,运行程序后窗口就显示出来了。如下所示
但看起来这个窗口有点简陋,只有中间一个蓝条,没有标题栏、没有状态栏,也不能关闭。先不着急,在接下来的教程中一点点循序渐进的往界面中添加内容。

本帖被以下淘专辑推荐:

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|断点社区 |网站地图

GMT+8, 2024-12-23 20:29 , Processed in 0.070302 second(s), 35 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表