图元视图类型对象

在 Qt 的图形视图框架中,GraphicsViewGraphicsItem 组合被广泛用于实现自定义绘图、流程图、拓扑图、坐标系、游戏场景等“画布 + 图元”的界面。

List / Table / Tree 等视图类似,GraphicsViewGraphicsItem 也都继承自 IQtControl,因此除了本节列出的专用方法外,还可以使用所有通用控件方法

图元视图控件:GraphicsView

GraphicsView 控件用于描述 Qt 中基于 QGraphicsView 的画布视图。它主要面向“场景坐标系”的操作,例如:

  • 获取画布场景的整体尺寸;
  • 在指定场景坐标点击 / 双击 / 按下 / 抬起;
  • 将指定场景坐标滚动到可见区域;
  • 获取画布中的子图元列表。

注意:sceneX / sceneY 参数均为 场景坐标(scene coordinates),而不是窗口像素坐标。

方法名 描述
sceneRect 获取画布场景的矩形区域。
clickScene 在指定场景坐标位置进行单击 / 双击 / 按下 / 抬起等鼠标操作。
moveToScene 将视图滚动到使指定场景坐标点可见。
items 获取画布中的子图元列表。

类型定义

JavaScript
Python
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对象,描述整个场景的逻辑坐标范围。

示例代码

JavaScript
Python
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)

在画布的场景坐标位置执行鼠标操作。如果目标位置当前不在可见区域内,会自动滚动画布使该点可见,然后执行鼠标事件。

支持两种调用方式:

  1. 简单单击 / 右键单击:

JavaScript
clickScene(sceneX: number, sceneY: number, mousekey?: number): Promise<void>;

  1. 通过 ClickOptions 精细控制(单击 / 双击 / 按下 / 抬起 / 指定按钮等):

JavaScript
clickScene(sceneX: number, sceneY: number, options: ClickOptions): Promise<void>;

参数

  • sceneX: number - 目标点在场景中的水平坐标。
  • sceneY: number - 目标点在场景中的垂直坐标。
  • mousekey(可选): number

    • 1:左键(默认)
    • 2:右键
  • options(可选): ClickOptions

    • doubletrue - 表示双击;
    • downtrue - 表示只按下不抬起;
    • uptrue - 表示只执行抬起;
    • button1 左键,2 右键(默认 1)。

mousekeyoptions 二选一使用;提供 options 时可同时指定 double / down / up / button 的组合。

返回值

  • 不返回任何值的异步方法。

示例代码

简单左键单击:

JavaScript
Python
// 在场景坐标 (100, 200) 处单击左键
await model.getGraphicsView("View").clickScene(100, 200);
# 在场景坐标 (100, 200) 处单击左键
model.getGraphicsView("View").clickScene(100, 200)

右键单击:

JavaScript
Python
await model.getGraphicsView("View").clickScene(150, 300, 2); // 2 = 右键
model.getGraphicsView("View").clickScene(150, 300, 2)

双击:

JavaScript
Python
await model.getGraphicsView("View").clickScene(200, 400, { double: true, button: 1 });
model.getGraphicsView("View").clickScene(200, 400, { "double": True, "button": 1 })

仅按下 / 抬起(模拟拖拽起点):

JavaScript
Python
// 按下
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

返回值

  • 不返回任何值的异步方法。

示例代码

JavaScript
Python
// 把场景中 (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(可选): boolean

    • true(默认):返回场景中的所有子图元;
    • false:返回直接子图元(视具体实现而定,通常仍为一层子项)。

返回值

  • 返回值为一组 GraphicsItem 控件对象(类型上是 IQtControl,使用时可按 GraphicsItem 方法进行调用)。

示例代码

JavaScript
Python
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 获取当前图元的子图元列表。

类型定义

JavaScript
Python
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: float

scrollIntoView()

将当前画布视角滚动到使当前 GraphicsItem 完全或部分可见。

  • 如图元所在区域被滚动出了视野,调用该方法会自动移动滚动条或调整视图中心到该图元附近。
  • TreeItem / TableItemscrollIntoView() 语义类似。

返回值

  • 不返回任何值的异步方法。

示例代码

JavaScript
Python
const item = model.getGraphicsItem("Node_1");
await item.scrollIntoView();
await item.click();   // 图元可见后执行点击
item = model.getGraphicsItem("Node_1")
item.scrollIntoView()
item.click()

bound()

获取当前图元的碰撞矩形(BoundingRect),包含位置坐标 xy 以及宽度 width 和高度 height,坐标为相对于场景的相对坐标。

返回值

  • 返回一个Rect对象,描述整个场景的逻辑坐标范围。

示例代码

JavaScript
Python
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() 做中心点击:

JavaScript
Python
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 类型,包含 xy 坐标。

示例代码

JavaScript
Python
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() 让视图居中到该图元附近:

JavaScript
Python
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 时通常表示默认数据。

返回值

  • stringnumber 类型,对应 keyitem 数据。

示例代码

JavaScript
Python
// 获取默认数据(通常是标识属性)
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 在所有图元中查找目标项:

JavaScript
Python
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()
        break

items()

获取当前图元的所有直接子图元列表。

这在图元分组(GroupItem)、复杂组件图元(如复合节点、带图标+文本的图元)中非常有用,可以沿层级结构深入查找需要的子元素。

返回值

  • IQtControl 类型,返回 GraphicsItem 子控件对象列表。

示例代码

JavaScript
Python
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 并点击:

JavaScript
Python
// 假设业务上图元的 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")

results matching ""

    No results matching ""