Home

Awesome

Thinking Wt 1: general

This article shows one way to think about program architecture when using the Wt library.

View a screenshot of the application developed in this article (png)

Overview

In the first two paragraph I will explain the rationale behind the architecture proposed. The following paragraphs describes the steps in implementing this architecture in a top-down way, followed by a conclusion.

Why these guidelines?

Wt is 'a widget-centric API' [1] for, primarily, dynamic web applications. I see many resemblances in its architecture with the Qt library, suitable for, among others, desktop applications. Due to their different running environments, Wt (web) and Qt (desktop) are mutually exclusive. Because I enjoy porting applications to as much platforms as possible, I have developed some applications that use both (but not simultaneously) a Wt and a Qt front-end. To be able to do this easily, I follow the guidelines presented in this article. Additionally, I like to reuse my own widgets and dialogs in multiple applications, which is only possible with a proper architecture.

Note that I follow the same guidelines for Qt front-ends.

Architecture

The architecture, from biggest to smallest, is: main, Wt::WApplication, dialog, widget:

 

Implementing main

In this example, main creates a single Wt::WApplication, and does not respond to command-line arguments.

The most basic main function would only call WRun with a createApplication function that only returns a newly created Wt::WApplication:

#include <Wt/WApplication>
#include <Wt/WEnvironment>

Wt::WApplication *createApplication(
  const Wt::WEnvironment& env)
{
  return new WtApplication(env);
}

int main(int argc, char **argv)
{
  return WRun(argc, argv, &createApplication);
}

This way of creating a Wt::WApplication is identical to [2][3].

Implementing the Wt::WApplication

The purpose of the Wt::WApplication is to create a dialog. In this example, WtApplication manages a single to pointer to a single dialog, called WtDialog. WtApplication does not respond to the Wt::WEnvironment parameters given at construction, but sets the WtDialog as its widget. Additionaly, it sets the browser title to 'My title'.

#include <Wt/WApplication>
#include <Wt/WEnvironment>

struct WtApplication : public Wt::WApplication
{
  WtApplication(const Wt::WEnvironment& env)
    : Wt::WApplication(env),
    m_dialog(new WtDialog)
  {
    this->setTitle("My title");
    root()->addWidget(m_dialog);
  }
  private:
  WtDialog * const m_dialog;
};

Because the pointer m_dialog is set to be managed by Wt in the 'addWidget' method, it should not be deleted (doing so results in a double deletion warning.  

Implementing the dialog

Because a dialog is a collection of at least one widget, WtDialog is a derived class from Wt::WContainerWidget. WtDialog manages two widgets, but does not respond to their signals.

#include <Wt/WContainerWidget>

struct WtDialog : public Wt::WContainerWidget
{
  WtDialog()
  : m_widget1(new WtWidget),
    m_widget2(new WtWidget)
  {
    this->addWidget(m_widget1);
    this->addWidget(m_widget2);
  }
  private:
  WtWidget * const m_widget1;
  WtWidget * const m_widget2;
};

Because the pointers m_widget1 and m_wiget2 are set to be managed by Wt in the 'addWidget' method, these should not be deleted (doing so results in a double deletion warning.

Implementing the widget

A widget is a single visual element. In this example, WtWidget is a button (and thus a derived class of Wt::WPushButton), that displays how often it is clicked.

#include <cstdlib>
#include <sstream>
#include <stdexcept>
#include <string>
#include <Wt/WString>
#include <Wt/WPushButton>

Wt::WString IntToWString(const int i)
{
  std::ostringstream s;
  if (!(s << i)) throw std::logic_error("IntToWString failed");
  return Wt::WString(s.str());
}

struct WtWidget : public Wt::WPushButton
{
  WtWidget()
    : m_clicks(0)
  {
    setText(IntToWString(m_clicks));
    this->clicked().connect(this,&WtWidget::OnClick);
  }
  private:
  void OnClick()
  {
    ++m_clicks;
    setText(IntToWString(m_clicks));
  }
  int m_clicks;
};

WtWidget responds to its own 'clicked'-signal only.

Running the Wt application

Add the following line to your Qt project file (to prevent link errors like undefined reference to 'Wt::WRun(int, char**, Wt::WApplication* (*)(Wt::WEnvironment const&))'):

 

LIBS += -lwt -lwthttp

Additionally, add the following line to your Qt project file, as Wt uses the Boost.Signals library, that needs to be linked to as well:

LIBS += -lboost_signals

Add the following arguments to the Run Settings (to prevent the misc error stat: No such file or directory. Document root ("") not valid.

--docroot . --http-address 0.0.0.0 --http-port 8080

Start the program and your favorite webbrowser. Take the webbrowser to the following address:

http://127.0.0.1:8080/

Conclusion

In this article I have shown one of many Wt program architectures you can use, for a very basic application. In my humble opinion, this architecture makes sense, but I am open to discussion on this subject.

My next article, Thinking Wt 2: TicTacToe widget describes how I implement the Wt widget of a Tic-tac-toe game.

View a screenshot of the application developed in this article (png)

External links

References

Acknowledgements

Thanks Tor Arne Fallingen for notifying me that I omitted linking to Boost.Signals.