0
votes

iI have a Qt application using QGLWidget for drawing (simply a Viewport for 3D drawing etc...)

There is two main classes in the application.

  • MainWindow Inherits from QWidget which holds many GUI widgets (menubar, toolbars, viewport, treeview...etc)
  • System Does every other operation from GUI (math, geometry, IO, data processing, etc and holds "Scene" object which has drawable components.) Also it has Singleton pattern to create one global Instance for itself.

I am using Qt signal-slot mechanism to communucate between MainWindow and System, actually MainWindow has the signals and System has the slots. My problem starts here, how can I signal from System to MainWindow slots? When I define MainWindow in System object it gives me lots of error. Normaly System references in MainWindow don't give error. But when I include MainWindow's header file in System.h, System references give error in MainWindow side "'System': the symbol to the left of a '::' must be a type".

Basically my structure is look like this.

// MainWindow.h
#include "System.h"
class MainWindow : public QWidget
{
    Q_OBJECT
public:
    QToolBar* MyToolBar; // etc...
    MainWindow()
    {
        ConnectSignals();
    }
    void ConnectSignals() { connect(my_action, SIGNAL(triggered()), System::GetInstance()->Actions, SLOT(action())); }
}
// System.h
#include "MainWindow.h" // if I wrote this, it gives me error in compile time.
class System
{
    static bool m_instance;
    static System* m_system;

    // private constructor
    System()
    {
        Actions = new MyActionList();
    }

public:

    MyActionList* Actions;

    System* GetInstance()
    {
        if (!m_instance)
        {
            m_system = new System();
            m_instance = true;
            return m_system;
        }
        else { return m_system; }
    }
}
// System.cpp
bool System::m_instance = false;
System* System::m_system = NULL;

Of course Actions has slot action() So how can I access MainWindow from System?

2

2 Answers

2
votes

The problem in your approach is the cyclic dependency between MainWindow and System - MainWindow includes System, System includes MainWindow.

In order to pass signals from System to MainWindow you need to make MyActionList of Sytem to emit signals that any receiver (MainWindow in your case) can handle. You absolutely do not need to include MainWindow stuff into the System - keep your backend (System) independent of any GUI component. Just incapsulate System into your MainWindow class and connect MyActionList signals to MainWindow slots. You need to have something like this in your MainWindow:

connect(my_action, SIGNAL(triggered()), System::GetInstance()->Actions, SLOT(action()));
connect(System::GetInstance()->Actions, SIGNAL(systemSignal()), this, SLOT(handleSystemSignal()));

where systemSignal() is a signal emitted from System or its MyActionList component.

1
votes

As @vahancho states, you should keep a separation between the GUI and other systems. Another method to do this would be to introduce a delegate object to handle the communication between the two.

In addition, if you're inlining code as you've shown in your question, then that will increase the possibility of cyclic dependencies. Move the implementation into the .cpp file and use forward declarations instead of including headers in other header files where possible. This also has the benefit of speeding up compilation, which you'll notice with large projects.