找回密码
 立即注册
查看: 771|回复: 20

怎么用C++写图形界面程序?

[复制链接]
发表于 2021-9-3 20:42 | 显示全部楼层 |阅读模式
我说的不是控制台,就是有边界有框,正常一点的界面
发表于 2021-9-3 20:52 | 显示全部楼层
来试试新鲜出炉的PainterEngine吧,开源,简单,易用

PainterEngine导引

PainterEngine是一个基于C语言编写的完全开源的图形游戏引擎。你可以在这里下载到PainterEngine的完整代码及相关帮助文档
PainterEnginematrixcascade/PainterEnginePainterEngine独立于操作系统、开发工具链及运行时环境,这意味着PainterEngine可以被移植到任意提供C语言编译环境的平台中,包括但不限windows,linux,android,ios及一系列单片机裸机环境中。
PainterEngine的设计理念精简,学习曲线平缓,你只需要花很少的时间在引擎的学习上,耗费极少的学习时间成本,快速实现你需要的功能。
PainterEngine 目录结构

*Core:PainterEngine基础算法库
*Kernel:PainterEngine模块代码库(基于Core)
Architecture:PainterEngine功能代码库(基于Kernel)
Platform:平台兼容层代码库
Support:相关支持、帮助文档
PainterEngine开发环境

Windows

Visual Studio

1.启动visual studio


2.菜单--文件—新建—项目—创建一个空项目


3.在项目上右键---添加---新建筛选器—命名为PainterEngine(非必须步骤,可跳过)


4.将PainterEngine目录下kernel、core、architecture三个文件夹(所有文件拖到新建的筛选器中,如跳过了步骤3可直接拖到项目中)


5.进入PainterEngine/platform,因为我们开发的是windows程序,因此将windows目录的同样拖动到筛选器中。


6.进入PainterEngine/platform/framework,复制当中的所有文件  


7.挑一个你喜欢的地方,新建一个文件夹(作为你的工程代码目录),将上面的文件复制到这个文件夹中(例如D盘中我新建了一个My First PainterEngine Project作为示范)


8.将复制的文件黏贴到这个文件夹中,并将这些文件拖动到项目中



9.选中项目,点击菜单项目—属性


10.将配置改成所有配置---VC++目录---包含目录


11.将PainterEngine的所在目录,windows平台库目录和你工程代码目录添加进来,然后点击确定


12.现在,你可以试运行第一个PainterEngine项目了



MingW(CLoin,Visual Studio code)

1.下载并安装mingw,设置环境变量(请参照mingw相关教程,过程略).
进入PainterEngine/platform/framework,复制当中的所有文件


2.挑一个你喜欢的地方,新建一个文件夹(作为你的工程代码目录),将上面的文件复制到这个文件夹中(例如D盘中我新建了一个MyPainterEngineMingWProject作为示范,注意文件夹名不要带有空格)  


3.进入PainterEngine\platform\makefile目录,用记事本打开makefile文件





4.修改makefile的配置,包含生成exe的路径,工程代码的路径和PainterEngine的路径
其中target为生成exe的路径
project_path为工程代码的路径
painterengine_path 为PainterEngine路径
(以上路径注意不要带有空格)


5.双击PainterEngine\platform\makefile\build.bat,编译运行



Android

Android studio

1.打开android studio,File---new—new project—选择No Activity然后点击Next


2.选择一个你喜欢的位置,创建项目文件(以D:\MyPainterEngineForAndroid为例),点击finish


3.在项目目录的app中点击右键,选择show in explorer


4.依次进入\app\src\main


5.打开PainterEngine目录下的platform/android,将AndroidManifest.xml和CMakeList覆盖和复制到\app\src\main



5. 进入PainterEngine/platform/framework,复制当中的所有文件



6.挑一个你喜欢的地方,新建一个文件夹(作为你的工程代码目录),将上面的文件复制到这个文件夹中(例如D盘中我新建了一个PainterEngineProject作为示范,注意文件夹名不要带有空格)




7.打开\app\src\main\CMakeLists.txt,




PAINTERENGINE_DIR 修改为你的PainterEngine路径
PAINTERENGINE_PROJECT_DIR 修改为你的工程代码目录路径  



8.回到Android Studio,选中App,右键点击Link C++ Project With Gradle  



9.选择之前配置好的CMakeLists.txt





10.在Android Studio中按下Ctrl+F9或点击菜单栏上的build


编译成功,现在你可以连接手机运行PainterEngine的Android应用了  


PainterEngine基础框架结构

Application 基础架构

PainterEngine architecture包含着PainterEngine默认的运行时配置与执行框架,使用PainterEngine的框架体系开发PainterEngine程序是强烈建议的.
别担心,PainterEngine的框架极为简单,PainterEngine将占用您短短几分钟的时间快速搭建并了解其框架。
打开工程目录,其中:
PainterEngine_Startup  PainterEngine运行时框架,在当中定义了内存池大小,运行平台,窗体大小等应用的基本参数.
PainterEngine_Application 为功能逻辑运行框架,是编写用户代码的主要地方.
打开PainterEngine_Application.c,你可以看到三个函数
PX_ApplicationInitialize

px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)PainterEngine初始化函数,在该函数中,完成应用的一系列初始化操作,例如,在这个函数中将会先初始化PainterEngine的运行时环境,创建的PainterEngine应用的窗口,或者如果你有对音频播放的需求你可以你加上对音频的支持。
其中
pApp 是应用的描述结构
Screen_width 是当前屏幕的像素宽度
Screen_height是当前屏幕的像素高度

当然为了减少PainterEngine部署难度,你可以看到在这个函数已经调用了一个默认的初始化函数
PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);

这个函数将初始化一个最初默认的运行时环境,并依据当前的屏幕创建了一个窗口。你可以在PainterEngine_Startup.c找到这个函数的详细实现,但在入门阶段和之后开发应用的大部分情况,你都可以直接使用这个默认的初始化函数或对其进行少量的修改,这个部分将在之后的章节详细介绍。
PX_ApplicationUpdate

px_void PX_ApplicationUpdate(PX_Application *pApp,px_dword elpased)PainterEngine的更新函数,在大部分的情况下,PainterEngine的运行环境会循环调用这个函数。
其中:
pApp 是应用的描述结构
elapsed 是上次更新后经历的时间,单位是毫秒
对于其详细应用将在之后详细介绍
PX_ApplicationRender

px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)PainterEngine的渲染函数,在大部分的情况下,PainterEngine的运行环境会循环调用这个函数(实时渲染),这个函数的主要作用是绘制图像,当然,为了让显示和动画看起来尽可能流畅,你应该保证这个函数在每秒钟能被执行60次以上。但如果你对渲染没有非常高的实时性要求,你可以降低其帧率以实现更低的渲染功耗。
在这个函数中,你可以看到两行已经写好的代码
px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));其中,第一句中的pRenderSurface表示渲染表面
PX_RuntimeRenderClear表示用某种颜色清空当前的渲染表面(或者绘制背景色),在上面PX_COLOR是一个颜色生成函数,四个参数分别表示a,r,g,b颜色分量
简单来说,PainterEngine的绘制流程是,先将surface成背景色,然后在上面绘制图像,在下一帧,再将这个surface重新刷成背景色,再画下一帧的图像。
其中
pApp 是应用的描述结构
elapsed 是上次更新后经历的时间,单位是毫秒
对于其详细应用将在之后详细介绍
PX_ApplicationPostEvent

这个函数用户响应用户输入事件,最常见的是鼠标移动,键盘按键,触摸屏按键等事件
px_void PX_ApplicationPostEvent(PX_Application *pApp,PX_Object_Event e)其中:
pApp是应用的描述结构
e是事件类型,
e.event有以下几种常用事件类型
#define PX_OBJECT_EVENT_ANY                 0  //任意类型
#define PX_OBJECT_EVENT_CURSORMOVE          1        //光标移动
#define PX_OBJECT_EVENT_CURSORUP            2        //光标抬起
#define PX_OBJECT_EVENT_CURSORRDOWN         3  //光有右键按下
#define PX_OBJECT_EVENT_CURSORDOWN          4  //光标按下(触摸屏按下)
#define PX_OBJECT_EVENT_CURSORRUP           5  //光标抬起(触摸屏抬起)
#define PX_OBJECT_EVENT_CURSOROVER          6  //光标移动到区域*
#define PX_OBJECT_EVENT_CURSOROUT           7  //光标移出区域*
#define PX_OBJECT_EVENT_CURSORWHEEL         8  //光标滚轮*
#define PX_OBJECT_EVENT_STRING              9  //输入法字符串*
#define PX_OBJECT_EVENT_EXECUTE             10 //按钮按下
#define PX_OBJECT_EVENT_CURSORCLICK         11 //光标单击*
#define PX_OBJECT_EVENT_CURSORDRAG          12 //光标拖拽(触摸屏手指滑动)
#define PX_OBJECT_EVENT_VALUECHANGED        13 //值改变*
#define PX_OBJECT_EVENT_DRAGFILE            14 //文件拖进
#define PX_OBJECT_EVENT_KEYDOWN             15 //键盘按键按下
#define PX_OBJECT_EVENT_IMPACT              16 //对象碰撞(PX_World事件)
#define PX_OBJECT_EVENT_ONFOCUSCHANGED      17 //焦点改变
#define PX_OBJECT_EVENT_SCALE               18 //缩放
#define PX_OBJECT_EVENT_WINDOWRESIZE        19 //窗体尺寸改变详细内容将在之后讨论
获取PainterEngine绘制表面基础信息

PainterEngine的所有绘制是基于px_surface(渲染表面)的
在PX_ApplicationRender中pApp->runtime.RenderSurface是默认的渲染表面,在这个渲染表面绘制的图像会被直接显示在渲染结果中
因为显示设备的不一样,或者用户调整显示窗口的大小,默认渲染表面的长度和宽度可能会发生变化
你可以使用
pApp->runtime.surface_width 来获取当前渲染表面的像素宽度
pApp->runtime.surface_height来获取当前渲染表面的像素高度
使用PainterEngine绘制几何图形

*PainterEngine中使用的二维坐标系布置如下(屏幕坐标系)



其中,左上角为原点(0,0)右下角为终点(surface宽度,surface高度)
*PainterEngine采用了反走样算法进行几何绘制
绘制圆形

线

函数原型


函数名px_void PX_GeoDrawLine(px_surface *psurface, px_int x0, px_int y0, px_int x1, px_int y1 ,pt_int lineWidth, px_color color);
说明绘制一个反走样线段
参数psurface 渲染表面x0 y0起始点坐标x1 y1 终点坐标lineWidth 线宽color 颜色

示范

在PX_ApplicationRender中添加画线代码(如下所示),分别绘制三根:
(100,100)--->  (600,100) 的 宽度为2的 红线
(100,200)--->  (600,200) 的 宽度为6的 绿线
(100,300)--->  (600,300) 的 宽度为12的 蓝线
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawLine(pRenderSurface,100,100,600,100,2,PX_COLOR(255,255,0,0));
    PX_GeoDrawLine(pRenderSurface,100,200,600,200,6,PX_COLOR(255,0,255,0));
    PX_GeoDrawLine(pRenderSurface,100,300,600,300,12,PX_COLOR(255,0,0,255));
}


边框

函数原型



函数名px_void PX_GeoDrawBorder(px_surface *psurface, px_int left, px_int top, px_int rignt, px_int bottom ,px_int lineWidth,px_color color);
说明绘制一个边框
参数psurface 渲染表面left top right bottom 位置描述lineWidth 边框宽度像素color 颜色

示范1

在PX_ApplicationRender中添加代码(如下所示),分别绘制一个:
(100,100)--->  (300,300) 的 宽度为3的 黑色 边框
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawBorder(pRenderSurface,100,100,300,300,3,PX_COLOR(255,0,0,0));
}



示范2

在PX_ApplicationRender中添加代码(如下所示),分别绘制一个:
(100,100)--->  (300,300) 的 宽度为8的 红色 半透明 边框
(200,200)--->  (500,500) 的 宽度为8的 蓝色 半透明 边框
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawBorder(pRenderSurface,100,100,300,300,8,PX_COLOR(128,255,0,0));
    PX_GeoDrawBorder(pRenderSurface,200,200,500,500,8,PX_COLOR(128,0,0,255));
}



矩形

函数原型



函数名px_void PX_GeoDrawRect(px_surface *psurface, px_int left, px_int top, px_int right, px_int bottom,px_color color);
说明绘制一个实心矩形
参数psurface 渲染表面left top right bottom 位置描述color 颜色

示范

在PX_ApplicationRender中添加代码(如下所示),分别绘制一个:
(100,100)--->  (300,300) 的 宽度为8的 红色 半透明 矩形
(200,200)--->  (500,500) 的 宽度为8的 蓝色 半透明 矩形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawRect(pRenderSurface,100,100,300,300,PX_COLOR(128,255,0,0));
    PX_GeoDrawRect(pRenderSurface,200,200,500,500,PX_COLOR(128,0,0,255));
}




实心圆

函数原型


函数名px_void PX_GeoDrawSolidCircle(px_surface *psurface, px_int x,px_int y,px_int Radius,px_color color );
说明绘制一个反走样实心圆
参数psurface 渲染表面x,y 圆心radius 半径color 颜色

示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
(300,300) 的 半径为200的 紫色 圆形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
     px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawSolidCircle(pRenderSurface,300,300,200,PX_COLOR(255,255,0,255));

}

函数原型


函数名px_void PX_GeoDrawCircle(px_surface *psurface,px_int x,px_int y,px_int Radius ,pt_int lineWidth,px_color color);
说明绘制一个反走样圆
参数psurface 渲染表面x,y 圆心radius 半径lineWidth 线宽color 颜色

示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
(300,300) 的 半径为200 线宽为10的 紫色 圆形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
     px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_GeoDrawCircle(pRenderSurface,300,300,200,10,PX_COLOR(255,255,0,255));
}



函数原型


函数名px_void PX_GeoDrawRing(px_surface *psurface, px_int x,px_int y,px_int Radius,px_int lineWidth,px_color color,px_uint start_angle,px_uint end_angle)
说明绘制一个反走样环
参数psurface 渲染表面x,y 环心radius 半径lineWidth 线宽color 颜色start_angle 起始角度(大于0)end_angle 终止角度(大于0)这个环遵循顺时针方向


示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
环心在(300,300) 的 半径为200 线宽为10 开始角度45度终止角度270度的 蓝色 环形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawRing(pRenderSurface,300,300,200,50,PX_COLOR(255,0,0,255),45,270);

}



扇形

函数原型



函数名px_void PX_GeoDrawSector(px_surface *psurface, px_int x,px_int y,px_int Radius_outside,px_int Radius_inside,px_color color,px_uint start_angle,px_uint end_angle);
说明绘制一个反走样扇形
参数psurface 渲染表面x,y 环心outside 外径inside 内径color 颜色start_angle 起始角度end_angle 终止角度这个扇形遵循顺时针方向


示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
扇心在(300,300) 的 内径为0 外径为200 开始角度45度终止角度270度的 蓝色 扇形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawSector(pRenderSurface,300,300,200,0,PX_COLOR(255,0,0,255),45,270);

}


圆角矩形

函数原型



函数名px_void PX_GeoDrawRoundRect(px_surface *psurface, px_int left, px_int top, px_int right, px_int bottom,px_float roundRaduis,px_float linewidth,px_color color);
说明绘制一个反走样圆角矩形
参数psurface 渲染表面left top right bottom 位置描述roundRadius 圆角半径lineWidth 线宽color 颜色


示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
(100,100)(600,200) 圆角半径为25,线宽为5的红色圆角矩形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawRoundRect(pRenderSurface,100,100,600,200,25,5,PX_COLOR(255,0,0,255));

}


实心圆角矩形

函数原型



函数名px_void PX_GeoDrawSolidRoundRect(px_surface *psurface, px_int left, px_int top, px_int right, px_int bottom,px_float roundRaduis,px_color color);
说明绘制一个反走样实心圆角矩形
参数psurface 渲染表面left top right bottom 位置描述roundRadius 圆角半径color 颜色


示范

在PX_ApplicationRender中添加代码(如下所示),绘制一个:
(100,100)(600,200) 圆角半径为25的蓝色实心圆角矩形
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));

    PX_GeoDrawSolidRoundRect(pRenderSurface,100,100,600,200,25,5,PX_COLOR(255,0,0,255));

}


使用PainterEngine绘制图片纹理

加载纹理

在绘制图片纹理前PainterEngine需要先将纹理加载到内存中
PainterEngine_startup.c中,默认提供了一系列从文件加载资源的函数实现,当然这需要对应平台提供文件系统的支持.

在加载纹理之前,先定义px_texture用于存储纹理信息,为此,打开PainterEngine_Application.h在PX_Application中定义一个px_texture的实例MyTexture
typedef struct
{
    px_texture MyTexture;
    PX_Runtime runtime;
}PX_Application;(当然,这个MyTexture你也可以声明在其它地方,比如把它定义为全局变量,这里仅仅是作为一个例子)
现在,我们需要加载纹理,PainterEngine默认支持bmp和traw两种格式的文件,其中,traw格式文件可以由png文件转换,转换工具你可以在support/tools中找到(PainterEngine_PngToTraw.exe)
然后你可以使用PX_LoadTextureFromFile完成纹理的加载
px_bool PX_LoadTextureFromFile(px_memorypool *mp,px_texture *tex,const px_char path[]);其中:
Mp:表示将纹理加载后存储到的内存池,一般情况下,静态资源可以存储在pApp->runtime.mp_resources中
Tex:px_texture实例
Path:纹理文件的路径(windows以D盘下的test.traw)为例
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(PX_LoadTextureFromFile(pApp->runtime.mp_resources,&pApp->MyTexture,"D:/test.traw"))
    {
        //加载成功
    }
    else
    {
        //加载失败
    }

    return PX_TRUE;
}如果的你的程序使用Android平台,你可以将图片资源放在assets目录下,然后通过assets/图片名访问这个资源例如:
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(PX_LoadTextureFromFile(&pApp->runtime.mp_resources,&pApp->MyTexture,"asssets/test.traw"))
    {
        //加载成功
    }
    else
    {
        //加载失败
    }

    return PX_TRUE;
}现在,纹理资源加载完成了

绘制纹理

PainterEngine提供多种纹理绘制函数

函数原型



函数名px_void PX_TextureRender(px_surface *psurface,px_texture *tex,px_int x,px_int y ,PX_TEXTURERENDER_REFPOINT refPoint,PX_TEXTURERENDER_BLEND *blend);
说明渲染一个纹理到表面
参数psurface 渲染到的表面 px_texture需要渲染的纹理 x,y偏移量(该坐标以纹理左上角为参照)refPoint 参考中心点,用于表示纹理绘制的相对位置blend blend类型结构体,用于调整绘制纹理的alpha,hdr值当它为PX_NULL时,表示采用默认blend值typedef struct{        float hdr_R; //HDR of Red        float hdr_G; //HDR of Green        float hdr_B; //HDR of Blue        float alpha; //Blend of alpha}PX_TEXTURERENDER_BLEND;
返回值-


示范

在PX_ApplicationInitialize,PX_ApplicationRender中添加代码(如下所示),绘制一个纹理
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(PX_LoadTextureFromFile(&pApp->runtime.mp_resources,&pApp->MyTexture,"D:/test.traw"))
    {
        //加载成功
    }
    else
    {
        //加载失败
    }

    return PX_TRUE;
}

px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_TextureRender(pRenderSurface,&pApp->MyTexture,pApp->runtime.surface_width/2,pApp->runtime.window_height/2,PX_TEXTURERENDER_REFPOINT_CENTER,PX_NULL);
}




使用PainterEngine绘制文本

绘制默认ANSI字模

PainterEngine默认集成了ANSI文本字模,使用默认字模绘制文本十分简单
函数原型

函数名px_int PX_FontDrawText(px_surface *psurface,int x,int y,PX_FONT_ALIGN align,const px_char *Text,px_color Color);
说明绘制ANSI文本
参数psurface 表面x,y偏移坐标align 对齐模式PX_FONT_ALIGN_LEFTTOP, 左上角对齐        PX_FONT_ALIGN_MIDTOP,居中顶部对齐        PX_FONT_ALIGN_RIGHTTOP,右上角对齐        PX_FONT_ALIGN_LEFTMID,靠左居中对齐        PX_FONT_ALIGN_CENTER,中心对齐        PX_FONT_ALIGN_RIGHTMID,靠右居中对齐        PX_FONT_ALIGN_LEFTBOTTOM,靠左底部对齐        PX_FONT_ALIGN_MIDBOTTOM,居中底部对齐        PX_FONT_ALIGN_RIGHTBOTTOM,靠右底部对齐Text ANSI字符集文本指针Color 颜色
返回值-


示范

在PX_ApplicationRender中添加代码(如下所示),绘制深蓝色文本”Hello World 123”
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_FontDrawText(pRenderSurface,10,100,PX_FONT_ALIGN_LEFTTOP,"Hello World 123",PX_COLOR(255,0,0,128));
}



创建字模文件

PainterEngine运行您使用TTF文件创建自定义的字模文件,字模制作工具你可以在PainterEngine/supports/tools中找到(PainterEngine_Fontmodule.exe)

1.运行字模制作工具,选择你需要的ttf文件(以幼圆为例)




2.选择字典文件(TXT),字典文件里应该包含你程序需要用到的所有文字(如果没有,这个文字将不被显示),同时,字典文件必须按照特定的编码进行保存(强烈建议UTF8或GBK).在
PainterEngine/supports/tools/Font Module Dictionary中,你可以找到ANSI和汉字不同编码的所有字符字典,你可以直接使用这些字典,当然,在一些存储空间紧张的情况下,强烈建议使用裁剪后的字典以减小生成字模的文件大小(这里,笔者以UTF8的字典为例).




3.选择字模的生成路径(D:/test.pxf)




4.设定字体大小




5.设定编码(必须和字典文件的使用编码一致)




6.生成字模




现在,你可以在D盘中找到test.pxf的字模文件了

*注意,chs中仅包含汉字文件,并不包含ANSI中的英文字符及标点,因此,如果你希望支持所有的汉字及英文标点,你应该使用ANSI_utf8.txt和英文字体制作另一份字模文件,下面是例子:




绘制字模文本

相关函数原型

字模初始化


函数名px_bool PX_FontModuleInitialize(px_memorypool *mp,PX_FontModule *module,PX_FONTMODULE_CODEPAGE codepage)
说明初始化一个字模库
参数Mp 内存池Module 字模库codepage 字模代码页
返回值如果成功返回PX_TRUE,否者返回PX_FALSE


以字模库绘制文本


函数名px_int PX_FontModuleDrawText(px_surface *psurface,PX_FontModule *mod,int x,int y,PX_FONT_ALIGN align,const px_char *Text,px_color Color)
说明以该字模库绘制文本,注意,输入的字模必须是UTF-16 littleendia编码的
参数Psurface 目标表面X 原点x坐标Y 原点y坐标 Text 文本Color字颜色Mod 字模库Align 字体对齐模式PX_FONT_ALIGN_LEFTTOP, 左上角对齐        PX_FONT_ALIGN_MIDTOP,居中顶部对齐        PX_FONT_ALIGN_RIGHTTOP,右上角对齐        PX_FONT_ALIGN_LEFTMID,靠左居中对齐        PX_FONT_ALIGN_CENTER,中心对齐        PX_FONT_ALIGN_RIGHTMID,靠右居中对齐        PX_FONT_ALIGN_LEFTBOTTOM,靠左底部对齐
返回值-绘制文本的像素宽度


1.创建字模库

使用PainterEngine绘制字模文本,首先需要创建字模库,打开PainterEngine_Application.h,在PX_Application的结构体定义中,添加PX_FontModule
typedef struct
{
    PX_FontModule fm;
    PX_Runtime runtime;
}PX_Application;
2.初始化字模库

打开PainterEngine_Application.c,添加初始化字模库代码
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(!PX_FontModuleInitialize(&pApp->runtime.mp_resources,&pApp->fm,PX_FONTMODULE_CODEPAGE_UTF8)) return PX_FALSE;

    return PX_TRUE;
}3.加载字模文件

打开PainterEngine_Application.c,添加初始化字模加载代码
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(!PX_FontModuleInitialize(&pApp->runtime.mp_resources,&pApp->fm,PX_FONTMODULE_CODEPAGE_UTF8)) return PX_FALSE;
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test.pxf")) return PX_FALSE;//加载中文字模
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test2.pxf")) return PX_FALSE;//加载ANSI字模
    return PX_TRUE;
}
4.绘制字模文本

打开PainterEngine_Application.c, 在PX_ApplicationRender中绘制字模文本:
”你好,PainterEngine”
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(!PX_FontModuleInitialize(&pApp->runtime.mp_resources,&pApp->fm,PX_FONTMODULE_CODEPAGE_UTF8)) return PX_FALSE;
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test.pxf")) return PX_FALSE;//加载中文字模
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test2.pxf")) return PX_FALSE;//加载ANSI字模
    return PX_TRUE;
}

px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_FontModuleDrawText(pRenderSurface,&pApp->fm,10,100,PX_FONT_ALIGN_LEFTTOP,"你好,PainterEngine",PX_COLOR(255,0,0,128));
}


使用PainterEngine创建交互式组件(UI控件)

PainterEngine的应用的组建是以对象的形式存在的.PainterEngine内部集成了多种常用交互式组件(对象)供用户使用,PainterEngine强烈鼓励用户自己设计或拓展需要的功能组件(对象),下面是几个简单的交互式组件(对象)例子.
创建根对象

函数原型


函数名PX_Object *PX_ObjectCreate(px_memorypool *mp,PX_Object *Parent,px_float x,px_float y,px_float z,px_float Width,px_float Height,px_float Lenght);
功能创建一个对象
mp对象使用的内存池
parent父对象(如果为NULL表示这是一个根对象)
x,y,z坐标信息,注意z坐标信息,z的值越大,这个对象在渲染时将被最先绘制,这也就意味着z值小的对象将会覆盖在z值较大的对象中
Width,Heigth,Lenght宽度,高度,长度
返回值返回创建的对象指针


示范

在创建其它交互式组件(对象)之前,强烈建议创建一个根对象以便于对象树的管理,创建根对象很简单,打开PainterEngine_Application.h,定义一个PX_Object *ui_root;
typedef struct
{
    PX_Object *ui_root;
    PX_FontModule fm;
    PX_Runtime runtime;
}PX_Application;打开PainterEngine_Application.c,在PX_ApplicationInitialize中添加代码
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    if(!PX_FontModuleInitialize(&pApp->runtime.mp_resources,&pApp->fm,PX_FONTMODULE_CODEPAGE_UTF8)) return PX_FALSE;
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test.pxf")) return PX_FALSE;//加载中文字模
    if(!PX_LoadFontModuleFromFile(&pApp->fm,"D:/test2.pxf")) return PX_FALSE;//加载ANSI字模

    pApp->ui_root=PX_ObjectCreate(&pApp->runtime.mp_ui,0,0,0,0,0,0,0);
    return PX_TRUE;
}
创建按钮控件

函数原型



函数名PX_Object *PX_Object_PushButtonCreate(px_memorypool *mp,PX_Object *Parent,px_int x,px_int y,px_int Width,px_int Height,const px_char *Text,PX_FontModule *fontmodule,px_color Color);
说明创建一个按钮交互控件
参数mp内存池Parent 父对象x,y 控件左上角位置width 宽度height 高度Text 控件显示文本fontmodule 控件显示文本的字模(为PX_NULL表示使用ANSI默认字模)color 文本颜色
返回值如果成功PX_Object指针,否者返回PX_NULL


示范

打开PainterEngine_Application.h,定义一个PX_Object * button;
typedef struct
{
    PX_Object *ui_root;
    PX_Object *button;
    PX_Runtime runtime;
}PX_Application;


打开PainterEngine_Application.c,在PX_ApplicationInitialize中添加代码
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);

    pApp->ui_root=PX_ObjectCreate(&pApp->runtime.mp_ui,0,0,0,0,0,0,0);

    pApp->button=PX_Object_PushButtonCreate(&pApp->runtime.mp_ui,pApp->ui_root,100,100,84,32,"Button",PX_NULL,PX_COLOR(255,0,0,0));
    return PX_TRUE;
}在PX_ApplicationUpdate中添加代码
px_void PX_ApplicationUpdate(PX_Application *pApp,px_dword elpased)
{
    PX_ObjectUpdate(pApp->ui_root,elpased);
}在PX_ApplicationRender中添加代码
px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_ObjectRender(pRenderSurface,pApp->ui_root,elpased);
}
在PX_ApplicationPostEvent中添加代码
px_void PX_ApplicationPostEvent(PX_Application *pApp,PX_Object_Event e)
{
    PX_ApplicationEventDefault(&pApp->runtime, e);
    PX_ObjectPostEvent(pApp->ui_root,e);
}



添加点击事件

函数原型


注册对象事件



函数名px_int PX_ObjectRegisterEvent(PX_Object *Object,px_uint Event,px_void (*ProcessFunc)(PX_Object *,PX_Object_Event e,px_void *user_ptr),px_void *ptr);
功能为一个对象注册响应事件
参数Object需要绘制的对象指针
参数Event响应的事件类型
ProcessFunc响应处理函数
ptr用户自定义指针


示范

首先编写按钮点击处理函数, 打开PainterEngine_Application.c添加下面的代码
#include "windows.h"
px_void OnButtonExecute(PX_Object *pObject,PX_Object_Event e,px_void *ptr)
{
    MessageBox(0,"Button Clicked","",MB_OK);
}
然后将处理函数和对象事件进行绑定
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);
    pApp->ui_root=PX_ObjectCreate(&pApp->runtime.mp_ui,0,0,0,0,0,0,0);

    pApp->button=PX_Object_PushButtonCreate(&pApp->runtime.mp_ui,pApp->ui_root,100,100,84,32,"Button",PX_NULL,PX_COLOR(255,0,0,0));
    PX_ObjectRegisterEvent(pApp->button,PX_OBJECT_EVENT_EXECUTE,OnButtonExecute,pApp);//注册按钮事件
    return PX_TRUE;
}

完整代码

#include "PainterEngine_Application.h"

PX_Application App;

#include "windows.h"
px_void OnButtonExecute(PX_Object *pObject,PX_Object_Event e,px_void *ptr)
{
    MessageBox(0,"Button clicked","",MB_OK);
}

px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);

    pApp->ui_root=PX_ObjectCreate(&pApp->runtime.mp_ui,0,0,0,0,0,0,0);//创建根对象

    pApp->button=PX_Object_PushButtonCreate(&pApp->runtime.mp_ui,pApp->ui_root,100,100,84,32,"Button",PX_NULL,PX_COLOR(255,0,0,0));
    PX_ObjectRegisterEvent(pApp->button,PX_OBJECT_EVENT_EXECUTE,OnButtonExecute,pApp);//注册按钮事件
    return PX_TRUE;
}

px_void PX_ApplicationUpdate(PX_Application *pApp,px_dword elpased)
{
    PX_ObjectUpdate(pApp->ui_root,elpased);
}

px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_ObjectRender(pRenderSurface,pApp->ui_root,elpased);
}

px_void PX_ApplicationPostEvent(PX_Application *pApp,PX_Object_Event e)
{
    PX_ApplicationEventDefault(&pApp->runtime, e);
    PX_ObjectPostEvent(pApp->ui_root,e);
}
创建文本控件

函数原型



函数名PX_Object* PX_Object_EditCreate(px_memorypool *mp, PX_Object *Parent,px_int x,px_int y,px_int Width,px_int Height,PX_FontModule *fontModule,px_color TextColor )
说明创建一个编辑框控件
参数mp内存池Parent 父对象x,y 控件左上角位置width 宽度height 高度fontmodule 控件显示文本的字模(为PX_NULL表示使用ANSI默认字模)color 文本颜色
返回值如果成功PX_Object指针,否者返回PX_NULL

示范

打开PainterEngine_Application.h,定义一个PX_Object * Edit;
typedef struct
{
    PX_Object *ui_root;
    PX_Object * Edit;
    PX_Runtime runtime;
}PX_Application;打开PainterEngine_Application.c,在PX_ApplicationInitialize中添加代码
px_bool PX_ApplicationInitialize(PX_Application *pApp,px_int screen_width,px_int screen_height)
{
    PX_ApplicationInitializeDefault(&pApp->runtime, screen_width, screen_height);


    pApp->ui_root=PX_ObjectCreate(&pApp->runtime.mp_ui,0,0,0,0,0,0,0);//创建根对象


    pApp->edit=PX_Object_EditCreate(&pApp->runtime.mp_ui,pApp->ui_root,100,100,128,32,PX_NULL,PX_COLOR(255,0,0,0));
    return PX_TRUE;
}在PX_ApplicationUpdate,PX_ApplicationRender,PX_ApplicationPostEvent中添加代码
px_void PX_ApplicationUpdate(PX_Application *pApp,px_dword elpased)
{
    PX_ObjectUpdate(pApp->ui_root,elpased);
}

px_void PX_ApplicationRender(PX_Application *pApp,px_dword elpased)
{
    px_surface *pRenderSurface=&pApp->runtime.RenderSurface;
    PX_RuntimeRenderClear(&pApp->runtime,PX_COLOR(255,255,255,255));
    PX_ObjectRender(pRenderSurface,pApp->ui_root,elpased);
}
px_void PX_ApplicationPostEvent(PX_Application *pApp,PX_Object_Event e)
{
    PX_ApplicationEventDefault(&pApp->runtime, e);
    PX_ObjectPostEvent(pApp->ui_root,e);
}



===============================================
基于PainterEngine的网络游戏
自己拥有一台服务器可以做哪些很酷的事情?
演示下基于PainterEngine的服务端Console程序,写个简单的JIT(脚本即时编译执行)功能


一个基于PainterEngine的小游戏



PainterEngine支持群

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-9-3 20:54 | 显示全部楼层
事实上,Windows到现在也没有能用的官方的C++ GUI框架。
你以为是开玩笑。但是这确实是事实。
推销员鲍尔默担任微软总裁10年,windows没有实质性的进步。
建议用第三方的QT。
最烂的编程体验就是c++配合mfc或者win32 api编程windows桌面程序。你想死的心估计都有了。对比之下用mac你跟玩的一样就能用oc配合cocoa框架写出漂亮美观的gui程序。这是我对win平台最大不满的地方。
发表于 2021-9-3 20:59 | 显示全部楼层
建议用Qt。
或者转C#
发表于 2021-9-3 21:08 | 显示全部楼层
看的人比较多,所以我觉得还是完善一下回答比较好!//2017年10月17日0点28分
这个问题问得非常好,虽然问题中的描述不准确,但我们都知道他想问的问题是什么意思:就是怎样用C++写一个有窗体界面的程序(很有可能是指在Windows下)。先回答一下这个问题,答案在这儿:从WinMain开始
回想当年,我初学C语言的时候,也有这样的困惑:为啥我写的程序背景是黑不溜秋的,文字也是一行一行显示的,而别人写的程序都带着界面和按钮?
这得从何说起呢?
由于我们最常接触的就是Windows系统中各种带有窗体的程序,使得很多人误以为,这就是程序原本的样子……其实程序原本是没有界面的,就一堆代码在CPU里跑,之所以有界面,是因为人类自身的需要。人类发明了一些硬件设备,来展示程序的过程和结果,最常见的就是普通的电脑显示器。最早我们用一行行的文字来显示界面,俗称CLI(就是控制台,终端,命令行这类界面),随着科技的进步,后来我们发展出了更加人性化的图形界面,俗称GUI。但CLI并没有消失,甚至在某些应用场合,它比GUI方便得多。
其实代码的本质就是控制硬件,比如在显示器上显示一个点,其实是程序对某个硬件进行赋值操作(不同的硬件设备在程序里有着不同的地址,这就是总线结构),所以你要在屏幕上画个点,本质上就是往某个地址上写个值,简单来说就是这样。这个东西也叫作驱动程序。
通过控制屏幕显示各种各样不同的点,我们就可以弄出各种图案,比如窗口啊,按钮啊,文字啊,图片啊,2D或者3D动画啊,这个东西就叫作计算机图形学。
然而我们在Windows这种操作系统下开发程序,并不用关心怎么样去绘制一个窗口或文字,因为已经有人把这部分工作给我们做好了,并且封装成了一个个的函数或类,俗称API(应用程序接口),我们只要调用那个函数,告诉操作系统,给我画个窗口吧,它就屁颠屁颠的去帮你干活了,就是这么简单。
把一堆API打包装在一起,就变成了库。
在命令行上面显示“hello world”和在窗口上显示“hello world”的区别,只是使用了不同库中的不同API而已。对于程序员来说,并没有本质上的区别,仅仅只是调用的函数不一样。
所以,我们实际开发时,需要学习这些API怎么用,有哪些特点,这就属于应用开发的内容了,比如“Windows编程”,“wxWidget应用开发”等等等等……手机软件开发,也是一样的原理。所以,学完C++只是第一步,接下来,如何在相应的操作系统环境下开发软件,还需要学习相应的API。
发表于 2021-9-3 21:11 | 显示全部楼层
Win32:需要手写大量代码,可控性高,学习成本也高,可以了解 Windows 界面编程的很多底层原理。
MFC:微软对 Win32 进行封装的一个类库,开发过程比 Win32 简单,比如可以通过拖动、点击界面编辑器创建一个大致可用的软件框架。缺点是,代码可读性差,技术比较老旧,无论是代码还是逻辑,都很难做到优雅。
Qt:一个开源的 C++ 界面框架,功能与 MFC 类似,比 MFC 好用一万倍,优雅一万倍,而且用得好的话,还可以跨平台。
发表于 2021-9-3 21:20 | 显示全部楼层
初学编程也和题主一样,觉得别人的程序怎么都有界面,看着notepad都很羡慕。觉得别人的那才是程序,有界面酷酷,自己的都是啥呀。现在写东西能不用界面的就不用,包括给非专业的人,一个轮回呀。。
发表于 2021-9-3 21:24 | 显示全部楼层
虽然是两年前的老问题了, 但是想必这个问题是很多新手都会关注的问题, 所以还是在此列举一下新手适合使用的非常流行的图形界面框架.
PS: 容我先吐槽一下目前最高赞答案, 这个东西看起来不错, 但是我闻所未闻, 没什么知名度. 如果不是故意广告的话, 那就是审题不太仔细了. 人家要图形界面框架, 你给介绍了个画图的...... 虽说用这个做图形界面当然没问题, 但是你确定这个给新手能很快入手?
MFC

言归正传, C++新手做图形界面, 首推微软自带的 MFC 框架:



Visual Studio 2017 中新建 MFC 项目



MFC 新建项目向导



新建的MFC项目

有网友可能会说了, MFC这种过时的东西你介绍他干啥? 没错, MFC确实过时了, 但是如果一个新手只是想体验图形界面编程, 并通过图形界面的方式进一步学习C++, 那么MFC作为一种学习工具, 是没有任何问题的, 我们又不是要用MFC做新产品
如上图所示, 只需要简单的几步即可新建一个对话框, 然后从右边的工具箱拖动控件到界面上即可添加文字/按钮/输入框/图片/选择框/滑块/菜单等等各种常用控件, 双击控件可以直接跳转到该控件常用事件(如按钮单击)的响应函数中, 这些方便简洁的功能是对新手非常友好的, 作为C++初学者也不必对着蹩脚的控制台学习, 可以利用图形界面丰富的功能, 更好地探索编程.



双击确定按钮, VS会自动跳转到其单击响应函数



右边的属性栏可以编辑更多类型的响应事件

当然, 说起MFC的缺点, 过来人可能有一肚子苦水要吐, Win32API本身的反人类设计(其实是C语言下无奈而为之), 加上MFC的过时设计思想, 以及偶尔出现的神奇bug, 都显示着这已经是一个严重过时的产品框架. 然而, 即使技术框架本身已经淘汰过时, 但微软产品的使用便捷性也使得MFC仍然适合编程初学者.
QT

作为桌面端最流行的图形界面程序框架, QT不仅可以应用于Windows桌面. 还可以跨平台到Mac和Linux系统, 甚至移动端. 如果你最终希望成为一名PC桌面程序客户端程序员, 那么学习QT就是你的必经之路.
QT可以在官网(https://www.qt.io/cn)下载安装, 分为免费开源版和付费商业版, 我们可以免费下载开源版来学习使用.



QT编辑器界面



QT设计对话框界面

QT在Windows下还与VS有着很好的集成, 你可以充分利用VS强大的编辑器智能提示以及调试功能.
Cocos2d-x

这不是一个简单的图形界面框架, 这是一个游戏编程框架. 游戏与普通图形界面的区别就是, 前者会以较高的帧率时刻刷新, 从而占用比后者高很多的系统资源. 所以 Cocos2d-x更适合制作游戏, 或者是2D动画比较频繁的应用程序. 而且, 作为一个游戏编程框架, 入手也比以上两个困难很多, 这里不推荐初学者使用, 仅作简单提及. 除了Cocos2d-x, 还有业界知名的3D游戏引擎 Unreal Engine 也是使用C++作为开发语言的

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-9-3 21:28 | 显示全部楼层
要C++写UI?
告诉你一个连后端C农都用的爽的UI库, 号称UI界的printf。
QT/WxWidgets之类的重型货并非老哥的心头好,所以向你推荐imgui。
这是给运维人员开发的工具,只用到了imgui,非常轻量,无依赖,还支持docking。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-9-3 21:29 | 显示全部楼层
切,命令行才是程序,界面只是个粉骷髅而已。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 13:24 , Processed in 0.098650 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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