[LVGL] 在VC_MFC中移植LVGL

前言:

0. 在MFC中开发LVGL的优点是可以用多个Window界面做辅助扩展

1.本文基于VC2022-MFC单文档框架移植lvgl8

2. gitee上下载lvgl8.3 源码,并将其文件夹改名为lvgl

lvgl: LVGL 是一个开源图形库,提供您创建具有易于使用的图形元素、漂亮的视觉效果和低内存占用的嵌入式 GUI 所需的一切。 - Gitee.com

步骤:

1.新建一个MFC应用程序,命名为LVGL_MFC [可以自定义]

2.将下载的lvgl源码放到刚新建的LVGL_MFC工程目录下

3. 设置VS工程的属性:取消C/C++ 预编译头 ;VC++目录包含目录 添加:$(MSBuildThisFileDirectory)lvgl;$(MSBuildThisFileDirectory)lvgl\src;$(IncludePath)

4.在解决方案资源管理器第一栏,点击“显示所有文件”,然后展开lvgl文件夹,在src文件夹右击选择“包含在项目中”。

5.在lvgl目录下将lv_conf_template.h改名为lv_conf.h

6.编译MFC工程,此时应该会出现一个空白的对话框。

7.在lvgl目录下新建文件夹my_porting,文件夹里新建lv_driver_mfc.cpp,并将examples文件夹下的lv_port_disp_template.c 和lv_port_indev_template.c 复制到my_porting目录中,然后两个C文件分别改名为lv_port_disp.c和lv_port_indev.c ;注意将这两个C文件里面开头的#if 0 改为 #if 1 ; 然后在my_porting后击选择“包含在项目中”

8.在lv_port_disp.c中修改如下:

/*********************
 *      DEFINES
 *********************/
#ifndef MY_DISP_HOR_RES
    //#warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now.
    #define MY_DISP_HOR_RES   400// Define your window size width
#endif

#ifndef MY_DISP_VER_RES
    //#warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now.
    #define MY_DISP_VER_RES    400// Define your window size height
#endif

#define LV_VER_RES_MAX  600


//此函数修改如下
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{

extern void mfc_disp_flush_ex(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p);
    if (disp_flush_enabled) {
        mfc_disp_flush_ex(disp_drv, area, color_p);
    }
    return;
}

 9.在lv_port_indev.c中修改如下:

static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    extern void mfc_mouse_read_ex(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
    mfc_mouse_read_ex(indev_drv, data);
    return;
}

void lv_port_indev_init(void)
{
    static lv_indev_drv_t indev_drv;
    /*Register a mouse input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = mouse_read;
    indev_mouse = lv_indev_drv_register(&indev_drv);    
    return;
}

 10. lv_driver_mfc.cpp 内容如下:

#include "afxdialogex.h"
#include"lvgl.h"
#include <src/hal/lv_hal_disp.h>

HWND g_myMainWnd;


#include <io.h>
#include <fcntl.h>
void RedirectIOToConsole()
{
#if 1  //enable=1,在MFC下仍能使用printf在cmd窗口看日志,在初始化中调用即可
	// 分配控制台
	AllocConsole();
	// 重定向标准输入、输出和错误流
	FILE* fp;
	freopen_s(&fp, "CONOUT$", "w", stdout); // 将 stdout 绑定到控制台
	freopen_s(&fp, "CONOUT$", "w", stderr); // 将 stderr 绑定到控制台
	freopen_s(&fp, "CONIN$", "r", stdin);  // 将 stdin 绑定到控制台
#endif
}



extern "C"
{
	void lv_init(void);
	void lv_port_disp_init(void);
	void lv_port_indev_init(void);
	void ui_init(void);
	void mfc_mouse_read_ex(lv_indev_drv_t* indev_drv, lv_indev_data_t* data);
	void mfc_disp_flush_ex(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p);

}


void mfc_disp_flush_ex(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p)
{
	CWnd* pWnd = CWnd::FromHandle(g_myMainWnd);
	CDC* pDC = pWnd->GetDC(); // 获取设备上下文指针

	if (pDC) {
		// 定义位图信息
		BITMAPINFO bitmapInfo;
		memset(&bitmapInfo, 0, sizeof(bitmapInfo));

		// 设置位图信息头
		bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		bitmapInfo.bmiHeader.biWidth = area->x2 - area->x1 + 1;
		bitmapInfo.bmiHeader.biHeight = -(area->y2 - area->y1 + 1);  // 使用负值以表示自上而下的位图
		bitmapInfo.bmiHeader.biPlanes = 1;
		bitmapInfo.bmiHeader.biBitCount = LV_COLOR_DEPTH;  // 与LV_COLOR_DEPTH相符
		bitmapInfo.bmiHeader.biCompression = BI_RGB;  // 不压缩

		// 使用StretchDIBits将LVGL显存绘制到窗口,比单点SetPixel刷图效率高很多
		StretchDIBits(pDC->GetSafeHdc(),
			area->x1, area->y1,
			area->x2 - area->x1 + 1,
			area->y2 - area->y1 + 1,
			0, 0,
			area->x2 - area->x1 + 1,
			area->y2 - area->y1 + 1,
			color_p,
			&bitmapInfo,
			DIB_RGB_COLORS,
			SRCCOPY);
	}
	// 通知LVGL刷新完成
	lv_disp_flush_ready(disp_drv);
}

void mfc_mouse_read_ex(lv_indev_drv_t* indev_drv, lv_indev_data_t* data)
{
	POINT pt;
	GetCursorPos(&pt);  // 获取鼠标位置
	ScreenToClient(g_myMainWnd, &pt);  // 转换为窗口内坐标

	data->point.x = pt.x;
	data->point.y = pt.y;
	data->state = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
}


UINT Thread_Lvgl_UiTimer(LPVOID pParam)
{
	while (1)
	{
		lv_tick_inc(5);// 提供lvlg系统定时基准
		Sleep(5);  // 模拟耗时任务
	}
	return 0;
}


UINT Thread_Lvgl_Flushing(LPVOID pParam)
{
	RedirectIOToConsole();//启动日志printf打印窗口
	printf("Start Thread_Lvgl_Flushing.\n");
	int hor = lv_disp_get_hor_res(lv_disp_get_default());
	int ver = lv_disp_get_ver_res(lv_disp_get_default());
	printf("window h=%d,v=%d.\n", hor, ver);

	while (1)
	{
		lv_timer_handler();
		Sleep(50);  // 模拟耗时任务
	}
	return 0;  // 返回值
}


extern "C"
{
	void my_event_cb(lv_event_t* ev)
	{
		static int cnt = 0;
		lv_obj_t* m_parent = lv_scr_act();
		lv_obj_t* m_label = lv_obj_get_child(m_parent, 0);
		lv_label_set_text_fmt(m_label, "LVGL Cnt=%d.", ++cnt);
		printf("UI_Event_Code=%d.Count=%d.\n", ev->code,cnt);
		
	}

	void ui_init()
	{
		lv_obj_t* m_parent = lv_scr_act();
		lv_obj_t* m_label = lv_label_create(m_parent);
		lv_obj_t* m_btn = lv_btn_create(m_parent);

		lv_obj_set_style_bg_opa(m_parent, 0xFF, 0);
		lv_obj_set_style_bg_color(m_parent, lv_color_hex(0xeeaabb), 0);
		lv_label_set_text(m_label, "LVGL on MFC!");
		lv_obj_align(m_label, LV_ALIGN_CENTER, 0, 0);
		
		lv_obj_align(m_btn, LV_ALIGN_DEFAULT, 0, 50);
		lv_obj_add_event_cb(m_btn, my_event_cb, LV_EVENT_CLICKED, NULL);
    }
}


void lvgl_init()
{

	AfxBeginThread(Thread_Lvgl_UiTimer, NULL);
	AfxBeginThread(Thread_Lvgl_Flushing, NULL);

	lv_init();
	lv_port_disp_init();
	lv_port_indev_init();
	ui_init();//do your demo ui layout code
 	
}

11. 在主界面LVGL_MFCDlg.cpp的OnInitDialog()中添加初始化代码:

	// TODO: 在此添加额外的初始化代码
	extern HWND g_myMainWnd; 
	g_myMainWnd = m_hWnd;
	extern void lvgl_init(void);
	lvgl_init();

12. 在lv_conf_internal.h 修改   #define LV_COLOR_DEPTH 32  【PC在16bit颜色下会有色差】

13.运行效果:

后续:

完整工程VS_Demo:

lvgl_mfc: 基于lvgl8.3源代码移植到MFC(VC2022)单对话框平台。

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965440.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java----线程池

什么是线程池呢&#xff0c;先举一个情景&#xff1a; 一个火锅店开业了&#xff0c;早上人比较少&#xff0c;大家进店后不需要预约&#xff0c;直接付款在店里的桌子上吃饭&#xff0c;慢慢的人多了&#xff0c;店里的桌子不够用了&#xff0c;没座位的人可以先预约&#xf…

安卓开发,底部导航栏

1、创建导航栏图标 使用系统自带的矢量图库文件&#xff0c;鼠标右键点击res->New->Vector Asset 修改 Name , Clip art 和 Color 再创建一个 同样的方法再创建四个按钮 2、添加百分比布局依赖 app\build.gradle.kts 中添加百分比布局依赖&#xff0c;并点击Sync Now …

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注&#xff1a;cpp扩展请参考作者原…

Git--使用教程

Git的框架讲解 Git 是一个分布式版本控制系统&#xff0c;其架构设计旨在高效地管理代码版本&#xff0c;支持分布式协作&#xff0c;并确保数据的完整性和安全性。 Git 的核心组件&#xff1a; 工作区&#xff08;Working Directory&#xff09;&#xff1a; 工作区是你在本…

智慧停车系统:不同规模停车场的应用差异与YunCitys解决方案

在智慧停车领域&#xff0c;不同规模停车场因自身特点&#xff0c;对智慧停车系统的需求和应用效果存在显著差异。云创智城凭借丰富的经验和先进的技术&#xff0c;为各类规模停车场打造了贴合需求的智慧停车系统&#xff0c;下面为您详细剖析。 小型停车场&#xff1a;精准高…

snort的学习记录

一、what is snort&#xff1f;什么是snort? Snort 是一款开源的 网络入侵检测系统&#xff08;NIDS&#xff09; 和 网络入侵防御系统&#xff08;NIPS&#xff09;&#xff0c;能够实时监控网络流量&#xff0c;检测恶意行为&#xff08;如端口扫描、SQL注入、DDoS攻击等&a…

PHP-trim

[题目信息]&#xff1a; 题目名称题目难度PHP-trim1 [题目考点]&#xff1a; trim() 函数移除字符串两侧的空白字符或其他预定义字符。[Flag格式]: SangFor{dl9hFiITmhQNAJysCgigAskyCZ6kQaDc}[环境部署]&#xff1a; docker-compose.yml文件或者docker tar原始文件。 ht…

maven如何不把依赖的jar打包到同一个jar?

spring boot项目打jar包部署&#xff1a; 经过以下步骤&#xff0c; 最终会形成maven依赖的多个jar&#xff08;包括lib下添加的&#xff09;、 我们编写的程序代码打成一个jar&#xff0c;将程序jar与 依赖jar分开&#xff0c;便于管理&#xff1a; success&#xff1a; 最终…

【ArcGIS Pro 简介1】

ArcGIS Pro 是由 Esri &#xff08;Environmental Systems Research Institute&#xff09;公司开发的下一代桌面地理信息系统&#xff08;GIS&#xff09;软件&#xff0c;是传统 ArcMap 的现代化替代产品。它结合了强大的空间分析能力、直观的用户界面和先进的三维可视化技术…

DeepSeek 部署过程中的问题

文章目录 DeepSeek 部署过程中的问题一、部署扩展&#xff1a;docker 部署 DS1.1 部署1.2 可视化 二、问题三、GPU 设置3.1 ollama GPU 的支持情况3.2 更新 GPU 驱动3.3 安装 cuda3.4 下载 cuDNN3.5 配置环境变量 四、测试 DeepSeek 部署过程中的问题 Windows 中 利用 ollama 来…

Elasticsearch基本使用详解

文章目录 Elasticsearch基本使用详解一、引言二、环境搭建1、安装 Elasticsearch2、安装 Kibana&#xff08;可选&#xff09; 三、索引操作1、创建索引2、查看索引3、删除索引 四、数据操作1、插入数据2、查询数据&#xff08;1&#xff09;简单查询&#xff08;2&#xff09;…

点(线)集最小包围外轮廓效果赏析

“ 图像、点集、线集合最小外轮廓计算应用较为广泛&#xff0c;如抠图、神奇选择、LOD、碰撞检查等领域&#xff0c;提高场景效率” 1.前言 作者基于递归迭代求解实现点集的最小外轮廓计算&#xff0c;在CGLib库中实现&#xff0c;已集成于CGViewer&#xff0c;可联系作者试用&…

IOPS与吞吐量、读写块大小及延迟之间的关系

IOPS&#xff08;每秒输入/输出操作次数&#xff09;、吞吐量、读写块大小及延迟是衡量存储系统性能的四个关键指标&#xff0c;它们之间存在密切的关系。以下从多个方面详细说明这些指标之间的关系&#xff1a; 1. IOPS与吞吐量的关系 公式关系&#xff1a;吞吐量&#xff0…

FPGA与ASIC:到底选哪个好?

不少人想转行FPGA&#xff0c;但在ASIC和FPGA之间犹豫不决。要做出选择&#xff0c;首先需要清楚两者的区别和各自特点。 FPGA (Field Programmable Gate Array) 是一种现场可编程门阵列芯片&#xff0c;本质上它是一种半定制的芯片&#xff0c;可以根据需要重新编程&#xff…

LLMs之data:synthetic-data-generator的简介、安装和使用方法、案例应用之详细攻略

LLMs之data&#xff1a;synthetic-data-generator的简介、安装和使用方法、案例应用之详细攻略 目录 synthetic-data-generator的简介 1、核心功能和优势 2、特点 synthetic-data-generator的安装和使用方法 1、安装 pip安装 安装依赖项 运行应用 2、使用方法 快速入…

第二天:系统从BIOS/UEFI到GRUB/bootloader的启动过程

目录 **一、BIOS/UEFI初始化阶段****二、引导加载程序&#xff08;GRUB&#xff09;的启动过程****1. BIOS模式下的GRUB分阶段加载****2. UEFI模式下的GRUB加载** **三、操作系统内核加载与初始化****四、关键组件与配置文件****五、故障排查与恢复****总结**常见问题如何在UEF…

113,【5】 功防世界 web unseping

进入靶场 代码审计 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;方便开发者查看代码结构和内容 highlight_file(__FILE__);// 定义一个名为 ease 的类 class ease {// 私有属性 $method&#xff0c;用于存储要调用的方法名private $method;// 私有属性 $args&…

图解BWT(Burrows-Wheeler Transform) 算法

Burrows-Wheeler Transform (BWT) 是一种数据转换算法, 主要用于数据压缩领域. 它由 Michael Burrows 和 David Wheeler 在 1994 年提出, 广泛应用于无损数据压缩算法(如 bzip2)中. BWT 的核心思想是通过重新排列输入数据, 使得相同的字符更容易聚集在一起, 从而提高后续压缩算…

DeepSeek辅助学术写作【句子重写】效果如何?

句子重写(功能指数:★★★★★) 当我们想引用一篇文章中的一-些我们认为写得很好的句子时&#xff0c;如果直接将原文加人自己的文章&#xff0c;那么即使我们标注上了引用&#xff0c;也依旧会被查重软件计算在重复比例中。查重比例过高的话&#xff0c;会影响投稿或毕业答辩送…

【CAD】卸载清理注册表后安装失败/错误 1402无法打开主键:UNKNOWN Components DAFE。。。

这是因为注册表中的 CurrentVersion\Installer\UserData二级子目录中Components的文件缺少权限&#xff0c;只需要将权限添加为administors即可 一图流&#xff0c;就是把权限给到Administrators&#xff0c;然后就再以管理员权限安装就可以了&#xff0c;还有如果破解的软件可…