Visualization
This guide covers the graphics system: scenes, views, painters, and geometry.
Scene and View
QtNodes uses Qt’s Graphics View Framework:
BasicGraphicsScene – A
QGraphicsScenethat creates visual objects for your modelGraphicsView – A
QGraphicsViewwith node-editing interactions built in
// Connect model to scene to view
MyGraphModel model;
BasicGraphicsScene scene(model);
GraphicsView view(&scene);
view.show();
For data flow applications, use the specialized scene:
DataFlowGraphModel model(registry);
DataFlowGraphicsScene scene(model); // Handles delegate creation
GraphicsView view(&scene);
Graphics Objects
The scene creates graphics objects automatically:
NodeGraphicsObject – Visual representation of each node
ConnectionGraphicsObject – Visual representation of each connection
Access them when needed:
NodeGraphicsObject* nodeObj = scene.nodeGraphicsObject(nodeId);
ConnectionGraphicsObject* connObj = scene.connectionGraphicsObject(connId);
Custom Node Painter
Replace the default node appearance by subclassing AbstractNodePainter:
class MyNodePainter : public QtNodes::AbstractNodePainter
{
public:
void paint(QPainter* painter, NodeGraphicsObject& ngo) const override
{
auto& geometry = ngo.nodeScene()->nodeGeometry();
auto& model = ngo.graphModel();
NodeId nodeId = ngo.nodeId();
QRectF rect = geometry.boundingRect(nodeId);
// Custom drawing
painter->setBrush(QColor(70, 130, 180));
painter->setPen(QPen(Qt::white, 2));
painter->drawRoundedRect(rect, 10, 10);
// Draw caption
QString caption = model.nodeData(nodeId, NodeRole::Caption).toString();
painter->drawText(rect, Qt::AlignCenter, caption);
}
};
// Register with scene
scene.setNodePainter(std::make_unique<MyNodePainter>());
Custom Connection Painter
Similarly for connections:
class MyConnectionPainter : public QtNodes::AbstractConnectionPainter
{
public:
void paint(QPainter* painter, ConnectionGraphicsObject const& cgo) const override
{
QPointF start = cgo.endPoint(PortType::Out);
QPointF end = cgo.endPoint(PortType::In);
// Draw as straight line with arrow
painter->setPen(QPen(Qt::cyan, 3));
painter->drawLine(start, end);
// Draw arrow head at end
drawArrow(painter, end, start);
}
QPainterPath getPainterStroke(ConnectionGraphicsObject const& cgo) const override
{
// Return path for hit testing
QPainterPath path;
path.moveTo(cgo.endPoint(PortType::Out));
path.lineTo(cgo.endPoint(PortType::In));
QPainterPathStroker stroker;
stroker.setWidth(10);
return stroker.createStroke(path);
}
};
scene.setConnectionPainter(std::make_unique<MyConnectionPainter>());
Custom Node Geometry
Control node layout by subclassing AbstractNodeGeometry:
class MyNodeGeometry : public QtNodes::AbstractNodeGeometry
{
public:
QRectF boundingRect(NodeId nodeId) const override;
QPointF portPosition(NodeId, PortType, PortIndex) const override;
QPointF captionPosition(NodeId) const override;
QPointF widgetPosition(NodeId) const override;
// ... other layout methods
};
scene.setNodeGeometry(std::make_unique<MyNodeGeometry>());
The library provides two built-in geometries:
DefaultHorizontalNodeGeometry– Ports on left/right (default)DefaultVerticalNodeGeometry– Ports on top/bottom
Vertical Layout
For top-to-bottom graphs:
scene.setOrientation(Qt::Vertical);
GraphicsView Features
Zoom control:
// Set zoom limits (0 = unlimited)
view.setScaleRange(0.25, 4.0);
// Zoom programmatically
view.scaleUp();
view.scaleDown();
view.setupScale(1.5);
// Fit content
view.zoomFitAll(); // Fit all nodes
view.zoomFitSelected(); // Fit selected nodes
// React to zoom changes
connect(&view, &GraphicsView::scaleChanged, [](double scale) {
qDebug() << "Zoom:" << scale * 100 << "%";
});
Built-in actions:
view.clearSelectionAction(); // Clear selection
view.deleteSelectionAction(); // Delete selected items
Copy/paste:
view.onCopySelectedObjects();
view.onPasteObjects();
view.onDuplicateSelectedObjects(); // Ctrl+D
Scene Signals
Connect to user interactions:
// Node interactions
connect(&scene, &BasicGraphicsScene::nodeClicked, [](NodeId id) {
qDebug() << "Clicked node" << id;
});
connect(&scene, &BasicGraphicsScene::nodeDoubleClicked, [](NodeId id) {
// Open node properties dialog
});
connect(&scene, &BasicGraphicsScene::nodeMoved, [](NodeId id, QPointF pos) {
qDebug() << "Node" << id << "moved to" << pos;
});
// Hover events (for tooltips, highlights)
connect(&scene, &BasicGraphicsScene::nodeHovered,
[](NodeId id, QPoint screenPos) {
QToolTip::showText(screenPos, "Node info here");
});
connect(&scene, &BasicGraphicsScene::connectionHovered,
[](ConnectionId id, QPoint screenPos) {
// Show connection info
});
// Context menus
connect(&scene, &BasicGraphicsScene::nodeContextMenu,
[](NodeId id, QPointF scenePos) {
// Show custom context menu for this node
});
Headless Mode
Run without any visualization:
// Model works without scene
DataFlowGraphModel model(registry);
NodeId source = model.addNode("NumberSource");
NodeId display = model.addNode("Display");
model.addConnection({source, 0, display, 0});
// Data flows, computations happen, no GUI needed
// Or: scene without view
BasicGraphicsScene scene(model);
// Scene tracks model changes but nothing is rendered