Instantiating gui object issue



  • Hi all

    I'm currently trying to write a gui app that has a menu with two options add order and view orders. when add order is clicked the central widget should be a order form and if view orders is selected a QTextEdit with showing all entered orders should be the central widget of the main window. When I try to instantiate a order form object in the add_order_clicked slot I keep getting a error saying 'orderForm was not declared in this scope. I did #include the orderForm class so why won't it let me instantiate it? I tryed re-building/cleaning and running cmake but no luck. Any idea why this would happen?
    Thanks

    my code:

    @
    #include <QTGui>
    #include "ordergui.h"
    #include "orderForm.h"

    ordergui::ordergui() {
    m_text = new QTextEdit;
    setCentralWidget(m_text);
    createActions();
    createMenu();
    }

    void ordergui::createActions() {
    add_order = new QAction(("Add Order"), this);
    connect(add_order, SIGNAL(triggered()), this, SLOT(add_order_clicked()));

    view_orders = new QAction(("View Order"), this);
    connect(view_orders, SIGNAL(triggered()), this, SLOT(view_order_clicked()));
    

    }

    void ordergui::createMenu() {
    orderMenu = menuBar()->addMenu("Order");
    orderMenu->addAction(add_order);
    orderMenu->addAction(view_orders);
    orderMenu->exec();
    }

    void ordergui::add_order_clicked() {
    orderForm obj;
    setCentralWidget(obj);
    }
    @


  • Lifetime Qt Champion

    Hi,

    Is orderForm really the class name ? Casing is important.

    On a side note, you're not calling the base class constructor in your constructor



  • Yes i'm sure i'm using the correct name. which base class are you talking about?
    this code is copied from another project example. What does it mean when in the constructor QWidget is initialized to parent? What is the parent of QWidget?
    Thanks again
    Deon

    code for orderForm implimentation file:
    @
    #include "orderform.h"
    #include "order.h"
    #include <QFormLayout>

    //constructor
    OrderForm::OrderForm(QWidget *parent):QWidget(parent){
    setUpGui();
    }

    //sets up the GUI
    void OrderForm::setUpGui(){
    m_nameEdit = new QLineEdit();
    m_dateEdit = new QDateEdit();
    m_quantitySpin = new QSpinBox();
    m_quantitySpin->setRange(1,1000);
    m_priceSpin = new QDoubleSpinBox();
    m_priceSpin->setRange(1.0,1000.00);
    m_totalEdit = new QLineEdit();
    m_totalEdit->setReadOnly(true);
    m_submitButton = new QPushButton("OK");
    m_cancelButton = new QPushButton("Cancel");

    QGridLayout* gridLayout = new QGridLayout();
    gridLayout->addWidget(m_submitButton,0,0);
    gridLayout->addWidget(m_cancelButton,0,1);
    
    QFormLayout *formLayout = new QFormLayout();
    formLayout->addRow(tr("&Name"), m_nameEdit);
    formLayout->addRow(tr("&Date Added"), m_dateEdit);
    formLayout->addRow(tr("&Quantity"), m_quantitySpin);
    formLayout->addRow(tr("&Unit Price"), m_priceSpin);
    formLayout->addRow(tr("&Total Price"), m_totalEdit);
    formLayout->addRow(gridLayout);
    
    connect(m_submitButton, SIGNAL(clicked()), this, SLOT(submit()));
    connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(m_quantitySpin, SIGNAL(editingFinished()), this, SLOT(calculateCost()));
    connect(m_priceSpin, SIGNAL(editingFinished()), this, SLOT(calculateCost()));
    
    this->setLayout(formLayout);
    this->setWindowTitle("Manual Order Form");
    

    }

    // sets an order
    void OrderForm::setOrder(Order prod){
    m_Order = prod;
    viewOrder();
    }

    //create a new order
    void OrderForm::submit(){
    m_Order.setName(m_nameEdit->text());
    m_Order.setDateAdded(m_dateEdit->date());
    m_Order.setQuantity(m_quantitySpin->value());
    m_Order.setPrice(m_priceSpin->value());
    }

    //view an order
    void OrderForm::viewOrder(){
    m_nameEdit->setText(m_Order.name());
    m_dateEdit->setDate(m_Order.dateAdded());
    m_quantitySpin->setValue(m_Order.quantity());
    m_priceSpin->setValue(m_Order.price());
    calculateCost();
    }
    //calculate the cost of an order
    void OrderForm::calculateCost(){
    double total = double(m_quantitySpin->value()* m_priceSpin->value());
    m_totalEdit->setText(QString::number(total, 'f', 2));
    }

    @


  • Lifetime Qt Champion

    Your class is not called orderForm but OrderForm, that's why it fails. Casing is important.

    Have look "here":http://qt-project.org/doc/qt-5/qwidget.html#QWidget to get an explanation about the parent of QWidget



  • Thanks SGaist stupid error on my side... What do you mean by the base constructor isn't called in the constructor? I get the program to run but there's no gui output


  • Lifetime Qt Champion

    Since both are QWidget:

    Clean way:
    @
    OrderForm::OrderForm(QWidget *parent):
    QWidget(parent){

    }@

    Only if you don't expect to parent your widget in the constructor:
    @
    ordergui::ordergui() {
    }@

    Edit: corrected the wording



  • Thanks again... So I obviously didn't understand the explanation on the previous link you posted. What I understood from there was that if QWidget* parent = 0; it will be a window otherwise it would be a widget on a window?



  • When I do that I get an error saying QWidget is not a direct base type of ordergui...

    Also why was that not done in this example?

    http://qt-project.org/doc/qt-4.8/mainwindows-application.html


  • Lifetime Qt Champion

    I've updated the wording of my last post (was a bit tired)

    Since you have that error, it means that ordergui doesn't inherit from QWidget. It should inherit from QMainWindow.

    Since you don't see anything do you call show somewhere in you main.cpp ?



  • Yes I call show from main.cpp but for some reason I don't get any output, any idea what i'm doing wrong?

    main.cpp:

    @
    #include <QtGui>
    #include <QApplication>
    #include "ordergui.h"

    int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    ordergui order;

    order.show();
    return app.exec();
    

    }
    @



  • could it be becuase you orderForm is created on the stack before being sent to setCentralWidget ? It then goes out of scope and is not available.
    You should allocate it off the heap with "new".



  • I just tried that but still no luck...



  • Just wondering, how can you even call setCentralWidget without a pointer to QWidget? :)
    @
    void QMainWindow::setCentralWidget(QWidget * widget)
    @
    you should get a compile error here:
    @
    orderForm obj;
    setCentralWidget(obj);
    @



  • Hi Xander. Sorry yes I changed it to OrderForm* obj but for some reason there's no output. Also when I try to close the running program I have to force quit



  • [quote author="Dn588" date="1397930234"]Hi Xander. Sorry yes I changed it to OrderForm* obj but for some reason there's no output. Also when I try to close the running program I have to force quit[/quote]
    Then you have most like created another (invisible) top level windows, if you have to "kill" the app.
    you can try setting the parent of your central widget, I though the setCentralWidget would reparent it, but maybe not:
    @
    setCentralWidget(new orderForm(this));
    @
    maybe that works.



  • No still no visible output and I still have to force quit...



  • Is it possible that you can upload your whole project code somewhere? I don't know if you can publish your code or how large your codebase is beside what you already posted, but an logic error like this is hard to debug over the forums.. :/



  • My Code:

    @
    order.h

    #ifndef ORDER_H
    #define ORDER_H

    #include <QString>
    #include <QDate>

    class Order {

    public:
    //getters
    QString name() const {return m_name;}
    QDate dateAdded() const { return m_added; }
    int quantity() const {return m_quantity; }
    double price() const {return m_price;}

    //return a string representation of an order
    QString toString() const;
    
    //setters
    void setName(const QString &name) {m_name = name;}
    void setDateAdded(const QDate &added) {m_added = added;}
    void setQuantity(int qty) {m_quantity = qty;}
    void setPrice(double unitPrice) {m_price = unitPrice;}
    

    private:
    //data members
    QString m_name;
    QDate m_added;
    int m_quantity;
    double m_price;

    };

    #endif // #ifndef ORDER_H

    order.cpp

    #include "order.h"
    #include <QString>

    //returns the string representation of an order
    QString Order::toString() const {
    return QString("%1 %2 (%3)at $ %4 total: %5").arg(m_name)
    .arg(m_added.toString("yyyyMMdd")).arg(m_quantity)
    .arg(m_price).arg(m_quantity*m_price);
    }

    OrderForm.h
    #ifndef ORDERFORM_H
    #define ORDERFORM_H

    #include <QtGui>
    #include "order.h"

    class OrderForm : public QWidget {
    Q_OBJECT

    public:
    //constructor
    OrderForm(QWidget* parent);
    //view a given order
    void setOrder(Order prod);

    private slots:
    //create a new order
    void submit();
    //calculate the cost of an order
    void calculateCost();

    private:
    //private data members
    QLineEdit* m_nameEdit;
    QDateEdit* m_dateEdit;
    QSpinBox* m_quantitySpin;
    QDoubleSpinBox* m_priceSpin;
    QLineEdit* m_totalEdit;
    QPushButton* m_submitButton;
    QPushButton* m_cancelButton;

    Order m_Order;
    
    //to view an order
    void viewOrder();
    //sets up the GUI
    void setUpGui();
    

    };

    #endif // #ifndef ORDERFORM_H

    OrderForm.cpp

    #include "orderform.h"
    #include "order.h"
    #include <QFormLayout>

    //constructor
    OrderForm::OrderForm(QWidget *parent) : QWidget(parent) {
    setUpGui();
    }

    //sets up the GUI
    void OrderForm::setUpGui(){
    m_nameEdit = new QLineEdit();
    m_dateEdit = new QDateEdit();
    m_quantitySpin = new QSpinBox();
    m_quantitySpin->setRange(1,1000);
    m_priceSpin = new QDoubleSpinBox();
    m_priceSpin->setRange(1.0,1000.00);
    m_totalEdit = new QLineEdit();
    m_totalEdit->setReadOnly(true);
    m_submitButton = new QPushButton("OK");
    m_cancelButton = new QPushButton("Cancel");

    QGridLayout* gridLayout = new QGridLayout();
    gridLayout->addWidget(m_submitButton,0,0);
    gridLayout->addWidget(m_cancelButton,0,1);
    
    QFormLayout *formLayout = new QFormLayout();
    formLayout->addRow(tr("&Name"), m_nameEdit);
    formLayout->addRow(tr("&Date Added"), m_dateEdit);
    formLayout->addRow(tr("&Quantity"), m_quantitySpin);
    formLayout->addRow(tr("&Unit Price"), m_priceSpin);
    formLayout->addRow(tr("&Total Price"), m_totalEdit);
    formLayout->addRow(gridLayout);
    
    connect(m_submitButton, SIGNAL(clicked()), this, SLOT(submit()));
    connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(m_quantitySpin, SIGNAL(editingFinished()), this, SLOT(calculateCost()));
    connect(m_priceSpin, SIGNAL(editingFinished()), this, SLOT(calculateCost()));
    
    this->setLayout(formLayout);
    this->setWindowTitle("Manual Order Form");
    

    }

    // sets an order
    void OrderForm::setOrder(Order prod){
    m_Order = prod;
    viewOrder();
    }

    //create a new order
    void OrderForm::submit(){
    m_Order.setName(m_nameEdit->text());
    m_Order.setDateAdded(m_dateEdit->date());
    m_Order.setQuantity(m_quantitySpin->value());
    m_Order.setPrice(m_priceSpin->value());
    }

    //view an order
    void OrderForm::viewOrder(){
    m_nameEdit->setText(m_Order.name());
    m_dateEdit->setDate(m_Order.dateAdded());
    m_quantitySpin->setValue(m_Order.quantity());
    m_priceSpin->setValue(m_Order.price());
    calculateCost();
    }
    //calculate the cost of an order
    void OrderForm::calculateCost(){
    double total = double(m_quantitySpin->value()* m_priceSpin->value());
    m_totalEdit->setText(QString::number(total, 'f', 2));
    }

    ordergui.h

    #ifndef ORDERGUI_H
    #define ORDERGUI_H
    #include <QMainWindow>
    #include <QTextEdit>

    class ordergui : public QMainWindow {
    Q_OBJECT
    public:
    ordergui();
    public slots:
    void add_order_clicked();
    void view_orders_clicked();
    private:
    void createMenu();
    void createActions();
    QTextEdit* m_text;
    QMenu* orderMenu;
    QAction* add_order;
    QAction* view_orders;
    };

    #endif // ORDERGUI_H

    ordergui.cpp

    #include <QTGui>
    #include "ordergui.h"
    #include "OrderForm.h"

    ordergui::ordergui() {
    m_text = new QTextEdit;
    setCentralWidget(m_text);
    createActions();
    createMenu();
    }

    void ordergui::createActions() {
    add_order = new QAction(("Add Order"), this);
    connect(add_order, SIGNAL(triggered()), this, SLOT(add_order_clicked()));

    view_orders = new QAction(("View Order"), this);
    connect(view_orders, SIGNAL(triggered()), this, SLOT(view_orders_clicked()));
    

    }

    void ordergui::createMenu() {
    orderMenu = menuBar()->addMenu("Order");
    orderMenu->addAction(add_order);
    orderMenu->addAction(view_orders);
    orderMenu->exec();
    }

    void ordergui::add_order_clicked() {
    //OrderForm* obj = new OrderForm;
    setCentralWidget(new OrderForm(this));
    }

    void ordergui::view_orders_clicked() {
    setCentralWidget(m_text);
    }

    main.cpp

    #include <QtGui>
    #include <QApplication>
    #include "ordergui.h"

    int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    ordergui order1;

    order1.show();
    return app.exec&#40;&#41;;
    

    }

    @

    [edit: modified the code to allow proper tagging SGaist]



  • HI, sorry I tried to copy your messed up code here but it's almost impossible because it puts everything into one line and the quotations are also messed up etc.

    If you put it in proper code tags or just zip and upload your project somewhere I will try finding your error, but not like this if I have to cleanup all the code just to recreate your whole project. :D



  • Hi Xander thanks for taking a look
    I uploaded it to dropbox, hope that's ok?

    download link:

    https://www.dropbox.com/s/i2hz6per5o78lry/Order-exercise.rar



  • Ok i had to add some stuff to the pro file and include QtWidgets in OrderForm.h to compile the project, I think you are using Qt 4 or why don't you need that?

    Anyway I didn't change the code and it works!? lol
    maybe a little weird to start the app with a menu only, but when i click on "Add Order" i see this:
    !http://i.imgur.com/2ADRudL.png(order form)!
    isn't that what you want, I am a little confused now because it seems to work or what is not working!?

    I noticed some other bugs, but i'm waiting for your response on this first.



  • Yes I am using QT 4



  • no idea why it's not working for me... it is a little strange yes i'm busy working through "Design patterns in C++ with QT" and this is a varient of one of the exercises...



  • I just tried to run it from command prompt but still nothing. A process gets created under windows processes but nothing happens...



  • are you sure your slot is working? how are you compiling your project?
    because I had to modify your project file to get it to work :D

    also if you start learning Qt now and have the choice you should use Qt5 and not the old version, or is there any other reason you use Qt4?

    maybe put a debug line in your slot to see if it's called, if you compile the project without qmake your signals and slots are not working I think.
    @
    void ordergui::add_order_clicked() {
    qDebug("add_order_clicked");
    //OrderForm* obj = new OrderForm;
    setCentralWidget(new OrderForm(this));
    }
    @
    I have the feeling your slot is never called..

    also the other bug in your slot:
    @
    void ordergui::view_orders_clicked() {
    setCentralWidget(m_text);
    }
    @
    that will crash the app because m_text has been deleted, check the doc of "setCentralWidget":http://qt-project.org/doc/qt-5/qmainwindow.html#setCentralWidget (Note: QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time.)
    that means if you set your ordner form as central widget it will delete the previous widget (your text)..



  • i'm currently busy with a university course that uses QT 4 which is why I am using it. I just commented out the slots but still not getting a main window... I created a new project and added the order and OrderForm files to it and it ran with no issues... So i'm guessing there's also something wrong with my main window's constructor?



  • Oh yeah I thought it was supposed to be like that, that's why I said it is a little weird your app starts with a menu and not the main window, so that is a bug too?

    comment out this line
    @
    orderMenu->exec();
    @
    in your ordergui::createMenu() function.
    you should sometimes read the Qt doc, it tells you that QMenu::exec() "Executes this menu synchronously." which means it will block the thread until you close the menu (click an item) and only after that display the window. if you don't call "exec" it will just show the main window with your menu and your text widget (like it should?).



  • Thanks a lot for all your effort Xander84. I read the QMenu reference page but misunderstood it. I thought exec() has to be called to activate the menu...



  • I now have to add all orders to a list that gets displayed when view_orders_clicked is triggered.

    What i've tried doing is create a function in OrderForm

    QString addToList() { return m_order.toString(); }

    then in my ordergui class I created a new varieable

    QStringList OrderList;

    So now the add_order_clicked slot looks like this:
    @
    void ordergui::add_order_clicked() {
    OrderForm* obj;
    setCentralWidget(obj);
    OrderList.append(obj->addToList());
    view_orders->setEnabled(true);;
    }
    @
    when I click on add order the program crashes every time...

    Am I going about this the right way?



  • you have not allocated an object
    @
    OrderForm* obj;
    @
    is just a pointer to nothing (invalid memory), that is why your app is crashing.

    this should work:
    @
    OrderForm* obj = new OrderForm; // creates an object on the heap memory (you have to delete it yourself usually, use this)
    OrderForm obj; // creates an object on the stack memory (will be deleted if the object leaves the current scope / end of function)
    @



  • When I do it that way I get an error saying that the constructor is invalid as it was called with no parameters and it should be called with a QWidget*. OrderForm::OrderForm(QWidget*)...



  • yeah well that is because your constructor is not defined in the default "Qt way":
    @
    OrderForm(QWidget* parent = 0);
    @
    so you can create objects without any parent, because setCentralWidget will reparent the widget anyway. :)



  • Thanks it works perfectly now:). when I try to add orders to the OrderList ad in my previous post and write it to a new instance of m_text when view_orders is triggered none of the m_order values gets read in. i'm guessing that happens because it immediately tries to call addToList in Orderform passing obj->m_Order before the ok button is clicked. How could I go about making sure that m_order gets converted to a QString and added to OrderList only after all the orderForm fields have been completed?



  • I am not sure what you want to achieve but you can try using "validators":http://qt-project.org/doc/qt-4.8/qvalidator.html for the form fields? e.g.
    "QLineEdit::setValidator(const QValidator * v)":http://qt-project.org/doc/qt-4.8/qlineedit.html#setValidator
    and then check if the input of all fields is valid before you add it to the list or show an error next if it isn't. that is the classic approach I would say. :)



  • My current issue isn't validating the order input. I have to create a list of orders which should then get printed to m_text when view_orders is triggered.
    What i've done is create a QList

    QList<Order> m_list in the orderForm class.

    I added m_list.append() to the submit slot of OrderForm to add orders to the list every time the ok button is clicked. then I added another function to OrderForm
    @
    QString OrderForm::displayOrders() {
    for (int i = 0; i < m_list.size(); ++i)
    return m_list.at(i).toString();
    }
    @

    also I changed my add_order_clicked slot to
    @
    void ordergui::add_order_clicked() {
    OrderForm *obj = new OrderForm;

    setCentralWidget(obj);
    OrderList.append(obj->displayOrders());
    view_orders->setEnabled(true);
    

    }
    @

    Then I changed my view_orders_clicked slot of ordergui to:

    @
    void ordergui::view_orders_clicked() {
    m_text = new QTextEdit;
    setCentralWidget(m_text);
    for (int i = 0; i < OrderList.size(); ++i) {
    m_text->append(OrderList.at(i));
    }

    }
    @

    whenever I add an order and then select view orders the program crashes... Any idea why that would happen?



  • Sounds a little chaotic to me, sorry :D
    Your order form keeps a list of all orders and then your have a list of the string values of all orders in another class!?

    I would suggest using a list view, why are you using a QTextEdit for a list of orders? Ok i might be a little bit easier at first, but the proper way would be to use a ListView which holds a list model with all your orders and displays them as their string representation I think? You could also use a TableView but is more complicated.

    Maybe take a look at these articles:
    http://qt-project.org/doc/qt-4.8/modelview.html
    http://qt-project.org/doc/qt-4.8/model-view-programming.html

    Also your for loop is useless:
    @
    QString OrderForm::displayOrders() {
    for (int i = 0; i < m_list.size(); ++i)
    return m_list.at(i).toString();
    }
    @
    the return expression will exit the function immediately, so that is the same as
    @
    QString OrderForm::displayOrders() {
    return m_list.at(0).toString();
    }
    @
    if you want to concatenate the values of all strings and return those you need to use QString::append or something else to build a string and return it at the end of the function.



  • The instructions in the exercise says to use a QTextEdig... So maybe I could change displayOrders to append all orders using QString::append?


Log in to reply
 

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