libui的简单使用

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值