Friday, May 30, 2014

Flirting with QT Creator -Building First Desktop App


  Here in this blog post we will build our first QT Widget Application using QT Creator.Mine Qt Creator version is 3.0.1 running on the top of Fedora 20 64 bit.

To proceed we will create a QT Widget Application project ,My Project has been christened as Calc as we will be building a simple Calculator.

Folder Structure After creating Project


Go To edit on vertical task pane of IDE & Click on Main Window UI ,it will give us a nice window form designer,we will drop PushButtons & TextEdit on it,change PushButton's Text property  & ObjectName Property.

In My Case design view is like this


How Controls are Named in my project:

The Push button of number 0-9 are named in analogy with  pbNum7 for 7 while for other operations as below


Meaning Text Object Name
Percent '% pbOprPercent
Divide '/ pbOprDivide
Multiply 'x pbOprMultiply
Substract '- pbOprMinus
Clear Current C pbOprC
Clear ALL AC pbOprAc
Sign '+/- pbOprSign
Equal '= pbOprEqual
Additional Button Show Register Value pushButton
Period . pbOprPeriod


Now Right Click on each push button select go to slot & then select click from list of events.

Under Source in Folder Structure there is main.cpp where event handler should be written which we have created by selecting there click slot   .

Here is code of my main.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>

QString strDisplay = "";
static double swap =0;
static bool isOpPending =false;
static bool isDispChangePending =false;
static char PendingOpr;


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->txtDisplay->setText("0");
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    ui->txtDisplay->setReadOnly(true);

}

MainWindow::~MainWindow()
{
    delete ui;
}

/*Helper*/
void ShowMsg(QString strMsg)
{
    QMessageBox msgBox;
    msgBox.setText(strMsg);
    msgBox.exec();
}




/*Clean Screen*/
void MainWindow::on_pbOprC_clicked()
{
    ui->txtDisplay->setText("");
}

void MainWindow::on_pbOprAc_clicked()
{
    strDisplay = "";
    swap =0;
    isOpPending =false;
    isDispChangePending =false;
    PendingOpr = '\0';
    ui->txtDisplay->setText("");
}

void MainWindow::on_pbNum7_clicked()
{
    QString numStr = QString::number(7);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
             strDisplay.remove( QRegExp("^[0]*") );
            //strDisplay = QString::number(strDisplay.toDouble());
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum8_clicked()
{
    QString numStr = QString::number(8);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum9_clicked()
{
    QString numStr = QString::number(9);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum4_clicked()
{
    QString numStr = QString::number(4);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum5_clicked()
{
   QString numStr = QString::number(5);
   if(isDispChangePending ==true){
        strDisplay = numStr;
        isDispChangePending =false;
   }else{
       strDisplay = ui->txtDisplay->toPlainText();
       strDisplay = strDisplay + numStr;

       if(strDisplay.contains(".") ==false)
       {
           strDisplay.remove( QRegExp("^[0]*") );
       }
   }

   ui->txtDisplay->setText(strDisplay);
   ui->txtDisplay->setAlignment(Qt::AlignRight);
   ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum6_clicked()
{
    QString numStr = QString::number(6);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum3_clicked()
{
    QString numStr = QString::number(3);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum2_clicked()
{
    QString numStr = QString::number(2);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum1_clicked()
{
    QString numStr = QString::number(1);
    if(isDispChangePending ==true){
          strDisplay = numStr;
          isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbNum0_clicked()
{
    QString numStr = QString::number(0);
    if(isDispChangePending ==true){
         strDisplay = numStr;
         isDispChangePending =false;
    }else{
        strDisplay = ui->txtDisplay->toPlainText();
        strDisplay = strDisplay + numStr;

        if(strDisplay.contains(".") ==false)
        {
            strDisplay.remove( QRegExp("^[0]*") );
        }
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

/*operation*/
void MainWindow::on_pbOprDivide_clicked()
{
    /*new logic*/
    if(isOpPending==true)
    {
        switch (PendingOpr) {
            case '+':
                swap = swap + strDisplay.toDouble();
                strDisplay = QString::number(swap);\
                break;
            case '-':
                swap = swap - strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case 'x':
                swap = swap * strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case '/':
                if(strDisplay.toDouble() != 0)
                {
                    swap = swap / strDisplay.toDouble();
                    strDisplay = QString::number(swap);
                }
                break;
            default:
                break;
        }

        ui->txtDisplay->setText(strDisplay);
        ui->txtDisplay->setAlignment(Qt::AlignRight);
        ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    }else{
        swap  = strDisplay.toDouble();
    }
    //register to store value
    swap  = strDisplay.toDouble();

    PendingOpr='/';
    isOpPending =true;
    isDispChangePending= true;
}

void MainWindow::on_pbOprMultiply_clicked()
{
    /*new logic*/
    if(isOpPending==true)
    {
        switch (PendingOpr) {
            case '+':
                swap = swap + strDisplay.toDouble();
                strDisplay = QString::number(swap);\
                break;
            case '-':
                swap = swap - strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case 'x':
                swap = swap * strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case '/':
                if(strDisplay.toDouble() != 0)
                {
                    swap = swap / strDisplay.toDouble();
                    strDisplay = QString::number(swap);
                }
                break;
            default:
                break;
        }

        ui->txtDisplay->setText(strDisplay);
        ui->txtDisplay->setAlignment(Qt::AlignRight);
        ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    }else{
        swap  = strDisplay.toDouble();
    }
    swap  = strDisplay.toDouble();


    PendingOpr='x';
    isOpPending =true;
    isDispChangePending= true;
}

void MainWindow::on_pbOprMinus_clicked()
{
    strDisplay = ui->txtDisplay->toPlainText();

    /*new logic*/
    if(isOpPending==true)
    {
        switch (PendingOpr) {
            case '+':
                swap = swap + strDisplay.toDouble();
                strDisplay = QString::number(swap);\
                break;
            case '-':
                swap = swap - strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case 'x':
                swap = swap * strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case '/':
                if(strDisplay.toDouble() != 0)
                {
                    swap = swap / strDisplay.toDouble();
                    strDisplay = QString::number(swap);
                }
                break;
            default:
                break;
        }

        ui->txtDisplay->setText(strDisplay);
        ui->txtDisplay->setAlignment(Qt::AlignRight);
        ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    }else{
        swap  = strDisplay.toDouble();
    }

    /*old logic*/
    swap  = strDisplay.toDouble();


    PendingOpr='-';
    isOpPending =true;
    isDispChangePending= true;
}

void MainWindow::on_pbOprPlus_clicked()
{
    strDisplay = ui->txtDisplay->toPlainText();

    /*new logic*/
    if(isOpPending==true)
    {
        switch (PendingOpr) {
            case '+':
                swap = swap + strDisplay.toDouble();
                strDisplay = QString::number(swap);\
                break;
            case '-':
                swap = swap - strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case 'x':
                swap = swap * strDisplay.toDouble();
                strDisplay = QString::number(swap);
                break;
            case '/':
                if(strDisplay.toDouble() != 0)
                {
                    swap = swap / strDisplay.toDouble();
                    strDisplay = QString::number(swap);
                }
                break;
            default:
                break;
        }

        ui->txtDisplay->setText(strDisplay);
        ui->txtDisplay->setAlignment(Qt::AlignRight);
        ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    }else{
        swap  = strDisplay.toDouble();
    }
    /*old logic*/

    PendingOpr='+';
    isOpPending =true;
    isDispChangePending= true;
}

/**/
void MainWindow::on_pbOprPeriod_clicked()
{
    strDisplay = ui->txtDisplay->toPlainText();
    if(strDisplay.contains(".") ==false)
    {
       if(strDisplay=="")
       {
           strDisplay="0";
       }
        strDisplay = strDisplay + ".";

       ui->txtDisplay->setText(strDisplay);
       ui->txtDisplay->setAlignment(Qt::AlignRight);
       ui->txtDisplay->setFocus(Qt::OtherFocusReason);
    }
}

void MainWindow::on_pbOprSign_clicked()
{
    strDisplay = ui->txtDisplay->toPlainText();
    if(strDisplay.mid(0,1) == "-")
    {
       strDisplay = strDisplay.mid(1,strDisplay.length());
    }else{
       strDisplay = '-' + strDisplay;
    }

    ui->txtDisplay->setText(strDisplay);
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);
}

void MainWindow::on_pbOprPercent_clicked()
{
     strDisplay = ui->txtDisplay->toPlainText();
     if(strDisplay!="")
     {
        strDisplay = QString::number(strDisplay.toDouble()/100);

        ui->txtDisplay->setText(strDisplay);
        ui->txtDisplay->setAlignment(Qt::AlignRight);
        ui->txtDisplay->setFocus(Qt::OtherFocusReason);
     }
}

/*get result*/
void MainWindow::on_pbOprEqual_clicked()
{
    strDisplay = ui->txtDisplay->toPlainText();

    switch (PendingOpr) {
        case '+':
            swap = swap + strDisplay.toDouble();
            strDisplay = QString::number(swap);

            ui->txtDisplay->setText(strDisplay);
            break;
        case '-':
            swap = swap - strDisplay.toDouble();
            strDisplay = QString::number(swap);

            ui->txtDisplay->setText(strDisplay);
            break;
        case 'x':
            swap = swap * strDisplay.toDouble();
            strDisplay = QString::number(swap);

            ui->txtDisplay->setText(strDisplay);
            break;
        case '/':
            if(strDisplay.toDouble() != 0)
            {
                swap = swap / strDisplay.toDouble();
                strDisplay = QString::number(swap);

                ui->txtDisplay->setText(strDisplay);
            }
            break;
        default:
            break;
    }
    //common to call cases
    ui->txtDisplay->setAlignment(Qt::AlignRight);
    ui->txtDisplay->setFocus(Qt::OtherFocusReason);

    swap =0;
    isOpPending =false;
    isDispChangePending =false;
    PendingOpr = '\0';
}

/*see through register*/
void MainWindow::on_pushButton_clicked()
{
    QString swapAsString = QString::number(swap);
    ShowMsg(swapAsString);
}


In my case I used a message box i.e why i have to include header #include <QMessageBox> the function

   The above code in main.cpp is written to mimic the common calc behaviour e.g say KCalc.

void ShowMsg(QString strMsg)
{
    QMessageBox msgBox;
    msgBox.setText(strMsg);
    msgBox.exec();
}
 

has been used to flash message on click on "Show Register Value",function is purposefully written on top so that it can be visible to all event handlers.
      The event we created by using slot are stored in mainwindow.h if you remove the certain event handler function then compilation errors will be shown for that purpose we need to remove occurance of your event from
qt_static_metacall function in moc_mainwindow.cpp & private slots: in mainwindow.h

Here is our calculator in action



Here is link to source code:
      https://drive.google.com/file/d/0B-pBDBdN-2kAX1l2aEVvSVI3MkE/edit?usp=sharing

unzip the  archive & open calc.pro  using Qt-Creator to view the project.

Thanks &  Happy Coding