Wiki

Using a Simple Web Service with Qt

Qt's networking classes allow all sorts of complex networked applications to be developed, but some Web services are still simple enough to be used with just a few lines of code and a bit of imagination.

One such service is provided by the MathTran project at www.mathtran.org. This open source project aims to provide services to automatically translate mathematical content into Web-friendly formats, such as PNG images and MathML markup. Run by the Open University in the United Kingdom and funded by the Joint Information Systems Committee (JISC), the project currently provides a Web service to translate TeX into images.

Mathtran-Gui

In this article, we show how we can use Qt's networking classes in the simplest possible way in a GUI application, using the MathTran Web service to preview TeX markup entered in a text editor as an image. In the future, the MathTran project hopes to offer a Web service to translate between TeX and presentation MathML which we could render using the MML Widget Qt Solution.

Using the Service

At the heart of the MathTran service is a Web server. Clients send TeX markup to the server by encoding it as part of the request URI of an HTTP GET request. The server decodes the input, passes it to a TeX daemon, converts the output to an image, and sends back the appropriate HTTP response.

For example, the equation

is written like this:

\vec{\nabla}\cdot\vec{B} = 0

This text is encoded and appended as a query to the rest of the request URI, giving us the following string:

http://www.mathtran.org/cgi-bin/mathtran?D=3;tex=\vec{\nabla}\cdot\vec{B}%20%3D%200

All an application needs to do to obtain the image of an equation is to send it to the service and wait for the response. Our application uses QUrl and QHttp to make this process as simple as possible.

Setting Things Up

In the constructor of our Window class, we construct a QHttp object to use to communicate with the server in a two-stage process:

  • We connect the clicked() signal from the Update button to the fetchImage() slot. This initiates the request to the server.
  • Since we are interested in the result of a HTTP GET request, we connect its done(bool) signal to the updateForm() slot.

Omitting the details of setting up the user interface, the constructor contains code to set up these connections:

    Window::Window(QWidget *parent)
        : QWidget(parent)
    {
        http = new QHttp(this);
        connect(http, SIGNAL(done(bool)),
                this, SLOT(updateForm(bool)));
        ...
        connect(updateButton, SIGNAL(clicked()),
                this, SLOT(fetchImage()));
        ...
    }

Sending and Receiving

Since we perform the request and receive the response using the same QHttp object, we must take care to ensure that this two-stage process runs smoothly. In the fetchImage() function, we prevent the user from making another request while one is already in progress by disabling the Update button:

    void Window::fetchImage()
    {
        updateButton->setEnabled(false);
 
        QUrl url;
        url.setPath("/cgi-bin/mathtran");
        url.setQueryDelimiters('=', ';');
        url.addQueryItem("D", "3");
        url.addQueryItem("tex", QUrl::toPercentEncoding( equationEditor->toPlainText()));
 
        http->setHost("mathtran.org");
        http->get(url.toString());
    }

We use the flexibility of the QUrl class to set up part of the request URI. Since we want to let the QHttp object buffer the data obtained from the server, we simply pass the string representation of the URL to the object's get() function.

When this slot returns, the Qt event loop continues to process events, and the QHttp object gets on with its job of managing HTTP requests and responses. When the final response arrives, it emits the done(bool) signal and our updateForm() slot is called:

    void Window::updateForm(bool error)
    {
        if (!error) {
            QImage image;
            if (image.loadFromData(http->readAll())) {
                QPixmap pixmap = QPixmap::fromImage(image);
                outputLabel->setPixmap(pixmap);
            }
        }
        updateButton->setEnabled(true);
    }

If no error occurred, we can convert the data we received to a pixmap for use in a label. No matter if the request succeeded or failed, we always re-enable the Update button to allow the user to try again.

Exploring Further

The MathTran service, while designed to be simple, also exposes other parameters that we can experiment with. The server software is available from SourceForge, so you can also run your own server if you like. See the service's terms and conditions for more information about using the public MathTran server.

The source code for the example shown in this article is also available.