Few basic questions about QT



  • I am a begginer to QT programming and as I tried creating a GUI application I encountered some issues and questions:

    · I have a 'Client' class, that stores the data from clients. I made this class to be a Designer form class (as i want to create a window where the user can input the data). I made it so that the data is set when a button is clicked. My question is if a simple class that stores data should have a Designer form or if this two things should be done separately.

    · Regarding the last question, when i create the "client" widget (the window that will open when the user wants to enter client data) I have to do it as a pointer Client window = new Client window->show(). If not done this way, the widget opens and closes inmediately. But I have another class called "List" that is a template class. When I want to store the client object in a List, it doesn't work, as List doesn't accept pointers, but a concrete object (i hope you understand what i'm saying). What can I do to solve this? The best would be to be able to do this: Client window; window.show(); Without it closing.

    · Should I make the whole app on main.cpp or mainwindow.cpp? I mean, all the functions that make the app work and the different variables needed, should they exist on main.cpp or mainwindow.cpp? What is the right way to do it?

    Thanks



  • You should separate your business logic (the data) from the GUI. i.e. you make a class or classes that know about the data required by the application. Then you have classes that are the GUI (the Widgets for forms and windows).


  • Moderators

    These are basically C++ questions and general programming and not-so-much Qt related. But here goes...

    1. I would separate the stored data and the form that allows input and editing of the data. So have an object Data and a GUI interface Form. Those names would be more appropriate to your project of course. :)

    2. Multiple ways to handle this one. The proper way is just to dereference the pointer (assuming your list takes a copy of it). So something like List::add(*myObject); The * does the magic on that one. Again if the List doesn't take a copy though and instead stores it by reference or pointer then when myObject is cleaned up it will cause crashing in the List when it is next accessed.

    The next way is you could use a QDialog instead of QWidget for your window then you can do a blocking call like so:

    @
    MyDialog dlg(this);
    dlg.exec();
    @

    When exec() returns it means the window has been closed. So you can then process your data without the use of the pointer.

    1. Lastly I use main.cpp for very very limited stuff. Everything else happens in files pertaining to their object. A pretty normal main.cpp for me is as simple as:

    @
    #include <QApplication>

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

    MyMainWindow mw;
    mw.show();

    return app.exec();
    }
    @

    Sometimes I add things like logger initialization and setting up the application object stuff like QCoreApplication::setOrginizationName("xx"); etc.



  • Thank you for the answers!
    So now i've run into this:
    I have a structure that stores my "Clients". By touching a button I open a window where I create a new Client. Then I need to store that client in the structure mentioned before. The thing is , using a slot function, i have no way to pass that structure by reference, so it would be modified. Any suggestions?


  • Moderators

    I don't quite understand what you're saying here. Can you show me some code so I can get an idea of what you are trying to pass and how?



  • [quote author="ambershark" date="1407809522"]I don't quite understand what you're saying here. Can you show me some code so I can get an idea of what you are trying to pass and how?[/quote]

    I would have a structure "Stack". Then i do:
    @
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(AddToStack(Stack, Client)).
    @
    Do you understand? That code is for example only, it doesn't matter if it is correct.
    Thanks


  • Moderators

    Oh yea I see what you're saying now.

    For this I would use a class member. I would set the client struct when I created the widget to modify it. Then I could access that struct from the widget on the button clicked signal.

    Then finally I could get that client struct from outside the widget when it was done being processed.

    Example:

    @
    class MyWidget : public QWidget
    {
    public:
    void setClient(Client *client) { mClient = client; }
    Client *client() const { return mClient; }

    private slots:
    void buttonClicked();

    private:
    Client *mClient;
    };

    // implementation
    void MyWidget::buttonClicked()
    {
    mClient->setSomething(x);
    }
    @

    There are other ways to accomplish this as well. You could use a global (not recommended), you could use a custom pushbutton that emitted a signal with the client as a parameter (I wouldn't really do this either). You could use a static type accessor. Something like Client::clientList()->at(i); although I wouldn't do that either. They are all options but I would use the method I showed above.



  • [quote author="ambershark" date="1407879931"]Oh yea I see what you're saying now.

    For this I would use a class member. I would set the client struct when I created the widget to modify it. Then I could access that struct from the widget on the button clicked signal.

    Then finally I could get that client struct from outside the widget when it was done being processed.

    Example:

    @
    class MyWidget : public QWidget
    {
    public:
    void setClient(Client *client) { mClient = client; }
    Client *client() const { return mClient; }

    private slots:
    void buttonClicked();

    private:
    Client *mClient;
    };

    // implementation
    void MyWidget::buttonClicked()
    {
    mClient->setSomething(x);
    }
    @

    There are other ways to accomplish this as well. You could use a global (not recommended), you could use a custom pushbutton that emitted a signal with the client as a parameter (I wouldn't really do this either). You could use a static type accessor. Something like Client::clientList()->at(i); although I wouldn't do that either. They are all options but I would use the method I showed above.[/quote]

    Thank you for the very detailed anwer! I don't think my previous message was sent correctly. I understand how to manage the client class, the thing is how to store that "Client" class in a "Stack" class , which i need to be modified to be used in other parts of the program.
    connect(ui->pushButton,SIGNAL),this,SLOT(client,stack).

    That was the original message. A slot function that when i click a pushButton, it creates the client, then stores it in stack. AND stack is modified throughout the program.

    Thanks!



  • Hi,
    When you want to use a custom type in a signal/slot operation you will be able to use Q_DECLARE_METATYPE and then (not for QObject derived classes) those classes are available in Signal/Slot operations


  • Moderators

    Ok just to make sure nomenclature isn't confusing this at all. When you say "stack" do you mean like the memory stack or are you talking about a custom class that you have called "stack" that contains a group of objects called "client"?

    If you are talking about memory stack then there isn't a way to do what you're asking without copying those objects in places, or you could pass things along as a reference to the object. So Client& instead of just Client. I personally don't like that way though as it can get confusing and things can go out of scope, namely the first one which is what the others refer to.

    If you are talking about the latter scenario let me know and I'll see if I can answer that for you as well.



  • [quote author="ambershark" date="1407914012"]Ok just to make sure nomenclature isn't confusing this at all. When you say "stack" do you mean like the memory stack or are you talking about a custom class that you have called "stack" that contains a group of objects called "client"?

    If you are talking about memory stack then there isn't a way to do what you're asking without copying those objects in places, or you could pass things along as a reference to the object. So Client& instead of just Client. I personally don't like that way though as it can get confusing and things can go out of scope, namely the first one which is what the others refer to.

    If you are talking about the latter scenario let me know and I'll see if I can answer that for you as well.[/quote]

    I am sorry for using the wrong words. I meant a "stack" as a class that contains a group of "client" (another class) object.


  • Moderators

    Ok, in order to help you further I'm going to have to see some code. I need to see headers for Stack, Client, and parts that store the client in your window widget implementation.



  • [quote author="ambershark" date="1408660823"]Ok, in order to help you further I'm going to have to see some code. I need to see headers for Stack, Client, and parts that store the client in your window widget implementation.[/quote]

    Well, I've realized that I don't know how to use variables with signal functions.
    I created a* ClientW* class for inserting the client data. Then I have the Client class that stores the data. So when i finish on the ClientW window, I push 'Create' button and in the signal function:
    @void ClienteW::on_pushButton_clicked()
    {
    QString name;
    name=ui->lineEdit->text();

    Cliente(name) client;
    

    }@

    I create the client, but i see no way in which the main window gets the client data.

    @void MainWindow::on_pushButton_clicked()
    {
    Cliente client;
    ClienteW * w = new ClienteW;
    w->show();

    }@

    EDIT:
    I just thought of an easy example.
    If I want the user to choose three options. The user presses a button, a menu opens (Widget) and the three options are available via Radio buttons. The thing is, after clicking "Done" in this widget, how would you do so that MainWindow receives the option selected?

    Thanks!


  • Moderators

    Ok, there are a bunch of ways to do this.

    1. You can use QDialog and exec() then when it returns pull the data you need. Here is an example:

    @
    void MainWindow::doSomething()
    {
    MyDialog dlg(this);
    if (dlg.exec() == QDialog::Accepted)
    {
    // access the data you need here
    bool myVar = dlg.radioButton->isChecked();
    }
    }
    @

    1. If sticking with a widget that you use new and show on. Oh and btw in your example since you do ClienteW *w = new ClienteW; without the parent that will memory leak as you have no way to clean that up later. If you do ClienteW *w = new ClienteW(this) that will have the parent clean it up. Although if you are going to call that a lot I would manage memory via delete w; yourself.

    Anyway back to #2, if you use the widget like above, you can save off the pointer in a class member variable and then access that when you need it. I would have a signal or something that tells mainwindow the widget is done and it's ok to access it's data.

    @
    void MainWindow::doSomething()
    {
    mWidget = new ClienteW(this); // mWidget is a member of mainwindow
    connect(mWidget, SIGNAL(widgetDone()), this, SLOT(clientWidgetFinished()));
    mWidget->show();
    }

    void MainWindow::clientWidgetFinished()
    {
    if (mWidget)
    {
    // access it here
    bool myVar = mWidget->radioButton->isChecked();

       // clean up
       mWidget->deleteLater();
       mWidget = 0;
    

    }
    }
    @

    Not a fan of this method but it's an option.

    1. You could also make ClientW aware of MainWindow or wherever you need the client data. Then inside ClientW when the radio is set you can call it to set the data in mainwindow, like so:

    @
    void ClientW::radioSelected()
    {
    // mMainWindow would be a pointer to mainwindow passed in the constructor
    mMainWindow->clientSelection = radioButton->isChecked();
    }
    @

    1. You could use a globally (static) available object to save the data in. Something you could access with a static function anywhere like Client::reference()->setRadioCheck(radioButton->isChecked()).

    Personally I would use either #1 or #2. If you are still stuck I can give you a working example that you can compile and run to see how it works.



  • [quote author="ambershark" date="1409006265"]Ok, there are a bunch of ways to do this.

    1. If sticking with a widget that you use new and show on. Oh and btw in your example since you do ClienteW *w = new ClienteW; without the parent that will memory leak as you have no way to clean that up later. If you do ClienteW *w = new ClienteW(this) that will have the parent clean it up. Although if you are going to call that a lot I would manage memory via delete w; yourself.

    Anyway back to #2, if you use the widget like above, you can save off the pointer in a class member variable and then access that when you need it. I would have a signal or something that tells mainwindow the widget is done and it's ok to access it's data.

    @
    void MainWindow::doSomething()
    {
    mWidget = new ClienteW(this); // mWidget is a member of mainwindow
    connect(mWidget, SIGNAL(widgetDone()), this, SLOT(clientWidgetFinished()));
    mWidget->show();
    }

    void MainWindow::clientWidgetFinished()
    {
    if (mWidget)
    {
    // access it here
    bool myVar = mWidget->radioButton->isChecked();

       // clean up
       mWidget->deleteLater();
       mWidget = 0;
    

    }
    }
    @

    Not a fan of this method but it's an option.

    [/quote]

    Thanks for the detailed information! I like option #2. But I don't see how MainWindow would be able to use that bool variable, i mean, it seems as if the bool would stay inside the clientWidgetFinished function, right?. Am I missing something? (I don't want to use global variables).

    Can the widgetDone function be a Clicked() function? The one that is the, for instance, pushButton signal.

    Thank you. Sorry for answering so late, but i've been busy.


  • Moderators

    If you needed access to that bool outside of the clientWidgetFinished() function you would make it a class variable. You will rarely need globals these days. In fact I would say I almost never use them and when I need global type variables they tend to be static members of a class.

    So if you added something like this:

    @
    class MainWindow : public QMainWindow
    {
    //...
    private:
    bool mMyMvar;
    };

    // and then in your function
    void MainWIndow::clientWidgetFinished()
    {
    //...
    mMyVar = mWidget->radioButton->isChecked();
    //...
    }
    @

    Now that mMyVar bool is accessible from anywhere in your class.


  • Moderators

    Oh and forgot to answer your other question, yes widgetDone() was just a generic made up signal. It could absolutely be linked to the click of a pushbutton.

    @
    // assume pushbutton is called pushOK
    connect(pushOK, SIGNAL(clicked()), this, SLOT(clientWidgetFinished()));
    @



  • [quote author="ambershark" date="1409957257"]Oh and forgot to answer your other question, yes widgetDone() was just a generic made up signal. It could absolutely be linked to the click of a pushbutton.

    @
    // assume pushbutton is called pushOK
    connect(pushOK, SIGNAL(clicked()), this, SLOT(clientWidgetFinished()));
    @
    [/quote]

    Thank you so much! I think I finally got it!
    If I need anything, I'll be posting here. Thanks again.


  • Moderators

    No problem, happy to help.


Log in to reply
 

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