My First Program Successfully Built



  • Hi All,
    I've managed to build and run my first Qt application. The application is based on a few examples in the documentation and the examples bundled with Qt creator. I'm sharing the source code with you guys. If you have some free time to spare, please take a look at it, and tell me if something can be improved in the current implementation. You can also give me secessions from your experiences in Qt development. Don't forget I'm still a n00b...!

    example1.pro
    @SOURCES +=
    main.cpp
    mywindow.cpp

    HEADERS +=
    mywindow.h@

    mywindow.h
    @#ifndef EXAMPLE1_H
    #define EXAMPLE1_H

    #include<QWidget>
    #include<QPushButton>
    #include<QLineEdit>
    #include<QBoxLayout>

    class MyWindow : public QWidget {
    Q_OBJECT
    private:
    QPushButton *button;
    QPushButton *button1;
    QLineEdit *edit;
    QHBoxLayout *myLayout;
    QVBoxLayout *myLayoutParent;
    public:
    MyWindow();
    private:
    void createUi();
    private slots:
    void youPushMe();
    void iPushYou();
    };

    #endif // EXAMPLE1_H@

    mywindow.cpp
    @#include"mywindow.h"

    MyWindow::MyWindow() {
    button = new QPushButton;
    button1 = new QPushButton;
    edit = new QLineEdit;
    myLayout = new QHBoxLayout;
    myLayoutParent = new QVBoxLayout;
    createUi();
    }

    void MyWindow::createUi() {
    setWindowTitle(tr("Window"));
    button->setText(tr("Push Me"));
    button->connect(button,SIGNAL(clicked()),this,SLOT(youPushMe()));
    button1->setText(tr("Push You"));
    button1->connect(button1,SIGNAL(clicked()),this,SLOT(iPushYou()));
    myLayout->addWidget(button);
    myLayout->addWidget(edit);
    myLayoutParent->addLayout(myLayout);
    myLayoutParent->addWidget(button1);
    setLayout(myLayoutParent);
    }

    void MyWindow::youPushMe() {
    edit->setText("You Pushed Me!");
    }

    void MyWindow::iPushYou() {
    edit->setText("I Pushed You!");
    }@

    main.cpp
    @#include"mywindow.h"
    #include<QApplication>

    int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    MyWindow wind;
    wind.show();
    return app.exec();
    }@

    Thanks in Advance.



  • Congratulations, with the first steps



  • The MyWindow constructor should get an optional parent parameter:

    @
    class MyWindow {
    O_OBJECT
    public:
    MyWindow(QWidget *parent = 0);
    // ...
    };

    MyWindow::MyWindow(QWidget *parent)
    : QWidget(parent)
    {
    // ...
    }
    @

    Every constructor of a QObject subclass should have an optional parent parameter. Make it a QWidget pointer for widget classes and a QObject pointer otherwise. Don't forget to call your base class constructor with the parent pointer.

    And I personally would create the widgets and layuts (new xxx) in the createUi method too, but that's only a matter of taste.



  • Except what Volker said, everything is ok, keep practicing!

    But I recommend you to start thinking about code style:

    • Start object declaration with public, the interface is more important, then implementation
    • Try to name members in obvious way, so that you can understand its purpose at first glance, like pushMeButton, pushYouButton, windowLayout etc.
    • constructor should be as short as possible. As far as I remember, google code style guide recommends to separate some huge code sequences to private methods. So your createUi is good, but you should actually have there ALL the code that creates UI


  • @qxoz,
    Thank You.

    @Volker,
    I've made changes in the source code as per your post. But I'm not sure what to pass in the main() function to match the parent parameter while creating a MyWindow object. By the way, I was not careful enough to strictly follow the catb link, but I will surely take care of that too :) Thanks a lot.



  • The parent parameter is optional (you indicate this with the default value "= 0" in the class header). In Qt, toplevel windows, like your MainWindow, usually do not have a parent. In your case, you can leave the main() function as it was before.

    Other toplevel dialogs, like QDialog subclasses, may benefit from a parent, as they are then displayed centered over the parent window. But even if you do not intend to use the parent, it is a good habit to always add the parent parameter to the constructor in order to have the API consistent.



  • volker,

    Got the point. Thank You.

    kxyu,

    I have seen your post right after I acknowledged the other two posts. Thanks for the reply. I've made all necessary changes as per your suggestions. Here is my final code.

    • By the way, Is there any solution to move the QLineEdit object (the 'edit') to the CreateUi() itself? It is the only UI widget left in the constructor.
    • I had an impression that Qt is a lot like GTK+ with Glade. My next step on this codebase would be the splitting up of the complete UI, from the code.

    mywindow.h
    @#include<QWidget>
    #include<QPushButton>
    #include<QLineEdit>
    #include<QBoxLayout>
    class MyWindow : public QWidget {
    Q_OBJECT
    public:
    MyWindow(QWidget *p = 0);
    private:
    QLineEdit *edit;
    void createUi();
    private slots:
    void youPushMe();
    void iPushYou();
    };@
    mywindow.cpp
    @#include"mywindow.h"
    MyWindow::MyWindow(QWidget *p):QWidget(p) {
    edit = new QLineEdit;
    createUi();
    }
    void MyWindow::createUi() {
    QPushButton *pushMebtn = new QPushButton(tr("Push Me"));
    QPushButton *pushYoubtm = new QPushButton(tr("Push You"));
    QHBoxLayout *horLayout = new QHBoxLayout;;
    QVBoxLayout *verLayoutParent = new QVBoxLayout;
    setWindowTitle(tr("Window"));
    pushMebtn->connect(pushMebtn,SIGNAL(clicked()),this,SLOT(youPushMe()));
    pushYoubtm->connect(pushYoubtm,SIGNAL(clicked()),this,SLOT(iPushYou()));
    horLayout->addWidget(pushMebtn);
    horLayout->addWidget(edit);
    verLayoutParent->addLayout(horLayout);
    verLayoutParent->addWidget(pushYoubtm);
    setLayout(verLayoutParent);
    }
    void MyWindow::youPushMe() {
    edit->setText("You Pushed Me!");
    }
    void MyWindow::iPushYou() {
    edit->setText("I Pushed You!");
    }@

    Thank you very much.



  • You can happily move the line

    @
    edit = new QLineEdit;
    @

    into method createUi unchanged.



  • Volker,

    To make it more cleaner, I've moved the QLineEdit object to the CreateUi() method. But, when I connect the buttons' signals to the class's slots, an error is shown and the program doesn't work properly.

    Change in mywindow.h
    @private slots:
    void youPushMe(QLineEdit *);
    void iPushYou(QLineEdit *);@
    mywindow.cpp
    @void MyWindow::createUi() {
    QPushButton *pushMebtn = new QPushButton(tr("Push Me"));
    QPushButton *pushYoubtm = new QPushButton(tr("Push You"));
    QHBoxLayout *horLayout = new QHBoxLayout;;
    QVBoxLayout *verLayoutParent = new QVBoxLayout;
    QLineEdit *edit = new QLineEdit;
    setWindowTitle(tr("Window"));
    pushMebtn->connect(pushMebtn,SIGNAL(clicked()),this,SLOT(youPushMe(edit)));
    pushYoubtm->connect(pushYoubtm,SIGNAL(clicked()),this,SLOT(iPushYou(edit)));
    horLayout->addWidget(pushMebtn);
    horLayout->addWidget(edit);
    verLayoutParent->addLayout(horLayout);
    verLayoutParent->addWidget(pushYoubtm);
    setLayout(verLayoutParent);
    }
    void MyWindow::youPushMe(QLineEdit *target) {
    target->setText(tr("You Pushed Me!"));
    }
    void MyWindow::iPushYou(QLineEdit *target) {
    target->setText("I Pushed You!");
    }@

    The error I get is,

    @Object::connect: No such slot MyWindow::youPushMe(edit)
    Object::connect: No such slot MyWindow::iPushYou(edit)@

    A quick search directs me to http://developer.qt.nokia.com/forums/viewthread/4054, but doesn't seems to be much related. The application's behaviour is, it runs the GUI but clicking on the buttons doesn't make any changes in the 'edit' object's content.



  • Congratulations. I am a newbie too..



  • Ah, the beginner's connect confusion :-)
    You have two errors here:

    The wrong slot signature syntax in the connect and trying to connect incompatible signals and slots.

    In your connect statement you must always give the type of the arguments, not the name of the variable. So the correct statement would be:

    @
    connect(pushMebtn,SIGNAL(clicked()),this,SLOT(youPushMe(QLineEdit *)));
    @

    Note, that I left out the pointer dereference (pushMebtn->) in front of the connect. connect is a static method of class QObject, so there is no need to use it together with an actual object. In fact, it's recommended to omit using an object in that cases, as it suggests a relationship, which is not given.

    But performing that change, will not make your program work, unfortunately: The compatible signature thingie enters the game.

    The connect statement binds a signal with a signature to a slot with a "compatible" signature.

    So, a signal can optionally have arguments, but it's not required to. For example, let's have a look at [[Doc:QAbstractButton]], the base class of [[Doc:QPushButton]], which defines all the signals for a push button:

    • signals pressed() and released() both don't have an argument. They are just sent out in case the button is pressed (e.g. by pushing a mouse button over it) or released (by releasing the mouse button). Your slot does not get any additional information.
    • signal toggled(bool checked) and clicked(bool checked) carry a boolean argument. In your slot you can check whether the button is checked or not (more a thing for a [[Doc:QCheckBox]])

    Other signals carry even more arguments. For example:

    @
    QAbstractItemModel::rowsMoved( const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow );
    @

    So what is a compatible signature of a slot that you want to connect to the signal? Easy! The slot's signature must be a prefix of the signal's signature, including the full signature, of course, and including a slot without arguments. So, using the rowsMoved signal, you can connect it to the following slots:

    @
    slot1( const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent, int destinationRow );
    slot2( const QModelIndex & sourceParent, int sourceStart, int sourceEnd, const QModelIndex & destinationParent );
    slot3( const QModelIndex & sourceParent, int sourceStart, int sourceEnd );
    slot4( const QModelIndex & sourceParent, int sourceStart );
    slot5( const QModelIndex & sourceParent );
    slot6();
    @

    The latter is important: you can connect any signal with any signature to slots that do not take arguments at all. Your slot's signature is compatible if you cut signal's arguments from the end.

    What you can not do, is connect a signal without arguments to a slot that must take an argument - as "have an argument" is not a prefix of "no argument" :-) And you cannot connect a signal with an argument of type x to a slot with argument type y. The latter is what you are trying: connecting the bool argument of the signal to a pointer-to-QLineEdit argument of a slot.

    Matters get a bit more complicated when you have default arguments to your slots, but that shouldn't be of any concern right now.

    If you need to know which object fired the signal, use method sender() - but take care, the method may return a null pointer, if the slot was called directly (outside of a signal/slot connection).



  • In your example if you want to have line edit pointer inside slots, you should just declare it as a private class member and remove argument from slots.



  • Volker, Kxyu,

    Got the point. There is actually no way to pass the QLineEdit pointer (or any other data) into the slot via a connect statement. The only data I can gather inside the slot will be the ones which is passed by the signal signature. So, I've to declare the QLineEdit inside the class itself. I think that resolves the problem at the moment for my code. But as I searched around little bit hard, I got another case which is almost similar to mine "here":http://www.qtcentre.org/threads/27919-Override-a-signal. The only different thing is that, he uses a UI file, which is I'm not clear about. Anyway, I think my problem is resolved as of now. :)

    Thanks a lot friends.


Log in to reply
 

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