图元视图类型对象
在 Qt 的图形视图框架中,GraphicsView 与 GraphicsItem 组合被广泛用于实现自定义绘图、流程图、拓扑图、坐标系、游戏场景等“画布 + 图元”的界面。
与 List / Table / Tree 等视图类似,GraphicsView 与 GraphicsItem 也都继承自 IQtControl,因此除了本节列出的专用方法外,还可以使用所有通用控件方法。
图元视图控件:GraphicsView
GraphicsView 控件用于描述 Qt 中基于 QGraphicsView 的画布视图。它主要面向“场景坐标系”的操作,例如:
- 获取画布场景的整体尺寸;
- 在指定场景坐标点击 / 双击 / 按下 / 抬起;
- 将指定场景坐标滚动到可见区域;
- 获取画布中的子图元列表。
注意:
sceneX/sceneY参数均为 场景坐标(scene coordinates),而不是窗口像素坐标。
| 方法名 | 描述 |
|---|---|
| sceneRect | 获取画布场景的矩形区域。 |
| clickScene | 在指定场景坐标位置进行单击 / 双击 / 按下 / 抬起等鼠标操作。 |
| moveToScene | 将视图滚动到使指定场景坐标点可见。 |
| items | 获取画布中的子图元列表。 |
类型定义
export interface GraphicsView extends IQtControl {
sceneRect(): Promise<Rect>
clickScene(sceneX: number, sceneY: number, mousekey?: number): Promise<void>;
clickScene(sceneX: number, sceneY: number, options: ClickOptions): Promise<void>;
moveToScene(sceneX: number, sceneY: number): Promise<void>;
items(all?: boolean): Promise<IQtControl[]>;
}
interface ClickOptions {
double?: boolean; // 是否双击
down?: boolean; // 是否仅按下
up?: boolean; // 是否仅抬起
button?: number; // 1: 左键, 2: 右键
}class GraphicsView(QtControl):
def sceneRect() -> "Rect"
def clickScene(sceneX: int, sceneY: int, mousekey: Optional[int]=None) -> None
def clickScene(sceneX: int, sceneY: int, options: ClickOptions) -> None
def moveToScene(sceneX: int, sceneY: int) -> None
def items(Optional[bool]=True) -> List[QtControl]
class ClickOptions:
double: bool # 是否双击
down: bool # 是否仅按下
up: bool # 是否仅抬起
button: int # 1: 左键, 2: 右键sceneRect()
获取画布场景的矩形区域(QGraphicsScene::sceneRect()),包含场景左上角坐标与宽高信息。
返回值
- 返回一个
Rect对象,描述整个场景的逻辑坐标范围。
示例代码
const rect = await model.getGraphicsView("View").sceneRect();
console.log(`Scene rect: x=${rect.x}, y=${rect.y}, w=${rect.width}, h=${rect.height}`);rect = model.getGraphicsView("View").sceneRect()
print(f"Scene rect: x={rect.x}, y={rect.y}, w={rect.width}, h={rect.height}")clickScene(sceneX, sceneY, mouseKeyOrOptions)
在画布的场景坐标位置执行鼠标操作。如果目标位置当前不在可见区域内,会自动滚动画布使该点可见,然后执行鼠标事件。
支持两种调用方式:
- 简单单击 / 右键单击:
clickScene(sceneX: number, sceneY: number, mousekey?: number): Promise<void>;- 通过
ClickOptions精细控制(单击 / 双击 / 按下 / 抬起 / 指定按钮等):
clickScene(sceneX: number, sceneY: number, options: ClickOptions): Promise<void>;参数
- sceneX:
number- 目标点在场景中的水平坐标。 - sceneY:
number- 目标点在场景中的垂直坐标。 mousekey(可选):
number1:左键(默认)2:右键
options(可选):
ClickOptionsdouble:true- 表示双击;down:true- 表示只按下不抬起;up:true- 表示只执行抬起;button:1左键,2右键(默认1)。
mousekey与options二选一使用;提供options时可同时指定double/down/up/button的组合。
返回值
- 不返回任何值的异步方法。
示例代码
简单左键单击:
// 在场景坐标 (100, 200) 处单击左键
await model.getGraphicsView("View").clickScene(100, 200);# 在场景坐标 (100, 200) 处单击左键
model.getGraphicsView("View").clickScene(100, 200)右键单击:
await model.getGraphicsView("View").clickScene(150, 300, 2); // 2 = 右键model.getGraphicsView("View").clickScene(150, 300, 2)双击:
await model.getGraphicsView("View").clickScene(200, 400, { double: true, button: 1 });model.getGraphicsView("View").clickScene(200, 400, { "double": True, "button": 1 })仅按下 / 抬起(模拟拖拽起点):
// 按下
await model.getGraphicsView("View").clickScene(100, 100, { down: true, button: 1 });
// 这里可以调用其它操作(如移动鼠标)
// 抬起
await model.getGraphicsView("View").clickScene(200, 200, { up: true, button: 1 });# 按下
model.getGraphicsView("View").clickScene(100, 100, { "down": True, "button": 1 })
# 这里可以调用其它操作(如移动鼠标)
# 抬起
model.getGraphicsView("View").clickScene(200, 200, { "up": True, "button": 1 })moveToScene(sceneX, sceneY)
将当前画布视图滚动到使指定场景坐标点进入可见区域。如果该点本来就在可见区域,则不会有可见变化。
通常用于:先将重要图元所在区域滚动出来,再配合 clickScene() 或 items() 做进一步操作。
参数
- sceneX:
number– 场景坐标X - sceneY:
number– 场景坐标Y
返回值
- 不返回任何值的异步方法。
示例代码
// 把场景中 (500, 500) 这一点滚动到可见区域
await model.getGraphicsView("View").moveToScene(500, 500);
// 然后在附近点击
await model.getGraphicsView("View").clickScene(500, 500);model.getGraphicsView("View").moveToScene(500, 500)
model.getGraphicsView("View").clickScene(500, 500)items(all?)
获取当前画布中的图元列表。
参数
all(可选):
booleantrue(默认):返回场景中的所有子图元;false:返回直接子图元(视具体实现而定,通常仍为一层子项)。
返回值
- 返回值为一组
GraphicsItem控件对象(类型上是IQtControl,使用时可按GraphicsItem方法进行调用)。
示例代码
const items = await model.getGraphicsView("View").items(true);
console.log(`Found ${items.length} graphics items`);
for (const item of items) {
// 这里可以尝试用 allProperties() 或 GraphicsItem 专用方法
const pos = await item.position();
if (pos) {
console.log("Item at: ", pos);
}
}items = model.getGraphicsView("View").items(True)
print(f"Found {len(items)} graphics items")
for item in items:
# 如果该项是 GraphicsItem,可以使用 position()
try:
pos = item.position()
print("Item at:", pos)
except AttributeError:
pass
图元控件:GraphicsItem
GraphicsItem 控件对应 Qt 中的 QGraphicsItem,代表画布上的一个具体图元。它可以是矩形、椭圆、线段、文本,也可以是自定义绘制的复杂对象。
通过 GraphicsItem 可以:
- 滚动视图使当前图元可见;
- 获取图元的碰撞矩形(BoundingRect);
- 获取图元在场景中的绝对位置;
- 读取
Qt ItemData(如业务 ID、类型标记等); - 获取其子图元。
对于更多内部属性(颜色、线宽、Z 值等),可配合
allProperties()进行调试和分析。
| 方法名 | 描述 |
|---|---|
| scrollIntoView | 将视图滚动到使当前图元可见。 |
| bound | 获取当前图元的碰撞矩形(BoundingRect)。 |
| position | 获取当前图元在场景中的绝对位置。 |
| data | 获取图元的业务数据(Qt item data)。 |
| items | 获取当前图元的子图元列表。 |
类型定义
export interface GraphicsItem extends IQtControl {
scrollIntoView(): Promise<void>;
bound(): Promise<number[]>; // [x, y, width, height]
position(): Promise<Point>;
data(key: number): Promise<string | number>;
items(): Promise<IQtControl[]>;
}
export interface Point {
x: number;
y: number;
}class GraphicsItem(QtControl):
def scrollIntoView(self) -> None: ...
def bound(self) -> list[float] | list[int]: ... # [x, y, width, height]
def position(self) -> "Point": ...
def data(self, key: int) -> str | int: ...
def items(self) -> list["QtControl"]: ...
class Point:
x: float
y: floatscrollIntoView()
将当前画布视角滚动到使当前 GraphicsItem 完全或部分可见。
- 如图元所在区域被滚动出了视野,调用该方法会自动移动滚动条或调整视图中心到该图元附近。
- 与
TreeItem/TableItem的scrollIntoView()语义类似。
返回值
- 不返回任何值的异步方法。
示例代码
const item = model.getGraphicsItem("Node_1");
await item.scrollIntoView();
await item.click(); // 图元可见后执行点击item = model.getGraphicsItem("Node_1")
item.scrollIntoView()
item.click()bound()
获取当前图元的碰撞矩形(BoundingRect),包含位置坐标 x 和 y 以及宽度 width 和高度 height,坐标为相对于场景的相对坐标。
返回值
- 返回一个
Rect对象,描述整个场景的逻辑坐标范围。
示例代码
const item = model.getGraphicsItem("Node_1");
const bound = await item.bound();
console.log(`Bounding: x=${bound.x}, y=${bound.y}, w=${bound.width}, h=${bound.height}`);item = model.getGraphicsItem("Node_1")
bound = item.bound()
print(f"Bounding: x={bound.x}, y={bound.y}, w={bound.width}, h={bound.height}")结合 clickScene() 做中心点击:
const bound = await item.bound();
const centerX = bound.x + bound.width / 2;
const centerY = bound.y + bound.height / 2;
await model.getGraphicsView("View").clickScene(centerX, centerY);bound = item.bound()
centerX = bound.x + bound.width / 2
centerY = bound.y + bound.height / 2
model.getGraphicsView("View").clickScene(centerX, centerY)position()
获取当前图元在场景坐标系中的绝对位置(通常为图元的参考点 / 原点位置)。
返回值
Point类型,包含x和y坐标。
示例代码
const item = model.getGraphicsItem("Node_1");
const pos = await item.position();
console.log(`Item position: (${pos.x}, ${pos.y})`);item = model.getGraphicsItem("Node_1")
pos = item.position()
print(f"Item position: ({pos['x']}, {pos['y']})")配合 moveToScene() 让视图居中到该图元附近:
const item = model.getGraphicsItem("Node_1");
const pos = await item.position();
await model.getGraphicsView("View").moveToScene(pos.x, pos.y);item = model.getGraphicsItem("Node_1")
pos = item.position()
model.getGraphicsView("View").moveToScene(pos['x'], pos['y'])data(key)
获取当前图元的 item data 数据。Qt 中每个 QGraphicsItem 都可以通过 QGraphicsItem::data(key) 存储业务数据(如 ID、类型、标签等)。
在 CukeTest 中,通过 data(key) 可读取这些数据。常见约定:
key = 0时,往往用来存放图元的标识属性或业务 ID;- 其它 key 由应用开发者自行定义。
参数
- key:
number– 数据索引,缺省为0时通常表示默认数据。
返回值
string或number类型,对应key的item数据。
示例代码
// 获取默认数据(通常是标识属性)
const item = model.getGraphicsItem("SomeItem");
const id = await item.data(0);
console.log("Item ID:", id);item = model.getGraphicsItem("SomeItem")
id_ = item.data(0)
print("Item ID:", id_)按业务 ID 在所有图元中查找目标项:
const view = model.getGraphicsView("View");
const items = await view.items(true);
const targetId = "NODE_123";
for (const item of items) {
if (!item.data) continue;
const id = await item.data(0);
if (id === targetId) {
await item.scrollIntoView();
await item.click();
break;
}
}view = model.getGraphicsView("View")
items = view.items(True)
target_id = "NODE_123"
for item in items:
if not hasattr(item, "data"):
continue
item_id = item.data(0)
if item_id == target_id:
item.scrollIntoView()
item.click()
breakitems()
获取当前图元的所有直接子图元列表。
这在图元分组(GroupItem)、复杂组件图元(如复合节点、带图标+文本的图元)中非常有用,可以沿层级结构深入查找需要的子元素。
返回值
IQtControl类型,返回GraphicsItem子控件对象列表。
示例代码
const group = model.getGraphicsItem("GroupNode");
const children = await group.items();
console.log(`Group has ${children.length} children`);
for (const child of children) {
const pos = await child.position();
console.log("Child at:", pos);
}group = model.getGraphicsItem("GroupNode")
children = group.items()
print(f"Group has {len(children)} children")
for child in children:
try:
pos = child.position()
print("Child at:", pos)
except AttributeError:
pass典型使用示例:定位并点击图元
下面以一个完整流程示例,展示如何在 GraphicsView 上按业务 ID 查找对应 GraphicsItem 并点击:
// 假设业务上图元的 ID 保存在 data(0) 中
async function clickNodeById(model, viewName, nodeId) {
const view = model.getGraphicsView(viewName);
const items = await view.items(true);
for (const item of items) {
if (!item.data) continue;
const id = await item.data(0);
if (id === nodeId) {
// 先滚动到可见
await item.scrollIntoView();
// 通过图元的 bounding 计算中心,使用场景坐标点击
const bound = await item.bound();
await view.clickScene(bound.x + bound.width / 2, bound.y + bound.height / 2);
return;
}
}
throw new Error(`GraphicsItem with id=${nodeId} not found`);
}def click_node_by_id(model, view_name, node_id: str):
view = model.getGraphicsView(view_name)
items = view.items(True)
for item in items:
try:
if item.data(0) == node_id:
item.scrollIntoView()
bound = item.bound()
view.clickScene(bound.x + bound.width / 2, bound.y + bound.height / 2)
return
except Exception:
continue
raise RuntimeError(f"GraphicsItem with id={node_id} not found")