TouchGFX之容器

容器是TouchGFX中的一种组件,可以包含子节点(比如控件和其他容器)。

在TouchGFX Designer中,可以在Widgets(控件)选项卡中的containers(容器)类别下找到容器,向容器中添加控件的方法将控件拖放到树视图中的容器中。

子容器在Z轴上的顺序由向容器中添加子容器时的顺序决定 - 最后添加的子容器将显示在屏幕的最前面。

由于TouchGFX中控件的位置是相对于其父容器而确定的,因此改变父容器的位置也会相应地移动子容器。

容器充当视窗,这意味着只有与容器几何图形相交的子容器部分才可见。

在下面的动画中,您将看到容器的视窗部分是如何工作的。 首先,我们看到这个按钮的父容器的轮廓:

代码

可以看出可以向容器中添加子节点,形成新的控件

#ifndef TOUCHGFX_CONTAINER_HPP
#define TOUCHGFX_CONTAINER_HPP
#include <touchgfx/Callback.hpp>
#include <touchgfx/Drawable.hpp>
#include <touchgfx/hal/Types.hpp>

namespace touchgfx
{
/* 容器 */
class Container : public Drawable
{
public:
	Container() : Drawable(), firstChild(0)
	{
	}

	//添加一个Drawable实例作为此容器的子项。
	//添加的Drawable将被放置在最后绘制,因此会出现在容器之前添加的所有Drawable的顶部
	virtual void add(Drawable& d);

	//从容器中移除一个Drawable,通过将其从子项链表中移除。
	//如果Drawable不在子项列表中,则不会发生任何事情。
	virtual void remove(Drawable& d);

	//从容器中移除所有Drawable
	virtual void removeAll();

	//通过取消链接第一个子项来移除所有子项。子项的父项和同级指针不会被重置。
	virtual void unlink();

	//查询是否已将给定的Drawable直接添加到此容器中。搜索不是递归进行的。
	virtual bool contains(const Drawable& d);

	//在特定的子节点之后插入一个Drawable。如果上一个子节点为0,则将Drawable插入为列表的第一个元素。
	virtual void insert(Drawable* previous, Drawable& d);

	//获取子项列表中的最后一个子项。
	//如果此容器是可触摸的,它将作为结果返回。
	//否则,将递归遍历所有可见的子项,以找到与给定坐标相交的Drawable。
	virtual void getLastChild(int16_t x, int16_t y, Drawable** last);

	// 与getLastChild()类似,但还会考虑HAL中当前设置的手指大小。
	virtual void getLastChildNear(int16_t x, int16_t y, Drawable** last, int16_t* fingerAdjustmentX, int16_t* fingerAdjustmentY);

	/* 绘制该图。仅绘制包含在矩形内部分 */
	virtual void draw(const Rect& invalidatedArea) const;

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

	//对容器中的每个子项执行指定的回调函数。要执行的回调函数必须具有以下原型:void T::func(Drawable&)  
	virtual void forEachChild(GenericCallback<Drawable&>* function);

	//获取此容器的第一个子项的指针。
	//第一个子项是首先绘制的Drawable,因此它位于此容器的所有其他子项的后面。
	virtual Drawable *getFirstChild()
	{
		return firstChild;
	}

protected:
	// 获取一个矩形,该矩形描述此容器的子项所覆盖的总区域。
	virtual Rect getContainedArea() const;

	// 对所有子项调用moveRelative(移动到的相对位置)。
	virtual void moveChildrenRelative(int16_t deltaX, int16_t deltaY);

	Drawable *firstChild; //指向此容器的第一个子项的指针。后续子项可以通过firstChild的nextSibling找到。 
	friend class Screen;

	//设置绘制链,对给定的无效区域进行绘制,并准备下一个要绘制的元素。
	virtual void setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement);
};

}

#endif
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/hal/HAL.hpp>

namespace touchgfx
{
//查询是否已将给定的Drawable直接添加到此容器中。搜索不是递归进行的。
bool Container::contains(const Drawable& d)
{
	bool found = false;
	Drawable *head = firstChild;
	while(head && !found)
	{
		found = (head == &d);
		head = head->nextSibling;
	}

	return found;
}

//添加一个Drawable实例作为此容器的子项,尾插
void Container::add(Drawable& d)
{
	assert(&d != this && "Cannot add Drawable to self");
	assert(d.parent == 0 && "Cannot add Drawable multiple times");

	//初始化该相的父对象和下一个对象
	d.parent = this;
	d.nextSibling = 0;

	//容器子项列表为空
	if(!firstChild)
	{
		firstChild = &d;
	}
	/* 不为空,尾插 */
	else
	{
		Drawable *head = firstChild;
		while(head->nextSibling)
		{
			assert(head != &d && "Cannot add Drawable multiple times");
			head = head->nextSibling;
		}
		assert(head != &d && "Cannot add Drawable multiple times");
		head->nextSibling = &d;
	}
}

//从容器中移除一个Drawable,通过将其从子项链表中移除。
void Container::remove(Drawable& d)
{
	if(!firstChild)
	{
		return;
	}

	/* 是第一个节点 */
	if(&d == firstChild)
	{
		d.parent = 0;
		if(!d.nextSibling)
		{
			firstChild = 0;
		}
		else
		{
			firstChild = d.nextSibling;
			d.nextSibling = 0;
		}
		
		return;
	}
	
	/* 不是第一个节点 */
	Drawable *tmp = firstChild;
	while(tmp)
	{
		if (tmp->nextSibling == &d)
		{
			tmp->nextSibling = d.nextSibling;
			d.parent = 0;
			d.nextSibling = 0;
			return;
		}
		else
		{
			tmp = tmp->nextSibling;
		}
	}
}

//从容器中移除所有Drawable
void Container::removeAll()
{
	while (firstChild)
	{
		Drawable* d = firstChild;
		firstChild = firstChild->nextSibling;
		d->parent = 0;
		d->nextSibling = 0;
	}
}

//通过取消链接第一个子项来移除所有子项。子项的父项和同级指针不会被重置。
void Container::unlink()
{
	firstChild = 0;
}

/* 绘制所有子项。仅绘制包含在矩形内部分 */
void Container::draw(const Rect& invalidatedArea) const
{
	if(!isVisible() || !firstChild)
	{
		return;
	}

	/* 循环绘制所有子项 */
	const Rect tmp = invalidatedArea;
	Drawable *d = firstChild;
	while (d)
	{
		/* 控件可见 */
		if(d->isVisible())
		{
			Rect drawableRegion = tmp & d->getRect();
			if(!drawableRegion.isEmpty())
			{
				/* drawableRegion在d中的坐标 */
				drawableRegion.x -= d->getX();
				drawableRegion.y -= d->getY();
				
				/* 绘制d */
				d->draw(drawableRegion);
			}
		}
		d = d->nextSibling;
	}
}

//获取该坐标相交的容器最顶层子项
void Container::getLastChild(int16_t x, int16_t y, Drawable **last)
{
	/* 容器可触摸,则容器算作最底层 */
	if(isTouchable())
	{
		*last = this;
	}

	/* 循环获取和坐标相交最顶层子项 */
	Drawable *d = firstChild;
	while (d)
	{
		/* d可见且坐标位于d内 */  
		if(d->isVisible() && d->getRect().intersect(x, y))
		{
			const int16_t xadj = x - d->getX();
			const int16_t yadj = y - d->getY();
			d->getLastChild(xadj, yadj, last);
		}
		
		d = d->nextSibling;
	}
}

// 与getLastChild()类似,但还会考虑HAL中当前设置的手指大小。
void Container::getLastChildNear(int16_t x, int16_t y, Drawable **last, int16_t *fingerAdjustmentX, int16_t *fingerAdjustmentY)
{
	/* 获取手指大小 */
	const int fingerSize = HAL::getInstance()->getFingerSize();
	
	*fingerAdjustmentX = 0;
	*fingerAdjustmentY = 0;
	*last = 0;
	
	//获取该坐标相交的容器最顶层子项
	Container::getLastChild(x, y, last);

	const int fingerSizeDistance = 3; // Up to this number is not multi-sampled
	if(fingerSize > fingerSizeDistance)
	{
		const Rect meAbsRect = getAbsoluteRect();

		uint32_t bestDistance = 0xFFFFFFFF;
		Drawable *previous = 0; // Speed up calculations if we hit the same drawable on next sample
		if(*last)
		{
			// Touched a drawable, but perhaps there is a better alternative
			previous = *last;
			const Rect absRect = (*last)->getAbsoluteRect();
			const int dx = (x + meAbsRect.x) - (absRect.x + (absRect.width / 2));
			const int dy = (y + meAbsRect.y) - (absRect.y + (absRect.height / 2));
			bestDistance = dx * dx + dy * dy;
		}

		const int samplePoints[2][4][2] = { { { 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 } },     // above, left, right, below
																				{ { -1, -1 }, { 1, -1 }, { -1, 1 }, { 1, 1 } } }; // up-left, up-right, down-left and down-right
		const int maxRings = 3;
		const int numRings = MIN(maxRings, (fingerSize - 1) / fingerSizeDistance);
		for (int ring = 0; ring < numRings; ring++)
		{
			// For each 'ring' "distance" increases up to "fingerSize":
			const int distance = fingerSize * (ring + 1) / numRings;
			for (int sampleIndex = 0; sampleIndex < 4; sampleIndex++)
			{
				const int* xy = samplePoints[ring % 2][sampleIndex];
				const int16_t deltaX = xy[0] * distance;
				const int16_t deltaY = xy[1] * distance;
				if (rect.intersect(x + deltaX, y + deltaY))
				{
					Drawable* drawable = 0;
					Container::getLastChild(x + deltaX, y + deltaY, &drawable);
					if (drawable && drawable != previous)
					{
						previous = drawable;
						const Rect absRect = drawable->getAbsoluteRect();
						// Find distance to center of drawable
						const int dx = (x + meAbsRect.x) - (absRect.x + (absRect.width / 2));
						const int dy = (y + meAbsRect.y) - (absRect.y + (absRect.height / 2));
						const uint32_t dist = dx * dx + dy * dy;
						// Check if this drawable center is closer than the previous
						if (dist < bestDistance)
						{
							bestDistance = dist;
							*last = drawable;
							*fingerAdjustmentX = deltaX;
							*fingerAdjustmentY = deltaY;
						}
					}
				}
			}
		}
	}
}

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

// 获取一个矩形,该矩形描述此容器的子项所覆盖的总区域。
Rect Container::getContainedArea() const
{
	Drawable* d = firstChild;
	Rect contained;
	
	while (d)
	{
		contained.expandToFit(d->getRect());
		d = d->nextSibling;
	}
	
	return contained;
}

// 对所有子项调用moveRelative(移动到的相对位置)。
void Container::moveChildrenRelative(int16_t deltaX, int16_t deltaY)
{
	Drawable* d = firstChild;
	while (d)
	{
		d->moveRelative(deltaX, deltaY);
		d = d->nextSibling;
	}
}

//对容器中的每个子项执行指定的回调函数。要执行的回调函数必须具有以下原型:void T::func(Drawable&)  
void Container::forEachChild(GenericCallback<Drawable&>* function)
{
	Drawable* d = firstChild;
	while (d)
	{
		function->execute(*d);
		d = d->nextSibling;
	}
}

//在特定的子节点之后插入一个Drawable。如果上一个子节点为0,则将Drawable插入为列表的第一个元素。
void Container::insert(Drawable* previous, Drawable& d)
{
	if (!firstChild)
	{
		// Insert as only element
		add(d);
		return;
	}
	else if (!previous)
	{
		// Insert as head element
		d.nextSibling = firstChild;
		firstChild = &d;
		d.parent = this;
	}
	else
	{
		Drawable* tmp = firstChild;
		while (tmp)
		{
			if (tmp == previous)
			{
				d.nextSibling = tmp->nextSibling;
				tmp->nextSibling = &d;
				d.parent = this;
				return;
			}
			tmp = tmp->nextSibling;
		}
	}
}

//设置绘制链,对给定的无效区域进行绘制,并准备下一个要绘制的元素。
void Container::setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement)
{
	// This function adds the children of this container to the list of drawables to draw.
	if (!isVisible())
	{
		// If this container itself is not visible, do not add anyone to draw chain.
		return;
	}

	if (!firstChild)
	{
		// If this container is empty, do not add anyone.
		return;
	}
	Drawable* d = firstChild;
	while (d)
	{
		if (d->isVisible())
		{
			// Only drawables intersecting with the specified invalidated area will be added.
			Rect drawableRegion = invalidatedArea & d->getRect();
			if (!drawableRegion.isEmpty())
			{
				drawableRegion.x -= d->getX();
				drawableRegion.y -= d->getY();
				d->setupDrawChain(drawableRegion, nextPreviousElement);
			}
		}
		d = d->nextSibling;
	}
}
}

touchgfx提供的几种容器

1.Container

容器是TouchGFX中的组件,可包含子节点。

 容器位于TouchGFX Designer中的容器控件组中

TouchGFX Designer中容器的属性

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

W 和 H 指定控件的宽度和高度。

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

可见 指定控件的可见性。 使控件不可见还将禁用与控件之间通过屏幕进行的交互。
缓存指定容器是否应生成为CachableContainer形式。

容器支持的操作​

控件特有的操作说明
调整控件的尺寸调整控件的宽度和高度。
标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

2.ScrollableContainer

可滚动容器属于容器,允许垂直和水平滚动其内容。

可滚动容器位于TouchGFX Designer中的容器控件组中。

TouchGFX Designer中可滚动容器的属性

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

W 和 H 指定控件的宽度和高度。

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

可见 指定控件的可见性。 如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
滚动启用水平滚动指定是否启用水平滚动。

启用垂直滚动指定是否启用垂直滚动。

显示滚动条指定滚动条是否应始终可见。

滚动时显示滚动条指定滚动条是否仅应在内容进行滚动时可见。
如果“显示滚动条”已启用,则将忽略此选项。

滚动条颜色 指定滚动条的颜色。

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

可滚动容器支持的操作​

控件特有的操作说明
调整控件的尺寸调整控件的宽度和高度。
标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

3.SwipeContainer

TouchGFX中的滑动容器是由多个页构成专门化的容器,可在各页之间滑动进行访问。 滑动容器中的页可包含其他控件,与容器类似。

滑动容器位于TouchGFX Designer中的容器控件组中

下面的部分介绍了滑动容器的属性

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

W 和 H 指定控件的宽度和高度。

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

可见 指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
已选页 指定画布上显示的页面。 该页也将作为项目运行时的起始页。

点击+按钮时会创建新页。
页指示符显示页指示符指定页指示符的可见性。

XY指定页指示符左上角相对于控件左上角的位置。

水平居中指定页指示符的位置是否应在控件的x轴上居中。

样式指定控件的预定义设置,用于将所选属性设为预定义的值。
这些样式包含可免费使用的图像。.

正常图像高亮图像指定分配给PageIndicator的正常和高亮状态的图像。
滑动设置滑动阈值指定切换页前用户需要滑动的距离。

结束滑动弹性宽度指定可将第一页和最后一页滑动到控件边界以外而不停止的距离。

下面的部分介绍了滑动容器支持的操作​

控件特有的操作说明
调整控件的尺寸调整控件的宽度和高度。
标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

4.ListLayout

列表布局控件属于容器,会自动按给定方向将其子控件排列在列表中。 向列表布局添加控件或从列表布局中移除控件会重新排列子部件。

列表布局位于TouchGFX Designer中的容器控件组中。

TouchGFX Designer中列表布局的属性。

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

W 和 H 指定控件的宽度和高度。 列表布局的大小总计为其子部件的总大小。

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

可见 指定控件的可见性。 如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
方向方向指定布局的排列方向。 在沿东向(向右)排列的水平布局与沿西向(向下)排列的垂直布局之间进行选择。

TouchGFX Designer中的列表布局支持的操作​

标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

5.ModalWindow

模式窗口是容器类型的控件,用于显示窗口,并禁止对下层视图和控件的触摸事件。 模式窗口由背景图像和边框构成,边框充当覆盖下层视图和控件的阴影,其Alpha值可调整。 模式窗口将填充整个屏幕,并始终应作为最后一个元素添加,以使其始终位于其他所有元素的顶部。

模式窗口位于TouchGFX Designer中的容器控件组中。

TouchGFX Designer中模式窗口的属性。

属性组属性说明
名称控件的名称。 名称是TouchGFX Designer和代码中使用的唯一标识符
模式图像位置X 和 Y指定图像左上角在模式窗口中的位置。

W 和 H 指定容器在模式窗口中的宽度和高度。
容器在模式窗口中的大小是从关联图像的大小获取的,其大小无法更改(除非更改图像)。

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

可见 指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
外观窗口图像 指定模式窗口应使用的图像。

阴影颜色 指定叠加阴影的颜色。

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

下面的部分介绍了模式窗口支持的操作​

标准控件操作说明
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

6.ScrollList

滚动列表是可滚动的菜单,由若干项目和控件构成,这些项目和控件滚动到视图中时会进行动态更新。 与滚动列表中的项目交互时,滚动列表还能调用回调函数。

滚动列表位于TouchGFX Designer中的容器控件组中。

TouchGFX Designer中滚动列表的属性。

属性组属性说明
名称控件的名称。 名称是TouchGFX Designer和代码中使用的唯一标识符
类型类型指定滚动列表方向为垂直方向或水平方向
位置X 和Y 指定控件左上角相对于其父的位置。

W 和 H 指定控件的宽度和高度。

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

可见 指定控件的可见性。 如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
项目模板项目模板指定用作模板的CustomContainer。

选项数指定滚动列表中存在的项目数。
列表外观循环指定到达列表末尾后,滚动列表中的项目是否将循环。

项目对齐指定项目是否应该对齐。
如果对齐为False,则项目可随意移动。 如果对齐为True,项目将按位对齐,始终位于所选位置。

项目间距指定项目之间的间距。

填充前 和 填充后 指定滚动列表中可见画板前后的距离偏移量。
动画缓动缓动选项指定动画使用的缓动方程。

Swipe Acc. 和 Drag Acc. 指定滚动时的加速度。

滚动列表中的项目基于名为“项目模板”的概念,项目模板属于CustomContainer,用作滚动列表中各项目图形元素的基础。 创建滚动列表之前,应创建自定义容器,为滚动列表提供项目模板。

创建滚动列表后,可在项目模板属性下选择CustomContainer。 指定项目模板会调整滚动列表大小,以适应所选自定义容器不在可滚动方向上的的尺寸属性(垂直滚动列表的宽度、水平滚动列表的高度)。 更改其他尺寸属性(垂直滚动列表的高度、水平滚动列表的宽度)决定了可见的项目数。

下面的部分介绍了滚动列表支持的操作​

标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

7.ScrollWheel

滚轮是包含多个项目的可滚动菜单,滚动浏览菜单中的项目时,这些项目会动态更新,且被选中的项目将突出显示。 启用响应与滚轮交互的代码后,可基于与轮中项目的交互调用不同的回调函数。

滚轮位于TouchGFX Designer中的容器控件组中。

TouchGFX Designer中滚轮的属性。

属性组属性说明
名称控件的名称。 名称是TouchGFX Designer和代码中使用的唯一标识符
类型类型指定滚轮方向为垂直方向或水平方向。
位置X 和Y 指定控件左上角相对于其父的位置。

W 和 H 指定控件的宽度和高度。

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

可见 指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
项目模板项目模板 指定用作模板的CustomContainer。

选项数 指定滚动列表中存在的项目数。

首选项目 指定首先选择哪个项目。

使用已选样式模板 指定是否为所选项目使用单独的模板。

已选样式模板 指定用作选定模板的CustomContainer。
列表外观循环 指定到达列表末尾后,滚轮中的项目是否将循环。

选中项偏移量 指定选定项目的位置。

项目边距 指定项目之间的间距。

前方额外尺寸后方额外尺寸 指定显示已选样式模板的区域的大小。

前边距后边距指定显示已选样式模板的区域前后的边距大小。
动画缓动缓动选项指定动画使用的缓动方程。

Swipe Acc. 和 Drag Acc. 指定滚动时的加速度。

滚动列表中的项目基于名为“项目模板”的概念,项目模板属于CustomContainer,用作滚轮中各项目图形元素的基础。 为了突出显示所选项目,滚轮包含用于选择名为“已选样式模板”的项目模板的选项,已选样式模板仅可用于已选项目。 创建滚轮之前,应为项目模板以及已选项目模板(若启用)创建CustomContainer。

创建滚轮后,可在项目模板属性下选择CustomContainer。 为项目模板选择自定义容器时,会调整滚轮大小,以适应所选自定义容器不在可滚动方向上的的尺寸属性(垂直方向的宽度、水平方向的高度)。 更改其他尺寸属性(垂直方向的高度、水平方向的宽度)决定了可见的项目数。

下面的部分介绍了滚轮支持的操作​

标准控件操作说明
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

8.SlideMenu

TouchGFX中的滑动菜单是由内部容器、图像和可选按钮构成的专门化的容器,可以动画形式显示收起和展开状态的变化过程。

滑动菜单位于TouchGFX Designer中的容器控件组中。

下面的部分介绍了滑动菜单的属性。

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

W 和 H 指定控件的宽度和高度。
滑动菜单的大小是由其背景和按钮图像的大小决定的。

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

可见 指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
展开方向展开方向指定滑动菜单的展开方向。
状态状态指定滑动菜单的初始状态。

收起:可见像素数指定状态为收起时应可见的像素数。

展开:隐藏像素数 指定状态为展开时应隐藏的像素数。

展开超时指定从展开状态自动恢复到收起状态之前的时长。
背景背景图像 指定用作背景的图像。

背景位置 指定背景图像相对于控件坐标的x、y坐标。
按钮使用按钮 指定是否使用按钮来控制控件的状态。

释放图像指定用于按钮已发布状态的图像。

按下图像指定用于按钮已按下状态的图像。

按钮位置指定按钮相对于控件坐标的x、y坐标。
动画缓动缓动选项指定动画使用的缓动方程。

持续时间指定动画应持续的时长。

下面的部分介绍了滑动菜单支持的操作​

控件特有的操作说明
更改滑动菜单的状态将滑动菜单的状态改为收起或展开
复位滑动菜单的定时器复位定时器会自动将滑动菜单状态恢复为收起状态
标准控件操作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

下面的部分介绍了滑动菜单支持的触发条件​

触发条件说明
滑动菜单动画结束从一种状态变为另一种状态的滑动菜单动画已结束。
滑动菜单状态已更改滑动菜单的状态已更改。

9.Slider

滑块使用三幅图像在垂直或水平方向显示滑块。 可以拖动滑块的指示图像修改通过回调函数广播的内部整数值。 广播的值位于一个整数值范围(例如0-100)内

滑块位于TouchGFX Designer中的Miscellaneous控件组中。

TouchGFX Designer中滑块的属性。

属性组属性说明
名称控件的名称。 名称是TouchGFX Designer和代码中使用的唯一标识符
类型类型指定滑块应该是垂直方向还是水平方向。
位置XY指定控件左上角相对于其父的位置。

WH指定控件的宽度和高度。
滑块的大小是从关联图像的大小获取的,其大小无法更改(除非更改图像)。

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

可见指定控件的可见性。
如果将控件标记为不可见,还会禁止通过屏幕与控件进行交互。
样式样式指定控件的预定义设置,用于将所选属性设为预定义的值。
这些样式包含可免费使用的图像。
图像背景图像指定指示器滑过的背景图像。

背景填充图像指定填充指示器后面背景图像顶部区域的图像。

指示图像指定可拖动以更改滑块值的图像。

背景图像和背景填充图像的大小必须一致。
位置X轴背景位置Y轴背景位置指定背景图像背景填充图像的左上角位置。

指示器位置最小值指示器位置最大值指定指示器图像位置的最小值和最大值。
对于水平滑块,这两个值在x轴上;对于垂直滑块,这两个值在y轴上

Y轴指示器位置指定指示器图像在Y轴上的位置。
如果滑块是垂直移动的,则该值应在X轴上进行调整。
最小值最大值指定使用回调函数从滑块进行广播的内部整数值范围。

初始指定滑块中的初始内部值。 这同样会改变指示器的初始位置。

下面的部分介绍了滑块支持的操作​

标准控件动作说明
移动控件随时间的推移将控件移动到新位置。
隐藏控件隐藏控件(将可见性设置为false)。
显示控件使隐藏的控件可见(将可见性设置为true)。

下面的部分介绍了滑块支持的触发条件​

触发说明
启动滑块调整滑块已被点击或拖动。
滑块调整已确认滑块指示器不再被拖动。
滑块值已更改滑块值已更改。

10.Keyboard

代码

#ifndef TOUCHGFX_KEYBOARD_HPP
#define TOUCHGFX_KEYBOARD_HPP
#include <touchgfx/Callback.hpp>
#include <touchgfx/TypedText.hpp>
#include <touchgfx/Unicode.hpp>
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/events/ClickEvent.hpp>
#include <touchgfx/events/DragEvent.hpp>
#include <touchgfx/hal/Types.hpp>
#include <touchgfx/widgets/Image.hpp>
#include <touchgfx/widgets/TextAreaWithWildcard.hpp>

namespace touchgfx
{
class Keyboard : public Container
{
public:
	/* 单个按键结构体 */
	struct Key
	{
		uint8_t keyId;              //按键ID
		Rect keyArea;               //按键区域
		BitmapId highlightBitmapId; //按键按下时位图ID
	};

	/* 矩形区域回调 */
	struct CallbackArea
	{
		Rect keyArea;                //按键区域
		GenericCallback<>* callback; //当区域被“按下”时要执行的回调
		BitmapId highlightBitmapId;  //按键按下时位图ID
	};

	/* 键盘布局的定义。键盘可以处理不断变化的布局,因此可以通过改变布局和键映射来实现不同的键盘模式 */
	struct Layout
	{
		BitmapId bitmap;                 //键盘位图ID
		const Key *keyArray;             //按键数组
		uint8_t numberOfKeys;            //按键个数
		CallbackArea *callbackAreaArray; //区域回调数组
		uint8_t numberOfCallbackAreas;   //区域回调个数
		Rect textAreaPosition;           //键盘缓冲区显示区域
		TypedText textAreaFont;          //键盘缓冲区显示区域TypedText
		colortype textAreaFontColor;     //键盘缓冲区显示区域TypedText颜色
		FontId keyFont;                  //按键字体
		colortype keyFontColor;          //按键字体颜色
	};

	/* 按键字符映射 */
	struct KeyMapping
	{
		uint8_t keyId;                 //按键ID
		Unicode::UnicodeChar keyValue; //按键字符
	};

	/* 按键字符映射表 */
	struct KeyMappingList
	{
		const KeyMapping *keyMappingArray; //按键字符映射数组指针
		uint8_t numberOfKeys;              //按键字符映射数组大小
	};

	Keyboard();

	/* 设置键盘要使用的缓冲区。输入的按键将添加到缓冲区 */
	void setBuffer(Unicode::UnicodeChar *newBuffer, uint16_t newBufferSize);

	/* 设置键盘布局 */
	void setLayout(const Layout *newLayout);

	/* 设置缩进 */
	void setTextIndentation();

	/* 获取键盘布局 */
	const Layout *getLayout() const
	{
		return layout;
	}

	/* 设置按键字符映射表 */
	void setKeymappingList(const KeyMappingList *newKeyMappingList);

	/* 获取按键字符映射表 */
	const KeyMappingList *getKeyMappingList() const
	{
		return keyMappingList;
	}

	/* 设置输入缓冲区当前指针 */
	void setBufferPosition(uint16_t newPos);

	/* 过去输入缓冲区当前指针 */
	uint16_t getBufferPosition()
	{
		return bufferPosition;
	}

	/* 获取输入缓冲区指针 */
	Unicode::UnicodeChar *getBuffer() const
	{
		return buffer;
	}

	/* 绘制该图(绘制所有按键字符)。仅绘制包含在矩形内部分 */
	virtual void draw(const Rect& invalidatedArea) const;

	/* 点击事件 */
	virtual void handleClickEvent(const ClickEvent& event);

	/* 拖拽事件:按下且离开按键区域 */
	virtual void handleDragEvent(const DragEvent& event);

	/* 设置按键释放时回调 */
	void setKeyListener(GenericCallback<Unicode::UnicodeChar>& callback)
	{
		keyListener = &callback;
	}

protected:
	GenericCallback<Unicode::UnicodeChar> *keyListener; //按键释放时回调指针

	Unicode::UnicodeChar *buffer;         //输入缓冲区
	uint16_t bufferSize;                  //输入缓冲区长度
	uint16_t bufferPosition;              //输入缓冲区当前指针
	Image image;                          //布局image
	TextAreaWithOneWildcard enteredText;  //能够显示输入的文本缓冲区
	const Layout *layout;                 //键盘布局的定义
	const KeyMappingList *keyMappingList; //按键字符映射表
	Image highlightImage;                 //按键高亮时显示位图
	bool cancelIsEmitted;                 //按键事件取消(按下后离开控件区域)

	/* 根据坐标获取该按键 */
	Key getKeyForCoordinates(int16_t x, int16_t y) const;

	/* 获取按键字符 */
	Unicode::UnicodeChar getCharForKey(uint8_t keyId) const;

	/* 根据坐标获取该区域回调 */
	CallbackArea getCallbackAreaForCoordinates(int16_t x, int16_t y) const;

	/// @cond
	/**
	 * Add to draw chain.
	 *
	 * @param          invalidatedArea     Include drawables that intersect with this area only.
	 * @param [in,out] nextPreviousElement Modifiable element in linked list.
	 *
	 * @note For TouchGFX internal use only.
	 */
	virtual void setupDrawChain(const Rect& invalidatedArea, Drawable** nextPreviousElement);
};

}

#endif
#include <touchgfx/Bitmap.hpp>
#include <touchgfx/Color.hpp>
#include <touchgfx/Drawable.hpp>
#include <touchgfx/Font.hpp>
#include <touchgfx/FontManager.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/lcd/LCD.hpp>
#include <touchgfx/widgets/Keyboard.hpp>

namespace touchgfx
{
Keyboard::Keyboard()
    : Container(), keyListener(0), buffer(0), bufferSize(0), bufferPosition(0), image(), enteredText(), layout(0), keyMappingList(0), highlightImage(), cancelIsEmitted(false)
{
	setTouchable(true);

	image.setXY(0, 0);
	Keyboard::add(image);

	highlightImage.setVisible(false);
	Keyboard::add(highlightImage);

	enteredText.setColor(Color::getColorFromRGB(0, 0, 0));
	Keyboard::add(enteredText);
}

/* 设置键盘输入的文本缓冲区 */
void Keyboard::setBuffer(Unicode::UnicodeChar *newBuffer, uint16_t newBufferSize)
{
	buffer = newBuffer;
	bufferSize = newBufferSize;

	enteredText.setWildcard(buffer);

	bufferPosition = Unicode::strlen(buffer);
}

/* 设置键盘布局 */
void Keyboard::setLayout(const Layout *newLayout)
{
	layout = newLayout;
	if(newLayout != 0)
	{
		/* 设置新的布局位图 */
		image.setBitmap(Bitmap(newLayout->bitmap));

		/* 设置缓冲区显示的显示的字体、颜色、区域 */
		enteredText.setTypedText(newLayout->textAreaFont);
		enteredText.setColor(newLayout->textAreaFontColor);
		enteredText.setPosition(newLayout->textAreaPosition.x, newLayout->textAreaPosition.y,
														newLayout->textAreaPosition.width, newLayout->textAreaPosition.height);
	}
	
	/* 重绘 */
	invalidate();
}

/* 设置缩进 */
void Keyboard::setTextIndentation()
{
	if (layout != 0)
	{
		const uint8_t indentation = layout->textAreaFont.getFont()->getMaxPixelsLeft();
		enteredText.setPosition(layout->textAreaPosition.x - indentation, layout->textAreaPosition.y,
														layout->textAreaPosition.width + indentation * 2, layout->textAreaPosition.height);
		enteredText.setIndentation(indentation);
	}
}

/* 根据坐标获取该按键 */
Keyboard::Key Keyboard::getKeyForCoordinates(int16_t x, int16_t y) const
{
	Key key;
	key.keyId = 0; // No key
	if (layout != 0)
	{
		for (uint8_t i = 0; i < layout->numberOfKeys; i++)
		{
			if (layout->keyArray[i].keyArea.intersect(x, y))
			{
				key = layout->keyArray[i];
				break;
			}
		}
	}
	return key;
}

/* 根据坐标获取该区域回调 */
Keyboard::CallbackArea Keyboard::getCallbackAreaForCoordinates(int16_t x, int16_t y) const
{
	CallbackArea area;
	area.callback = reinterpret_cast<GenericCallback<>*>(0);
	if(layout != 0)
	{
		for (uint8_t i = 0; i < layout->numberOfCallbackAreas; i++)
		{
			if (layout->callbackAreaArray[i].keyArea.intersect(x, y))
			{
				area = layout->callbackAreaArray[i];
				break;
			}
		}
	}
	return area;
}

/* 绘制该图。仅绘制包含在矩形内部分 */
void Keyboard::draw(const Rect& invalidatedArea) const
{
	assert(layout && "No layout configured for Keyboard");
	
	/* 绘制所有按键字符 */
	if(layout != 0)
	{
		Font *font = FontManager::getFont(layout->keyFont);
		assert(font && "Keyboard::draw: Unable to find font, is font db initialized?");
		if (font != 0)
		{
			// Setup visuals for h-center of "string"
			LCD::StringVisuals visuals;
			visuals.font = font;
			visuals.alignment = CENTER;
			visuals.color = layout->keyFontColor;
			// String with room for a single character
			Unicode::UnicodeChar character[2] = { 0, 0 }; // The last is important as string terminator.

			const uint16_t fontHeight = font->getHeight();

			for (uint8_t i = 0; i < layout->numberOfKeys; i++)
			{
				const Key& key = layout->keyArray[i];
				if (key.keyArea.intersect(invalidatedArea))
				{
					const uint8_t keyId = key.keyId;
					const Unicode::UnicodeChar c = getCharForKey(keyId);
					if (c != 0)
					{
						// Get a copy of the keyArea and v-center the area for the character
						Rect keyArea = key.keyArea;
						const uint16_t offset = (keyArea.height - fontHeight) / 2;
						keyArea.y += offset;
						keyArea.height -= offset;
						// Calculate the invalidated area relative to the key
						Rect invalidatedAreaRelative = key.keyArea & invalidatedArea;
						invalidatedAreaRelative.x -= keyArea.x;
						invalidatedAreaRelative.y -= keyArea.y;
						// Set up string with one character
						character[0] = c;
						translateRectToAbsolute(keyArea);
						HAL::lcd().drawString(keyArea, invalidatedAreaRelative, visuals, character);
					}
				}
			}
		}
	}
}

/* 点击事件 */
void Keyboard::handleClickEvent(const ClickEvent& event)
{
	const ClickEvent::ClickEventType type = event.getType();
	
	/* 不检查按键松开事件:手离开后区域后松开不处理 */
	if(type == ClickEvent::RELEASED && cancelIsEmitted)
	{
		cancelIsEmitted = false;
		return;
	}
	
	const int16_t x = event.getX();
	const int16_t y = event.getY();
	Rect toDraw;

	/* 根据坐标获取该区域回调 */
	Keyboard::CallbackArea callbackArea = getCallbackAreaForCoordinates(x, y);
	/* 有回调:功能按键 */
	if(callbackArea.callback != 0)
	{
		/* 按下重绘 */
		if(type == ClickEvent::PRESSED)
		{
			/* 绘制按键高亮 */
			highlightImage.setXY(callbackArea.keyArea.x, callbackArea.keyArea.y);
			highlightImage.setBitmap(Bitmap(callbackArea.highlightBitmapId));
			highlightImage.setVisible(true);
			toDraw = highlightImage.getRect();
			invalidateRect(toDraw);
		}

		/* 松开按键,回调 */
		if((type == ClickEvent::RELEASED) && callbackArea.callback->isValid())
		{
			callbackArea.callback->execute();
			if(keyListener)
			{
				keyListener->execute(0);
			}
		}
	}
	/* 没有回调:字符按键 */
	else
	{
		/* 根据坐标获取该按键 */
		const Keyboard::Key key = getKeyForCoordinates(x, y);

		/* 按下 */
		if (type == ClickEvent::PRESSED)
		{
			/* 绘制按键高亮 */
			if(key.keyId != 0)
			{
				highlightImage.setXY(key.keyArea.x, key.keyArea.y);
				highlightImage.setBitmap(Bitmap(key.highlightBitmapId));
				highlightImage.setVisible(true);
				toDraw = highlightImage.getRect();
				invalidateRect(toDraw);
			}
		}

		/* 松开按键,重绘键盘缓冲区显示区域 */
		if (type == ClickEvent::RELEASED)
		{
			if (key.keyId != 0 && buffer)
			{
				const Unicode::UnicodeChar c = getCharForKey(key.keyId);
				if (c != 0 && bufferPosition < (bufferSize - 1))
				{
					enteredText.invalidateContent();
					buffer[bufferPosition++] = c;
					buffer[bufferPosition] = 0;
					enteredText.invalidateContent();
					if (keyListener)
					{
						keyListener->execute(c);
					}
				}
			}
		}
	}

	/* 按键释放/取消,不显示高亮图片 */
	if (type == ClickEvent::RELEASED || type == ClickEvent::CANCEL)
	{
		toDraw = highlightImage.getRect();
		highlightImage.setVisible(false);
		invalidateRect(toDraw);

		if(type == ClickEvent::CANCEL)
		{
			cancelIsEmitted = true;
		}
	}
}

/* 拖拽事件:按下且离开按键区域 */
void Keyboard::handleDragEvent(const DragEvent& event)
{
	if(highlightImage.isVisible() && (!highlightImage.getRect().intersect(static_cast<int16_t>(event.getNewX()), static_cast<int16_t>(event.getNewY()))) && (!cancelIsEmitted))
	{
		//按键取消事件
		const ClickEvent cancelEvent(ClickEvent::CANCEL, static_cast<int16_t>(event.getOldX()), static_cast<int16_t>(event.getOldY()));
		handleClickEvent(cancelEvent);
	}
}

/* 获取按键字符 */
Unicode::UnicodeChar Keyboard::getCharForKey(uint8_t keyId) const
{
	Unicode::UnicodeChar ch = 0;
	if (keyMappingList != 0)
	{
		for (uint8_t i = 0; i < keyMappingList->numberOfKeys; i++)
		{
			if (keyMappingList->keyMappingArray[i].keyId == keyId)
			{
				ch = keyMappingList->keyMappingArray[i].keyValue;
				break;
			}
		}
	}
	return ch;
}

/* 将绘图插入容器的绘图链 */
void Keyboard::setupDrawChain(const Rect& invalidatedArea, Drawable **nextPreviousElement)
{
	/* 将该容器中所有绘图插入父容器的绘图链 */
	Container::setupDrawChain(invalidatedArea, nextPreviousElement);
	/* 将该容器自己插入父容器的绘图链 */
	Drawable::setupDrawChain(invalidatedArea, nextPreviousElement);
}

/* 设置输入缓冲区当前指针 */
void Keyboard::setBufferPosition(uint16_t newPos)
{
	bufferPosition = newPos;
	enteredText.invalidate();
}

/* 设置按键字符映射表 */
void Keyboard::setKeymappingList(const KeyMappingList *newKeyMappingList)
{
	keyMappingList = newKeyMappingList;
	invalidate();
}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正大国际:国内做外盘qi货的人多吗?

整个中国&#xff0c;期货也就五百万个账户&#xff0c;活跃的也就两百万个&#xff0c;股票账户三亿多个 所以说在国内做期货的是真的少&#xff0c;大部分人聊天知道股票&#xff0c;期货听都没听过 这所有的国内期货账户中&#xff0c;小散户是寥寥无几的&#xff0c;基本…

content warning内容警告中文汉化快捷教程分享

content warning(内容警告)是近期steam上非常受欢迎的一款恐怖题材多人联机游戏,自4月1日上线后,一直保持较高的玩家人数,steam好评率也稳定维持在93%,可以说是4月初发售游戏中的最大黑马。本作首发虽然支持中文,不过游戏内的中文阅读体验并不完整,经常会出现中英文字幕混杂等情…

IoTeX的旅程并非孤军奋战

自2017年起&#xff0c;IoTeX便作为一个雄心勃勃的开源项目&#xff0c;踏上了一条为机器打造开放经济的道路。这个宏伟的目标背后&#xff0c;是一个去中心化的平台愿景&#xff0c;一个能够让人类和机器在有保障的信任、自由意志及精心设计的经济激励下相互协作的开放生态系统…

前端学习<四>JavaScript基础——10-运算符

我们在前面讲过变量&#xff0c;本文讲一下运算符和表达式。 运算符的定义和分类 运算符的定义 运算符&#xff1a;也叫操作符&#xff0c;是一种符号。通过运算符可以对一个或多个值进行运算&#xff0c;并获取运算结果。 表达式&#xff1a;数字、运算符、变量的组合&…

华为 2024 届校园招聘-硬件通⽤/单板开发——第十套

华为 2024 届校园招聘-硬件通⽤/单板开发——第十套 部分题目分享&#xff0c;完整版带答案&#xff08;共十套&#xff09;获取&#xff08;WX:didadidadidida313&#xff0c;加我备注&#xff1a;CSDN huawei硬件单板题目&#xff0c;谢绝白嫖哈&#xff09; 1、I2 C 总线…

代码随想录算法训练营Day14|二叉树理论基础和递归遍历

代码随想录卡哥视频 理论基础 需要了解 二叉树的种类&#xff0c;存储方式&#xff0c;遍历方式 以及二叉树的定义 文章讲解&#xff1a;代码随想录 递归遍历 &#xff08;必须掌握&#xff09; 二叉树的三种递归遍历掌握其规律后&#xff0c;其实很简单 题目链接/文章讲解/…

如何制作软件安装包第二步

目录 0.文章目的1.第二次打开发现之前生成的2.重新引导引入文件--制作安装包3.输入安装包基本信息4.确认安装路径5.选择制作完成的exe执行文件6.加入jre运行环境--这步很重要&#xff0c;否则项目运行不起来7.填写安装包名称8.添加版权信息文件&#xff08;可选操作&#xff09…

android-自定义TextView在文字内容末尾添加图片icon、可以添加间距

样式示意图 自定义属性 style.xml <declare-styleable name"IconLabelTextView"><attr name"iconSrc" format"reference"/><attr name"iconPaddingStart" format"dimension"/><attr name"iconPad…

PKI:构建数字安全基石的关键技术

在数字化时代&#xff0c;网络安全已成为我们日常生活和工作的重要组成部分。为了确保数据的完整性、机密性和身份的真实性&#xff0c;公钥基础设施&#xff08;Public Key Infrastructure&#xff0c;简称PKI&#xff09;技术应运而生&#xff0c;为构建数字安全基石提供了重…

无人机控制框架的设计

无人机控制框架的设计主要包括以下几个模块&#xff1a;传感器模块、控制模块、通信模块和执行器模块。 传感器模块&#xff1a;负责获取无人机当前的状态信息&#xff0c;包括位置、姿态、速度等。常用的传感器包括GPS、陀螺仪、加速度计、气压计等。 控制模块&#xff1a;根…

Mysql底层原理二:Buffer Pool

1.数据区 就是描述信息缓存页这块&#xff0c;用来存放从磁盘加载的数据页&#xff08;看上图 索引页和数据页是分开的&#xff09; 2. free链表 用来标识数据区哪些数据页是可用的 3. flush链表 update的时候&#xff0c;如果数据在数据区可以找到&#xff0c;那就直接内…

Novel Influence Maximization Algorithm for Social Network Behavior Management

Abstract: 通过影响力最大化的过程来识别对社交网络中的产品采用或信息利用做出重大贡献的用户。社交网络的指数增长给这些网络的分析带来了一些挑战。现有文献非常重视对结构属性进行建模&#xff0c;而忽略了用户与其社会行为之间的关系。对于社会行为&#xff0c;本文将影响…

基于Java+SpringBoot+vue3+uniapp点餐/外卖管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

第九届蓝桥杯大赛个人赛省赛(软件类)真题C 语言 A 组-航班时间

#include<iostream> using namespace std;int getTime(){int h1, h2, m1, m2, s1, s2, d 0;//d一定初始化为0&#xff0c;以正确处理不跨天的情况 scanf("%d:%d:%d %d:%d:%d (%d)", &h1, &m1, &s1, &h2, &m2, &s2, &d);return d …

使用高德微信小程序插件实现精准获取打卡位置

由于微信小程序的 getFuzzyLocation 误差太大 不得不改用高德微信sdk 使用方法&#xff1a; 一、下载 sdk 相关下载-微信小程序插件 | 高德地图API 二、引入 sdk //引入 var amapFile require(../../libs/amap-wx.js); Page({onLoad: function() {var that this;va…

基于springboot+vue+Mysql的滴答拍摄影项目

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

组合数(费马小定理, 快速幂)

给定 n 组询问&#xff0c;每组询问给定两个整数 a&#xff0c;b&#xff0c;请你输出 Cbamod(1097)的值。 输入格式 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含一组 a 和 b。 输出格式 共 n 行&#xff0c;每行输出一个询问的解。 数据范围 1≤n≤10000, 1≤…

战争中的AI应用:道德、伦理与技术的交织

AI在战争中的应用是一个极具争议和复杂的话题&#xff0c;无法简单地回答是好还是坏。其影响取决于多个因素&#xff0c;包括使用方式、目的、伦理框架以及技术本身的发展水平。 一方面&#xff0c;AI在战争中具有潜在的积极作用。它可以提高军事行动的效率和精确性&#xff0c…

持续交付工具Argo CD的部署使用

Background CI/CD&#xff08;Continuous Integration/Continuous Deployment&#xff09;是一种软件开发流程&#xff0c;旨在通过自动化和持续集成的方式提高软件交付的效率和质量。它包括持续集成&#xff08;CI&#xff09;和持续部署&#xff08;CD&#xff09;两个主要阶…

自然语言处理技术(Natural Language Processing)知识点

自然语言处理知识点 自然语言处理1. word2vec是什么2. 常用的NLP工具和软件3. 朴素贝叶斯分类器4. BiLSTM-CRF模型怎么去实现5. Bert模型实现NER6. 命名实体识别任务中&#xff0c;怎么去处理数据分布不均的问题&#xff1f;7. 用户问题检索相关文本时&#xff0c;具体都用了哪…