Wednesday, November 26, 2014

Hearty Welcome!

Hi, I am a new blogger who is interested in sharing things on a variety of topics as and when I learn something new, both technical and non-technical. Some might be facts and some might be my views. Feel free to comment about my views which will help me refine my thought process more. 

Thanks for visiting!

Find below links to my posts:


General Topics

  1. A Successful Nation

Technical

Tuesday, February 18, 2014

How to use QCustomPlot library with Qt? - An Introduction

QCustomPlot is a very useful plotting library developed for Qt. One can plot various types of graphs (ex. line graph, bar graph) with flexible parameters. Using Qt's "Signal-Slot" mechanism (click here to know more), these graphs can also be plotted in a real-time scenario. For example, this might be useful when you receive data continuously from a Bluetooth device over the computer's COM port (serial port in Windows) and it is required to visualize the data as it comes. This post is about getting started with including graph plots in Qt using this QCustomPlot library. The necessary (header and source) files for QCustomPlot can be downloaded from the official website. Copy the two files (probably "qcustomplot.h" and "qcustomplot.cpp") into your Qt project's folder. Then right-click on your Qt project in the "Projects" window on the left hand side in Qt Creator and select "Add Existing Files". Choose the two files (that you just copied) in the window and add them to your project. Once you are done, you must see them included in your project's tree under "Headers" and "Sources" for "qcustomplot.h" and "qcustomplot.cpp" respectively.

If you already have a good understanding on general plotting methods, you can look into the examples that are provided in the folder extracted from the QCustomPlot library download from the link above. I will be giving a general overview of including plots in a Qt project and a few extensions to it based on my limited experience with it.

For this post, I will assume the following scenario (for Windows 7): Data is received from a COM port (can be a bluetooth or a USB port) and it is just a "double" value, one per line, with a prefix of "#" to each of them. The computer (basically your Qt project) has to receive each data (identified by a prefix, may be a "#" tag prefix) point and plot it dynamically on a graph.

(My project's main window is controlled by the source-header pair named "mainwindow")

Make sure to have the line "QT += widgets serialport printsupport" in your ".pro" file for the project.

Creating a plotting window in the GUI: (you can skip this if you already know)

  1. Open "mainwindow.ui" under the "Forms" folder in your Qt project's tree.
  2. Extend the "MainWindow" to whatever size is required at the minimum.
  3. Pick and place a "Grid Layout" to the MainWindow and maximize it to fit the whole window.
  4. Pick and place a "Widget" (found under the "Containers" category in the list) inside this grid. Right-click the widget and choose "Promote To".
  5. In the window that appears, give "qcustomplot" in the field named "Promoted class name". You should see the header being automatically defined in the next field as "qcustomplot.h". Check "Global include" and then "Add" and "Promote".
  6. Now ,in the "Objects" window on the right hand side of Qt Creator, you should see the class "QCustomPlot" against your widget's name (which is by default "widget"). I have renamed this widget to be "graph" to be more clear.
  7. Now pick and place two "QPushButton"s and rename them as "start" and "stop". I mean renaming the object and not just the caption that it carries in the GUI. These are just to control the graph.
  8. You are ready for giving "intelligence" to these objects now!

"mainwindow.h":

  1. Make sure to include the Qt Serial Port library with: #include <QtSerialPort/QSerialPort>.
  2. Create a section as "private slots:" if it does not exist already. Under that define the following slots:
    1. void readResponse( ) - to read responses from the serial port
    2. void realtimeDataSlot(double value) - to receive a "value" from readResponse() & plot it
    3. void setupGraph(QCustomPlot *graphPlot) - to set up the "graph" object with properties
    4. void on_start_clicked( ) - to define what happens when you click the "start" button
    5. void on_stop_clicked( ) - to define what happens when you click the "stop" button
  3. In the section named "private:", define the following variables:
    1. QByteArray response; - to read ans store the data from the serial port
    2. QTimer timer; - to control how often the graph is refreshed with a new data point
    3. QSerialPort serial;
    4. bool start = false; - to control when the graph should be plotting
    5. double rx_value, key_x, range_y_min = 0, range_y_max = 10

"mainwindow.cpp":

  1. MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),
    ui(new Ui::MainWindow)
    1. ui->setupUi(this);
    2. if (serial.portName() != QString("COM26")) { // change the COM port!

      serial.close();
      serial.setPortName("COM26");
      if (!serial.open(QIODevice::ReadWrite)) {
      processError(tr("Can't open %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      if (!serial.setBaudRate(QSerialPort::Baud57600)) {
      processError(tr("Can't set rate 9600 baud to port %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      if (!serial.setDataBits(QSerialPort::Data8)) {
      processError(tr("Can't set 8 data bits to port %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      if (!serial.setParity(QSerialPort::NoParity)) {
      processError(tr("Can't set no patity to port %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      if (!serial.setStopBits(QSerialPort::OneStop)) {
      processError(tr("Can't set 1 stop bit to port %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      if (!serial.setFlowControl(QSerialPort::NoFlowControl)) {
      processError(tr("Can't set no flow control to port %1, error code %2")
      .arg(serial.portName()).arg(serial.error()));
      return;
      }
      }
    3. processError( ) is just a function to display the text in its argument. Define it.
  2. void MainWindow::on_start_clicked( )
    1. Disable the "start" button: ui->start->setEnabled(false);
    2. Set the bool variable "start" to true
    3. Connect the "timeout( )" signal of "timer" to the slot "readResponse( )":
      1. connect(&timer, SIGNAL(timeout( )), this, SLOT(readResponse( )));
      2. timer.start(0); - this means the graph is refreshed all the time. If you give the parameter as 100 instead of 0, it means your graph refreshed only every 100ms i.e. the readResponse( ) routine is invoked only every 100ms.
  3. void MainWindow::on_stop_clicked( )
    1. Set the bool variable "stop" to false
    2. Exit the program: exit(0);
  4. void MainWindow::setupGraph(QCustomPlot *graphPlot)
    1. graphPlot->addGraph(); // blue dot 
    2. graphPlot->graph(0)->setPen(QPen(Qt::blue));
      graphPlot->graph(0)->setLineStyle(QCPGraph::lsLine);

    3. graphPlot->addGraph(); // blue dot 
    4. graphPlot->graph(1)->setPen(QPen(Qt::blue));
      graphPlot->graph(1)->setLineStyle(QCPGraph::lsNone);
      graphPlot->graph(1)->setScatterStyle(QCPScatterStyle::ssDisc);
    5. graphPlot->xAxis->setLabel("<-- Time -->");
      graphPlot->xAxis->setTickLabelType(QCPAxis::ltNumber);
      graphPlot->xAxis->setNumberFormat("gb");
      graphPlot->xAxis->setAutoTickStep(true);
    6. graphPlot->yAxis->setTickLabelColor(Qt::black);
      graphPlot->yAxis->setAutoTickStep(true);
    7. graphPlot->axisRect()->setupFullAxesBox();
    8. connect(graphPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), graphPlot->xAxis2, SLOT(setRange(QCPRange)));
      connect(graphPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), graphPlot->yAxis2, SLOT(setRange(QCPRange)));
  5. void MainWindow::readResponse( )
    1. if (start) {

      //Define your logic for reading the text. Remember that it starts with "#" 
      //Store the "double" finally extracted in "rx_value" 

      realtimeDataSlot(rx_value);
      }
    2. You can also abstract the serial port setup, reading the serial port etc. as classes which can be invoked here. This makes the project more robust.
  6. void MainWindow::realtimeDataSlot( )
    1. if (start) {

      QCustomPlot *graphPlot = (QCustomPlot*) (ui->graph);
      range_y_min = min(range_y_min,value);
      range_y_max = max(range_y_max,value);
      graphPlot->graph(0)->addData(key_x, value);
      // set data of dots:
      graphPlot->graph(1)->clearData();
      graphPlot->graph(1)->addData(key_x, value);
      graphPlot->xAxis->setRange(key_x+0.5, 50, Qt::AlignRight);
      graphPlot->yAxis->setRange(range_y_min,range_y_max);
      graphPlot->replot();
      key_x += 0.5; // defines horizontal gap between two data points on graph
      }
One simple way of implementing the data parsing logic is by reading the data character by character (using serial.getChar( )) and then doing the necessary processing in a loop. You can start this when you read the prefix (like a "#" that I had mentioned before; it should not be a character that can appear in your data!) and end it by setting a delimiter (like the new line character '\r\n'). Keep appending the read characters in a string and when you reach the delimiter, convert the string into double (using ".toDouble( )" function for strings), store it in "rx_value" and plot it.

That's it! Your project should be working fine if your logic for parsing the data is correct. I have left that because it can be implemented in many ways. As I have stated before, you can abstract serial port setup, reading data from serial port and parsing the data as three different classes and integrate them appropriately so that you have all the functions separated. This makes debugging more easier and also makes the project neat!

Friday, February 14, 2014

Qt Creator, QCustomPlot and PostgreSQL

Quick Links


What is Qt?

Qt is a cross-platform project developed for C++ programmers to build effective visualizations for various applications. On Windows, it can run either on the Visual Studio compiler or on the MinGW (Mimimalist GNU for Windows) compiler but the setup file for both of them are different. The setup includes all the necessary binaries and headers to build a Qt project. It also comes with the Qt Creator tool to facilitate the development of a GUI for the programmer’s application. The Qt Assistant tool can be used for any reference regarding the complete Qt project. It includes all the classes, functions that are used to develop the project. The setup file for the complete package is available for free from their official website: http://qt-project.org/downloads. But, it is important to download the correct setup file according to the compiler the user wishes to run it with.

Just like any other project, Qt has a whole lot of example projects to make the programmer get accustomed to the development environment. Even though Qt includes all C++ headers, it is generally advisable to use Qt’s corresponding custom headers to make much better use of the environment. For example, even though one can include <string.h> to perform string operations in his application, it’s more advisable to use the QString data type because the standard “string” data type may not interface with many Qt functions. Similarly, “qDebug()”  is used instead of “std::cout”. Once the programmer browses through a few projects, it’s very easy to get accustomed to this “custom” environment of Qt.


A Qt Project's Architecture

Every project consists of a “project” file with a “.pro” extension. This contains the general settings for the project and includes the names of all files that come along with the project categorized as Source files, Header files etc. If one creates a new Qt project without changing any default file names, then the project consists of a “main.cpp” file, a “mainwindow.cpp” file, a “mainwindow.h” header file and a “mainwindow.ui” file.
The “main.cpp” file just instantiates the QWindow class to create a new output window when the project is built and run. Then it transfers the control over to the “mainwindow.cpp” file which is the complete “brain” of the project. Any global declarations can be done in the “main.cpp” file with the extern keyword prefixed so that they can be accessed in every function (internal and external) of the “mainwindow.cpp” file. As every C++ programmer would guess, the “mainwindow.h” file has just has the declarations for every function, signal and slot defined in the corresponding .cpp file. The “signal and slot” mechanism of Qt is explained next.

All GUI development tools will have a mechanism to trigger a code based on an event that happens when the user interacts with the GUI. For Qt, this is the “signal and slot” mechanism. There are “signals” that the programmer define on specific events on different objects included in the GUI. While the events are defined by Qt, the signals to be “emitted” are defined by the user. These signals not only carry information defined in their code but also carry some sort of an encrypted code which will be used to authenticate the signal at its slot. The slot is again any function defined in any class of the project that is assigned to receive this signal using the “connect()” statement defined for every signal. Thus, any “emitted” signal can be defined to reach any “slot” which has the code to be performed corresponding to the event triggered by the user’s interaction. In a nutshell, this is what happens: the user clicks a button or hovers over a field or drags the scroll bar or does any such actions on an object in the GUI; this triggers a signal defined by the programmer for that event; the connect() statement directs the signal to the corresponding “slot”; the slot authenticates the signal with its code (which is not in the programmer’s control); then, it executes the code defined under it to produce a feedback for the user’s interaction.

On executing the “mainwindow.show()” in “main.cpp”, the code “MainWindow::MainWindow(QWidget *)” is first executed. Then, depending upon the flow of the code defined by the programmer, the other functions, signals and slots are executed. The “qDebug() << ” command can be used to find the state of the application anytime. The string to the right of the “<<” is output on the Qt Console (which is integrated with the Qt Creator tool itself).

The “mainwindow.ui” file defines the GUI completely. Qt Creator allows the developer to “drag and drop” GUI components directly and creates the corresponding xml file automatically thereby enabling the programmer to concentrate on improving the “working” of the application rather than spending an equivalent time on creating the GUI directly by tedious coding.

The QCustomPlot Library

The QCustomPlot library has extensive graphing capabilities which can be used to do almost everything that one wishes to see in a graph. It just contains a header named “qcustomplot.h” and a source “qcustomplot.cpp” which needs to be included in the project to be able to use it. Fortunately, it also comes with a lot of examples that demonstrate plotting of different type of graphs and also real-time ones. The complete documentation and downloads can be found at http://www.qcustomplot.com/index.php/introduction


PostrgreSQL and the QPSQL Plugin for Qt

PostgreSQL can be downloaded and installed for Windows from http://www.postgresql.org/download/windows/. It has its own GUI tool “pgAdmin” to enable easier interaction directly with the database. The installation directory has to be used next for QPSQL plugin. Prefer to download 32-bit version of PostgreSQL as it is not guaranteed that the QPSQL plugin can be built for the 64-bit version.

The next task is to be able to access the PostgreSQL database for which Qt needs a driver. The QPSQL driver is the one for this purpose and can again be integrated with Qt depending on whether Qt runs on the Visual Studio compiler or the MinGW compiler. Since the Qt project was installed to run with the MinGW compiler on Windows for this project, the steps to be followed to include the driver were followed as described in http://www.qtcentre.org/wiki/index.php?title=Building_the_QPSQL_plugin_on_Windows_using_MinGW

This is a straightforward process except when the versions of Qt mismatch with the one given in the link. In such case, change the “%QTDIR%” given in the webpage to be “C:\QtMinGW\Qt5.1.1\5.1.1\Src\qtbase” if the Qt installation directory is “C:\QtMinGW\Qt5.1.1”. Other than this, the installation of the QPSQL plugin is trouble-free.

I am giving an updated set of instructions (suitably modified from the above link) below for Qt 5.1.1 on Windows 7 (so that we are not lost if that link become invalid).

Throughout the instructions I will assume that the installation directory of Qt is "C:\QtMinGW\Qt5.1.1" and that of PostgreSQL is "C:\psql" (Mine is PostgreSQL 9.3). Suitably alter the instructions for yourself if your's is different. Thank you for the cooperation.


Pre-requisites for QPSQL Plugin

Make Tools

You need make tools if you are not using microsoft compiler. If make tools are not available already on your computer, download it from http://www.steve.org.uk/Software/make/. Extract it to a folder (preferably the C:\ drive directly and update your computer's PATH environment variable with this directory (which should be "C:\make\"). The necessary instructions are below.


Updating system's PATH Environment variable:

The following instructions are for Windows 7.
  1. Click on 'Start' and then right click on 'Computer'. Choose 'Properties' on the list.
  2. Click on the 'Advanced System Settings' tab on the left side.
  3. On the 'Advanced' tab in the pop-up window, click on the button 'Environment Variables' at the bottom.
  4. In the new window, scroll down the second list (for 'System Variables'), click on 'Path' and click on the 'Edit' button below.
  5. At the end of the 'Variable Value' box, insert a semi-colon (";") and copy the path of the folder that you want to update. (For the "make" folder described above, this should be "C:\make\" if you extracted the downloaded file there).

MinGW Utils:

Some of the tools required for the plugin installation (ex. the "reimp" tool) are not available with the QT 5.1.1 download. So, you will require to have mingw-utils which can be downloaded from the Source Forge website. 
Do NOT download mingw-utils-0.4 because it isn't working properly at least when I downloaded it.

Then, extract the folder somewhere and copy the contents of the "bin" folder in it to "C:\QtMinGW\Qt5.1.1\5.1.1\mingw48_32\bin".

("C:\QtMinGW\Qt5.1.1" is my installation directory for Qt)


Update PATH Variable for Qt and PostgreSQL:

Update the system's PATH variable (using instructions above) with the following string after adding a semi-colon (";") to the existing value):
"C:\PSQL\LIB\;C:\QTMINGW\QT5.1.1\5.1.1\MINGW48_32\BIN\;C:\PSQL\BIN\;C:\PSQL\INCLUDE\;C:\MINGW\BIN\"

Once again, this string is valid for me due to my installation directories of Qt & PostgreSQL. Change it according to your's.


QPSQL Plugin Installation

I am giving an updated set of instructions (suitably modified from the link http://www.qtcentre.org/wiki/index.php?title=Building_the_QPSQL_plugin_on_Windows_using_MinGW) below for Qt 5.1.1 on Windows 7 (so that we are not lost if this link become invalid).

Throughout the instructions I will assume that the installation directory of Qt is "C:\QtMinGW\Qt5.1.1" and that of PostgreSQL is "C:\psql" (Mine is PostgreSQL 9.3). Suitably alter the instructions for yourself if your's is different. Thank you for the cooperation.
  1. Open a Qt Command Prompt. Access it by: "Start->Qt 5.1.1->5.1.1->MinGW->Qt 5.1.1 for Desktop.
  2. Navigate to the PostgreSQL folder (which is "C:\psql\ for me) using the commands "cd" and/or "cd.."
  3. Go into the sub-folder "include" and open "pthread.h". Comment out lines 307-310 that contains definition for "struct timespec".
  4. Now, go into the sub-folder "lib" in "C:\psql\" and run the command "reimp libpq.lib" which will produce the files "liblibpq.a" and "libpq.def" in the same directory.
  5. Open this directory in windows explorer and then open the file "libpq.def" that just got created with the "Wordpad" application. In that, remove all the "_"s in the definitions whether the character (underscore) is present in the beginning or in the middle of any of the definitions in the file. Once done, check by performing a search for the "_" character and it should return no results. Close the file.
  6. Now, run the command "dlltool --input-def libpq.def --output-lib libpq.a --dllname libpq.dll" in the Qt command prompt. This is the import library to use with MinGW.
  7. Using the command prompt, navigate to the location "C:\QtMinGW\Qt5.1.1\5.1.1\Src\qtbase\src\plugins\sqldrivers\psql".
  8. Run the following command (with the quotes wherever present): 
  9. qmake -o Makefile "INCLUDEPATH+=C:\psql\include" "LIBS+=C:\psql\lib\libpq.a" psql.pro
  10. Run the command "mingw32-make" - this should build the "qsqlpsql.dll" and "libqsqlpsql.a" files in the "C:\QtMinGW\Qt5.1.1\5.1.1\Src\qtbase\plugins\sqldrivers" directory.
This should complete the plugin installation. Open a Qt Project and in the "main.cpp" file of the project, copy the following code and try running the project:
Before you run the project, open the ".pro" file of your project and do the following:
  • Find the line "QT + = core gui" and add "sql" to it to make it "QT + = core gui sql"
  • Find the line "QT + = widgets" and add "printsupport" to it (for 'qDebug' to work).
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug() << QSqlDatabase::drivers();
    return a.exec();
}

The output in the "Application Output" window should be:
("QSQLITE", "QODBC3", "QODBC","QPSQL7","QPSQL")

Last Step:

Unfortunately, for all your Qt projects that use PostgreSQL, you need to copy the following files from the directory: "C:\psql\bin\" to each of those project folders.

"libeay32.dll", "libiconv.dll", "libintl.dll", "libpq.dll", "ssleay32.dll"

If this isn't required, kindly comment below the alternative.

That's it! You can now access your PostgreSQL database from your Qt project. Refer to online sources for various commands associated with the QPSQL plugin for PostgreSQL.
I hope this helps and it works!