Getting Started
In this article, we will focus on the Qt library, as it is the open source GUI library of choice for C++ developers. In the next article, we will have a look at the general concept of actor companions. An actor companion is an actor that co-exists with another object. In our case, this object is a QWidget-base class. The companion is used to receive and send messages, but it does not have any behavior itself. All it takes to enable a class to have such a companion is to use the actor_widget_mixin.The following class implements a simple group-based chat widget with a QTextEdit for text output and a QLineEdit for user input (chat messages). The full source code can be found in the examples folder in the Git repository.
#include <QWidget> #include "cppa/qtsupport/actor_widget_mixin.hpp" class ChatWidget : public cppa::actor_widget_mixin<QWidget> { Q_OBJECT typedef cppa::actor_widget_mixin<QWidget> super; // ... public: ChatWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0); // ... private: std::string m_name; cppa::group_ptr m_chatroom; };The mixin adds the following member functions to ChatWidget:
- actor_ptr as_actor()
returns the companion of this widget - set_message_handler
sets the partial function for message processing
Handle Messages to the Widget
In our example, the widget should handle 'join', 'setName', and 'quit' messages as well as display chat messages (received as std::string). We encode our message handling directly into the constructor of ChatWidget:ChatWidget::ChatWidget(QWidget* parent, Qt::WindowFlags f) : super(parent, f) { set_message_handler ( on(atom("join"), arg_match) >> [=](const group_ptr& what) { if (m_chatroom) { send(m_chatroom, m_name + " has left the chatroom"); self->leave(m_chatroom); } self->join(what); print(("*** joined " + to_string(what)).c_str()); m_chatroom = what; send(what, m_name + " has entered the chatroom"); }, on(atom("setName"), arg_match) >> [=](string& name) { send(m_chatroom, m_name + " is now known as " + name); m_name = std::move(name); print("*** changed name to " + QString::fromUtf8(m_name.c_str())); }, on(atom("quit")) >> [=] { close(); // close widget }, on<string>() >> [=](const string& txt) { // don't print own messages if (self != self->last_sender()) { print(QString::fromUtf8(txt.c_str())); } } ); }
Pitfalls & Things to Know
The code is pretty straight forward if you are already familiar with libcppa, but there is one important thing to note: Unhandled messages are lost. Although the widget is able to handle libcppa messages now, it does not have a mailbox. Messages are delivered to the widget as QEvent objects that are disposed afterwards.The second thing to note is that you should never use self outside the message handler. This includes using functions such as send, because
To send a message from outside of your handler, you have to tell libcppa who is the sender of the message by hand:
send_as(as_actor(), m_chatroom, "hello world!");
Have fun!