This forum has been archived. All content is frozen. Please use KDE Discuss instead.

[SOLVED] Qt: Access GUI from another class

Tags: None
(comma "," separated)
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
Baaah. The following is driving me mad for quite some time now. First off, I'm not an experienced Qt/C++ programmer, so please forgive me any stupidity or the overlooking blatant obviousness.

Basically I'm building a Qt application which uses a mainwindow designed in Qt Designer. I have a lot of functions belonging to my MainWindow class which makes the class bloated and many of those functions could be reused by other classes. What I wanted is some sort of separate base class (called DataModel) which provides several methods for manipulating GUI elements (e.g. QTreeViewWidgets which need to be filled with data from a database) to be called by different classes.

The problem is I can't seem to find out how to access those GUI elements from a separate class. So this might mean that it's either bad practice and should be avoided or I haven't found the holy grail yet. Any ideas? [size=x-small]Or am I too vague...[/size]


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
This should be possible. As long as the other classes have access to the object, they should be able to do it, by passing that to the DataModel class. ( or make the DataModel class handle the Window, avoiding that )

Hope that helped you, I can probably explain it better if you post the sources.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
I know that in theory you should pass the object, in practice the only that happens is that my application segfaults. ;)

Below are my mainwindow.h, mainwindow.cpp, datamodel.h and datamodel.cpp. I've stripped out most of the unnecessary functions, declarations, etc. for the sake of clarity.

mainwindow.h
Code: Select all
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include "ui_mainwindow.h"

class MainWindow : public QMainWindow, public Ui::MainWindow
{
  Q_OBJECT

  public:
    MainWindow(QWidget* parent=0);
 
  protected:
    void getData(const QString& queryString, const QString& dataType);

  public:
    Ui::MainWindow ui;
};

#endif

mainwindow.cpp
Code: Select all
#include
#include
#include
#include
#include "mainwindow.h"
#include "datamodel.h"
#include "client.h"
#include "project.h"
#include "document.h"
#include "work.h"
#include "ratestaxes.h"
#include "statusbar.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
  setupUi(this);

  QSqlDatabase database = QSqlDatabase::addDatabase("QMYSQL");
  database.setHostName("localhost");
  database.setDatabaseName("***");
  database.setUserName("***");
  database.setPassword("***");

  if (database.open()) {
    //Initialise all data for all QTreeWidgets
    getData("SELECT * FROM clients","clients");
  }
}

datamodel.h
Code: Select all
#ifndef DATAMODEL_H
#define DATAMODEL_H

#include
#include
#include
#include

class dataModel : public QObject
{
  Q_OBJECT

  public:
    dataModel(QObject* parent);
};
#endif

datamodel.cpp
Code: Select all
#include "datamodel.h"
#include "mainwindow.h"
#include
#include
#include
#include

dataModel::dataModel(QObject* parent) : QObject(parent)
{
}


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
Looks fine to me, although I wouldn't make MainWindow a subclass of Ui::MainWindow. You should be able to pass around a pointer to MainWindow.ui without any problems ( unless it somehow is destroyed, which would require destroying MainWindow )

Without seeing how it is actually crashing, I would speculate that either the pointer became invalid, or you were passing around the Ui::MainWindow instance directly ( copying it ) instead of a pointer.

Last edited by bcooksley on Wed Apr 08, 2009 10:10 am, edited 1 time in total.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
I've modified my code a bit and try to access a test function belonging to the MainWindow class, to see if the pointer is valid:
Code: Select all
MainWindow *mainWindow = MainWindow::test();

When building I get this error:
Code: Select all
error: cannot call member function 'void MainWindow::test()' without object


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
anda_skoa
KDE Developer
Posts
783
Karma
4
OS
As the compiler tells you, you try to call a member function (a.k.a method) without having an object to call on.

Code: Select all
mainWindow->test();


Cheers,
_


anda_skoa, proud to be a member of KDE forums since 2008-Oct.
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
I think that's the root of my problem; not having the right object passed. The declaration above (MainWindow *mainWindow = MainWindow::test();) doesn't seem to be correct.

The following code gives me this error (error: expected primary-expression before ';' token), which seems logical as well:
Code: Select all
MainWindow *mainWindow = MainWindow;
mainWindow->test();


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
This should work:
Code: Select all
MainWindow *mainWindow = new MainWindow();
mainWindow->test();


Then pass the mainWindow pointer to anything that needs it, as part of the function call that uses MainWindow functions.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
It builds that way, but the resulting build won't start. It doesn't crash, but rather seems to stay looping forever.


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
You wouldn't be trying to create the MainWindow pointer inside the MainWindow constructor would you?

If so, try this instead:
Code: Select all
MainWindow *mainWindow = this;
mainWindow->test();


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
I'm afraid not. :) I'm calling it inside my dataModel class:

Code: Select all
dataModel::dataModel(QObject* parent) : QObject(parent)
{
  MainWindow *mainWindow = new MainWindow();
  mainWindow->test();
}

Last edited by mensch on Thu Apr 09, 2009 12:55 pm, edited 1 time in total.


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
Whoops! I know what the culprit was and removed it. I had an old call to my dataModel class still in the MainWindow class. So in a sense I was calling it in the MainWindow constructor. All is well know, on to the next obstacle.

Thanks!

Is there a way to call dataModel in my MainWindow class, without triggering the eternal looping?

Last edited by mensch on Thu Apr 09, 2009 12:56 pm, edited 1 time in total.


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
anda_skoa
KDE Developer
Posts
783
Karma
4
OS
mensch wrote:Is there a way to call dataModel in my MainWindow class, without triggering the eternal looping?


You can just pass its instance to the MainWindow constructor or the other way around

Code: Select all
class MainWindow
{
public:
    MainWindow(dataModel* model);

private:
    dataModel* m_model;
};


Code: Select all
dataModel::dataModel()
{
    MainWindow* mainWindow = new MainWindow(this);
};


Cheers,
_


anda_skoa, proud to be a member of KDE forums since 2008-Oct.
User avatar
mensch
Registered Member
Posts
178
Karma
0
OS
That seem to work.

However, if I try to call m_model->test() from my mainwindow class the application crashes due to a EXC_BAD_ACCESS error. The test function in dataModel should manipulate a QTreeWidget belonging to MainWindow (at the moment it should just printing the widget's name).

mainwindow.h
Code: Select all
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include
#include "ui_mainwindow.h"

class dataModel;

class MainWindow : public QMainWindow, public Ui::MainWindow
{
  Q_OBJECT

  public:
    MainWindow(QWidget* parent=0);

  private:
    dataModel* m_model;
};
#endif

mainwindow.cpp
Code: Select all
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
  m_model->test();
}

Code: Select all
#ifndef DATAMODEL_H
#define DATAMODEL_H

#include
#include
#include
#include

class MainWindow;

class dataModel : public QObject
{
  Q_OBJECT

  public:
    dataModel(QObject* parent);
    void test();

    private:
      MainWindow *mainWindow;
};
#endif


datamodel.cpp
Code: Select all
dataModel::dataModel(QObject* parent) : QObject(parent)
{
  mainWindow = new MainWindow();
}

void dataModel::test() {
  qDebug() clientList->objectName();
}


I have forced myself to contradict myself in order to avoid conforming to my own taste. Marcel Duchamp
User avatar
bcooksley
Administrator
Posts
19765
Karma
87
OS
This is because you never initialised m_model.
Change the MainWindow constructor as follows:
Code: Select all
MainWindow(QWidget* parent = 0, DataModel* parentModel);


Then change the following
Code: Select all
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)

Into this
Code: Select all
MainWindow::MainWindow(QWidget *parent, DatModel* parentModel) : QMainWindow(parent)


Finally add the following before calling m_model->test();
Code: Select all
m_model = parentModel;


And change this:
Code: Select all
mainWindow = new MainWindow();

To this:
Code: Select all
mainWindow = new MainWindow(this, this);


Hope this helps.

Last edited by bcooksley on Thu Apr 09, 2009 9:34 pm, edited 1 time in total.


KDE Sysadmin
[img]content/bcooksley_sig.png[/img]


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Sogou [Bot]