PDA

View Full Version : Cannot access QSystemTrayIcon object of MainWindow class from other classes



rgarnett
18th April 2020, 06:08
Hi,

The purpose of my program is to run all the time and update a real time sqlite db with half hour aggregates of the raw 2 second data.

The program has the following elements


simple gui which can be minimized to the windows system tray which has a context menu attached to it.




database update class that provides for all of the db functions which are controlled by a worker object with the main
process being an infinite loop with a wait function that provides sets the loop repeat time.


There is no requirement for multiple objects of any class as only one instance of any class is required at a time.

The program works fine for the core functionality with all of the database functions ok. The system tray and the minimize to tray and restore functions are all sweet.

The problem:

I use the system tray object message system to bring up notifications of the programs state such as database update running/stopped.
When I try and reference this function from the MainWindow class I get a compile error:




void MainWindow::dbErrorNotifyTray(QString TitleSuffix,
QString MessageSuffix,
int errNumber)
{ ...

if(mSystemTrayIcon->isVisible()) error: invalid use of member in static member function
mSystemTrayIcon->showMessage(nRec.MainHeading, nRec.Message, error: invalid use of member in static member function
QIcon(nRec.IconURLPath),
2000);
...
}


My header file for the MainWindow class mainwindow.h

is shown below. The function definition for the dbErrorNotifyTray method is found on line 50.

mainwindow.h


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QObject>
...

#include <QSystemTrayIcon>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QCloseEvent>


QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

protected:
void closeEvent(QCloseEvent *event) override;

signals:
void startWork_mwSig();
void stopWork_mwSig();

private slots:
void on_pbStartThread_clicked();
void on_pbStopThread_clicked();
void dbErrorFcn_Slot(QString errstr);

void on_actionClose_triggered();

void on_actionAbout_Energy_Server_triggered();

void createTrayIconAndMenu();
void createTrayActions();

public:
static void dbErrorNotifyTray(QString TitleSuffix,
QString MessageSuffix,
int errNumber);
public:
Ui::MainWindow *ui;
QSystemTrayIcon *mSystemTrayIcon;

private:
QMenu *trayIconMenu;
QAction *minimizeAction; ...


worker *myWorker;
QThread *threadSQL;
bool closing;

...
};

#endif // MAINWINDOW_H



The MainWindow implementation file which contains the problem code is shown below with the code producing the compile error on lines 68 and 69
mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dbupdate.h"

class Sleeper : public QThread
{
public:
...
};


MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

createTrayActions();
createTrayIconAndMenu();

ui->pbStopThread->setEnabled(false);
ui->pbStartThread->setEnabled(true);

myWorker = new worker();
threadSQL = new QThread;

myWorker->moveToThread(threadSQL);
threadSQL->start();
threadSQL->setPriority(QThread::NormalPriority);

connect(this, SIGNAL(stopWork_mwSig()), myWorker, SLOT(StopWorkFcn()));
connect(this, SIGNAL(startWork_mwSig()), myWorker, SLOT(StartWorkFcn()));
connect(myWorker, SIGNAL(error_dbTaskSig(QString)), this, SLOT(dbErrorFcn_Slot(QString)));
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_pbStartThread_clicked()
{
...


void MainWindow::closeEvent(QCloseEvent *event)
{
if(mSystemTrayIcon->isVisible())
mSystemTrayIcon->showMessage("Power Monitor Energy Server",
"Minimized to system tray.",
QIcon(":/images/bluewren9mmhrBlackOnGreyNotRunning.png"),
2000);
if(closing)
{
...
}

void MainWindow::dbErrorNotifyTray(QString TitleSuffix,
QString MessageSuffix,
int errNumber)
{
typedef struct
{
...
} noteRecord_t;
...

if(mSystemTrayIcon->isVisible())
mSystemTrayIcon->showMessage(nRec.MainHeading, nRec.Message,
QIcon(nRec.IconURLPath),
2000);
NOTIFY_ERROR:
db.close();
}

void MainWindow::createTrayIconAndMenu()
{
mSystemTrayIcon = new QSystemTrayIcon(this);
mSystemTrayIcon->setIcon(QIcon(":/images/bluewren9mmhrBlackOnGreyNotRunning.png"));
mSystemTrayIcon->setVisible(true);
mSystemTrayIcon->setToolTip("Power Monitor Energy Server");
trayIconMenu = new QMenu(this); ...

...
mSystemTrayIcon->setContextMenu(trayIconMenu);
}

void MainWindow::createTrayActions()
{
...
}
...


The compiler is complaining about using the mSystemTrayIcon object in a static function, however if I make the function non-static:

void dbErrorNotifyTray(QString TitleSuffix,
QString MessageSuffix,
int errNumber);

then i get a compile error in my dbupdate class:

MainWindow::dbErrorNotifyTray("", "", errNumber);


error: cannot call member function 'void MainWindow::dbErrorNotifyTray(QString, QString, int)' without object
MainWindow::dbErrorNotifyTray("", "", errNumber);


The header file for the dbupdate class and the first part of the implementation are shown below:
dbupdate.h

#ifndef DBUPDATE_H
#define DBUPDATE_H


#include <QObject>
...
#include "mainwindow.h"


typedef struct
{...
} energyRecord_t;

typedef struct
{...
} energyRecInput_t;

...

class dbupdate : public QObject
{
Q_OBJECT
public:
explicit dbupdate(QObject *parent = nullptr);

signals:
void sendMsgToNotify(QString TitleSuffix,
QString MessageSuffix,
int errNumber);

private slots:

static bool agregateData();
...

static QString dbErrorHandler(QString errStr,
QSqlError eQuery,
QSqlError eEnergyDb,
QSqlError ePMonDb,
int errNumber,
bool returnErrString);
...

public slots:
static double getNextHalfHourTimeFromClock();
...

public:
static QSqlDatabase dbPMon;
static QSqlDatabase dbEnergy;
double nextHalfHourClock;
double nextHalfHourDB;
};

#endif // DBUPDATE_H


The implementation of the dbupdate (just the first part) is shown below
dbupdate.cpp

#include "dbupdate.h"
#include "juliandate.h"
#include "mainwindow.h"
#include <QSystemTrayIcon>

#ifndef STR_EQUAL
#define STR_EQUAL 0
#endif

#ifndef PRAGMA_OK
#define PRAGMA_OK "ok"
#endif

QSqlDatabase dbupdate::dbPMon;
QSqlDatabase dbupdate::dbEnergy;


/*------------------------------------------------------------------------------------------------------*/
dbupdate::dbupdate(QObject *parent) : QObject(parent)
{

}
...


So I am between a rock and a hard place. I have spent five days trying to get this to work, I've also tried using signals and slots, but I always end up with the same issue of one class.

I was almost tempted to use global variables and a timer running as an object of the Main Window, but I thought this to be something that even an embedded c programmer like myself wouldn't do.

I think my problem is caused by not constructing an instance of one of the classes, but although I have tried this I haven't been able to get this to work.

Most of the examples given about C++ Qt C++ only provide trivial examples which don't seem to bear much relationship with more complex code.

Can anyone suggest how I might tackle this problem as I am at a complete standstill.

I have attached a zip of the project to assist. Some files such as images and the databases are deleted as they make the file too large.