Real-Time 2D Track Display Using Qt GraphicsScene

Qt GraphicsScene - Manya Technologies

Introduction

Qt’s Graphics View Framework (QGraphicsView, QGraphicsScene, QGraphicsItem) is widely used for building real-time 2D visualization systems such as radar displays, tactical maps, UAV monitoring dashboards, and simulation tools.

In this article, we walk through how a radar-like 2D track display is implemented using Qt GraphicsScene, including:

  • Static polar grid (range rings & bearings)
  • Dynamic moving tracks
  • Velocity vectors and short trails
  • Zoom-independent symbols and labels

Only key code fragments are shown to explain the technique—not a full application.


Why Qt GraphicsScene?

Qt GraphicsScene is ideal when you need:

  • High-frequency updates (10–60 Hz)
  • Large numbers of moving objects
  • Layer-based rendering
  • Interactive graphics items
  • Clean separation of logic and visualization

This makes it a natural choice for radar, defense, aviation, and GIS-based systems.


Scene Initialization

At the core is a QGraphicsScene attached to a custom QGraphicsView:

m_scene = new QGraphicsScene(this);
setScene(m_scene);

The scene uses logical coordinates (meters or kilometers), not screen pixels, which simplifies real-world mapping.


Static Layer: Polar Grid & Range Rings

The static layer is created once and rarely updated.
It typically includes concentric rings, bearing lines, and distance labels.

Creating a Static Layer Group

m_staticLayer = new QGraphicsItemGroup();
m_scene->addItem(m_staticLayer);

Drawing Range Rings (Key Fragment)

QPen ringPen(QColor(180, 180, 180));
ringPen.setCosmetic(true);   // constant line width

auto *ring = new QGraphicsEllipseItem(-r, -r, 2*r, 2*r);
ring->setPen(ringPen);
ring->setBrush(Qt::NoBrush);
m_staticLayer->addToGroup(ring);

Distance Labels (Zoom-Safe)

auto *label = new QGraphicsTextItem("50 km");
label->setFlag(QGraphicsItem::ItemIgnoresTransformations);
label->setPos(r + 4, -4);
m_staticLayer->addToGroup(label);

Bearing Lines (Every 30°)

double rad = qDegreesToRadians(angleDeg);
QPointF end(radius * qCos(rad), radius * qSin(rad));

auto *line = new QGraphicsLineItem(0, 0, end.x(), end.y());
line->setPen(ringPen);
m_staticLayer->addToGroup(line);

This produces the familiar radar polar grid.


Dynamic Tracks: Targets on the Map

Each moving target is represented by:

  • A blip (ellipse)
  • A text label (track ID)
  • A velocity vector
  • A short movement trail

Creating Track Graphics (Once)

auto *trackItem = new QGraphicsEllipseItem(-4, -4, 8, 8);
trackItem->setFlag(QGraphicsItem::ItemIgnoresTransformations);
m_scene->addItem(trackItem);

auto *trackLabel = new QGraphicsTextItem(QString::number(trackId));
trackLabel->setFlag(QGraphicsItem::ItemIgnoresTransformations);
m_scene->addItem(trackLabel);

Updating Track Position

Track updates happen whenever new data arrives from sensors, simulators, or network feeds.

QPointF pos = convertLatLonToScene(lat, lon);
trackItem->setPos(pos);
trackLabel->setPos(pos + QPointF(6, -6));

The conversion function maps real-world coordinates to scene coordinates.


Velocity Vector (Heading Indicator)

Velocity vectors show direction of motion and remain visually consistent across zoom levels.

double angleRad = qDegreesToRadians(headingDeg);
double sceneLen = screenPixels / transform().m11();

QPointF v(sceneLen * qSin(angleRad),
          -sceneLen * qCos(angleRad));

velocityLine->setLine(pos.x(), pos.y(),
                      pos.x() + v.x(), pos.y() + v.y());

This ensures the vector length stays constant on screen, not in scene units.


Track Trails (Recent History)

Trails help operators understand movement patterns.

history.append({pos, timestamp});

while (!history.isEmpty() &&
       now - history.front().time > 5000)
    history.pop_front();

Rendering the Trail Path

QPainterPath path;
path.moveTo(history.first().pos);

for (int i = 1; i < history.size(); ++i)
    path.lineTo(history[i].pos);

trailItem->setPath(path);

Only the last few seconds are kept for performance.


Interaction Support

Each track can support interaction:

trackItem->setFlag(QGraphicsItem::ItemIsSelectable);
trackItem->setAcceptHoverEvents(true);

This enables:

  • Tooltips
  • Context menus
  • Track designation changes
  • Selection and highlighting

Advantages of This Design

✔ Performance-Friendly

Static grid drawn once, only tracks update

✔ Scalable

Handles hundreds or thousands of targets

✔ Clean Architecture

Separate layers for grid, tracks, and overlays

✔ Professional UI

Zoom-safe symbols and consistent visuals


Conclusion

Qt GraphicsScene offers a mature, production-ready framework for building radar-like 2D tracking displays. By combining static polar grids, dynamic track items, velocity vectors, and trails, developers can create high-performance tactical views without resorting to heavy OpenGL pipelines.

This approach is proven in defense, aviation, drone, and simulation systems, and integrates easily with real-time data feeds, GIS backends, and playback engines.


Need Similar Qt-Based Visualization Software?

Manya Technologies specializes in:

  • Qt C++ real-time applications
  • Radar & tactical display systems
  • Custom GIS viewers (QGIS / PostGIS)
  • Simulation and tracking software

🌐 Website: https://manyatechnologies.com

If you’re building a custom radar, drone, or tracking visualization, we can design and deliver a robust, scalable solution tailored to your needs.

Scroll to Top