I need some exercises for each chapter



  • According to the advice of some the nice and professional guys of this forum, I started to read the book C++ GUI Programming using Qt-4 2nd Edition as the entrance way to the world of Qt.

    OK, I started to read the book and I'm now about to begin chapter 3. I have followed the codes and forms of designer for each example in the book and have run them correctly on my Windows machine so far. But the book has some defect; it doesn't provide any drill of exercises!
    Without exercises, I cannot be sure I've learnt the contents correctly. And can't convince myself that I will be able to write a real application throughout passing the book.

    What I have seen in the other technical books is that each chapter includes some drill and exercises and the end of itself. This is what I need.

    What is/are your suggestion(s) please?



  • Hi! Here is your first exercise: Make a desktop calculator like this:

    :-)


  • Moderators

    @tomy

    I guess you have to live with what is available. Since there is no really big change from Qt 4 to Qt 5, there is no Qt 5 book available. Therefore, someone recommended a book describing details for Qt 4. In the past people used examples either from the book directly or the official Qt examples for getting experience with the programming.

    Therefore, you can use Qt 5 examples or Qt 4 examples and the book you have as a reference.

    The examples are typically quite detailed and for a lot of people enough to learn Qt. A book is merely another method to deepen some details respectively to have way of description.



  • @Wieland
    Thank you for your suggestion but isn't this too advanced for a novice that has just learned the first two-chapter of that book (page 58 of the book)?
    If not, OK, I'm interested in it, but may you guide me on the process until end?

    Since it was the first practical example (out of the book) for me, I designed a form by Qt Designer using Dialog Without Buttons template. And I designed the form in its basic style by putting only some widgets as follows:

    alt text

    Then I wrote a calculator.h file like this:

    #ifndef CALCULATOR_H
    #define CALCULATOR_H
    
    #include <QDialog>
    #include "ui_calculator.h"
    
    class Calculator : public QDialog, public Ui::Calculator
    {
       Q_OBJECT
    public:
       Calculator(QWidget* parent = 0);
    };
    
    #endif // CALCULATOR_H
    

    Then, a calculator.cpp this way:

    #include <QtWidgets>
    #include "calculator.h"
    
    Calculator::Calculator(QWidget *parent)
        : QDialog(parent)
    {
        setupUi(this);
    }
    

    And finally the main.cpp this way:

    #include <QApplication>
    #include "calculator.h"
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
        Calculator* dialog = new Calculator;
        dialog -> show();
        return app.exec();
    }
    

    Please note that this kind of exercise is new for me as a newcomer to Qt! So I thought it was better to develop the app step-by-step.

    I used qmake and run the code but got these two errors:

    1- C:\Users\Me\Documents\Qt\Calculator\calculator.h:8: error: expected class-name before '{' token
    {
    ^
    2- C:\Users\Me\Documents\Qt\Calculator\calculator.cpp:7: error: 'setupUi' was not declared in this scope
    setupUi(this);
    ^

    And as the final question of this reply! Would what I did be the same as yours if you were me to have this exercise please?


  • Moderators

    @tomy You should not derive your class from Ui::Calculator, instead add a pointer to your class:

    class Calculator : public QDialog
    {
       Q_OBJECT
    public:
       Calculator(QWidget* parent = 0);
    private:
        Ui::Calculator *ui;
    };
    

    You should create a form via "New file or project/Qt designer Form Class" and check how it works. This way it is easier to get started.



  • @jsulm said in I need some exercises for each chapter:

    @tomy You should not derive your class from Ui::Calculator, instead add a pointer to your class:

    Thanks for your reply but what I wrote was according to the method of examples of the book!

    class Calculator : public QDialog
    {
       Q_OBJECT
    public:
       Calculator(QWidget* parent = 0);
    private:
        Ui::Calculator *ui;
    };
    

    You should create a form via "New file or project/Qt designer Form Class" and check how it works. This way it is easier to get started.

    OK, I re-start from there this time, but how to get it worked?


  • Moderators

    @tomy Can you show the content of ui_calculator.h?



  • @jsulm said in I need some exercises for each chapter:

    ui_calculator.h

    Yes, that's it:

    /********************************************************************************
    ** Form generated from reading UI file 'calculator.ui'
    **
    ** Created by: Qt User Interface Compiler version 5.5.1
    **
    ** WARNING! All changes made in this file will be lost when recompiling UI file!
    ********************************************************************************/
    
    #ifndef UI_CALCULATOR_H
    #define UI_CALCULATOR_H
    
    #include <QtCore/QVariant>
    #include <QtWidgets/QAction>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QButtonGroup>
    #include <QtWidgets/QDialog>
    #include <QtWidgets/QHeaderView>
    #include <QtWidgets/QLineEdit>
    #include <QtWidgets/QPushButton>
    
    QT_BEGIN_NAMESPACE
    
    class Ui_Dialog
    {
    public:
        QLineEdit *lineEdit;
        QPushButton *oneButton;
        QPushButton *twoButton;
        QPushButton *equalButton;
        QPushButton *quitButton;
        QPushButton *plusButton;
        QPushButton *menusButton;
    
        void setupUi(QDialog *Dialog)
        {
            if (Dialog->objectName().isEmpty())
                Dialog->setObjectName(QStringLiteral("Dialog"));
            Dialog->resize(400, 300);
            lineEdit = new QLineEdit(Dialog);
            lineEdit->setObjectName(QStringLiteral("lineEdit"));
            lineEdit->setGeometry(QRect(220, 100, 113, 20));
            oneButton = new QPushButton(Dialog);
            oneButton->setObjectName(QStringLiteral("oneButton"));
            oneButton->setGeometry(QRect(40, 90, 75, 23));
            twoButton = new QPushButton(Dialog);
            twoButton->setObjectName(QStringLiteral("twoButton"));
            twoButton->setGeometry(QRect(40, 160, 75, 23));
            equalButton = new QPushButton(Dialog);
            equalButton->setObjectName(QStringLiteral("equalButton"));
            equalButton->setGeometry(QRect(240, 130, 75, 23));
            quitButton = new QPushButton(Dialog);
            quitButton->setObjectName(QStringLiteral("quitButton"));
            quitButton->setGeometry(QRect(240, 190, 75, 23));
            plusButton = new QPushButton(Dialog);
            plusButton->setObjectName(QStringLiteral("plusButton"));
            plusButton->setGeometry(QRect(160, 130, 31, 21));
            menusButton = new QPushButton(Dialog);
            menusButton->setObjectName(QStringLiteral("menusButton"));
            menusButton->setGeometry(QRect(120, 130, 31, 21));
    
            retranslateUi(Dialog);
            QObject::connect(equalButton, SIGNAL(clicked()), Dialog, SLOT(accept()));
            QObject::connect(quitButton, SIGNAL(clicked()), Dialog, SLOT(reject()));
            QObject::connect(oneButton, SIGNAL(clicked()), lineEdit, SLOT(paste()));
            QObject::connect(menusButton, SIGNAL(clicked()), lineEdit, SLOT(paste()));
            QObject::connect(twoButton, SIGNAL(clicked()), lineEdit, SLOT(paste()));
            QObject::connect(plusButton, SIGNAL(clicked()), lineEdit, SLOT(paste()));
    
            QMetaObject::connectSlotsByName(Dialog);
        } // setupUi
    
        void retranslateUi(QDialog *Dialog)
        {
            Dialog->setWindowTitle(QApplication::translate("Dialog", "Calculator", 0));
            oneButton->setText(QApplication::translate("Dialog", "1", 0));
            twoButton->setText(QApplication::translate("Dialog", "2", 0));
            equalButton->setText(QApplication::translate("Dialog", "=", 0));
            quitButton->setText(QApplication::translate("Dialog", "Quit", 0));
            plusButton->setText(QApplication::translate("Dialog", "+", 0));
            menusButton->setText(QApplication::translate("Dialog", "-", 0));
        } // retranslateUi
    
    };
    
    namespace Ui {
        class Dialog: public Ui_Dialog {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    
    #endif // UI_CALCULATOR_H
    


  • Thank you guys. Apparently I will get no help here. I pose the issue on another thread.


  • Moderators

    @tomy The name of your UI class is Dialog not Calculator, so change to:

    class Calculator : public QDialog, public Ui::Dialog
    

    see here from ui_calculator.h:

    namespace Ui {
        class Dialog: public Ui_Dialog {};
    }
    

    "Apparently I will get no help here" - you should be more patient. People here are volunteers.



  • @jsulm
    Yeah, you are right. Thank you for the answer. :)

    On the process of developing the app step-by-step, I made these changes.
    The .uifile:

    alt text

    My main.cpp:

    #include <QApplication>
    #include <QDialog>

    #include "ui_Calculator.h"

    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
    
        Ui::Calculator ui;
        QDialog* dialog = new QDialog;
        ui.setupUi(dialog);
        dialog -> show();
    
        return app.exec();
    }
    

    The .h file:

    #ifndef CALCULATOR_H
    #define CALCULATOR_H
    
    #include<QDialog>
    #include "ui_Calculator.h"
    
    class Calculator : public QDialog, public Ui::Calculator
    {
        Q_OBJECT
    
    public:
        Calculator(QWidget* parent = 0);
    private slots:
       void on_lineEdit_textChanged();
    };
    
    #endif // CALCULATOR_H
    

    The .cpp file:

    #include <QtWidgets>
    #include "calculator.h"
    
    Calculator::Calculator(QWidget *parent)
        :QDialog(parent)
    {
        setupUi(this);
    
        connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("1")));
        connect(twoButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("2")));
        connect(addButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("+")));
    }
    
    void Calculator::on_lineEdit_textChanged() { // I will add some code here
    }
    

    My problems:
    The program runs without errors but there is a red line under each lines of the connect.
    And when I run the app and click on 1, 2 or + button, they will not be shown in lineEdit!
    What are the reasons please?


  • Qt Champions 2016

    Hi
    The reason it do not work is that you say

    connect(twoButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("2")));

    The signal should go to a slot with same signature, meaning it should take same parameters
    and you cannot give it "fixed" ones like "2" as it would need to store it for later then and it cannot.
    so
    connect(twoButton,SIGNAL(clicked(bool)), this/"Calculator"/, SLOT(myslot(bool)));

    in myslot could do

    void Calculator::myslot(bool) {
    lineEdit->setText("2");
    }



  • Thanks but it didn't work!

    I even wanted to use the myslot function in a better way, like this:

    #include <QtWidgets>
    #include "calculator.h"
    
    Calculator::Calculator(QWidget *parent)
        :QDialog(parent)
    {
        setupUi(this);
    
        connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("1")));
        connect(twoButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("2")));
        connect(addButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("+")));
    }
    
    void Calculator::on_lineEdit_textChanged() {// I will add some code here
    }
    
    void Calculator::myslot(const QString& str){
        lineEdit -> setText(str);
    }
    

    But this one too didn't work. That is, when I run the app, clicking the 1, 2, + write nothing in the lineEdit.

    PS: In the Calculator.h:

    ...
    private slots:
       void on_lineEdit_textChanged();
       void myslot(const QString&);
    };
    

    PS2: The red lines under the connects exist still!


  • Qt Champions 2016

    • PS2: The red lines under the connects exist still!

    Well
    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("1")));

    Cannot work. Its not valid and will never work.
    You cannot use it like that. "1" is not used, not valid and it do not work like this.
    please read
    http://doc.qt.io/qt-5/signalsandslots.html

    Please note:
    connect return true and false , so please do

    qDebug () << "one:" << connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("1")));

    You will see it says "one:false" and wont accept it.

    You might want to look into
    http://doc.qt.io/qt-5/qsignalmapper.html#details



  • I read the first link until "Advanced Signal & Slot ..." part but couldn't find the reason. According to C++ conventions what I wrote seems quite right. And if you think it's not in Qt, speak about the reason please.

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));
    

    &

    void Calculator::myslot(){
        lineEdit -> setText("1");
    }
    

    also show nothing in lineEdit!


  • Qt Champions 2016

    Hi

    • According to C++ conventions what I wrote seems quite right:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(setText("1")));
    This is wrong for the SLOT macro.

    The new code you show is correct.
    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool))); << no "1" just the type

    void Calculator::myslot(bool){
    lineEdit -> setText("1"); // correct. for normal Qt , it would be ui->lineEdit->setText.
    }


  • Moderators

    @tomy You should check what connect(...) returns. My guess is that the connection fails because in the connect you have:

    SLOT(myslot(bool))
    

    but your slot does not have any parameter:

    void Calculator::myslot()
    

    So, connect(...) cannot find slot myslot(bool)



  • Thanks to all.
    @jsulm
    So apparently you disagree with mrjj. I write what he says but the code shows nothing. I think your assumption is correct because myslot() has no parameters.

    Now the question is this: How to connect the buttons (1, 2 & +) to a slot so that, that slot prints out the values of these buttons onto the lineEdit please?

    Based on what I'd learned form C++ I thought the code below would work for that purpose:

    in the Calculator.h:

    ...
    private slots:
       void myslot(const QString&);
    };
    

    And in Calculator.cpp:

    ...
    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("1")));
     connect(twoButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("2")));
     connect(addButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("+")));
    }
    
    void Calculator::myslot(const QString& str){
     lineEdit -> setText(str);
    }
    

    But this does not work. I have a good experience in C++ but I'm a novice in Qt.
    Now what would be your solution for that purpose please?


  • Moderators

    @tomy Where did I disagree with @mrjj?
    You should read more carefully what I wrote.
    The problem with your code is that you provide a wrong slot signature in connect. Again:

    SLOT(myslot(bool))
    

    there is no such slot! Your slot has this signature (no bool parameter):

    void Calculator::myslot()
    

    So, either change

    SLOT(myslot(bool))
    to
    SLOT(myslot())
    

    or

    void Calculator::myslot()
    to
    void Calculator::myslot(bool)
    


  • @jsulm

    OK & thanks a bunch but still it doesn't work!



  • I appreciate your time that you all dedicate to help me but is it that hard to write a function that has a string parameter so that when we call it by strings it prints out the sent string onto the lineEdit?


  • Moderators

    @tomy If you say "does not work" you should say what does not work or what happens.
    You should really read about signals/slots.

    You could use lambdas (C++11) and new connect syntax like this:

    connect(oneButton, &QPushButton::clicked, []() { lineEdit->setText("1"); });
    


  • This post is deleted!


  • I meant using neither:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot("1")));

    void Calculator::myslot(const QString& str){
    lineEdit -> setText(str);
    }
    Nor:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));

    void Calculator::myslot(bool){
    lineEdit -> setText("1");
    }
    And Nor:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot()));

    void Calculator::myslot(){
    lineEdit -> setText("1");
    }
    the program works!

    That is when I each time using the above methods run the code and click on the buttons, nothing will be printed out onto the lineEdit, that is clicking the buttons do nothing.

    Now you say I should read about:
    lambdas (C++11) and new connect syntax like this:
    connect(oneButton, &QPushButton::clicked, { lineEdit->setText("1"); });

    BUT THESE ARE VERY ADVANCED FOR ME. AT THE BEGINING OF THIS THREAD I SAID I NEED SOME PROPER EXERCISE FOR WHAT I HAVE LEARNED THROUGH THESE 2 CHAPTERS OF THAT BOOK, NOT ADVANCED TOPICS THAT ARE IN THE NEXT CHAPTERS OF THE BOOK.


  • Moderators

    @tomy I already suggested to check what connect(...) returns to see whether it works or not. Did you try it?

    qDebug() << connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));
    

    it should print true if it succeeded.

    This connect call is wrong:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));
    

    lineEdit is QLineEdit, right? QLineEdit does not have a slot named "myslot(bool)". This slot is in your Calculator class, right?
    Then it should be:

    connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot(bool)));
    

    connect() will print a warning if it cannot do the connection - you can check "Application output" tab in QtCreator.
    Furthermore you can try to debug: set a break point inside the slot run your app with debugger (F5 in QtCreator), press the button and see whether the slot is called or not.

    You wrote "I have a good experience in C++", so I assumed you're familiar with lambdas as they were introduced in C++11. And in your current use case they are very handy.



  • @jsulm said in I need some exercises for each chapter:

    @tomy I already suggested to check what connect(...) returns to see whether it works or not. Did you try it?

    qDebug() << connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));
    

    it should print true if it succeeded.

    This is the Calculator.cpp now:

    #include <QtWidgets>
    #include "calculator.h"
    
    Calculator::Calculator(QWidget *parent)
        :QDialog(parent)
    {
        setupUi(this);
    
       qDebug() << connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot()));
    }
    
    void Calculator::myslot(){
        lineEdit -> setText("1");
    }
    

    I ran it (Ctrl+R) but it show no errors and runs successfully. How to know what it has printed?

    This connect call is wrong:

    connect(oneButton,SIGNAL(clicked(bool)), lineEdit, SLOT(myslot(bool)));
    

    lineEdit is QLineEdit, right? QLineEdit does not have a slot named "myslot(bool)". This slot is in your Calculator class, right?
    Then it should be:

    connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot(bool)));
    

    OK, I changed the connect to:

    connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot()));
    

    But no changes again.

    connect() will print a warning if it cannot do the connection - you can check "Application output" tab in QtCreator.

    Application output is in the bottom, I checked it in both cases (above). There is no warning message there.

    Furthermore you can try to debug: set a break point inside the slot run your app with debugger (F5 in QtCreator), press the button and see whether the slot is called or not.

    I also tried this option. I pressed F5 for the two above cases. In the Application output this has been printed:
    Debugging starts
    Debugging has finished

    You wrote "I have a good experience in C++", so I assumed you're familiar with lambdas as they were introduced in C++11. And in your current use case they are very handy.

    Yes, I have a good experience in C++ but it's not 11. But do you the book I read for Qt? Do you know at what level (of Qt) is the reader of it?
    I've passed the first two chapters and can start chapter 3, but, I don't like to deceive myself, rather, I want to examine myself to see whether I have learned the contents good enough or not.


  • Moderators

    @tomy said in I need some exercises for each chapter:

    connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot()));

    You should print the connect() return value:

    qDebug() << connect(oneButton,SIGNAL(clicked(bool)), this, SLOT(myslot()));
    

    The output should be in "Application Output" tab in QtCreator when you start the application.

    To debug you need first to set a breakpoint inside your slot and then start with F5, then press the button.

    Another thing to check is whether "oneButton" is really the button you see when you start your application. Usually all UI objects are accessed via ui->oneButton. But you decided to do it differently. Since I don't have your complete code I cannot check this.

    "But do you the book I read for Qt? Do you know at what level (of Qt) is the reader of it?" - no I don't. I just try to help you. Lambdas are not Qt, they are pure C++11. The only new Qt thing for you is the new connect() syntax. In my opinion it is not wrong to learn something new during exercises even if it was not yet covered by the book. But if you don't want to then just ignore the suggested lambda based solution.



  • First I know you want to help me and for that I appreciate you and thank you.

    You also are right about learning new things during solving a given exercise but I think the way is improper. It's probably my fault either.

    Anyway, we all (in this thread) want to solve the issue. I have a suggestion! Design a simplest form that is possible to do a single work please. That is, a form with one button and one lineEdit, when you run it and click on the button it will be printed on the lineEdit.
    To sum up, a form named (say) "test" with a test.h, test.cpp and a main.cpp file in the most simple style/method (that is, suitable for low level beginner of Qt).

    I think that way most of the issues will be solved.


  • Moderators

    @tomy This works for me just fine.
    ButtonEdit.pro file:

    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = ButtonEdit
    TEMPLATE = app
    
    
    SOURCES += main.cpp\
            mainwindow.cpp
    
    HEADERS  += mainwindow.h
    
    FORMS    += mainwindow.ui
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private slots:
        void mySlot();
    
    private:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(mySlot()));
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::mySlot()
    {
        ui->lineEdit->setText("+");
    

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    mainwindow.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>400</width>
        <height>300</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <widget class="QPushButton" name="pushButton">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>10</y>
          <width>99</width>
          <height>27</height>
         </rect>
        </property>
        <property name="text">
         <string>+</string>
        </property>
       </widget>
       <widget class="QLineEdit" name="lineEdit">
        <property name="geometry">
         <rect>
          <x>10</x>
          <y>50</y>
          <width>113</width>
          <height>27</height>
         </rect>
        </property>
       </widget>
      </widget>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    


  • @jsulm
    Thank you. Would you please take a screenshot of the design page (mainwindow.ui) and send it?


  • Moderators

    @tomy I could, but there is nothing special: just a button and a line edit bellow the button.



  • It couldn't help. But I thank you and appreciate your time. The thread is finished.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.