TouchGFX之文本区域

news2024/12/26 20:44:34

文本区域在屏幕上显示文本。 文本区域的文本在大小、颜色、自定义字体、动态文本等方面是完全可以配置的

#ifndef TOUCHGFX_TEXTAREA_HPP
#define TOUCHGFX_TEXTAREA_HPP
#include <touchgfx/Font.hpp>
#include <touchgfx/TextProvider.hpp>
#include <touchgfx/TypedText.hpp>
#include <touchgfx/Unicode.hpp>
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/widgets/Widget.hpp>

namespace touchgfx
{
/* 文本区域 */
class TextArea : public Widget
{
public:
	/* 构造函数 */
	TextArea()
			: Widget(), typedText(TYPED_TEXT_INVALID), color(0), linespace(0), alpha(255), indentation(0), rotation(TEXT_ROTATE_0), wideTextAction(WIDE_TEXT_NONE), boundingArea()
	{
	}

	// 设置宽度,并重新计算文本区域的边界
	virtual void setWidth(int16_t width)
	{
		Widget::setWidth(width);
		boundingArea = calculateBoundingArea();
	}

	// 设置高度,并重新计算文本区域的边界
	virtual void setHeight(int16_t height)
	{
		Widget::setHeight(height);
		boundingArea = calculateBoundingArea();
	}

	/* 获取可以保证为实心的(不透明的)最大矩形 */
	virtual Rect getSolidRect() const
	{
		return Rect();
	}

	/* 设置文本颜色 */
	FORCE_INLINE_FUNCTION void setColor(colortype newColor)
	{
		color = newColor;
	}

	/* 获取文本颜色 */
	FORCE_INLINE_FUNCTION colortype getColor() const
	{
		return color;
	}

	/* 设置透明度 */
	virtual void setAlpha(uint8_t newAlpha)
	{
		alpha = newAlpha;
	}

	/* 获取透明度值 */
	uint8_t getAlpha() const
	{
		return alpha;
	}

	// 调整TextArea的y坐标,使文本的基线(而不是TextArea)位于指定的y值
	virtual void setBaselineY(int16_t baselineY)
	{
		setY(baselineY - getTypedText().getFont()->getBaseline());
	}

	// 调整TextArea的x和y坐标,使文本的基线位于指定的y值,x坐标将被用作TextArea的x坐标
	virtual void setXBaselineY(int16_t x, int16_t baselineY)
	{
		setX(x);
		setBaselineY(baselineY);
	}

	// 设置TextArea的行间距。设置更大的值将增加行之间的距离。可以设置负值使行(部分)重叠
	FORCE_INLINE_FUNCTION void setLinespacing(int16_t space)
	{
		linespace = space;
		boundingArea = calculateBoundingArea();
	}

	// 获取TextArea的行间距。如果没有设置行间距,则行间距为0
	FORCE_INLINE_FUNCTION int16_t getLinespacing() const
	{
		return linespace;
	}

	// 设置文本的缩进。这对于斜体字体非常有用,可以防止某些字符(如"j"和"g")在左侧下方延伸到前一个字符下面
	FORCE_INLINE_FUNCTION void setIndentation(uint8_t indent)
	{
		indentation = indent;
		boundingArea = calculateBoundingArea();
	}

	// 获取文本的缩进
	FORCE_INLINE_FUNCTION uint8_t getIndentation()
	{
		return indentation;
	}

	/* 获取文本对齐方式 */
	virtual Alignment getAlignment() const;

	/* 获取文本高度 */
	virtual int16_t getTextHeight() const;

	/* 获取文本宽度 */
	virtual uint16_t getTextWidth() const;

	// 绘制文本区域
	virtual void draw(const Rect& area) const;

	/* 设置文本资源。如果之前没有设置过大小,TextArea将被调整以适应新的TypedText */
	void setTypedText(const TypedText& t);

	/* 获取文本资源 */
	const TypedText& getTypedText() const
	{
		return typedText;
	}

	/* 设置文本的旋转角度 */ 
	FORCE_INLINE_FUNCTION void setRotation(const TextRotation textRotation)
	{
		rotation = textRotation;
		boundingArea = calculateBoundingArea();
	}

	/* 获取文本旋转角度 */
	TextRotation getRotation() const
	{
		return rotation;
	}

	/* 根据文本尺寸和旋转方向调整控件尺寸 */
	void resizeToCurrentText();

	/* 根据对齐方式、旋转方向和尺寸调整控件尺寸和位置以适应文本 */
	void resizeToCurrentTextWithAlignment();

	/* 根据文本高度和旋转方向调整文本尺寸以适应文本 */
	void resizeHeightToCurrentText();

	/* 根据文本高度调整和旋转方向文本尺寸和位置以适应文本 */
	void resizeHeightToCurrentTextWithRotation();

	// 设置文本行过宽时的处理方式。并重新计算文本边界区域
	// 默认情况下,只有当文本中存在手动插入的换行符时,文本行才会换行。  
	// 如果启用了换行,并且文本将占用比TextArea更多的行数,  
	// 则在最后一行的末尾添加一个省略号(通常为&hellip;)以表示某些文本被省略。  
	// 用于省略的字符取自文本样式表
	FORCE_INLINE_FUNCTION void setWideTextAction(WideTextAction action)
	{
		wideTextAction = action;
		boundingArea = calculateBoundingArea();
	}

	// 获取之前通过文本过宽处理方式
	WideTextAction getWideTextAction() const
	{
		return wideTextAction;
	}

	// 根据文本格式和可变参数计算文本所需的总高度。  
	// 格式字符串中的<placeholder>占位符数量必须与后面的可变参数数量相匹配
	virtual int16_t calculateTextHeight(const Unicode::UnicodeChar* format, ...) const;

	// 获取TypedText中的第一个占位符。  
	// 如果此文本区域有占位符,则返回指向第一个占位符的指针,否则返回0
	virtual const Unicode::UnicodeChar* getWildcard1() const
	{
		return 0;
	}

	// 获取TypedText中的第二个占位符。  
	// 如果此文本区域有两个占位符,则返回指向第二个占位符的指针,否则返回0
	virtual const Unicode::UnicodeChar* getWildcard2() const
	{
		return 0;
	}

	//内容重新绘制
	virtual void invalidateContent() const;

protected:
	/* 刚好报文文本的边界区域 */
	class BoundingArea
	{
		public:
			// 使用给定的包围矩形和包含的文本初始化BoundingArea类的新实例
			BoundingArea(const Rect& boundingRect, const Unicode::UnicodeChar* containedText)
					: rect(boundingRect), text(containedText)
			{
			}

			// 初始化一个默认为无效的BoundingArea类的新实例
			BoundingArea() : rect(Rect(0, 0, -1, -1)), text(0)
			{
			}

			// 获取包围矩形
			Rect getRect() const
			{
				return rect;
			}

			// 查询包围区域是否有效
			bool isValid(const Unicode::UnicodeChar* currentText) const
			{
				return (rect.height >= 0 && rect.width >= 0 && text == currentText);
			}

		private:
			Rect rect;
			const Unicode::UnicodeChar* text;
	};

	// 计算此文本区域的最小包围矩形,并将其与包含的文本相关联,以获得包围区域。  
	// 注意:根据对齐方式和旋转角度调整包围矩形
	virtual TextArea::BoundingArea calculateBoundingArea() const;

	TypedText typedText;                //文本资源
	colortype color;                    //颜色
	int16_t linespace;                  //行间距
	uint8_t alpha;                      //透明度
	uint8_t indentation;                //缩进
	TextRotation rotation;              //旋转角度
	WideTextAction wideTextAction;      //过宽处理
	static const uint16_t newLine = 10; //换行值
	BoundingArea boundingArea;          //此文本区域的包围区域
};

}

#endif
#include <stdarg.h>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/lcd/LCD.hpp>
#include <touchgfx/widgets/TextArea.hpp>

namespace touchgfx
{
/* 获取文本对齐方式 */
Alignment TextArea::getAlignment() const
{
	if(typedText.hasValidId())
	{
		return typedText.getAlignment();
	}

	return LEFT;
}

/* 获取文本高度:考虑行数 */
int16_t TextArea::getTextHeight() const
{
	return typedText.hasValidId() ? calculateTextHeight(typedText.getText(), getWildcard1(), getWildcard2()) : 0;
}

/* 获取文本宽度 */
uint16_t TextArea::getTextWidth() const
{
	return typedText.hasValidId() ? typedText.getFont()->getStringWidth(typedText.getTextDirection(), typedText.getText(), getWildcard1(), getWildcard2()) : 0;
}

// 绘制文本区域
void TextArea::draw(const Rect& area) const
{
	if (typedText.hasValidId())
	{
		/* 边界矩形 */
		Rect rectToDraw = area;
		if(typedText.hasValidId() && boundingArea.isValid(typedText.getText()))
		{
			rectToDraw &= boundingArea.getRect();
		}
		
		if (!rectToDraw.isEmpty())
		{
			/* 绘制指定的Unicode字符串。在新行处换行 */
			const Font* fontToDraw = typedText.getFont();
			if (fontToDraw != 0)
			{
				const LCD::StringVisuals visuals(fontToDraw, color, alpha, getAlignment(), linespace, rotation, typedText.getTextDirection(), indentation, wideTextAction);
				HAL::lcd().drawString(getAbsoluteRect(), rectToDraw, visuals, typedText.getText(), getWildcard1(), getWildcard2());
			}
		}
	}
}

/* 设置文本资源 */
void TextArea::setTypedText(const TypedText& t)
{
	/* 设置文本资源 */
	typedText = t;
	
	/* 根据文本尺寸调整控件尺寸 */
	if (getWidth() == 0 && getHeight() == 0)
	{
		resizeToCurrentText();
	}
	
	/* 重新计算刚好包围文本的边界区域 */
	boundingArea = calculateBoundingArea();
}

/* 根据文本尺寸和旋转方向调整控件尺寸 */
void TextArea::resizeToCurrentText()
{
	if (typedText.hasValidId())
	{
		const uint16_t w = getTextWidth();
		const uint16_t h = getTextHeight();
		if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
		{
			setWidthHeight(w, h);
		}
		else
		{
			setWidthHeight(h, w);
		}
	}
}

/* 根据对齐方式、旋转方向和尺寸调整控件尺寸和位置以适应文本 */
void TextArea::resizeToCurrentTextWithAlignment()
{
	if (typedText.hasValidId())
	{
		const Alignment alignment = getAlignment();
		const uint16_t text_width = getTextWidth();
		const uint16_t text_height = getTextHeight();
		
		/* 0/180度 */
		if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
		{
			/* 文本不靠左放 */
			if (!((rotation == TEXT_ROTATE_0 && alignment == LEFT) || (rotation == TEXT_ROTATE_180 && alignment == RIGHT)))
			{
				const uint16_t old_width = getWidth();
				const uint16_t old_x = getX();
				if (alignment == CENTER)	//居中
				{
					setX(old_x + (old_width - text_width) / 2);	//调整控件位置
				}
				else	//靠右放
				{
					setX(old_x + (old_width - text_width));	//调整控件位置
				}
			}
			if (rotation == TEXT_ROTATE_180)
			{
				const uint16_t old_height = getHeight();
				const uint16_t old_y = getY();
				setY(old_y + (old_height - text_height));
			}
			
			setWidthHeight(text_width, text_height);
		}
		else
		{
			// 90+left or 270+right places text at the same y coordinate
			if (!((rotation == TEXT_ROTATE_90 && alignment == LEFT) || (rotation == TEXT_ROTATE_270 && alignment == RIGHT)))
			{
				const uint16_t old_height = getHeight();
				const uint16_t old_y = getY();
				if (alignment == CENTER)
				{
					setY(old_y + (old_height - text_width) / 2);
				}
				else
				{
					setY(old_y + (old_height - text_width));
				}
			}
			if (rotation == TEXT_ROTATE_90)
			{
				const uint16_t old_width = getWidth();
				const uint16_t old_x = getX();
				setX(old_x + (old_width - text_height));
			}
			setWidthHeight(text_height, text_width);
		}
	}
}

/* 根据文本高度和旋转方向调整文本尺寸以适应文本 */
void TextArea::resizeHeightToCurrentText()
{
	if (typedText.hasValidId())
	{
		const uint16_t h = getTextHeight();
		if (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180)
		{
			setHeight(h);
		}
		else
		{
			setWidth(h);
		}
	}
}

/* 根据文本高度调整和旋转方向文本尺寸和位置以适应文本 */
void TextArea::resizeHeightToCurrentTextWithRotation()
{
	if (typedText.hasValidId())
	{
		const uint16_t h = getTextHeight();
		switch (rotation)
		{
			case TEXT_ROTATE_0:
				setHeight(h);
				break;
			case TEXT_ROTATE_90:
				setX(rect.right() - h);
				setWidth(h);
				break;
			case TEXT_ROTATE_180:
				setY(rect.bottom() - h);
				setHeight(h);
				break;
			case TEXT_ROTATE_270:
				setWidth(h);
				break;
		}
	}
}

/* 计算文本高度:考虑换行 */
int16_t TextArea::calculateTextHeight(const Unicode::UnicodeChar *format, ...) const
{
	if(!typedText.hasValidId())
	{
		return 0;
	}

	va_list pArg;
	va_start(pArg, format);

	/* 获取字体和字体高度 */
	const Font *fontToDraw = typedText.getFont();
	const int16_t textHeight = fontToDraw->getHeight();

	/* 获取给定文本的行数,同时考虑换行 */
	TextProvider textProvider;
	textProvider.initialize(format, pArg, fontToDraw->getGSUBTable(), fontToDraw->getContextualFormsTable());
	const int16_t numLines = LCD::getNumLines(textProvider, wideTextAction, typedText.getTextDirection(), typedText.getFont(), getWidth() - indentation);

	va_end(pArg);
	
	/* 计算高度 */
	return textHeight + linespace > 0 ? numLines * textHeight + (numLines - 1) * linespace : (numLines > 0 ? textHeight : 0);
}

void TextArea::invalidateContent() const
{
    if (alpha == 0 || !typedText.hasValidId() || rect.isEmpty())
    {
        return;
    }
    if (boundingArea.isValid(typedText.getText()))
    {
        Rect boundingRect = boundingArea.getRect();
        invalidateRect(boundingRect);
        return;
    }
    invalidate();
}

/* 计算刚好包围文本的边界区域 */
TextArea::BoundingArea TextArea::calculateBoundingArea() const
{
	if(!typedText.hasValidId())
	{
		return TextArea::BoundingArea(); // Return Invalid BoundingArea
	}

	const Font* fontToDraw = typedText.getFont();
	const Unicode::UnicodeChar* textToDraw = typedText.getText();
	const int16_t fontHeight = fontToDraw->getHeight();
	const int16_t lineHeight = fontHeight + linespace;
	int16_t width = 0;
	uint16_t numberOfLines = 0;

	/* 计算最大行宽 */
	if (wideTextAction == WIDE_TEXT_NONE)
	{
		TextProvider textProvider;
		textProvider.initialize(textToDraw, fontToDraw->getGSUBTable(), fontToDraw->getContextualFormsTable(), getWildcard1(), getWildcard2());
		int16_t widgetRectHeight = (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180) ? getHeight() : getWidth();
		do
		{
			const uint16_t lineWidth = LCD::stringWidth(textProvider, *(fontToDraw), 0x7FFF, typedText.getTextDirection());
			width = MAX(width, lineWidth);
			numberOfLines++;
			widgetRectHeight -= lineHeight;
		}while (!textProvider.endOfString() && widgetRectHeight + fontToDraw->getPixelsAboveTop() > 0);
	}
	else
	{
		TextProvider wideTextProvider;
		wideTextProvider.initialize(textToDraw, fontToDraw->getGSUBTable(), fontToDraw->getContextualFormsTable(), getWildcard1(), getWildcard2());

		const int16_t widgetRectWidth = (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180) ? getWidth() : getHeight();
		int16_t widgetRectHeight = (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180) ? getHeight() : getWidth();
		LCD::WideTextInternalStruct wtis(wideTextProvider, widgetRectWidth - indentation, widgetRectHeight, typedText.getTextDirection(), fontToDraw, linespace, wideTextAction);

		// Iterate through each line, find the longest line width and sum up the total height of the bounding rectangle
		do
		{
				wtis.scanStringLengthForLine();
				const uint16_t lineWidth = wtis.getLineWidth();
				width = MAX(width, lineWidth);
				numberOfLines++;
				widgetRectHeight -= lineHeight;
				// Keep reading until end of string, ellipsis inserted or next line completely invisible.
		} while (wtis.getCurrChar() != 0 && !wtis.ellipsisAtEndOfLine() && widgetRectHeight + fontToDraw->getPixelsAboveTop() > 0);
	}
	
	/* 计算最大高度 */
	int16_t height = (numberOfLines * lineHeight) - linespace;
	height = MAX(height, fontHeight) + fontToDraw->getPixelsBelowBottom();

	/* 边界矩形 */
	Rect boundingRect(0, 0, width, height);

	/* 根据对齐方式调整边界矩形 */
	const int16_t areaWidth = (rotation == TEXT_ROTATE_0 || rotation == TEXT_ROTATE_180) ? getWidth() : getHeight();
	switch (getAlignment())
	{
		default:
		case LEFT:
			boundingRect.x = indentation;
			break;
		
		case CENTER:
			boundingRect.x = ((areaWidth - boundingRect.width) / 2);
			break;
		
		case RIGHT:
			boundingRect.x = areaWidth - (boundingRect.width + indentation);
			break;
	}

	/* 根据字体左右预留像素调整边界矩形 */
	const uint8_t maxPixelsLeft = fontToDraw->getMaxPixelsLeft();
	const uint8_t maxPixelsRight = fontToDraw->getMaxPixelsRight();
	boundingRect.x -= maxPixelsLeft;
	boundingRect.width += (maxPixelsLeft + maxPixelsRight);

	/* 根据文本旋转方向调整边界矩形 */
	switch (rotation)
	{
		case TEXT_ROTATE_0:
			break;
		case TEXT_ROTATE_90:
			boundingRect = Rect(getWidth() - boundingRect.bottom(), boundingRect.x, boundingRect.height, boundingRect.width);
			break;
		case TEXT_ROTATE_180:
			boundingRect = Rect(getWidth() - boundingRect.right(), getHeight() - boundingRect.bottom(), boundingRect.width, boundingRect.height);
			break;
		case TEXT_ROTATE_270:
			boundingRect = Rect(boundingRect.y, getHeight() - boundingRect.right(), boundingRect.height, boundingRect.width);
			break;
	}

	return TextArea::BoundingArea(boundingRect, typedText.getText());
}

}

控件组​

文本区域位于TouchGFX Designer中的Miscellaneous控件组中。

TouchGFX Designer中的文本区域

属性​

TouchGFX Designer中文本区域的属性。

属性组属性说明
名称控件的名称。 名称是TouchGFX Designer和代码中使用的唯一标识符
位置XY指定控件左上角相对于其父的位置。

WH指定控件的宽度和高度。

自动调整大小指定是否根据文本输入自动设置控件的大小。

锁定指定控件是否应锁定为其当前的X、Y、W和H。
如果锁定控件,还会禁止通过屏幕与控件进行交互。

可见指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
文本ID指定使用的文本。 如果控件使用自动生成的文本,ID将显示“自动生成”。.

翻译指定要显示的文本内容。

字体排印指定文本的格式。

对齐指定文本的水平对齐方式。

最多可以为动态文本输入创建两个通配符,表示为‘<tag>’,其中‘tag’可以是任意字符串。 如需详细了解关于文本配置的信息,请参阅“文本与字体”一节。
外观颜色指定所显示文本的颜色。

Alpha指定控件的透明度。
控件Alpha值的范围是0到255。 0表示完全透明,255表示不透明。

行距指定行之间的间距。

文本旋转设置文本的旋转角度。

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

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

相关文章

JavaSE day15 笔记

第十五天课堂笔记 数组 可变长参数★★★ 方法 : 返回值类型 方法名(参数类型 参数名 , 参数类型 … 可变长参数名){}方法体 : 变长参数 相当于一个数组一个数组最多只能有一个可变长参数, 并放到列表的最后parameter : 方法参数 数组相关算法★★ 冒泡排序 由小到大: 从前…

标准库不带操作系统移植FreeModbus到STM32

添加FreeModbus代码 首先准备一个空白的标准库项目。 下载FreeModbus源码。 将源码中的modbus文件夹复制到项目路径下&#xff0c;并把demo->BARE->port文件夹的内容也添加进来。 新建一个文件port.c备用。然后打开项目&#xff0c;将上述文件添加至项目&#xff0c;…

OSPF---开放式最短路径优先协议

1. OSPF描述 OSPF协议是一种链路状态协议。每个路由器负责发现、维护与邻居的关系&#xff0c;并将已知的邻居列表和链路费用LSU报文描述&#xff0c;通过可靠的泛洪与自治系统AS内的其他路由器周期性交互&#xff0c;学习到整个自治系统的网络拓扑结构;并通过自治系统边界的路…

Vscode 常用插件和快捷键 2024版笔记

1. 常用插件2.常用快捷键 1. 常用插件 1.1 Chinese vscode 转成中文&#xff08;更新版后有进要重装&#xff09; 1.2 Live Server 浏览成网页 1.3 Material Icon Theme 文件目录和文件图标样式&#xff08;没有自定义&#xff09; 1.4 vscode 主题 1.5 代码截图 1.6 代码补…

【01-20】计算机网络基础知识(非常详细)从零基础入门到精通,看完这一篇就够了

【01-20】计算机网络基础知识&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了 以下是本文参考的资料 欢迎大家查收原版 本版本仅作个人笔记使用1、OSI 的七层模型分别是&#xff1f;各自的功能是什么&#xff1f;2、说一下一次完整的HTTP请求…

新能源充电桩站场AI视频智能分析烟火检测方案及技术特点分析

新能源汽车充电起火的原因多种多样&#xff0c;涉及技术、设备、操作等多个方面。从技术层面来看&#xff0c;新能源汽车的电池管理系统可能存在缺陷&#xff0c;导致电池在充电过程中出现过热、短路等问题&#xff0c;从而引发火灾。在设备方面&#xff0c;充电桩的设计和生产…

Python环境下基于机器学习的空压机故障识别(出口阀泄漏等)

Python环境下基于机器学习&#xff08;多层感知机&#xff0c;决策树&#xff0c;随机森林&#xff0c;高斯过程&#xff0c;AdaBoost&#xff0c;朴素贝叶斯&#xff09;的压缩机故障识别&#xff08;出口阀泄漏&#xff0c;止逆阀泄露&#xff0c;轴承损伤&#xff0c;惯性轮…

京东数据API接口采集/京东商品详情页SKU实时采集

京东电商实时数据采集是指通过自动化工具和技术&#xff0c;定时或不间断地收集京东电商平台的数据。这些数据可以包括商品信息、价格、销量、评价等。通过实时数据采集&#xff0c;可以帮助京东电商平台及其卖家了解市场情况、监控竞争对手、优化产品定价和营销策略等。 企业级…

C语言从入门到精通- CLion安装配置Gitee

CLion安装Gitee 需要先申请Gitee账号。 下载gitee插件 在CLion的plugins中查找gitee,安装后重启CLion。 CLion上关联gitee账号 安装git软件 下载git 访问网站&#xff1a; Git - Downloading Package (git-scm.com) 安装 创建本地用户名和邮箱 在弹出的命令行窗体中输入用户名…

vite+vue3使用模块化批量发布Mockjs接口

在Vue3项目中使用Mock.js可以模拟后端接口数据&#xff0c;方便前端开发和调试。下面是使用vitevue3使用模块化批量发布Mockjs接口的步骤&#xff1a; 1. 安装Mock.js 在Vue3项目的根目录下&#xff0c;使用以下命令安装Mock.js&#xff1a; npm install mockjs --save-dev …

constexpr与std::is_same_v碰撞会产生什么火花?

1. 只编译会用到的if分支 示例代码一中&#xff0c;checkType_v1和checkType_v2两个函数的区别就是if的条件里一个加了constexpr一个没加&#xff0c;加与不加从结果来看都一样&#xff0c;那在编译时和运行时各有什么区别呢&#xff1f; 示例代码一&#xff0c;test_01.cpp&…

canvas画图,拖动已经画好的矩形

提示&#xff1a;canvas画图写文字 文章目录 前言一、写文字总结 前言 一、写文字 test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-widt…

【物联网】Qinghub opc-ua 连接协议

基础信息 组件名称 &#xff1a; opcua-connector 组件版本&#xff1a; 1.0.0 组件类型&#xff1a; 系统默认 状 态&#xff1a; 正式发布 组件描述&#xff1a;通过OPCUA连接网关&#xff0c;通过定时任务获取OPCUA相关的数据或通过执行指令控制设备相关参数。 配置文件&a…

基于spring boot的在线购票系统

在线购票系统的设计与实现 【摘要】这套在线购票系统是根据当前的现实需要&#xff0c;从现实工作中着手&#xff0c;剖析了以往的在线购票系统中出现的一些问题&#xff0c;并进一步提高了使用者的操作体验。利用电脑来对资料进行处理&#xff0c;以代替传统的手工方式进行资…

spring-boot之接口文档Swagger配置使用

Swagger 前后端分离 Vue SpringBoot 后端时代:前端只用管理静态页面; html> 后端。模板引擎JSP >后端是主力 前后端分离式时代: ●后端:后端控制层&#xff0c;服务层,数据访问层[后端团队] ●前端:前端控制层&#xff0c;视图层[前端团队] 。伪造后端数据&#xff0c;…

【保姆级】2024年最新Onlyfans使用订阅教程

【必看】开通步骤 订阅OnlyFans的步骤简要总结如下&#xff1a; 开通虚拟信用卡&#xff1a;虚拟信用卡开通使用教程。开卡后&#xff0c;进入首页&#xff0c;就能看到自己的虚拟信用卡信息把虚拟信用卡的信息填写到OnlyFans绑定信用卡界面就OK了 从上面的链接进入开卡费可…

Springboot工程依赖包与执行包分离打包与构建docker 镜像

文章目录 一、概述二、工程概况1. 代码原始结构2. 运行界面 三、常规打包1. 打包命令2. jar包结构 四、分离依赖包、执行包步骤1. 引入依赖包管理插件2. 打包验证 一、概述 某大数据项目&#xff0c;使用springboot常规打包方式&#xff0c;打出来的一体化执行包达几百兆&…

第三十二天-Django模板-DTL模板引擎

目录 1.介绍 2. 使用 1.配置jinja2 2.DTL模板变量使用 3.与jinja2区别 4.模板标签使用 1.循环 2.条件控制 3.注释 4.url解析 5.显示时间 5.模板的基础与包含 6.过滤器 内置过滤器 自定义过滤器 1.介绍 2. 使用 1.配置jinja2 2.DTL模板变量使用 与jinja2语法相似…

ssm 科研奖励申报管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 ssm 科研奖励申报管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用…

激发数据潜力:企业数据中台的策略性构建与优化_光点科技

在信息时代&#xff0c;数据是企业价值链中不可或缺的一环。构建一个策略性的企业数据中台不仅能够整合分散的数据资源&#xff0c;还能提高决策效率和业务敏捷性。本文聚焦于如何策略性地构建和优化数据中台&#xff0c;以便企业能够最大化地利用数据资源&#xff0c;推动企业…