strategy for structuring app
-
Hi
Please bear with me, I'am still a bloody C++/Qt beginner even if I already created some minor apps
just for fun and home use.But I always stumble upon the same difficulty... How shall I structure
my app if there is more that one window in it and data needs to be send
between the two windows.
My current goal is to have three classes: a main-mainwindow and a second mainwindow that has as centralwidget a custom derived QChartView. I want to override
a mouse move event in the QChartView and send the current mouse position to a QLabel the main-mainwindow.Now I have two ideas in my mind to exchange the data.
First, to send it via Signals&Slots and second, to implement setter/getter
methods between the main-mainwindow and the QChartview class.Now for the latter, how would you do this (if at all)?
Is it possible that I create a setter method in my mainwindow
that sets a QLabel's text. Now from the QChartview class if a mouseMoveEvent occurs I call somehow the setter method of my mainwindow
and pass over the mouseposition? But I cannot access my mainwindows object
in main.cpp:
MainWindow w.setLabel(QString mousepos)
from inside the QChartView class?
Where is my fallacy?I usually start with with "New Project->Application->Qt-Widget Application".
Then I have my mainwindow.h/cpp that gets created in the main.cpp (as MainWindow w;). Then I do it usually wrong by implementing any additional windows inside the mainwindow class and then I wonder why I cant use a setter method in the mainwindow class from the other window.Where should i create the second mainwindow object and where the Qchartview (as centralwidget)? Should I do it in main.cpp besides the MainWindow w; so that it acts as a third point where I can use the setter/getter methods of off all the three classes?
Or should I completly drop this setter/getter methods idea and use
signal and slots? -
Hi
Often using signals and slots makes a better design as you get better
encapsulation than using get/setter since the "other" window do not need to know anything about
the receivers of the signals.
So for your Chart you could define a new signal
void MousePos( QString mousepos ); // (signals have no bodies)and for mainwindow , define new slot ( both in .h and body in .cpp)
void MainWindow::MousePos( QString mousepos ) {
ui->label->setText(mousepos );
}and in main.cpp hook that up to a slot in mainwindow
(assuming you new the QChart widget there.)
connect(ChartWinPointer, SIGNAL(MousePos( QString)) , &w, SLOT(MousePos( QString ) ) );and in mouseMove in QChart child
void xxx::mouseMove(xx) {
QString mp;
mp=xxxx; // convert to text
emit MousePos(mp);// tell mainwin ( or what else ever u hook up)
}This way, none of the objects in question need to know much of each other. The QChart will simply emit info to the world
and what ever class that hooks up a slot to the signal will get informed.
Its very much like a setter in mainwindow, but free from types of the setter holder and more generic as
you can have multiple slots connected and all get the string. You could hook up something else than the first mainwindow by
simply giving it a slot that matches.So there is no real fallacy here, just that Qt offer a nice way to allow unrelated objects to communicate in a
generic way and it will in most cases just work better in the long run than directly calling a other windows functions.
But since its not (included in) normal c++, it takes some practice to start thinking in terms of signals and slots. -
It works!
I did it all from scratch and didn't use the templates.
But I did not wrote anything else to main.cpp than what
is needed for my mainwindow.main.cpp
#include <QApplication> #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication app(argc,argv); MainWindow w; w.show(); return app.exec(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QWidget> #include <QMainWindow> #include <QLineSeries> #include <QChart> #include <QChartView> #include <QLabel> class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); private: QMainWindow *chartWindow; QLabel *labelMouse; signals: public slots: void MousePos(QString mp); }; #endif // MAINWINDOW_H
mainwondow.cpp
#include "mainwindow.h" #include "mychartview.h" MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { this->setWindowTitle("Mainwindow"); this->resize(100,100); chartWindow = new QMainWindow(this); chartWindow->setWindowTitle("Chartwindow"); QChart *chart = new QChart(); QLineSeries *series = new QLineSeries(); series->append(1,2); series->append(2,4); series->append(3,5); series->append(4,7); chart->addSeries(series); chart->createDefaultAxes(); MyChartView *chartView = new MyChartView(chart); chartWindow->setCentralWidget(chartView); chartWindow->show(); chartWindow->move(30,30); labelMouse = new QLabel("n/a",this); labelMouse->setStyleSheet("font-size:14pt;"); labelMouse->resize(100,50); connect(chartView,&MyChartView::mousePos,this,&MainWindow::MousePos); } void MainWindow::MousePos(QString mp) { labelMouse->setText(mp); }
mychartview.h
#ifndef MYCHARTVIEW_H #define MYCHARTVIEW_H #include <QObject> #include <QChartView> QT_CHARTS_USE_NAMESPACE class MyChartView : public QChartView { Q_OBJECT public: explicit MyChartView(QChart *chart, QWidget *parent = nullptr); protected: void mouseMoveEvent(QMouseEvent *event)override; signals: void mousePos(QString mp); }; #endif // MYCHARTVIEW_H
mychartview.cpp
#include "mychartview.h" MyChartView::MyChartView(QChart *chart, QWidget *parent) :QChartView(chart, parent) { } void MyChartView::mouseMoveEvent(QMouseEvent *event) { QString xpos = QString::number(event->pos().x()); QString ypos = QString::number(event->pos().y()); QString mpos = xpos + "," + ypos; emit mousePos(mpos); }
I can now see the x,y position of my mouse in the QChartview.
My ultimate goal is to be able to somehow select an x range from the QLineSeries with the mouse and send the selected x-range to my mainwindow. I currently have no idea how to do that but I will do search, maybe someone already has done that.