Qt Model and View - Link data from model to view, how? - qt

I'm pretty new to the Model and View concept and I'm having trouble finding the right way to do this. So in my understanding the concept means, that I have one class that handles all the view (GUI) parts and an other class which handles the data processing.
The GUI I made has a few Display Widgets (LCDnumbers) which just have to get data from the other class and output it into the LCD.
So I made a function in the GUI class which can set a number into the LCD. And I've made a function which can change the value of the number in the data class.
Now I need something to connect those, for example when I change the number in the data class I want it to update in the GUI. I found somethings about Signals and Slots (and emitting a signal) but how does that work, while maintaining the Model and View concept?
It could be that this is answered somewhere else, if so, can you link me the source? I couldn't find anything to solve my problem.
Thanks for reading and I hope someone can help me.
Header file of the GUI:
#include <QMainWindow>
#include <QtCore>
namespace Ui {
class MainBoardView;
}
class MainBoardView : public QMainWindow
{
Q_OBJECT
public:
explicit MainBoardView(QWidget *parent = 0);
~MainBoardView();
void ChangeNumber(int value);
private:
Ui::MainBoardView *ui;
};
CPP file of the GUI:
#include "mainboardview.h"
#include "ui_mainboardview.h"
MainBoardView::MainBoardView(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainBoardView)
{
ui->setupUi(this);
}
MainBoardView::~MainBoardView()
{
delete ui;
}
void MainBoardView::ChangeNumber(int value)
{
ui->lcdNumber->display(value);
}
Code of the data class:
Header:
class MainBoard
{
public:
MainBoard();
void changeMoney(int value);
private:
int m_money;
}
CPP:
void MainBoard::ChangeMoney(int value)
{
m_money = value;
//emit a signal here with the value to the ChangeNumber function of the GUI?
//and how should I do this?
}

For applying model/view concept of Qt you should use at least one of a model classes. Such model classes provide unified interface for several types of data (string-list, trees, sql, etc.)
For displaying the data one would use either a view-class or widgets connected to the model via QDataWidgetMaper
In your case there is no use of model/view observable. MainBoard should be QObject for emitting the signal:
class MainBoard: public QObject
{
Q_OBJECT
public:
MainBoard();
void changeMoney(int value); //emit value with emit moneyChanged(value) in the implementation.
signals:
void moneyChanged(int)
private:
int m_money;
}

Related

QTextBrowser for Helper

I am trying to make a helper with QTextBrowser. As I understood, home(), backward() and forward() are already implemented in QTextBrowser and required only connections to the buttons. Below there is .h and .cpp files
#ifndef HELPWINDOW_H
#define HELPWINDOW_H
#include <QDialog>
namespace Ui {
class HelpWindow;
}
class HelpWindow : public QDialog
{
Q_OBJECT
public:
explicit HelpWindow(QWidget *parent = 0);
~HelpWindow();
private slots:
private:
Ui::HelpWindow *ui;
};
#endif // HELPWINDOW_H
and
#include "helpwindow.h"
#include "ui_helpwindow.h"
HelpWindow::HelpWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::HelpWindow)
{
ui->setupUi(this);
// connection
connect(ui->pushButton_home,SIGNAL(clicked()),ui->textBrowser,SLOT(home()));
connect(ui->pushButton_forward,SIGNAL(clicked()),ui->textBrowser,SLOT(forward()));
connect(ui->pushButton_backward,SIGNAL(clicked()),ui->textBrowser,SLOT(backward()));
}
HelpWindow::~HelpWindow()
{
delete ui;
}
There is no any error message. It is possible to read and click the links inside QTextBrowser. Only there are no any actions with buttons. What do I miss here?
You need to call either one or both of the following properties
ui->textBrowser.setOpenLinks(true);
ui->textBrowser.setOpenExternalLinks(true);
and if you want filter or re-route the links at runtime
connect(ui->textBrowser, SIGNAL(sourceChanged(QUrl)), pointerToYourCode, SLOT(slotSourceChanged(QUrl)));
and implement
void YourCode::slotSourceChanged(const QUrl& url) {...}
I found why it did not work. The initial source should be specify:
ui->textBrowser->setSource(QUrl::fromLocalFile("help/index.html"));
Thank you, Jens for spending time.

Connection of pure virtual signal of interface class

I want to connect some object's signals derived from an interface class.
The connection is done in QWidget::listenToAnimal(AnimalInterface*).
This does not work because qt_metacall is not a member of 'AnimalInterface' and static assertion failed: No Q_OBJECT in the class with the signal.
Of course AnimalInterface does not have the Q_OBJECT macro and does not inherit QObject because it is an interface...
I want to connect through the interface class because I do not want to manually retype the same code for Cat and for Dog.
Is it possible to connect the signal the way I want to? Perhaps with templates? Is this perhaps a lambda-specific problem?
header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class AnimalInterface{
public:
virtual ~AnimalInterface();
virtual void makeSound() = 0;
/*signals*/
virtual void madeSound() = 0;
};
Q_DECLARE_INTERFACE(AnimalInterface,"interface")
class Dog : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Cat : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Widget : public QWidget
{
Q_OBJECT
Cat *cat_;
Dog *dog_;
public:
Widget(QWidget *parent = 0);
~Widget();
void listenToAnimal(AnimalInterface *animal);
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
dog_ = new Dog;
cat_ = new Cat;
listenToAnimal(dog_);
listenToAnimal(cat_);
dog_->makeSound();
cat_->makeSound();
}
void Widget::listenToAnimal(AnimalInterface *animal)
{
connect(animal, &AnimalInterface::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
Widget::~Widget()
{
}
void Cat::makeSound()
{
qDebug()<<"Cat says miaow";
emit madeSound();
}
void Dog::makeSound()
{
qDebug()<<"Dog says wuff";
emit madeSound();
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Since you know the derived type at compile type, you can connect to the proper, statically-known QObject-derived type. No need for dynamic casting or anything of the sort. You just don't want the listenToAnimal method to be available for non-AnimalInterface-inheriting types, though, even if it they have a compatible madeSound method:
C++11
#include <type_traits>
template< class T,
typename =
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value>::type >
void listenToAnimal(T * animal) {
connect(animal, &T::madeSound, this, []{ qDebug() << "animal made sound"; });
}
C++03
template <class T>
void listenToAnimal(T * animal) {
Q_UNUSED(static_cast<AnimalInterface*>(animal));
connect(animal, &T::madeSound, this, &Widget::onAnimalMadeSound);
}
You can then use it without having to spell out the type - it's already known to the compiler:
listenToAnimal(dog_);
listenToAnimal(cat_);
If the derived type is not known at compile time, you have to dynamically cast to QObject and connect by name, not by method pointer. It will assert at runtime if you've passed in a wrong type - after all, it's not enough for it to be an instance of AnimalInterface, it also needs to be a QObject instance.
void listenToAnimal(AnimalInterface * animal) {
auto object = dynamic_cast<QObject*>(animal);
Q_ASSERT(object);
connect(object, SIGNAL(madeSound()), this, SLOT(onAnimalMadeSound()));
}
The fact that the type AnimalInterface has a virtual madeSound method is somewhat relevant - it guarantees that the derived class implements the method with such a signature. It doesn't guarantee that the method is a signal, though. So you should probably rethink your design and ask yourself: "What do I gain by using a static type system when I can't really use it for static type checking"?
Most likely you should make any methods that would nominally accept the AnimalInterface*, be parametrized and take a pointer to the concrete class. Modern code generators and linkers will deduplicate such code if type erasure leads to identical machine code.
Found a solution with templates. Did not work the first time I tried, obviously did something wrong first. Here it goes...
Just replace the corresponding parts from the example in the question (and remove definition of listenToAnimal from the source file):
header:
template<class T>
void listenToAnimal(AnimalInterface *animal)
{
T *animal_derivate = dynamic_cast<T*>(animal);
if (animal_derivate){
connect(animal_derivate, &T::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
}
cpp:
listenToAnimal<Dog>(dog_);
listenToAnimal<Cat>(cat_);
Update:
After trying Kuba Ober's answer, it seems like this is working best now:
template<typename T>
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value,void>::type
listenToAnimal(T *animal)
{
connect(animal, &T::madeSound, this, [](){ qDebug()<<"animal made sound"; });
}
However, the one point still not working is how to connect if I create an animal like AnimalInterface *bird = new Bird, because it throws the same error that the base class does not have the signal.

Get rid of god object of QMainWindow

I am making an application with three libraries ITK VTK and Qt. Since I want all functionality in the event loop and connection of signals and slots so I defined all functionality under QMainWindow definition. Now mainwindow object became bulky and I tried to make different classes for different functionality but then all things messing in main.cpp Idea of modularization is missing. Can you suggest how should be structure of a program?
I rarely have anything more in main.cpp than creating and showing my QMainWindow, then calling app.exec().
If your QMainWindow starts to become bulky, then it means you should probably organize this code into different coherent classes (instead of moving it to main.cpp). The basic idea is to change a code that looks like this:
class MainWindow : public QMainWindow
{
public:
void doSomething();
void foo1();
void foo2();
void foo3();
void bar1();
void bar2();
void bar3();
private:
// ...
}
To a code that looks like this:
class Foo:
{
public:
void doSomething1();
void doSomething2();
void doSomething3();
private:
// ...
}
class Bar:
{
public:
void doSomething1();
void doSomething2();
void doSomething3();
private:
// ...
}
class MainWindow : public QMainWindow
{
public:
void doSomething();
private:
Foo foo_;
Bar * bar_;
// ...
}
How do you choose the classes Foo and Bar and which members of MainWindow you transfer to these new classes depends of course of your context. But the idea is to organize your code smartly so that each class have a "responsibility", and then MainWindow can delegate each work to the class that is responsible for this work. Like in a house, there are electricians for managing electricity, plumbers for managing water, etc... and the responsibility of the house keeper is only to call the appropriate guys to do the appropriate job. In your case, you probably want a class to perform any work related to ITK, and a class to perform any work related to VTK, then if they become bulky also, subdivide these classes.

SIGSEGV with QMainWindow singleton

The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!

Qt subclassing from QWidget

I write my own class which subclass from QWidget
And this is my header file
#ifndef GRAPHMATRIX_H
#define GRAPHMATRIX_H
#include "treemodel.h"
#include <QWidget>
#include <Qt/qtableview.h>
class GraphMatrix : public QWidget
{
Q_OBJECT
public:
TreeModel& getModel();
GraphMatrix(QWidget* parent = 0);
void addTop(QString name);
void cutComponent(GraphMatrix* component, QVector<int> columns);
private:
TreeModel model;
QTableView* view;
public slots:
void changeValue(const QModelIndex& index);
};
#endif // GRAPHMATRIX_H
And I am getting this error
error C2248: 'QWidget::QWidget' : cannot access private member declared in class 'QWidget'
Can anyone help me?
Updated to add: I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem
It looks like you are trying to call the default constructor of QWidget which is private. Instead, your constructor needs to call the public constructor of QWidget as follows:
GraphMatrix::GraphMatrix(QWidget* parent) : QWidget(parent) {}
I find answer, problem is in QList I must write QList. because QList is using copy constructor. Thank you for giving time for my problem

Resources