Simple Window using C++

The sample metavision_simple_window.cpp shows the basic usage of the Metavision::Window and Metavision::MTWindow classes.

Principle of the Window Management Implementation

The Window Management System implemented in the UI module relies on the use of GFLW and OpenGL which allows rendering multiple windows in different threads.

Two kinds of window are available:

  • a Metavision::Window that will be updated on demand, and

  • a Metavision::MTWindow that owns an internal rendering thread allowing a fixed frequency display (synchronized with the screen’s refresh rate)

Note

Both kinds of window can be used from any thread.

The principle is the following: system input events are polled from the main thread and then dispatched to the windows they belong to using the Metavision::EventLoop::poll_and_dispatch() function.

Events are automatically polled, and the callbacks associated with them are called, when a window is updated (using either the Metavision::Window::show() or Metavision::MTWindow::show_async() methods). Events can also be explicitly polled from a window by calling the Metavision::BaseWindow::poll_events() method.

Principle of the Window Management Implementation

Warning

To ensure the compatibility across the different platforms, some operations must only be done from the main thread. These operations are:

Expected Output

Two resizable windows the user can interact with.

Expected Output from Metavision Simple Window Sample Expected Output from Metavision Simple Window Sample

How to start

First, compile the sample as described in this tutorial.

To start the sample, run:

Linux

./metavision_simple_window

Windows

metavision_simple_window.exe

Code Overview

Window Creation

In this sample two windows are created:

Metavision::Window w1("Window GRAY", img.cols, img.rows, Metavision::Window::RenderMode::GRAY);
Metavision::MTWindow w2("MTWindow BGR", img.cols, img.rows, Metavision::Window::RenderMode::BGR);

Note

The windows can be resized after creation.

System Events Subscription

The windows can react to 3 kinds of system input events and to which the user can subscribe:

  • the key events, when the user presses a key on the keyboard while the window has the focus,

  • the mouse events, when the user clicks on a mouse’s button while the mouse’s cursor is in the window’s area, and

  • the cursor events, when the user moves the mouse’s cursor in the window’s area

In this sample we subscribe to the key and mouse events of the first window:

// An example of a Key callback. It will be called only when a key is pressed while the window 1 has the focus.
w1.set_keyboard_callback([&w1](Metavision::UIKeyEvent key, int scancode, Metavision::UIAction action, int mods) {
    if (action == Metavision::UIAction::RELEASE) {
        const auto it = key_to_names.find(key);

        if (it != key_to_names.end())
            MV_LOG_INFO("[KEYBOARD EVENT]") << " " << it->second;

        if (key == Metavision::UIKeyEvent::KEY_ESCAPE)
            w1.set_close_flag();
    }
});

w1.set_mouse_callback([](Metavision::UIMouseButton button, Metavision::UIAction action, int mods) {
    if (action == Metavision::UIAction::RELEASE) {
        const auto it = button_to_names.find(button);

        if (it != button_to_names.cend())
            MV_LOG_INFO("[MOUSE EVENT]") << " " << it->second;
    }
});

and to the key and cursor events of the second window:

// An example of a mouse cursor callback. It will be called whenever the mouse's cursor is on top of the window 2.
w2.set_cursor_pos_callback(
    [](double x, double y) { MV_LOG_INFO("[MOUSE CURSOR EVENT]") << " x:" << x << "y:" << y; });

// Another Key callback called when a key is pressed while the window 2 has the focus.
w2.set_keyboard_callback([&w2](Metavision::UIKeyEvent key, int scancode, Metavision::UIAction action, int mods) {
    if (action == Metavision::UIAction::RELEASE && key == Metavision::UIKeyEvent::KEY_ESCAPE)
        w2.set_close_flag();
});

The application stops when the ‘ESCAPE’ key is pressed while one of the two windows has the focus.

Using the Windows from any thread

Once instantiated from the main thread, the windows can be used from any thread. In this sample we create a rendering loop in a separate thread for the first window to illustrate that:

// The window 1 will be rendered in a separate thread
auto rendering_thread_w1 = std::thread([&]() {
    // Continue until one of the two windows is asked to close
    while (!w1.should_close() && !w2.should_close()) {
        // This call will:
        // - Poll and process the events received by the window 1. The attached callbacks are processed here in this
        // thread.
        // - Immediately update the displayed image.
        w1.show(img1);

        // Here we make the window 1 have a 40Hz refresh rate
        std::this_thread::sleep_for(std::chrono::milliseconds(25));
    }
});

While the second window, which has its own internal rendering thread, is asynchronously updated from the main thread (but it could have been done from any thread as well):

// The window 2 will be updated asynchronously from the main thread (i.e. the image will be updated in the internal
// rendering thread).
// Continue until one of the two windows is asked to close
while (!w1.should_close() && !w2.should_close()) {
    // Poll all the events from the system and send them to the corresponding windows' internal queues.
    Metavision::EventLoop::poll_and_dispatch();

    auto img2 = img.clone();

    // This call will:
    // - Poll and process the events received by the window 2. The attached callbacks are processed here in the main
    // thread.
    // - Asynchronously update the displayed image.
    w2.show_async(img2);
}

However, as opposed to using the windows from any thread, it is very important for the Metavision::EventLoop::poll_and_dispatch() function to be called from the main thread.