PDA

View Full Version : Subclassed QLabel won't update the model



panoss
20th February 2017, 15:42
I have subclassed a QLabel in order to add the ability to connect to a database field through a QDataWidgetMapper.


This is my class' header:


#ifndef IMAGELABEL_H
#define IMAGELABEL_H

#include <QWidget>
#include <QLabel>
#include <qdebug.h>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDebug>
#include <QPixmap>

class ImageLabel : public QLabel
{
Q_OBJECT
Q_PROPERTY(QString Imagetext READ imagetext WRITE setImagetext NOTIFY imagetextChanged)

public:
ImageLabel(QWidget *parent = 0);

QString Imagetext;

void setImagetext(QString newValue);
QString imagetext();


signals:
void imageDropped(QString file);
void imagetextChanged(QString file);

public slots:


protected:
void dropEvent(QDropEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dragLeaveEvent(QDragLeaveEvent *event) override;

private:
QString m_imagetext;
};

#endif // IMAGELABEL_H




This is the source:


#include "imagelabel.h"

ImageLabel::ImageLabel(QWidget *parent) :
QLabel(parent)
{
setAcceptDrops(true);
m_imagetext="";
}


void ImageLabel::dropEvent(QDropEvent *event)
{
const QMimeData *mimeData = event->mimeData();

if (mimeData->hasImage()) {
setPixmap(qvariant_cast<QPixmap>(mimeData->imageData()));
} else if (mimeData->hasHtml()) {
setText(mimeData->html());
setTextFormat(Qt::RichText);
} else if (mimeData->hasText()) {
setText(mimeData->text());
setTextFormat(Qt::PlainText);

// remove string "file:///" from mimeData->text()
QString subStr = QLatin1String("file:///");
QLatin1String newStr = QLatin1String("");
QString mimeDataText = QString(mimeData->text().replace(mimeData->text().indexOf(subStr), subStr.size(), newStr));

setImagetext(mimeDataText);
emit imageDropped(mimeDataText);

} else if (mimeData->hasUrls()) {
QList<QUrl> urlList = mimeData->urls();
QString text;
for (int i = 0; i < urlList.size() && i < 32; ++i)
text += urlList.at(i).path() + QLatin1Char('\n');
setText(text);
} else {
setText(tr("Cannot display data"));
}

setBackgroundRole(QPalette::Dark);
event->acceptProposedAction();

}

void ImageLabel::dragEnterEvent(QDragEnterEvent *event)
{
setBackgroundRole(QPalette::Highlight);
event->acceptProposedAction();
}

void ImageLabel::dragMoveEvent(QDragMoveEvent *event)
{
event->acceptProposedAction();
}

void ImageLabel::dragLeaveEvent(QDragLeaveEvent *event)
{
clear();
event->accept();
}

void ImageLabel::setImagetext(QString newValue)
{
m_imagetext = newValue;

if(!m_imagetext.isEmpty()){
QPixmap pixmap(m_imagetext);
pixmap = pixmap.scaled(width(), height(), Qt::KeepAspectRatio);
setPixmap(pixmap);
}else{
clear();
}
emit imagetextChanged(m_imagetext);
}
QString ImageLabel::imagetext()
{
return m_imagetext;
}




It's mapped through my custom property "Imagetext":


mapper->addMapping(ui.photo_lbl, photoIndex, "Imagetext");


I works normally, it displays the images as expected.
But, in order to be saved in the model, I have to do it 'manually':
When an image is dropped, the label sends a signal named 'imageDropped'.

I use this signal to save the new value of the image path in the model:



connect(ui.photo_lbl,SIGNAL(imageDropped(QString)) ,this, SLOT(setModelPhoto(QString)));
.....................
void RepairDevices::setModelPhoto(QString file)
{
model->setData(model->index(mapper->currentIndex(), photoIndex), file);
}



So I set the model 's data this way.
But, shouldn't, automatically, the new value of the field to be saved in the model? Like every other field?

Obviously, I've done something wrong, that's why it's not auto-saved in the model.
How can I fix this?

d_stranz
20th February 2017, 19:36
I don't understand your problem. A QLabel is just a label. It doesn't know anything about models; likewise, a model knows nothing about where (or how) its content is displayed if anywhere. So if you want a change in the label that occurs through some user interaction to be saved in the model, you have to connect up the proper signals and slots (probably by writing your own, as you have done) to do that. Likewise, if your model is changed and you want to display a new photo on the label, you have to do the same thing from the other direction.

panoss
20th February 2017, 21:13
I don't understand your problem. A QLabel is just a label.
And a QPlainTextEdit is just a textbox.
But, when it's text changes, it's new content is saved in the model, without having to use model->setData.
This same behavior I want for my subclassed QLabel.

d_stranz
21st February 2017, 03:43
And a QPlainTextEdit is just a textbox.

No it isn't. It is a QWidget-based class designed for displaying and editing the contents of a QTextDocument. The interaction between the widget and its document are in the implementation of the class, and it is that implementation which results in the document's content being updated as it is being edited and the text edit's display likewise being updated if the document is changed programmatically.

Have you looked at the QLabel documentation? Do you see anything like a "QLabelDocument" or "QLabelModel" which serves the same purpose? Of course not, because there is no such thing. If you want a relationship between a QLabel and some QAbstractItemModel-based class, you have to write it yourself as well as write all the code needed to keep the model and label synchronized as you wish. From what you posted, it looks like you have pretty much done that.

Santosh Reddy
21st February 2017, 05:15
https://bugreports.qt.io/browse/QTBUG-10672

d_stranz
21st February 2017, 16:25
https://bugreports.qt.io/browse/QTBUG-10672

I see that I misunderstood the OP's use of the QDataWidgetMapper. Thanks for pointing out this bug report so I could learn yet another new thing about Qt.