# How to Add New Terminal Screens to the Fincept Qt6 Application

> Learn to add new terminal screens to the Fincept Qt6 application. Discover QWidget class creation, DockScreenRouter registration, and state persistence for enhanced UI functionality.

- Repository: [Fincept Corporation/FinceptTerminal](https://github.com/Fincept-Corporation/FinceptTerminal)
- Tags: how-to-guide
- Published: 2026-04-20

---

**To add new terminal screens to the Fincept Qt6 application, create a QWidget-derived class, register it with the DockScreenRouter using either eager or lazy factory registration in MainWindow::setup_app_screens(), and optionally implement IStatefulScreen for UI state persistence.**

The Fincept Terminal is a Qt6-based financial terminal that uses an Advanced Docking System (ADS) to manage multiple screens. When you need to add new terminal screens to the Fincept Qt6 application, you will work with the `DockScreenRouter` class to handle registration, navigation, and state management across the docking grid.

## Step 1: Create the Screen Class

Every terminal screen must derive from `QWidget`. If the screen needs to persist UI state across sessions, it should also inherit from `fincept::screens::IStatefulScreen` and implement the required virtual methods.

### Deriving from QWidget

Create your screen in the `fincept-qt/src/screens/` directory structure:

```cpp
// fincept-qt/src/screens/my_screen/MyScreen.h
#pragma once
#include <QWidget>

namespace fincept::screens {

class MyScreen : public QWidget {
    Q_OBJECT
public:
    explicit MyScreen(QWidget* parent = nullptr);
    ~MyScreen() override;
};

} // namespace fincept::screens

```

```cpp
// fincept-qt/src/screens/my_screen/MyScreen.cpp
#include "screens/my_screen/MyScreen.h"
#include <QLabel>
#include <QVBoxLayout>

namespace fincept::screens {

MyScreen::MyScreen(QWidget* parent) : QWidget(parent) {
    auto* layout = new QVBoxLayout(this);
    layout->addWidget(new QLabel("Hello Fincept!"));
}

MyScreen::~MyScreen() = default;

} // namespace fincept::screens

```

### Implementing IStatefulScreen for Persistence

If your screen needs to remember user preferences or UI configuration, implement the `IStatefulScreen` interface located in [`fincept-qt/src/screens/IStatefulScreen.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/IStatefulScreen.h):

```cpp
// fincept-qt/src/screens/my_screen/MyScreen.h
#pragma once
#include <QWidget>
#include "screens/IStatefulScreen.h"

namespace fincept::screens {

class MyScreen : public QWidget, public IStatefulScreen {
    Q_OBJECT
public:
    explicit MyScreen(QWidget* parent = nullptr);
    ~MyScreen() override = default;

    // IStatefulScreen implementation
    QVariantMap save_state() const override;
    void restore_state(const QVariantMap& state) override;
    QString state_key() const override { return "my_screen"; }
};

} // namespace fincept::screens

```

```cpp
// fincept-qt/src/screens/my_screen/MyScreen.cpp
#include "screens/my_screen/MyScreen.h"
#include <QLabel>
#include <QVBoxLayout>

namespace fincept::screens {

MyScreen::MyScreen(QWidget* parent) : QWidget(parent) {
    auto* layout = new QVBoxLayout(this);
    layout->addWidget(new QLabel("Hello Fincept!"));
}

QVariantMap MyScreen::save_state() const {
    return { {"exampleFlag", true} };
}

void MyScreen::restore_state(const QVariantMap& state) {
    // Read back persisted values
    Q_UNUSED(state);
}

} // namespace fincept::screens

```

## Step 2: Register the Screen with DockScreenRouter

All screen registration happens in `MainWindow::setup_app_screens()` in [`fincept-qt/src/app/MainWindow.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/app/MainWindow.cpp) (around line 801). The `DockScreenRouter` supports two registration patterns.

### Lazy Factory Registration (Preferred)

Use `register_factory()` for heavy screens that should only instantiate when first navigated to. The factory lambda is stored in `DockScreenRouter::factories_` until the first navigation triggers it (see lines 86-88 in [`DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/DockScreenRouter.cpp)):

```cpp
// In MainWindow::setup_app_screens()
dock_router_->register_factory(
    "my_screen",
    []() { return new screens::MyScreen; });

```

### Eager Registration

For ultra-lightweight utility screens that must exist immediately, use `register_screen()`:

```cpp
dock_router_->register_screen(
    "about",
    new screens::AboutScreen);

```

## Step 3: Add a Human-Readable Title

To display a friendly name in the tab header instead of the raw ID, add an entry to `DockScreenRouter::title_for_id()` in [`fincept-qt/src/app/DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/app/DockScreenRouter.cpp) (around lines 71-74):

```cpp
QString DockScreenRouter::title_for_id(const QString& id) {
    static const QHash<QString, QString> titles{
        // Existing entries...
        {"my_screen", "My Custom Screen"},
        {"about", "About"},
        // ...
    };
    return titles.value(id, id);
}

```

## Step 4: Navigate to the Screen

Any UI element (menu, button, or shortcut) can trigger navigation using the screen ID:

```cpp
connect(ui->actionMyScreen, &QAction::triggered,
        this, [this]() { dock_router_->navigate("my_screen"); });

```

The `DockScreenRouter::navigate()` method (starting at line 90 in [`DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/DockScreenRouter.cpp)) performs four operations:

1. Locates or creates the `ads::CDockWidget` wrapper
2. Materializes the screen widget if it was lazily registered
3. Places the widget in the 2×2 docking grid or tabs it into an existing area
4. Persists the current screen ID via `SessionManager` (see lines 68-70 in [`DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/DockScreenRouter.cpp))

## Step 5: Handle State Persistence

If your screen implements `IStatefulScreen`, `DockScreenRouter` automatically manages state persistence:

- When the screen is hidden or the application shuts down, `DockScreenRouter::save_screen_state()` calls your `save_state()` implementation
- On application startup or when the screen is first shown, `DockScreenRouter::restore_screen_state()` invokes your `restore_state()` method after the dock widget materializes

These methods are located near the bottom of [`DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/DockScreenRouter.cpp) (search for `save_screen_state` and `restore_screen_state`). No additional wiring is required beyond implementing the interface.

## Summary

- **Create** your screen by deriving from `QWidget` in `fincept-qt/src/screens/<your_screen>/` and optionally implementing `IStatefulScreen` for persistence.
- **Register** the screen in `MainWindow::setup_app_screens()` using `register_factory()` for lazy loading or `register_screen()` for eager instantiation.
- **Title** the screen by adding an entry to `DockScreenRouter::title_for_id()` in [`DockScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/DockScreenRouter.cpp).
- **Navigate** using `dock_router_->navigate("screen_id")` from menus, buttons, or shortcuts.
- **Persist** UI state automatically by implementing the `IStatefulScreen` interface methods.

## Frequently Asked Questions

### Where do I place the new screen files in the Fincept Qt6 codebase?

Place your header and implementation files in `fincept-qt/src/screens/<your_screen>/` (for example, [`fincept-qt/src/screens/my_screen/MyScreen.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/my_screen/MyScreen.h) and [`MyScreen.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MyScreen.cpp)). This follows the existing project structure where each screen resides in its own directory under the screens folder.

### What is the difference between eager and lazy registration in DockScreenRouter?

**Eager registration** using `register_screen()` creates the widget immediately and keeps it in memory, which is suitable for lightweight utility screens like an About dialog. **Lazy registration** using `register_factory()` stores a factory lambda that only instantiates the widget on first navigation, which is preferred for heavy screens to improve startup performance and reduce memory usage.

### How does Fincept Qt6 save and restore screen state across sessions?

If your screen implements the `IStatefulScreen` interface and provides `save_state()`, `restore_state()`, and `state_key()` methods, the `DockScreenRouter` automatically calls `save_state()` when the screen closes or the app shuts down, and `restore_state()` when the screen is recreated. The data is persisted through the `SessionManager` to maintain UI configuration across application restarts.