Question

We're building a Qt4.8/C++ application (no QML) that will run on an embedded ARM device. This device constantly receives values of a lot of datapoints that need to be held in an object. Now I want to bind UI elements to specific properties of this model object in order to automatically always show the current and up-to-date values in the UI.

Is there a mechanism in Qt that I can use? Or do I have to keep track of any changes and manually update the UI? It would be great if someone could give me a very basic example on how to, for example, data-bind a label text to a double value property of an object. Thanks in advance!

Was it helpful?

Solution

Here is my solution. Let's assume you have some data receiver class and identifiers for your data sources:

enum SourceIds
{
    SourceCamera,
    SourcePort,
    SourceMagic
}

class DataReceiver : public QObject
{
    Q_OBJECT

public:
    DataReceiver(QObject *parent = 0);

    void updateValue(int sourceId, const QVariant &value);

signals:
    void valueChanged(int sourceId, const QVariant &newValue);

private:
    QHash<int, QVariant> data;
};

void DataReceiver::updateValue(int sourceId, const QVariant &value)
{
    QVariant oldValue = data.value(sourceId);

    data[sourceId] = value;

    if (oldValue != value)
    {
        emit valueChanged(sourceId, value);
    }
}

Then you can create a data mapper class that will listen to your receiver valueChanged signal:

class DataMapper : public QObject
{
    Q_OBJECT

public:
    DataMapper(QObject *parent = 0);
    void registerLabel(int sourceId, QLabel *label);

public slots:
    void updateLabel(int sourceId, const QVariant &value);

private:
    QHash<int, QLabel*> labels;
};

void DataMapper::registerLabel(int sourceId, QLabel *label)
{
   labels[sourceId] = label;
}

void DataMapper::updateLabel(int sourceId, const QVariant &value)
{
   QLabel *label = labels.value(sourceId, NULL);
   if (label != NULL)
   {
       label->setText(value.toString());
   }
}

You create a receiver and a mapper objects and connect them:

DataReceiver *receiver = new DataReceiver;

QLabel *cameraLabel = new QLabel;
QLabel *portLabel = new QLabel;
QLabel *magicLabel = new QLabel;

DataMapper *mapper = new DataMapper;
mapper->registerLabel(SourceCamera, cameraLabel);
mapper->registerLabel(SourcePort, portLabel);
mapper->registerLabel(SourceMagic, magicLabel);

connect(receiver, SIGNAL(valueChanged(int, QVariant)), mapper, SLOT(updateLabel(int, QVariant)));

I hope this will be usefull for you.

OTHER TIPS

You might want to use Qt signal/slot mechanism, if you are not concerned with performance. I an example sketch would be:

class MyModel: public QObject
{
    Q_OBJECT
public:
    void setElement(int newValue);
signals:
    void elementUpdated(int newValue);
private:
    int element;
}

void MyModel::setElement(int newValue)
{
    element = newValue;
    emit elementUpdated(newValue);
}

Then you can connect this signal to a slot on you QMainWindow and update the corresponding label in it.

If the number of updates is more than a few per second, perhaps it is better to look at the problem backwards: Instead of changing QLabel text on every update, use a QTimer to update the QLabel text on a periodic interval.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top