[LVGL] 在VC_MFC中移植LVGL

news2025/3/13 0:43:49

前言:

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

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

2. gitee上下载lvgl8.3 源码,并将其文件夹改名为lvgllvgl: 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_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)
	{
#define LV_INDEV_STATE_REL      LV_INDEV_STATE_RELEASED
#define LV_INDEV_STATE_PR       LV_INDEV_STATE_PRESSED
		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_LvglFlushing.\n");

	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()
{
	lv_init();
	lv_port_disp_init();
	lv_port_indev_init();
	ui_init();//do your demo ui layout code
	AfxBeginThread(Thread_Lvgl_UiTimer, NULL);
	AfxBeginThread(Thread_Lvgl_Flushing, NULL);
	
}

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.运行效果:

        

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Crewai框架配置回调函数

官方文档里只指提了一句 不过不太难&#xff0c;在crew.py文件里配置一下就行了&#xff0c;下面是一个demo&#xff0c;这个函数会在research_task任务执行完触发&#xff08;配置LLM这里请看我这篇博客&#xff09; from crewai import Crew, Process, Agent, Taskfrom src.…

拧紧“安全阀”,AORO-P300 Ultra防爆平板畅通新型工业化通信“大动脉”

在油气管道泄漏的浓烟中&#xff0c;在矿道坍塌的密闭空间里&#xff0c;在洪水肆虐的救援现场&#xff0c;传统通讯设备频频失效的困境已成为历史。AORO-P300 Ultra防爆平板集5G通讯、红外感知、应急照明等实用功能于一体&#xff0c;以军工级防护与全场景智能应用&#xff0c…

基于docker搭建Kafka集群,使用KRaft方式搭建,摒弃Zookeeper

KAFKA基于docker使用KRaft进行集群搭建 环境&#xff1a;已成功搭建kafka服务 可点击链接跳转至安装kafka-3.8.0版本 并启用SASL认证 教程 使用基于Zookeeper方式搭建集群教程 kafka-3.8.0版本 并启用SASL认证 教程 搭建kafka-ui可视化工具 192.168.2.91 192.168.2.92 192…

CAD导入与解析,助力工业数据可视化高效呈现

背景 在企业的日常设计与管理中&#xff0c;CAD图纸早已成为不可或缺的重要资产&#xff0c;多年来知识积累的载体&#xff0c;凝聚了大量的心血与智慧。然而&#xff0c;CAD图纸往往只作为静态文件保存&#xff0c;应用场景较为有限。在数字经济时代&#xff0c;如何让CAD图纸…

基于docker部署kafka-3.8.0版本,并开启SASL认证模式

1、下载安装包 &#xff08;1&#xff09;https://kafka.apache.org/downloads 下载如下图版本 2、解压安装包 执行tar -xvf kafka_2.13-3.8.0.tgz命令对安装包进行解压。 3、增加配置文件 &#xff08;1&#xff09;进入 /kafka_2.13-3.8.0/config 目录 &#xff08;2&a…

从零开始人工智能Matlab案例-KNN的二维数据分类

基于K最近邻&#xff08;K-Nearest Neighbors, KNN&#xff09;算法的二分类案例&#xff0c;包含完整MATLAB代码、算法原理和核心思想说明。此案例使用合成数据集&#xff0c;无需复杂数据预处理&#xff0c;适合快速理解。 案例&#xff1a;基于KNN的二维数据分类 目标&…

Spring AOP 扫盲

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

DeepSeek 提示词之角色扮演的使用技巧

老六哥的小提示&#xff1a;我们可能不会被AI轻易淘汰&#xff0c;但是会被“会使用AI的人”淘汰。 在DeepSeek的官方提示库中&#xff0c;有“角色扮演&#xff08;自定义人设&#xff09;”的提示词案例。截图如下&#xff1a; 在“角色扮演”的提示词案例中&#xff0c;其实…

python3中错误与异常初识

一. 简介 在 编写 Python时&#xff0c;经常会遇到一些报错信息。接下来开始学习 Python3 中错误和异常。 本文首先初步了解一下 Python3中的错误和异常。 二. python3 中错误与异常初识 Python 中有两种错误&#xff1a;语法错误与异常。 1. 语法错误 Python 的语法错误…

【图像处理】- 基本图像操作

基本图像操作详解 基本图像操作是图像处理的基础&#xff0c;涵盖了对图像进行简单但重要的变换。以下是几种常见的基本图像操作及其详细说明&#xff1a; 1. 裁剪 (Cropping) 描述&#xff1a;从原始图像中提取一个矩形区域。 实现方法&#xff1a; 使用图像的坐标系指定…

Attention is All You Need-Transformer模型论文精读+架构分析--简单易懂版

Foreword写在前面的话&#xff1a; 大家好&#xff0c;我是一名刚开始学习Transformer的新手。这篇文章是我在学习Transformer过程中的一些笔记和心得&#xff0c;希望能和同样在学习人工智能深度学习模型的朋友们分享。由于我的知识有限&#xff0c;文章中可能存在错误或不准确…

Qt跨屏窗口的一个Bug及解决方案

如果我们希望一个窗口覆盖用户的整个桌面&#xff0c;此时就要考虑用户有多个屏幕的场景&#xff08;此窗口要横跨多个屏幕&#xff09;&#xff0c;由于每个屏幕的分辨率和缩放比例可能是不同的&#xff0c;Qt底层在为此窗口设置缩放比例&#xff08;DevicePixelRatio&#xf…

Spark--算子执行原理

一、sortByKey SortByKey是一个transformation算子&#xff0c;但是会触发action&#xff0c;因为在sortByKey方法内部&#xff0c;会对每个分区进行采样&#xff0c;构建分区规则&#xff08;RangePartitioner&#xff09;。 内部执行流程 1、创建RangePartitioner part&…

javaEE-6.网络原理-http

目录 什么是http? http的工作原理&#xff1a; 抓包工具 fiddler的使用 HTTP请求数据: 1.首行:​编辑 2.请求头(header) 3.空行&#xff1a; 4.正文&#xff08;body&#xff09; HTTP响应数据 1.首行&#xff1a;​编辑 2.响应头 3.空行&#xff1a; 4.响应正文…

windows版的docker如何使用宿主机的GPU

windows版的docker使用宿主机的GPU的命令 命令如下 docker run -it --nethost --gpus all --name 容器名 -e NVIDIA_DRIVER_CAPABILITIEScompute,utility -e NVIDIA_VISIBLE_DEVICESall 镜像名效果 (transformer) rootdocker-desktop:/# python Python 3.9.0 (default, Nov 15 …

【C++】STL——list的使用

目录 &#x1f495;1.带头双向链表List &#x1f495;2.list用法介绍 &#x1f495;3.list的初始化 &#x1f495;4.size函数与resize函数 &#x1f495;5.empty函数 &#x1f495;6.front函数与back函数 &#x1f495;7.push_front,push_back,pop_front,pop_back函数…

6.PPT:魏女士-高新技术企业政策【19】

目录 NO1234​ NO567 ​ NO1234 创建“PPT.pptx”考生文件夹Word素材文档&#xff1a;选中对应颜色的文字→选中对应的样式单击右键按下匹配对应文字&#xff1a;应用所有对应颜色的文字开始→创建新的幻灯片→从大纲&#xff1a;考生文件夹&#xff1a;Word素材重置 开始→版…

MLA 架构

注&#xff1a;本文为 “MLA 架构” 相关文章合辑。 未整理去重。 DeepSeek 的 MLA 架构 原创 老彭坚持 产品经理修炼之道 2025 年 01 月 28 日 10:15 江西 DeepSeek 的 MLA&#xff08;Multi-head Latent Attention&#xff0c;多头潜在注意力&#xff09;架构 是一种优化…

7.抽象工厂(Abstract Factory)

抽象工厂与工厂方法极其类似&#xff0c;都是绕开new的&#xff0c;但是有些许不同。 动机 在软件系统中&#xff0c;经常面临着“一系列相互依赖的对象”的创建工作&#xff1b;同时&#xff0c;由于需求的变化&#xff0c;往往存在更多系列对象的创建工作。 假设案例 假设…

旋钮屏设备物联网方案,ESP32-C3无线通信应用,助力设备智能化升级

在智能家居的浪潮中&#xff0c;旋钮屏以其独特的交互方式和便捷的操作体验&#xff0c;逐渐成为智能家电控制面板上的新宠儿。从智能冰箱、洗衣机到烤箱、空气炸锅等设备&#xff0c;旋钮屏的应用无处不在。 通过简单的旋转和按压操作&#xff0c;用户可以轻松调节温度、时间…