I have a list of functions with parameters. For each parameter I create a spinbox holding its value. Some functions have zero parameters others have n>1 parameters.
The code looks like this (simplified)
for (int i = 0; i < parameterList.size(); ++i) {
QString valueName = parameterList().at(i);
double value = parameter(valueName);
QDoubleSpinBox * spinbox = new QDoubleSpinBox();
QLabel * label = new QLabel();
label->setText(valueName);
spinbox->setValue(value);
// does NOT work, Slot need three parameters!
QObject::connect(spinbox, &QDoubleSpinBox::valueChanged,
this, &OnAmplitudeParameterChanged);
... add widgets to layout
}
However the slot needs to know which widgets was calling, the parameter name and its value. The signal however provides only a value.
The slot looks like this
OnAmplitudeParameterChanged(int index, QString name, double value)
How is this solved in Qt? I found a QSignalMapper class but not how this would solve my problem.
I would use a little lambda for that
auto func = [i, valueName, this](double value){
OnAmplitudeParameterChanged(i, valueName, value);
};
QObject::connect(spinbox, &QDoubleSpinBox::valueChanged, func);
EDIT
Jon Harper's answer inspired me to use the QObject::setProperty() as another interesting solution:
QDoubleSpinBox* spinbox = new QDoubleSpinBox();
spinbox->setProperty("myindex", i);
spinbox->setProperty("myname", valueName);
and then in your slot:
void SomeClass::OnAmplitudeParameterChanged(double value)
{
int index = sender()->property("myindex").toInt();
QString name = sender()->property("myname").toString();
}
But still, I would probably use the lambda anyway.
To expand on Wiki Wang's answer, use the combination of sender(), qobject_cast and the spinbox's object name:
In your code:
QString valueName = parameterList().at(i);
double value = parameter(valueName);
QDoubleSpinBox * spinbox = new QDoubleSpinBox();
spinbox->setObjectName(valueName);
Then in the slot:
void SomeClass::OnAmplitudeParameterChanged(double value)
{
QDoubleSpinBox *spinbox = qobject_cast<QDoubleSpinBox *>(sender());
if (spinbox && parameterList.contains(spinbox->objectName()) {
int value = parameter(spinbox->objectName());
// your code here
}
}
You can use QObject::sender() to get the caller spinbox in the slot function.
QDoubleSpinBox *spinbox = static_cast<QDoubleSpinBox *>(QObject::sender());
Related
I have a QTableWidget that is made up of two columns: Diameters and Areas
I inserted QDoubleSpinBoxes into every cell. When I enter data into one, I want to be able to detect that and automatically generate the area using the value I inserted in the corresponding cell.
So how exactly do I send a signal when I changed the value of a diameter at a certain row, to the function to calculate the area using that diameter and then update the cell right next to it in the Area column on the same row with that value calculated?
QObject::connect(TabUI.tableWidget,SIGNAL(cellChanged()), this, SLOT(CalculateArea()));
void Pressurator::CalculateArea()
{
// QTableWidgetItem * item = new QTableWidgetItem;
// double area = 0;
// QDoubleSpinBox * diameter_SB = static_cast<QDoubleSpinBox*>(TabUI.tableWidget->cellWidget(item->row(),0));
// QDoubleSpinBox * area_SB = static_cast<QDoubleSpinBox*>(TabUI.tableWidget->cellWidget(item->row(),1));
// area = M_PI * qPow(diameter_SB->value()/2, 2);
// area_SB->setValue(area);
qDebug()<<"DETECTED";
}
This is where the QTableWidget is generated:
void Pressurator::NozzleCount()
{
int nozzleCount = TabUI.nozzlesNum_SB->value();
// QDoubleSpinBox * nozzleD_A_SB = new QDoubleSpinBox;
// nozzleD_A_SB->setRange(0,10000);
TabUI.tableWidget->setColumnCount(3);
TabUI.tableWidget->setRowCount(nozzleCount);
QStringList labels = {"Diameter","Area","Type"};
TabUI.tableWidget->setHorizontalHeaderLabels(labels);
// QHeaderView* header = TabUI.tableWidget->horizontalHeader();
// header->setSectionResizeMode(QHeaderView::Stretch);
for(int i=0 ; i< nozzleCount; i++)
{
QDoubleSpinBox * ND_SB = new QDoubleSpinBox;
QDoubleSpinBox * NA_SB = new QDoubleSpinBox;
QComboBox * nozzleType = new QComboBox;
ND_SB->setDecimals(5);ND_SB->setRange(0,500);
NA_SB->setDecimals(5);NA_SB->setRange(0,500);
nozzleType->addItems(nozzleTypesList);
TabUI.tableWidget->setCellWidget(i,0, ND_SB);
TabUI.tableWidget->setCellWidget(i,1, NA_SB);
TabUI.tableWidget->setCellWidget(i,2, nozzleType);
}
}
If you call setCellWidget, you won't get cellChanged signal from QTableWidget. You have to connect the QDoubleSpinBoxes's valueChanged signal. If you have bigger and dynamic table using ItemDelegates will better.
Also Qt has an example for QSpinBox delegate and it has a disadvantage if you use the code out of the box. The disadvantage is If you change the spinbox's value, the QTableWidget's cellChanged signal won't emit until press enter or click other cell.
If you want emit signal immediately you have to add this connection into createEditor function before return statement:
connect(editor, QOverload<decltype(editor->value())>::of(&QSpinBox::valueChanged), [=](auto val){
auto ptr = const_cast<SpinBoxDelegate*>(this);
emit ptr->commitData(editor);
});
I'm working on the following Window with QT:
For my rows i have the following structure:
typedef struct
{
struct{
int x;
int y;
int width;
int height;
int layer;
int idx;
}outputSettings;
QDoubleSpinBox *xSpinBox;
QDoubleSpinBox *ySpinBox;
QDoubleSpinBox *heightSpinBox;
QDoubleSpinBox *widthSpinBox;
QDoubleSpinBox *layerSpinBox;
// Checkboxes
QCheckBox *channelCheckBox;
}myUI;
QVector<myUI> inputBoxes; // Create a row of input boxes per channel
I then create them in a for loop:
for(i = 0; i < inputChannels; ++i)
{
inputBoxes[i].channelCheckBox = new QCheckBox;
inputBoxes[i].channelCheckBox->setChecked(true);
inputBoxes[i].xSpinBox = new QDoubleSpinBox;
inputBoxes[i].xSpinBox->setRange(minXPos, maxXPos);
inputBoxes[i].xSpinBox->setSingleStep(1);
inputBoxes[i].xSpinBox->setValue(0);
inputBoxes[i].xSpinBox->setDecimals(0);
connect(inputBoxes[i].xSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setXValue(double)));
inputBoxes[i].ySpinBox = new QDoubleSpinBox;
inputBoxes[i].ySpinBox->setRange(minYPos, maxYPos);
inputBoxes[i].ySpinBox->setSingleStep(1);
inputBoxes[i].ySpinBox->setValue(0);
inputBoxes[i].ySpinBox->setDecimals(0);
connect(inputBoxes[i].ySpinBox, SIGNAL(valueChanged(double)), this, SLOT(setYValue(double)));
...
Now i get stuck on the connect. I want to connect the valueChanged property of my spinboxes to my outputSettings struct. This struct will be my return type at the end.
I implemented the following slots:
public slots:
void setXValue(double x){inputBoxes[0].outputSettings.x = int(x);}
void setYValue(double y){inputBoxes[0].outputSettings.y = int(y);}
...
But here i don't know what vector item called the function. (currently i just entered inputBoxes[0] as a dummy)
My first idea was to add an extra parameter int channel. But then the connect doesn't work. So i tried to work around that with QMapper. But that doesn't seem to be a good option to me and i didn't really get it running.
I would largely appreciate if someone could help me out here or at least point me in the right direction.
Cheers.
Implement it by using a lambda function in your connect
connect(inputBoxes[i], static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
[i](double value)
{
// use i as your vector index here
handleDoubleSpinBoxChanged(i, value);
});
Then you can change your slot function to
void handleDoubleSpinBoxChanged(int i, double value)
{
inputBoxes[i].outputSettings.x = int(x);
}
Second option is to get the spin box index from the sender object
you will have to store it first inside your loop
inputBoxes[i].xSpinBox->setProperty("index",i);
Then you can get it
void MainWindow::setXValue(double d)
{
QDoubleSpinBox * sb = qobject_cast<QDoubleSpinBox *>(QObject::sender());
int iCallerVectorIndex = -1;
if (sb != Q_NULLPTR)
{
iCallerVectorIndex = sb->property("index").toInt(); // to get the caller index.
}
}
If I got you right, in your SLOT method you can call sender() to retrieve the object who emitted the signal. You can compare in a loop the spinBoxes of each of your inputBoxes to find out what caused the SLOT to execute, something like:
// in your SLOT method:
for (int i = 0; i < inputChannels; i++){
if (inputBoxes[i].xSpinBox == (QDoubleSpinBox *)sender()){
// the xSpinBox of the i-th inputBox emitted the signal
break();
}
}
You can also just make myUI a QObject and add slot function there.
You wouldnt need any indexes then.
typedef struct
{
Q_OBJECT
struct{
int x;
int y;
int width;
int height;
int layer;
int idx;
}outputSettings;
QDoubleSpinBox *xSpinBox;
QDoubleSpinBox *ySpinBox;
QDoubleSpinBox *heightSpinBox;
QDoubleSpinBox *widthSpinBox;
QDoubleSpinBox *layerSpinBox;
// Checkboxes
QCheckBox *channelCheckBox;
public slots:
setXValue(double);
setYValue(double);
}myUI;
Example of connect call:
connect(inputBoxes[i].ySpinBox, SIGNAL(valueChanged(double)), inputBoxes[i], SLOT(setYValue(double))
or you can call connect in constructor of myUI:
myUI() {
connect(xSpinBox, SIGNAL(valueChanged(double)),
this, SLOT(setXValue(double))
connect(ySpinBox, SIGNAL(valueChanged(double)),
this, SLOT(setYValue(double))
}
I think that would be much simpler and intuitive because your object is responsible to setting his own members and you dont need to remember any indexes.
EDIT: I have read Passing and argument to a slot it's helpful, but doesn't address my issue of passing multiple references to a function I called via a signal-slot.
I'm currently working on a Qt application that essentially is a unit converter. I'm implementing it using QDoubleSpinBoxes as the input and the output. I am running into an issue that i'm looking for help with. The implementation idea is that the user will input a value of whatever they want to convert and it will, upon the user losing focus on the spinbox or hitting enter, populate the other unit type boxes with the answer.
Here is how I currently do it:
// creates a custom spinbox for each option
modifiedSpinbox *FahrenheitDblSpinbox = new modifiedSpinbox();
modifiedSpinbox *CelciusDblSpinbox = new modifiedSpinbox();
modifiedSpinbox *KelvinDblSpinbox = new modifiedSpinbox();
modifiedSpinbox *RankineDblSpinbox = new modifiedSpinbox();
// Creates a signal mapper that allows passing of a parameter
// to the convert functions anytime a number is entered
QSignalMapper *tempMapper = new QSignalMapper(this);
// Connects the spinbox editing complete signal with the mapper
connect(tempMapper, SIGNAL(mapped(int)),
this,SLOT(on_userInput(int whoSignaled)));
// Connects the mapper with the function that calls the convert class
connect(FahrenheitDblSpinbox, SIGNAL(editingFinished()),
tempMapper, SLOT(map()));
tempMapper->setMapping(FahrenheitDblSpinbox, 1);
The way I would like to implement this conversion function is to, on user finishing their input into a spinbox, have the code send a signal (editingFinished()) to a slot function which calls a converttools class that has the functions needed to do the actual conversion. The problem that i'm running in to is that I cannot figure out how to pass references for these spinbox objects to my converttools class so that I can set the spinbox values directly.
The closest i've come is to use QSignalMapper (seen above) to pass a single int or Qwidget to my slot function, not the objects I want.
I would like some advice as to how to pass multiple references to my custom class after a signal is emitted. I've looked though numerous questions here and still cant seem to figure out how to do this or a better way i'm not seeing.
Thanks!
QSignalMapper is obsolete in C++11. It's only a band-aid against the cumbersomeness of declaring functors in C++98. If you're using a C++11 compiler, you never have to use QSignalMapper.
Lambdas make it trivial - and you really don't need to pass much. Side note: ideally, you should use a modern C++11 units library.
Here's a complete example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/tempconvert-42648860
#include <QtWidgets>
const char kUnit[] = "unit";
class MyWidget : public QWidget {
QFormLayout m_layout{this};
QDoubleSpinBox m_fahrenheit, m_celsius, m_kelvin;
QList<QDoubleSpinBox*> const m_spinBoxes{&m_fahrenheit, &m_celsius, &m_kelvin};
enum Unit { Fahrenheit, Celsius, Kelvin };
static double Q_DECL_RELAXED_CONSTEXPR fromK(Unit to, double val) {
if (to == Fahrenheit) return (val-273.15)*1.8 + 32.0;
else if (to == Celsius) return val - 273.15;
else return val;
}
static double Q_DECL_RELAXED_CONSTEXPR toK(Unit from, double val) {
if (from == Fahrenheit) return (val-32.0)/1.8 + 273.15;
else if (from == Celsius) return val + 273.15;
else return val;
}
void setTemp(Unit unit, double temp, QDoubleSpinBox * skip = nullptr) {
for (auto spin : m_spinBoxes) if (spin != skip) {
QSignalBlocker b{spin};
spin->setValue(fromK(unitOf(spin), toK(unit, temp)));
}
}
static Unit unitOf(QDoubleSpinBox * spin) {
return static_cast<Unit>(spin->property(kUnit).toInt());
}
public:
MyWidget(QWidget * parent = nullptr) : QWidget{parent} {
m_layout.addRow("Fahreneheit", &m_fahrenheit);
m_layout.addRow("Celsius", &m_celsius);
m_layout.addRow("Kelvin", &m_kelvin);
m_fahrenheit.setProperty(kUnit, Fahrenheit);
m_celsius.setProperty(kUnit, Celsius);
m_kelvin.setProperty(kUnit, Kelvin);
for (auto const spin : m_spinBoxes) {
auto const unit = unitOf(spin);
spin->setRange(fromK(unit, 0.), fromK(unit, 1000.));
connect(spin, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
[=]{ setTemp(unit, spin->value(), spin); });
}
setTemp(Celsius, 20.);
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
MyWidget ui;
ui.show();
return app.exec();
}
What you're looking for is:
Signals to carry the QDoubleSpinBox's assigned temperature
A conversion to a common temperature unit
A Signal to all other QDoubleSpinBoxs to update them
A conversion from common temperature unit to each QDoubleSpinBox's specific temperature unit
QSignalMapper is a bad choice here, because:
This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal
So we cannot take in the assigned temperature. Instead lets start with a map<QDoubleSpinBox*, pair<function<double(double)>, function<double(double)>>> which will serve to map from a given QDoubleSpinBox to its "conversion to a common temperature unit" and "conversion from a common temperature unit", respectively.
We'll then build an object around this map looking something like this:
class SlotMapper : public QObject
{
Q_OBJECT
map<QDoubleSpinBox*, pair<function<double(double)>, function<double(double)>>> mapping;
public:
SlotMapper() = default;
SlotMapper(const map<QDoubleSpinBox*, pair<function<double(double)>, function<double(double)>>> mapping) : mapping(mapping) {};
AddMapping(QDoubleSpinBox* key, function<double(double)> valueFirst, function<double(double)> valueSecond) { mapping.insert_or_assign(key, make_pair(valueFirst, valueSecond)); }
void map(const double assignedTemperature) const {
const auto commonTemperatureUnit = mapping.at(QObject()::sender).first(assignedTemperature);
for(auto it = cbegin(mapping); it != cend(mapping); ++it) {
if(it->first != QObject()::sender) {
it->first->blockSignals(true);
it->first->setValue(it->second.second(commonTemperatureUnit));
it->first->blockSignals(false);
}
}
}
};
This object should be constructed with all necessary conversion functions. in your case that probably looks something like:
SlotMapper mySlotMapper(map<QDoubleSpinBox*, pair<function<double(double)>, function<double(double)>>>{ {FahrenheitDblSpinbox, make_pair([](const double param){ return (param - 32.0) * 5.0 / 9.0; }, [](const double param){ return param * 9.0 / 5.0 + 32.0; })},
{CelciusDblSpinbox, make_pair([](const double param){ return param; }, [](const double param){ return param; })},
{KelvinDblSpinbox, make_pair([](const double param){ return param - 273.15; }, [](const double param){ return param + 273.15; })},
{RankineDblSpinbox, make_pair([](const double param){ return (param - 491.67) * 5.0 / 9.0; }, [](const double param){ return (param + 273.15) * 9.0 / 5.0; })} });
As far as your connections, they'll look like:
connect(FahrenheitDblSpinbox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), &mySlotMapper, &SlotMapper::map);
connect(CelciusDblSpinbox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), &mySlotMapper, &SlotMapper::map);
connect(KelvinDblSpinbox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), &mySlotMapper, &SlotMapper::map);
connect(RankineDblSpinbox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), &mySlotMapper, &SlotMapper::map);
I'm using c++ Qt library and I want to do something which would do :
connect(actionB11, SIGNAL(triggered()), this, SLOT(SetSomething(1, 1)));
connect(actionB12, SIGNAL(triggered()), this, SLOT(SetSomething(1, 2)));
connect(actionB21, SIGNAL(triggered()), this, SLOT(SetSomething(2, 1)));
connect(actionB22, SIGNAL(triggered()), this, SLOT(SetSomething(2, 2)));
The code above doesnt work because SIGNAL function has to have same number and argument types as SLOT function.
Does exist a way how to do it? I dont want to have about 20 function as SetSomething11, SetSomething12 calling SetSomething(1, 1) etc.
In situations like this you have three simple options:
connect each QAction to its own slot (not good)
use a QSignalMapper
add each QAction to a QActionGroup and use the QActionGroup::triggered(QAction*) signal, coupled with setting each QAction's data (see QAction::setData() and QAction::data())
When you set the data for a QAction, you can only store one QVariant (i.e., one value). So if you want two values, I would recommend just creating a simple mapping, like this:
void Window::onActionGroupTriggered(QAction *action);
{
int i = action->data().toInt();
int a, b;
a = i / 10;
b = i - 10;
setSomething(a, b); // for example if i = 15, then a = 1 and b = 5
}
You may modify QAction class.
class QMyAction : public QAction
{
Q_OBJECT
QMyAction ( QObject * parent ) :
QAction(parent), _x(0), _y(0)
{
connect(this, SIGNAL(triggered(bool)), this, SLOT(re_trigger(bool)));
}
QMyAction ( const QString & text, QObject * parent ) :
QAction (text, parent), _x(0), _y(0)
{
connect(this, SIGNAL(triggered(bool)), this, SLOT(re_trigger(bool)));
}
QMyAction ( const QIcon & icon, const QString & text, QObject * parent ) :
QAction(icon, text, parent), _x(0), _y(0)
{
connect(this, SIGNAL(triggered(bool)), this, SLOT(re_trigger(bool)));
}
void setX(int x)
{
_x = x;
}
int getX()
{
return _x;
}
void setY(int y)
{
_y = y;
}
int getY()
{
return _y;
}
public slots:
void re_trigger(bool)
{
emit triggered(_x, _y);
}
signals:
void triggered(int,int);
private:
int _x;
int _y;
};
Now, you can connect triggered(int,int) to SetSomething(int,int). But, you have to set x and y. Unless, they will always be 0.
You cannot use constant in SLOT signature, you have to use types there. When connecting signal to slot the slot must have the same subset of parameters signal has, otherwise they cannot be connected and QObject::connect() will return false.
connect(actionB11, SIGNAL(triggered()),
this, SLOT(SetSomething()));
This slot takes no parameters, but you can use QObject::sender() to get pointer to the object, which emitted the signal. Then this pointer can be used to discriminate the source of the signal:
void SetSomething() {
switch(sender()) {
case actionB11;
// do something
break;
case actionB12;
// do something
break;
case actionB21;
// do something
break;
case actionB22;
// do something
break;
default:
// Exceptional situation
}
}
Alternatively you can use QSignalMapper to append additional discriminating parameters to slots.
I have a Qt application where I am using a QStandardItemModel derived class, and a QTreeView to interact with it. I would like to enable drag and drop to copy and move items around the model. To enable this, I have done the following:
In QStandardItem subclasses that represent leaf nodes: setDragEnabled(true) and override clone() to return a real copy of the item.
In Folder nodes: setDropEnabled(true)
In QTreeView: setDragEnabled(true); setAcceptDrops(true); setDropIndicatorShown(true);
Drag and Drop works to the extent that it honors which items can be dragged and which can accept drops. However, whether moving or copying it does not create new items using my clone() functions. It only copies the settings and data available to the QStandardItem base class, losing subclass overrides and such.
How do I get the model and views to make use of my clone() functions, or work around this?
Thank you for any assistance.
I think I have found a work around that more or less does what I was expecting the Framework to do.
The header file:
class QextDragDropModel : public QStandardItemModel
{
public:
/**
* Uses the passed indexes, and encodes a list of QStandardItem pointers into
* the mime data.
*/
virtual QMimeData* mimeData(const QModelIndexList &indexes) const;
/**
* Decodes the mimedata, and uses the each QStandardItem::clone() implmentation
* to place a copy at the requested position of the model. If it is a move
* operation Qt will remove the previous item.
*/
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent);
};
The implmentation:
QMimeData* QextDragDropModel::mimeData(const QModelIndexList &indexes) const
{
// Need to have the base function create the initial mimeData.
// It apparently puts something in there that makes Qt call dropMimeData().
QMimeData* mimeData = QStandardItemModel::mimeData(indexes);
// The raw data that will be placed in the mimeData.
QByteArray mimeBytes;
// Scope the data stream.
{
QDataStream ds(&mimeBytes, QIODevice::WriteOnly);
// The first item encoded will be the number of pointers to expect.
ds << quint32(indexes.size());
// Now for each index get a pointer to the standardItem, and write
// itto the datastream.
for (int i = 0; i < indexes.size(); i++)
{
QStandardItem* ptrItem = itemFromIndex(indexes[i]);
ds.writeRawData((const char*)&ptrItem, sizeof(QStandardItem*));
}
}
// Add the encoded standard item pointers into the mimeData.
mimeData->setData("Qt/QStandardItemArray", mimeBytes);
return mimeData;
}
bool QextDragDropModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
// Get the QStandardItem target of the drop.
QStandardItem* target = itemFromIndex(parent);
// If the target is valid, accepts drops and the mimedata has QStandardItem pointers
// go ahead with decode and insertion. (Checking drop enabled pobably already
// done by the framework before calling this function.)
if ( NULL != target && target->isDropEnabled() && data->hasFormat("Qt/QStandardItemArray") )
{
// Fetch the encoded bytes, create a data stream for decoding,
// and variables to store the output.
QByteArray indexListBytes = data->data("Qt/QStandardItemArray");
QDataStream ds(&indexListBytes, QIODevice::ReadOnly);
quint32 numItems = 0;
// Get the number of items, allocate memory to store pointers to
// them and read the pointer data into that memory.
ds >> numItems;
int byteLen = numItems*sizeof(QStandardItem*);
QStandardItem** stdItems = (QStandardItem**)malloc(byteLen);
ds.readRawData((char*)stdItems, byteLen);
// Add items to the target at a specific child index if requested,
// using thier clone() function to create the items.
for (int i = 0; i < numItems; i++)
{
if ( 0 <= row )
target->insertRow(row, stdItems[i]->clone());
else
target->appendRow(stdItems[i]->clone());
}
// Free memory allocated to store item pointers.
free(stdItems);
return true;
}
return false;
}
For my application, I'll probably add a custom item class with functionality to accept or reject specific items, with the model querying that instead of simply dumping into anything that accepts drops, but for the main question, this is good.
Have you checked that your clone() prototype matches the one from the base class? I had a similar problem with sizeHint, which was not called during layout. The problem was a missing const modifier.