libui的简单使用

news2025/1/23 8:00:44

libui是一个 C 中简单且可移植(但并非不灵活)的 GUI 库,它使用每个平台原生的GUI技术进行绘制。
官网地址:链接
相关文件:链接

一、配置说明

1. 所需链接的库

在使用libui的过程中至少需要链接以下库

user32.lib
kernel32.lib
gdi32.lib
comctl32.lib
uxtheme.lib
msimg32.lib
comdlg32.lib
d2d1.lib
dwrite.lib
ole32.lib
oleaut32.lib
oleacc.lib
uuid.lib
windowscodecs.lib
libui.a

2. 静态库的使用

静态库在使用时还需要在项目中加入资源文件,下面的 文件 选择其中之一即可

  • static.manifest
  • resources.res

在这里插入图片描述

如果使用resources.res出现问题,请见 解决办法

二、简单使用

1. 空白窗口

#include <stdio.h>
#include "ui.h"

int onClosing(uiWindow* w, void* data)
{
	uiQuit();
	return 1;
}

int main(void)
{
	uiInitOptions o = { 0 };
	const char* err;
	uiWindow* window;

	// 初始化ui
	err = uiInit(&o);
	if (err != NULL) {
		fprintf(stderr, u8"初始化错误: %s\n", err);
		uiFreeInitError(err);
		return 1;
	}

	// 创建一个新窗口
	window = uiNewWindow("Hello World!", 300, 300, 0);
	uiWindowOnClosing(window, onClosing, NULL);

	// 显示窗口
	uiControlShow(uiControl(window));

	// 启动主循环
	uiMain();

	// 释放内存空间
	uiUninit();

	return 0;
}

在这里插入图片描述

2. 绘制文本

#include <stdio.h>
#include "ui.h"

int onClosing(uiWindow* w, void* data)
{
	uiQuit();
	return 1;
}

int main(void)
{
	uiInitOptions o = { 0 };
	const char* err;
	uiWindow* window;
	uiLabel* label;

	// 初始化ui
	err = uiInit(&o);
	if (err != NULL) {
		fprintf(stderr, u8"初始化错误: %s\n", err);
		uiFreeInitError(err);
		return 1;
	}

	// 创建一个新窗口
	window = uiNewWindow("Hello World!", 300, 300, 0);
	uiWindowOnClosing(window, onClosing, NULL);

	// 添加标签
	label = uiNewLabel("Hello, World!");
	uiWindowSetChild(window, uiControl(label));

	// 显示窗口
	uiControlShow(uiControl(window));

	// 启动主循环
	uiMain();
	uiUninit();
	return 0;
}

在这里插入图片描述

三、控件介绍

1. 容器控件

uiWindow

一个代表顶层窗口的控件,可包含其他控件。

uiBox

一个容纳一组控件的盒状容器。

uiTab

一个多页面控制界面容器,一次显示一个页面。

uiGroup

向所包含的子控件添加标签的控件容器。

uiForm

将包含的控件组织为带标签的字段的控件容器。

uiGrid

要在网格中排列的包含控件的控件容器。

2. 数据输入

uiCheckbox

带有用户可选框并带有文本标签的控件。

uiEntry

具有单行文本输入字段的控件。

uiSpinbox

通过文本字段或 +/- 按钮显示和修改整数值的控件。

uiSlider

通过用户可拖动的滑块显示和修改整数值的控件。

uiCombobox

通过下拉菜单从预定义项目列表中选择一项的控件。

uiEditableCombobox

用于从预定义的项目列表中选择一个项目或输入自己的项目的控件。

uiRadioButtons

复选按钮的多选控件,一次只能从中选择一个。

uiDateTimePicker

输入日期和/或时间的控件。

uiMultilineEntry

具有多行文本输入字段的控件。

uiFontButton

单击时打开字体选择器的类似按钮的控件。

uiColorButton

带有颜色指示器的控件,单击时会打开颜色选择器。

uiTable

以表格方式显示数据的控件。

3. 静态控件

uiLabel

显示非交互式文本的控件。

uiProgressBar

通过水平条的填充级别可视化任务进度的控件。

uiSeparator

用于在视觉上水平或垂直分隔控件的控件。

uiMenuItem

与uiMenu结合使用的菜单项。

uiMenu

应用程序级菜单栏。

uiImage

要在屏幕上显示的图像的容器。

4. 按钮控件

uiButton

uiFontButton

uiColorButton

5. 对话框窗口

6. 菜单

7. 表格

四、综合案例

1. 直方图

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "ui.h"

uiWindow* mainwin;
uiArea* histogram;
uiAreaHandler handler;
uiSpinbox* datapoints[10];
uiColorButton* colorButton;
int currentPoint = -1;

// some metrics
#define xoffLeft 20			/* 直方图的左边缘 */
#define yoffTop 20			/* 直方图的上边缘 */
#define xoffRight 20		/* 直方图的右边缘 */
#define yoffBottom 20		/* 直方图的下边缘 */
#define pointRadius 10		/* 点的大小 */

// 命名颜色
#define colorWhite 0xFFFFFF
#define colorBlack 0x000000
#define colorDodgerBlue 0x1E90FF

// 设置画刷的颜色
static void setSolidBrush(uiDrawBrush* brush, uint32_t color, double alpha)
{
	uint8_t component;

	brush->Type = uiDrawBrushTypeSolid;
	component = (uint8_t)((color >> 16) & 0xFF);
	brush->R = ((double)component) / 255;
	component = (uint8_t)((color >> 8) & 0xFF);
	brush->G = ((double)component) / 255;
	component = (uint8_t)(color & 0xFF);
	brush->B = ((double)component) / 255;
	brush->A = alpha;
}

// 根据给定的宽度和高度,计算出每个数据点在绘图区域中的位置坐标
static void pointLocations(double width, double height, double* xs, double* ys)
{
	double xincr, yincr;
	int i, n;

	xincr = width / 9;		// 10 - 1 to make the last point be at the end
	yincr = height / 100;

	for (i = 0; i < 10; i++) {
		// get the value of the point
		n = uiSpinboxValue(datapoints[i]);
		// because y=0 is the top but n=0 is the bottom, we need to flip
		n = 100 - n;
		xs[i] = xincr * i;
		ys[i] = yincr * n;
	}
}

// 据给定的宽度和高度以及当前界面上的数据点,构建一个绘制折线图的路径
static uiDrawPath* constructGraph(double width, double height, int extend)
{
	uiDrawPath* path;
	double xs[10], ys[10];
	int i;

	pointLocations(width, height, xs, ys);

	path = uiDrawNewPath(uiDrawFillModeWinding);

	uiDrawPathNewFigure(path, xs[0], ys[0]);
	for (i = 1; i < 10; i++)
		uiDrawPathLineTo(path, xs[i], ys[i]);

	if (extend) {
		uiDrawPathLineTo(path, width, height);
		uiDrawPathLineTo(path, 0, height);
		uiDrawPathCloseFigure(path);
	}

	uiDrawPathEnd(path);
	return path;
}

// 根据介绍的客户区域计算图形大小
static void graphSize(double clientWidth, double clientHeight, double* graphWidth, double* graphHeight)
{
	*graphWidth = clientWidth - xoffLeft - xoffRight;
	*graphHeight = clientHeight - yoffTop - yoffBottom;
}

static void handlerDraw(uiAreaHandler* a, uiArea* area, uiAreaDrawParams* p)
{
	uiDrawPath* path;
	uiDrawBrush brush;
	uiDrawStrokeParams sp;
	uiDrawMatrix m;
	double graphWidth, graphHeight;
	double graphR, graphG, graphB, graphA;

	// fill the area with white
	setSolidBrush(&brush, colorWhite, 1.0);
	path = uiDrawNewPath(uiDrawFillModeWinding);
	uiDrawPathAddRectangle(path, 0, 0, p->AreaWidth, p->AreaHeight);
	uiDrawPathEnd(path);
	uiDrawFill(p->Context, path, &brush);
	uiDrawFreePath(path);

	// figure out dimensions
	graphSize(p->AreaWidth, p->AreaHeight, &graphWidth, &graphHeight);

	// clear sp to avoid passing garbage to uiDrawStroke()
	// for example, we don't use dashing
	memset(&sp, 0, sizeof(uiDrawStrokeParams));

	// make a stroke for both the axes and the histogram line
	sp.Cap = uiDrawLineCapFlat;
	sp.Join = uiDrawLineJoinMiter;
	sp.Thickness = 2;
	sp.MiterLimit = uiDrawDefaultMiterLimit;

	// draw the axes
	setSolidBrush(&brush, colorBlack, 1.0);
	path = uiDrawNewPath(uiDrawFillModeWinding);
	uiDrawPathNewFigure(path,
		xoffLeft, yoffTop);
	uiDrawPathLineTo(path,
		xoffLeft, yoffTop + graphHeight);
	uiDrawPathLineTo(path,
		xoffLeft + graphWidth, yoffTop + graphHeight);
	uiDrawPathEnd(path);
	uiDrawStroke(p->Context, path, &brush, &sp);
	uiDrawFreePath(path);

	// now transform the coordinate space so (0, 0) is the top-left corner of the graph
	uiDrawMatrixSetIdentity(&m);
	uiDrawMatrixTranslate(&m, xoffLeft, yoffTop);
	uiDrawTransform(p->Context, &m);

	// now get the color for the graph itself and set up the brush
	uiColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA);
	brush.Type = uiDrawBrushTypeSolid;
	brush.R = graphR;
	brush.G = graphG;
	brush.B = graphB;
	// we set brush->A below to different values for the fill and stroke

	// now create the fill for the graph below the graph line
	path = constructGraph(graphWidth, graphHeight, 1);
	brush.A = graphA / 2;
	uiDrawFill(p->Context, path, &brush);
	uiDrawFreePath(path);

	// now draw the histogram line
	path = constructGraph(graphWidth, graphHeight, 0);
	brush.A = graphA;
	uiDrawStroke(p->Context, path, &brush, &sp);
	uiDrawFreePath(path);

	// now draw the point being hovered over
	if (currentPoint != -1) {
		double xs[10], ys[10];

		pointLocations(graphWidth, graphHeight, xs, ys);
		path = uiDrawNewPath(uiDrawFillModeWinding);
		uiDrawPathNewFigureWithArc(path,
			xs[currentPoint], ys[currentPoint],
			pointRadius,
			0, 6.23,		// TODO pi
			0);
		uiDrawPathEnd(path);
		// use the same brush as for the histogram lines
		uiDrawFill(p->Context, path, &brush);
		uiDrawFreePath(path);
	}
}

static int inPoint(double x, double y, double xtest, double ytest)
{
	// TODO switch to using a matrix
	x -= xoffLeft;
	y -= yoffTop;
	return (x >= xtest - pointRadius) &&
		(x <= xtest + pointRadius) &&
		(y >= ytest - pointRadius) &&
		(y <= ytest + pointRadius);
}

static void handlerMouseEvent(uiAreaHandler* a, uiArea* area, uiAreaMouseEvent* e)
{
	double graphWidth, graphHeight;
	double xs[10], ys[10];
	int i;

	graphSize(e->AreaWidth, e->AreaHeight, &graphWidth, &graphHeight);
	pointLocations(graphWidth, graphHeight, xs, ys);

	for (i = 0; i < 10; i++)
		if (inPoint(e->X, e->Y, xs[i], ys[i]))
			break;
	if (i == 10)		// not in a point
		i = -1;

	currentPoint = i;
	// TODO only redraw the relevant area
	uiAreaQueueRedrawAll(histogram);
}

static void handlerMouseCrossed(uiAreaHandler* ah, uiArea* a, int left)
{
	// do nothing
}

static void handlerDragBroken(uiAreaHandler* ah, uiArea* a)
{
	// do nothing
}

static int handlerKeyEvent(uiAreaHandler* ah, uiArea* a, uiAreaKeyEvent* e)
{
	// reject all keys
	return 0;
}

static void onDatapointChanged(uiSpinbox* s, void* data)
{
	uiAreaQueueRedrawAll(histogram);
}

// 回调函数,当颜色按钮改变时调用
static void onColorChanged(uiColorButton* b, void* data)
{
	uiAreaQueueRedrawAll(histogram);
}

// 回调函数,用户关闭窗口时,销毁主窗口,再执行释放内存
static int onClosing(uiWindow* w, void* data)
{
	uiControlDestroy(uiControl(mainwin));
	uiQuit(); //关闭整个 UI 程序并释放所有分配的内存
	return 0;
}


static int shouldQuit(void* data)
{
	uiControlDestroy(uiControl(mainwin));  // 销毁窗口对象
	return 1;
}

int main(void)
{
	uiInitOptions o;
	const char* err;
	uiBox* hbox, * vbox;
	int i;
	uiDrawBrush brush;

	handler.Draw = handlerDraw;
	handler.MouseEvent = handlerMouseEvent;
	handler.MouseCrossed = handlerMouseCrossed;
	handler.DragBroken = handlerDragBroken;
	handler.KeyEvent = handlerKeyEvent;

	memset(&o, 0, sizeof(uiInitOptions));
	err = uiInit(&o);
	if (err != NULL) {
		fprintf(stderr, "error initializing ui: %s\n", err);
		uiFreeInitError(err);
		return 1;
	}

	// 通过回调函数判断程序是否退出
	uiOnShouldQuit(shouldQuit, NULL);

	mainwin = uiNewWindow("libui Histogram Example", 640, 480, 1);
	uiWindowSetMargined(mainwin, 1);
	uiWindowOnClosing(mainwin, onClosing, NULL);

	hbox = uiNewHorizontalBox();
	uiBoxSetPadded(hbox, 1);
	uiWindowSetChild(mainwin, uiControl(hbox));

	vbox = uiNewVerticalBox();
	uiBoxSetPadded(vbox, 1);
	uiBoxAppend(hbox, uiControl(vbox), 0);

	// 设置10组数据框,添加到vbox
	srand(time(NULL));
	for (i = 0; i < 10; i++) {
		datapoints[i] = uiNewSpinbox(0, 100);
		uiSpinboxSetValue(datapoints[i], rand() % 101);
		uiSpinboxOnChanged(datapoints[i], onDatapointChanged, NULL); // 设置数据区域变化时发生的操作
		uiBoxAppend(vbox, uiControl(datapoints[i]), 0);
	}

	// 设置颜色选择按钮,添加到vbox
	colorButton = uiNewColorButton();
	setSolidBrush(&brush, colorDodgerBlue, 1.0);
	uiColorButtonSetColor(colorButton, brush.R, brush.G, brush.B, brush.A);
	uiColorButtonOnChanged(colorButton, onColorChanged, NULL);  // 设置颜色按钮变化时执行的操作
	uiBoxAppend(vbox, uiControl(colorButton), 0);

	// 设置绘图区域,添加到hbox
	histogram = uiNewArea(&handler);
	uiBoxAppend(hbox, uiControl(histogram), 1);

	// 显示窗口
	uiControlShow(uiControl(mainwin));
	// 执行循环
	uiMain();
	// 释放内存空间
	uiUninit();
	return 0;
}


在这里插入图片描述

附录

其他分支:

  • https://github.com/neroist/uing
  • https://github.com/libui-ng/libui-ng

参考文档:https://libui-ng.github.io/libui-ng/annotated.html

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

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

相关文章

NumPy 秘籍中文第二版:一、使用 IPython

原文&#xff1a;NumPy Cookbook - Second Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 在本章中&#xff0c;我们将介绍以下秘籍&#xff1a; 安装 IPython使用 IPython 作为 Shell阅读手册页安装 matplotlib运行 IPython 笔记本导出 IPython 笔记本导入网…

分享:如何给 DBA 减负?

欢迎访问 OceanBase 官网获取更多信息&#xff1a;https://www.oceanbase.com/ 本文来自OceanBase社区分享&#xff0c;仅限交流探讨。原作者肖杨&#xff0c;OceanBase 软件开发工程师。 研发、数据分析师及运维内部人员有数据查询、数据订正等需求&#xff0c;若无管控平台&…

vscode推送文件至github步骤

@目录 1、步骤: 提交到本地仓库从本地仓库再提交到远程仓库2、具体操作: 2.1 准备工作 设置提交代码时的用户信息 开始前我们需要先设置提交的用户信息,包括用户名和邮箱: git config --global user.name "runoob" git config --global user.email "tes…

【mysql性能调优 • 二】mysql的启动关闭原理和实战,及常见的错误排查

前言 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系…

【CSS】定位 ⑥ ( 使用绝对定位在父容器任意位置显示子容器 | 代码示例 )

文章目录一、需求分析及核心开发要点二、完整代码示例一、需求分析及核心开发要点 要实现如下功能 , 下图 粉色 部分是 整体 父容器 , 紫色元素 是 中心的核心位置 , 蓝色是左上角的浮标 , 红色是右下角的浮标 ; 首先分析父容器元素 ; 由于 子元素 需要使用 绝对定位 , 此处的…

【权限维持】Windows自启动映像劫持粘滞键辅助屏保后门WinLogon

文章目录权限维持-域环境&单机版-自启动权限维持-域环境&单机版-粘滞键权限维持-域环境&单机版-映像劫持权限维持-域环境&单机版-屏保&登录权限维持-域环境&单机版-自启动 1、自启动路径加载 C:\Users\Administrator\AppData\Roaming\Microsoft\Wind…

家装产业的数字化,正在成为越来越多人的新共识

一场数字化的浪潮&#xff0c;正在各行各业上演着。家装行业&#xff0c;亦不例外。可以说&#xff0c;家装产业的数字化&#xff0c;正在成为越来越多人的新共识。如何借助数字化的手段改造家装行业&#xff0c;如何乘着数字化的东风实现家装行业的全面转型升级&#xff0c;正…

uni-app--》如何实现网上购物小程序(中下)?

&#x1f3cd;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名在校大学生 &#x1f6f5;个人主页&#xff1a;亦世凡华、 &#x1f6fa;系列专栏&#xff1a;uni-app &#x1f6b2;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&#xf…

STM32 W25QXX芯片

W25QXX芯片介绍 W25QXX芯片是华邦公司推出的大容量SPI FLASH产品&#xff0c;该系列有W25Q16/32/62/128等。本例程使用W25Q64&#xff0c;W25Q64容量为64Mbits&#xff08;8M字节&#xff09;&#xff1a;8MB的容量分为128个块(Block)&#xff08;块大小为64KB&#xff09;&…

Python每日一练(20230413)

目录 1. 最后一个单词的长度 ※ 2. 全排列 &#x1f31f;&#x1f31f; 3. 计数质数 ※ &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 1. 最后一个单词的长度 给你一个字符串 s&…

clickhouse布隆过滤器跳数索引最佳实践

背景 本文来聊一下clickhouse的这个列式存储数据库的布隆过滤器的跳数索引类型,来了解它的数据结构&#xff0c;它可以为那些查询类型提供查询优化。 跳数索引-布隆过滤器 首先布隆过滤器家族的跳数索引分成三种类型&#xff1a; ngrambf_v1,tokenbf_v1,bloom_filter其原理是…

Visual Studio 2022如何安装和使用MSDN

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;在后台收到提问&#xff0c;问我Visual Studio 2022如何安装和使用MSDN&#xff0c;这个我之前也没有在这个版本上装过MSDN&#xff0c;我之前是在Visual Studio 2017版上装过MSDN&#xff0c;那既然有人问了…

蓝桥杯【第14届省赛】Python B组

测试链接&#xff1a;https://www.dotcpp.com/oj/train/1093/ 测试结果还是蛮惨烈&#xff0c;主要原因有几个&#xff1a; C 语言网的时间限制是 3 s&#xff1a;但实际比赛的时间限制都是 10 s 起步&#xff0c;甚至有 30 s 的莫名其妙的运行报错&#xff1a;我不知道 D 题…

浅谈ChatGPT的关键技术与落地发展

分享嘉宾 | 刘焕勇 文稿整理 | William 1、从大规模语言模型看ChatGPT的起源与本质 ChatGPT可以拆开分为Chat和GPT去理解&#xff0c;前一个表示一种应用形式&#xff0c;后一个是生成式的模型。在百度百科里面定义为ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c…

数组与字符串C语言代码总结

《array》 arr.c #include <stdio.h>int main(int argc, char *argv[]) {int a[2][3]; int i, j;for (i 0; i < 2; i) {for (j 0; j < 3; j) printf("%p ", &a[i][j]); //验证二维数组连续性}printf("%p %…

d2l Markov序列模型

本节的任务是使用Markov模型对后续序列进行预测&#xff0c;使用sin函数&#xff0b;噪声绘制1000个样本点&#xff0c;取tau为4&#xff0c;即利用后四个的信息预测第五个。 目录 1.构造样本点 2.抽取iter 3.构造网络 4.训练 5.预测 5.1单步 5.1多步 1.构造样本点 T …

【程序人生】5个月从职场打杂到月薪14000的女测试工程师逆袭之路

大家好&#xff0c;我是来自湖南的一位辣妹子&#xff0c;毕业于一所工业大学&#xff0c;大学的专业是软件与工程&#xff0c;其实也算是本专业&#xff0c;大学期间掌握的知识也算比较广&#xff0c;各个方面都会一丢丢&#xff0c;就是不是特别深入。 之所以这么说&#xf…

nginx配置文件介绍

nginx配置文件介绍 nginx默认的配置文件是在安装目录下的 conf目录下&#xff0c;后续对 nginx 的使用基本上都是对此配置文件进行相应的修改。 配置文件中用#符号表示注释内容。 配置文件主要包括三部分&#xff0c;main、events和http main 用于进行nginx全局信息的配置…

Netty应用篇

Netty应用 粘包和半包 服务器代码 public class StudyServer {static final Logger log LoggerFactory.getLogger(StudyServer.class);void start() {NioEventLoopGroup boss new NioEventLoopGroup(1);NioEventLoopGroup worker new NioEventLoopGroup();try {ServerBoo…

【WebRTC技术专题】未来可期,WebRTC的诞生发展的概述介绍(1)

近几年实时音视频通信应用呈现出了大爆发的趋势。在这些实时通信技术的背后&#xff0c;有一项不得不提的技术 ——WebRTC。 前言背景 2021年1月26日&#xff0c;W3C&#xff08;万维网联盟&#xff09; 和 IETF &#xff08;互联网工程任务组&#xff09; 同时宣布 WebRTC&…