PDA

View Full Version : QT Class GUI Interactions??



mikey33
18th November 2009, 09:55
This is a question that I can't seem to figure out for some reason I don't know why but...

I have a main class which includes the header files of all the other classes and in the cpp of the main class it goes something like this...



MainClass::MainClass(QWidget *parent) : QWidget(parent), mainWindow(new Ui::MainClass)
{
mainWindow->setupUi(this);

classTwo = new SecondClass(this);
classThree = new ThirdClass(this);
}


but in classTwo for instance I want to disable a button in classThree. Now I can do this through the mainClass say like this...



connect(classTwo->classTwoGui->disableClassThree_Button, SIGNAL(clicked()), this, SLOT(disableButtonInClassThree()));


where in the above example disableButtonInClassThree() would be a member function of the main class and the function defined in the MainClass cpp would probably be...



void MainClass::disableButtonInClassThree()
{
classThree->classThreeGui->buttonOne->setEnabled(false);
}


the problem is that I don't want to go through MainClass as I'd imagine that is very inefficient and creates a cluttered clumsy MainClass when using way more than 2 other classes in interaction so I talked to a couple friends and they told me to try this...

In the SecondClass header I have...



#include "thirdclass.h"

class SecondClass : public QMainWindow
{
Q_OBJECT

public:
SecondClass (ThirdClass *test, QWidget *parent = 0);
Ui::SecondClass *classTwoGui;

public slots:
void on_disableClassThree_Button_clicked();

}


In the SecondClass cpp I have...




SecondClass::SecondClass (ThirdClass *test, QWidget *parent) : QMainWindow(parent), classTwoGui(new Ui::SecondClass )
{
classTwoGui->setupUi(this);

test->classThreeGui->buttonOne->setEnabled(false);
}


Now the above code works BUT it only works in the constructor of SecondClass so essentially meaning I can't really control it through a button clicked in SecondClass because doing any code outside of the constructor is not recognizing test.

I have thus researched all over and found nothing to help, I have tried forward class declarations but that's not my problem I believe and that didn't work either, I have also tried taking it out of the constructor and initializing a pointer of the ThirdClass below the constructor such as...



public:
SecondClass (QWidget *parent = 0);
ThirdClass *test,
Ui::SecondClass *classTwoGui;


which could then be accessed in any function inside of the SecondClass but then it caused an instant crash upon launching I believe due to the fact that in the MainClass it is also being initialized too??

I almost forgot to mention that in order for me to get the constructor working working I had to change...classTwo = new SecondClass(this); in the MainClass constructor to...



classTwo = new SecondClass(classThree, this);


I hope someone can help me as I'm really struggling with this part and I have had no success for awhile although I can still get it to work the inefficient way by going through the MainClass but I'd rather not due to the reasons above so simply put...

I need to access GUI objects, such as a button, from a class using another class without going through the MainClass.

Final Example to hopefully clear things up is...

Clicking a button in a second class GUI will disable a button in a third class GUI without going through the main class, essentially have the second class somehow recognize GUI objects of the third class in any section of the second class so any member function of the second class can interact with objects of the third class.

I hope this all makes sense I tried my best to explain it, sorry if it's to long :(

Thanks again for trying to help!!!

montuno
18th November 2009, 11:15
IMHO it seems to me your problem comes because you're unsure about the dependencies between your classes. Therefore, my answer depends on what you want to achieve in particular. For example

...if the classes are independent of eachother then you need a class like MainClass to control things like you've explained. Signals/Slots are a very powerful feature of Qt. Perfect for designing loose coupled dependencies. For example use MainClass as a mediator between the others and establish connects like...

connect(classTwo, SIGNAL(needPushButtonDeactivate()), classThree, SLOT(deactivatePushButton()));

squidge
18th November 2009, 13:52
It seems like you have a group of classes controlling ui elements and you need a controller, kind of like the Model View Controller (MVC), as described here: http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

You have the classes controlling the view, so you need a controller. So instead of main constructing the classes and controlling them, you put that code into the controller, and let main just initialise the controller class which will look after SecondClass/ThirdClass and so on.

Or, if you prefer SecondClass to have access to the gui of ThirdClass, then pass in a class pointer of ThirdClass in the constructor of SecondClass, and then copy that pointer to a member variable also of ThirdClass *, then any member function can access the ui of thirdclass.

To me though, I'd say SecondClass talking to ThirdClass would be messy code, and that you should go down the MVC route.

mikey33
19th November 2009, 02:01
Or, if you prefer SecondClass to have access to the gui of ThirdClass, then pass in a class pointer of ThirdClass in the constructor of SecondClass, and then copy that pointer to a member variable also of ThirdClass *, then any member function can access the ui of thirdclass.

You both are correct and I believe I forgot to mention that MainClass is acting like the controller in this situation but I just figured since the SecondClass was only interacting with the ThirdClass then it should have a direct link between the two instead of using the MainClass as a middleman aka controller so thanks a ton for both of your replys...

Although I have thus solved the problem just like what fatjuicymole said above but in a slightly different way which works below...

MainClass Constructor...



classTwo = new SecondClass(this);
classThree = new ThirdClass(this);

classTwo->setThirdClassPointer(classThree);


SecondClass header...



public:
void setThirdClassPointer(ThirdClass *classThree);

private:
ThirdClass *test;


SecondClass cpp...



void SecondClass::setThirdClassPointer(ThirdClass *classThree)
{
test = classThree;
}


and then I was able to use the ThirdClass objects essentially anywhere in the SecondClass.

My issue before was one of the simplest mistakes anyone can probably make. I'm using QSettings in the SecondClass and my read/load function for QSettings is placed in the SecondClass constructor and the function defined is right below the constructor so in testing to ensure the code worked I was lazy and put the test code in the nearest available function below the constructor, I used the test code below...



test->classThreeGui->buttonOne->setEnabled(false);


in the read/load function so I'm gonna guess the initial problem revolved around trying to access objects that weren't created yet since the read/load function was placed in the constructor and at that time the instance of the ThirdClass wasn't created yet if that makes sense or is right so basically it was pointing to an invalid unknown location causing the program to crash. If only I knew that the first time I could've saved a lot of time hehe! Thanks again everyone! Hope this helps someone else!!! :D