Qt QPropertyAnimation for widgets in layout - widgets shaking - c++

I want to make widgets increase in height with QPropertyAnimation, when widgets are arranged with QVboxLayout.
The problem is that when I open more than one widget, they start to move/shake during animation.
I have prepared minimum working example, here tar gz project
The problem appears when you press "open" button for first, second, then third widget, you can see then that they are shaking, moving slightly up and down during "open" animation.
Has someone idea what to do to avoid this ?
I can set setSizeConstraint(QLayout::SetFixedSize) on main layout and they dont shake, but then resizing and other doesn't work.
Best Regards
Marek

Some time ago I've wrote a layout which animates widget position it contains.
You should build your layout in such way that each widget which should be animated should be inside this layout (one AnimLayout per widget which should be animated):
#include <QLayout>
QT_FORWARD_DECLARE_CLASS(QPropertyAnimation)
class AnimLayout : public QLayout
{
Q_OBJECT
Q_PROPERTY(QPoint delta
READ delta
WRITE setDelta
NOTIFY deltaChanged)
Q_PROPERTY(QRect widgetRect
READ widgetRect
WRITE setWidgetRect
NOTIFY widgetRectChanged)
Q_PROPERTY(bool active
READ isDeltaActive
WRITE setDeltaActive
NOTIFY deltaActiveChanged)
public:
explicit AnimLayout(QWidget *parent = 0);
~AnimLayout();
QPoint delta() const;
void setDelta(const QPoint &value);
QSize sizeHint() const;
void setGeometry(const QRect &);
QSize minimumSize() const;
int count() const;
QSize deltaSize() const;
QRect widgetRect() const;
void setWidgetRect(const QRect &value);
bool isDeltaActive() const;
void setDeltaActive(bool active = true);
void updateItemPosition();
private:
void addItem(QLayoutItem *item);
QLayoutItem *itemAt(int index) const;
QLayoutItem *takeAt(int index);
signals:
void deltaChanged(const QPoint &value);
void widgetRectChanged(const QRect &value);
void deltaActiveChanged(bool active);
public slots:
void testIt();
private:
QLayoutItem *item;
QPropertyAnimation *animation;
QPoint mDelta;
bool mDeltaActive;
};
///////////////////////////////////////////////////////////
#include "animlayout.h"
#include <QPropertyAnimation>
AnimLayout::AnimLayout(QWidget *parent) :
QLayout(parent) ,
item(0)
{
animation = new QPropertyAnimation(this);
animation->setPropertyName("widgetRect");
animation->setDuration(400);
animation->setTargetObject(this);
mDeltaActive = false;
}
AnimLayout::~AnimLayout()
{
delete item;
}
QPoint AnimLayout::delta() const
{
return mDelta;
}
void AnimLayout::setDelta(const QPoint &value)
{
if (mDelta != value) {
mDelta = value;
emit deltaChanged(mDelta);
invalidate();
}
}
void AnimLayout::addItem(QLayoutItem *newItem)
{
Q_ASSERT(!item);
animation->stop();
item =newItem;
emit widgetRectChanged(item->geometry());
invalidate();
}
QSize AnimLayout::sizeHint() const
{
if (!item)
return QSize();
QSize result(item->sizeHint());
result += deltaSize();
int m = 2*margin();
result += QSize(m,m);
return result;
}
void AnimLayout::updateItemPosition()
{
QRect dest = contentsRect();
QPoint d = delta();
if (isDeltaActive()) {
d = -d;
}
if (d.x()!=0) {
if (d.x()>0) {
dest.setLeft(dest.left()+d.x());
} else {
dest.setRight(dest.right()+d.x());
}
}
if (d.y()) {
if (d.y()>0) {
dest.setTop(dest.top()+d.y());
} else {
dest.setBottom(dest.bottom()+d.y());
}
}
animation->setEndValue(dest);
if (widgetRect()!=dest) {
animation->start();
}
}
void AnimLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
updateItemPosition();
}
QLayoutItem *AnimLayout::itemAt(int i) const
{
return i==0?item:0;
}
QLayoutItem *AnimLayout::takeAt(int i)
{
Q_ASSERT(i==0);
QLayoutItem *r = item;
item = 0;
return r;
}
void AnimLayout::testIt()
{
setDeltaActive(!isDeltaActive());
}
QRect AnimLayout::widgetRect() const
{
if (item)
return item->geometry();
return QRect();
}
void AnimLayout::setWidgetRect(const QRect &value)
{
if (item && item->geometry()!=value) {
item->setGeometry(value);
emit widgetRectChanged(item->geometry());
}
}
bool AnimLayout::isDeltaActive() const
{
return mDeltaActive;
}
void AnimLayout::setDeltaActive(bool active)
{
if (active!=mDeltaActive) {
mDeltaActive = active;
animation->stop();
updateItemPosition();
emit deltaActiveChanged(active);
}
}
QSize AnimLayout::minimumSize() const
{
QSize result(deltaSize());
if (item) {
result += item->minimumSize();
}
int m = 2*margin();
result += QSize(m,m);
return result;
}
int AnimLayout::count() const
{
return item?1:0;
}
QSize AnimLayout::deltaSize() const
{
return QSize(qAbs(mDelta.x()), qAbs(mDelta.y()));
}
It has some extra functionality you don't need (mDelta).

Sorry it took me so long ;)
I have tested it and it works great.
However, when I was working with my previous code I have made it work without shaking. The change I made was to add QWidget into QScrollArea and then set QVBoxLayout on that widget.
Anyway many thanks for help.
Below there is example in one main.cpp and there is variable "animatedLayout" which turns on or off your AnimLayout.
#include
#include
class AnimLayout : public QLayout
{
Q_OBJECT
Q_PROPERTY(QRect widgetRect
READ widgetRect
WRITE setWidgetRect
NOTIFY widgetRectChanged)
public:
explicit AnimLayout(QWidget *parent = 0);
~AnimLayout();
QSize sizeHint() const;
void setGeometry(const QRect &);
QSize minimumSize() const;
int count() const;
QRect widgetRect() const;
void setWidgetRect(const QRect &value);
void updateItemPosition();
private:
void addItem(QLayoutItem *item);
QLayoutItem *itemAt(int index) const;
QLayoutItem *takeAt(int index);
signals:
void widgetRectChanged(const QRect &value);
public slots:
private:
QLayoutItem *item;
QPropertyAnimation *animation;
};
struct FrameDataStruct {
QFrame *mainFrame;
QFrame *upFrame;
QFrame *downFrame;
QPushButton *button;
QVBoxLayout *upFrameLayout;
QLabel *text;
QVBoxLayout *downFrameLayout;
QVBoxLayout *frameLayout;
QPropertyAnimation *animation;
int frame_id;
int basic_height;
bool expanded;
AnimLayout *animLayout;
};
class Proptest : public QMainWindow
{
Q_OBJECT
public:
explicit Proptest();
~Proptest();
private slots:
void setDataStruct();
void startAnimation(int frame_id);
void animFinished(int frame_id);
private:
QMap frameMap;
QSignalMapper *animStartMapper;
QSignalMapper *animFinishedMapper;
bool initialized;
QWidget *scrollWidget;
QVBoxLayout *main_layout;
QWidget *widget;
QScrollArea *scrollArea;
QVBoxLayout *central_layout;
bool layoutAnimated;
};
Proptest::Proptest()
: widget(new QWidget)
{
setCentralWidget(widget);
this->setGeometry(200,200,300,600);
central_layout=new QVBoxLayout(widget);
scrollArea=new QScrollArea(widget);
central_layout->addWidget(scrollArea);
animStartMapper=new QSignalMapper(this);
connect(animStartMapper,SIGNAL(mapped(int)),this,SLOT(startAnimation(int)));
animFinishedMapper=new QSignalMapper(this);
connect(animFinishedMapper,SIGNAL(mapped(int)),this,SLOT(animFinished(int)));
scrollWidget=new QWidget(widget);
scrollArea->setWidget(scrollWidget);
main_layout=new QVBoxLayout(scrollWidget);
main_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
layoutAnimated=true;
this->setDataStruct();
}
void Proptest::setDataStruct() {
for(int i=0;iexpanded=false;
r->frame_id=i;
r->mainFrame=new QFrame(scrollWidget);
r->upFrame=new QFrame(r->mainFrame);
r->upFrame->setMinimumHeight(40);
r->button=new QPushButton(QString("open"),r->upFrame);
r->upFrameLayout=new QVBoxLayout(r->upFrame);
r->upFrameLayout->addWidget(r->button);
r->downFrame=new QFrame(r->mainFrame);
r->text=new QLabel(QString("some text SOME TEXT some text"),r->downFrame);
r->downFrameLayout=new QVBoxLayout(r->downFrame);
r->downFrameLayout->addWidget(r->text);
r->frameLayout=new QVBoxLayout(r->mainFrame);
r->frameLayout->addWidget(r->upFrame);
r->frameLayout->addItem(new QSpacerItem(10,10));
r->frameLayout->addWidget(r->downFrame);
r->frameLayout->setStretch(0,0);
r->frameLayout->setStretch(1,1);
r->frameLayout->setStretch(2,0);
r->downFrame->setVisible(false);
r->animation=new QPropertyAnimation(r->mainFrame,"minimumHeight");
r->animation->setDuration(500);
connect(r->button,SIGNAL(clicked(bool)),animStartMapper,SLOT(map()));
animStartMapper->setMapping(r->button,r->frame_id);
connect(r->animation,SIGNAL(finished()),animFinishedMapper,SLOT(map()));
animFinishedMapper->setMapping(r->animation,r->frame_id);
if(layoutAnimated) {
r->animLayout=new AnimLayout();
r->animLayout->addWidget(r->mainFrame);
main_layout->addItem(r->animLayout);
}
else {
main_layout->addWidget(r->mainFrame);
}
frameMap.insert(r->frame_id,r);
}
main_layout->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding));
main_layout->setStretch(main_layout->count()-1,1);
}
void Proptest::startAnimation(int frame_id) {
FrameDataStruct *r=frameMap[frame_id];
if(r->expanded) {
r->expanded=false;
if(layoutAnimated) {
r->downFrame->hide();
}
else {
r->downFrame->setVisible(false);
r->animation->setStartValue(r->mainFrame->geometry().height());
r->animation->setEndValue(r->basic_height);
}
} else {
r->expanded=true;
if(layoutAnimated) {
r->downFrame->show();
}
else {
r->basic_height=r->mainFrame->geometry().height();
r->animation->setStartValue(r->basic_height);
r->animation->setEndValue(r->basic_height*2);
r->upFrame->setMinimumHeight(r->upFrame->height());
}
}
if(!layoutAnimated)
r->animation->start();
}
void Proptest::animFinished(int frame_id) {
FrameDataStruct *r=frameMap[frame_id];
if(r->expanded)
r->downFrame->setVisible(true);
}
Proptest::~Proptest() {
}
AnimLayout::AnimLayout(QWidget *parent) :
QLayout(parent) ,
item(0)
{
animation = new QPropertyAnimation(this);
animation->setPropertyName("widgetRect");
animation->setDuration(400);
animation->setTargetObject(this);
}
AnimLayout::~AnimLayout()
{
delete item;
}
void AnimLayout::addItem(QLayoutItem *newItem)
{
Q_ASSERT(!item);
animation->stop();
item =newItem;
emit widgetRectChanged(item->geometry());
invalidate();
}
QSize AnimLayout::sizeHint() const
{
if (!item)
return QSize();
QSize result(item->sizeHint());
int m = 2*margin();
result += QSize(m,m);
return result;
}
void AnimLayout::updateItemPosition()
{
QRect dest = contentsRect();
animation->setEndValue(dest);
if (widgetRect()!=dest) {
animation->start();
}
}
void AnimLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
updateItemPosition();
}
QLayoutItem *AnimLayout::itemAt(int i) const
{
return i==0?item:0;
}
QLayoutItem *AnimLayout::takeAt(int i)
{
Q_ASSERT(i==0);
QLayoutItem *r = item;
item = 0;
return r;
}
QRect AnimLayout::widgetRect() const
{
if (item)
return item->geometry();
return QRect();
}
void AnimLayout::setWidgetRect(const QRect &value)
{
if (item && item->geometry()!=value) {
item->setGeometry(value);
emit widgetRectChanged(item->geometry());
}
}
QSize AnimLayout::minimumSize() const
{
QSize result(item->minimumSize());
int m = 2*margin();
result += QSize(m,m);
return result;
}
int AnimLayout::count() const
{
return item?1:0;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Proptest w;
w.show();
return a.exec();
}
#include "main.moc"
Best Regards
Marek

My answer again, dont know why but previosu was deleted.
I have used Your AnimLayout and it works great.
Below there is example in main.cpp with "layoutAnimated" variable to switch on and off AnimLayout.
#include <QApplication>
#include <QtWidgets>
class AnimLayout : public QLayout
{
Q_OBJECT
Q_PROPERTY(QRect widgetRect
READ widgetRect
WRITE setWidgetRect
NOTIFY widgetRectChanged)
public:
explicit AnimLayout(QWidget *parent = 0);
~AnimLayout();
QSize sizeHint() const;
void setGeometry(const QRect &);
QSize minimumSize() const;
int count() const;
QRect widgetRect() const;
void setWidgetRect(const QRect &value);
void updateItemPosition();
private:
void addItem(QLayoutItem *item);
QLayoutItem *itemAt(int index) const;
QLayoutItem *takeAt(int index);
signals:
void widgetRectChanged(const QRect &value);
public slots:
private:
QLayoutItem *item;
QPropertyAnimation *animation;
};
struct FrameDataStruct {
QFrame *mainFrame;
QFrame *upFrame;
QFrame *downFrame;
QPushButton *button;
QVBoxLayout *upFrameLayout;
QLabel *text;
QVBoxLayout *downFrameLayout;
QVBoxLayout *frameLayout;
QPropertyAnimation *animation;
int frame_id;
int basic_height;
bool expanded;
AnimLayout *animLayout;
};
class Proptest : public QMainWindow
{
Q_OBJECT
public:
explicit Proptest();
~Proptest();
private slots:
void setDataStruct();
void startAnimation(int frame_id);
void animFinished(int frame_id);
private:
QMap<int,FrameDataStruct*> frameMap;
QSignalMapper *animStartMapper;
QSignalMapper *animFinishedMapper;
bool initialized;
QWidget *scrollWidget;
QVBoxLayout *main_layout;
QWidget *widget;
QScrollArea *scrollArea;
QVBoxLayout *central_layout;
bool layoutAnimated;
};
Proptest::Proptest()
: widget(new QWidget)
{
setCentralWidget(widget);
this->setGeometry(200,200,300,600);
central_layout=new QVBoxLayout(widget);
scrollArea=new QScrollArea(widget);
central_layout->addWidget(scrollArea);
animStartMapper=new QSignalMapper(this);
connect(animStartMapper,SIGNAL(mapped(int)),this,SLOT(startAnimation(int)));
animFinishedMapper=new QSignalMapper(this);
connect(animFinishedMapper,SIGNAL(mapped(int)),this,SLOT(animFinished(int)));
scrollWidget=new QWidget(widget);
scrollArea->setWidget(scrollWidget);
main_layout=new QVBoxLayout(scrollWidget);
main_layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
scrollArea->setWidgetResizable(true);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
layoutAnimated=true;
this->setDataStruct();
}
void Proptest::setDataStruct() {
for(int i=0;i<5;i++) {
FrameDataStruct *r=new FrameDataStruct;
r->expanded=false;
r->frame_id=i;
r->mainFrame=new QFrame(scrollWidget);
r->upFrame=new QFrame(r->mainFrame);
r->upFrame->setMinimumHeight(40);
r->button=new QPushButton(QString("open"),r->upFrame);
r->upFrameLayout=new QVBoxLayout(r->upFrame);
r->upFrameLayout->addWidget(r->button);
r->downFrame=new QFrame(r->mainFrame);
r->text=new QLabel(QString("some text SOME TEXT some text"),r->downFrame);
r->downFrameLayout=new QVBoxLayout(r->downFrame);
r->downFrameLayout->addWidget(r->text);
r->frameLayout=new QVBoxLayout(r->mainFrame);
r->frameLayout->addWidget(r->upFrame);
r->frameLayout->addItem(new QSpacerItem(10,10));
r->frameLayout->addWidget(r->downFrame);
r->frameLayout->setStretch(0,0);
r->frameLayout->setStretch(1,1);
r->frameLayout->setStretch(2,0);
r->downFrame->setVisible(false);
r->animation=new QPropertyAnimation(r->mainFrame,"minimumHeight");
r->animation->setDuration(500);
connect(r->button,SIGNAL(clicked(bool)),animStartMapper,SLOT(map()));
animStartMapper->setMapping(r->button,r->frame_id);
connect(r->animation,SIGNAL(finished()),animFinishedMapper,SLOT(map()));
animFinishedMapper->setMapping(r->animation,r->frame_id);
if(layoutAnimated) {
r->animLayout=new AnimLayout();
r->animLayout->addWidget(r->mainFrame);
main_layout->addItem(r->animLayout);
}
else {
main_layout->addWidget(r->mainFrame);
}
frameMap.insert(r->frame_id,r);
}
main_layout->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding));
main_layout->setStretch(main_layout->count()-1,1);
}
void Proptest::startAnimation(int frame_id) {
FrameDataStruct *r=frameMap[frame_id];
if(r->expanded) {
r->expanded=false;
if(layoutAnimated) {
r->downFrame->hide();
}
else {
r->downFrame->setVisible(false);
r->animation->setStartValue(r->mainFrame->geometry().height());
r->animation->setEndValue(r->basic_height);
}
} else {
r->expanded=true;
if(layoutAnimated) {
r->downFrame->show();
}
else {
r->basic_height=r->mainFrame->geometry().height();
r->animation->setStartValue(r->basic_height);
r->animation->setEndValue(r->basic_height*2);
r->upFrame->setMinimumHeight(r->upFrame->height());
}
}
if(!layoutAnimated)
r->animation->start();
}
void Proptest::animFinished(int frame_id) {
FrameDataStruct *r=frameMap[frame_id];
if(r->expanded)
r->downFrame->setVisible(true);
}
Proptest::~Proptest() {
}
AnimLayout::AnimLayout(QWidget *parent) :
QLayout(parent) ,
item(0)
{
animation = new QPropertyAnimation(this);
animation->setPropertyName("widgetRect");
animation->setDuration(400);
animation->setTargetObject(this);
}
AnimLayout::~AnimLayout()
{
delete item;
}
void AnimLayout::addItem(QLayoutItem *newItem)
{
Q_ASSERT(!item);
animation->stop();
item =newItem;
emit widgetRectChanged(item->geometry());
invalidate();
}
QSize AnimLayout::sizeHint() const
{
if (!item)
return QSize();
QSize result(item->sizeHint());
int m = 2*margin();
result += QSize(m,m);
return result;
}
void AnimLayout::updateItemPosition()
{
QRect dest = contentsRect();
animation->setEndValue(dest);
if (widgetRect()!=dest) {
animation->start();
}
}
void AnimLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
updateItemPosition();
}
QLayoutItem *AnimLayout::itemAt(int i) const
{
return i==0?item:0;
}
QLayoutItem *AnimLayout::takeAt(int i)
{
Q_ASSERT(i==0);
QLayoutItem *r = item;
item = 0;
return r;
}
QRect AnimLayout::widgetRect() const
{
if (item)
return item->geometry();
return QRect();
}
void AnimLayout::setWidgetRect(const QRect &value)
{
if (item && item->geometry()!=value) {
item->setGeometry(value);
emit widgetRectChanged(item->geometry());
}
}
QSize AnimLayout::minimumSize() const
{
QSize result(item->minimumSize());
int m = 2*margin();
result += QSize(m,m);
return result;
}
int AnimLayout::count() const
{
return item?1:0;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Proptest w;
w.show();
return a.exec();
}
#include "main.moc"
Best Regards
Marek

Related

Qt C++ Drag QHeaderView between tables

I want to copy the selected column of a QTableWidget to another one.
So I tried to make selected columns draggable by adding this code:
void makeDraggable(QTableWidget *table)
{
table->setDragEnabled(true);
table->setAcceptDrops(true);
table->setSelectionBehavior(QAbstractItemView::SelectColumns);
}
Result I got:
But I want to drag a whole column (horizontal and vertical headers) by clicking on headers only, not on cells, and copy its data to another table including the header text.
Dragging between different tables inside one application can be done with reimplementing custom QHeaderView and QTableWidget. In my example I generate text with indecies of table and column for drag event. Custom header:
#include <QHeaderView>
class ITableManager;
class DraggableHeaderView : public QHeaderView
{
Q_OBJECT
public:
explicit DraggableHeaderView(Qt::Orientation orientation, QWidget *parent = 0);
int tag() const;
void setTag(const int tag);
void setTableManager(ITableManager* manager);
protected:
void mouseMoveEvent(QMouseEvent *e);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
signals:
public slots:
private:
int m_tag; //internal index of table
ITableManager *m_tableManager; //manager will convert table index into pointer
};
Custom header cpp
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <QDebug>
#include <QTableWidget>
#include <ITableManager.h>
DraggableHeaderView::DraggableHeaderView(Qt::Orientation orientation, QWidget *parent) :
QHeaderView(orientation, parent)
{
m_tag = 0;
m_tableManager = 0;
setAcceptDrops(true);
}
void DraggableHeaderView::mouseMoveEvent(QMouseEvent *e)
{
if (e->buttons() & Qt::LeftButton)
{
int index = logicalIndexAt(e->pos());
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
//custom drag text with indecies inside
QString mimeTxt = "MoveHeader;Table:" + QString::number(m_tag) +
";Index:" + QString::number(index);
mimeData->setText(mimeTxt);
drag->setMimeData(mimeData);
Qt::DropAction dropAction = drag->exec();
}
}
int DraggableHeaderView::tag() const
{
return m_tag;
}
void DraggableHeaderView::setTag(const int tag)
{
m_tag = tag;
}
void DraggableHeaderView::dragEnterEvent(QDragEnterEvent *event)
{
if (!m_tableManager)
{
event->ignore();
return;
}
QString dragText = event->mimeData()->text();
int index = dragText.indexOf("MoveHeader;");
if (index == 0)
{
event->accept();
}
else
{
event->ignore();
}
}
void DraggableHeaderView::dropEvent(QDropEvent *event)
{
if (!m_tableManager)
{
event->ignore();
return;
}
QStringList dragText = event->mimeData()->text().split(';');
if (dragText.count() < 3 || dragText.at(0) != "MoveHeader")
{
event->ignore();
return;
}
int tableIndex = dragText.at(1).mid(6).toInt();//6 - length 'Table:'
QTableWidget* tableSrc = m_tableManager->getTableFromIndex(tableIndex);
if (!tableSrc)
{
event->ignore();
return;
}
//dst table as parent for header view
QTableWidget *tableDst = qobject_cast<QTableWidget*> (this->parentWidget());
if (!tableDst)
{
event->ignore();
return;
}
//move column: modify for your needs
//now moves only items text
int columnIndex = logicalIndexAt(event->pos());
int srcColumnIndex = dragText.at(2).mid(6).toInt(); //6 - length of 'Index:'
tableDst->insertColumn(columnIndex);
for (int iRow = 0; iRow < tableDst->rowCount() && iRow < tableSrc->rowCount(); ++iRow)
{
if (tableSrc->item(iRow, srcColumnIndex))
{
tableDst->setItem(iRow, columnIndex,
new QTableWidgetItem(tableSrc->item(iRow, srcColumnIndex)->text()));
}
else
{
tableDst->setItem(iRow, columnIndex, new QTableWidgetItem());
}
}
tableSrc->removeColumn(srcColumnIndex);
}
void DraggableHeaderView::setTableManager(ITableManager *manager)
{
m_tableManager = manager;
}
Now create custom QTableWidget with DraggableHeaderView inside
class CustomTableWidget : public QTableWidget
{
Q_OBJECT
public:
explicit CustomTableWidget(QWidget *parent = 0);
void setTag(const int tag);
void setTableManager(ITableManager* manager);
};
CustomTableWidget::CustomTableWidget(QWidget *parent) :
QTableWidget(parent)
{
DraggableHeaderView *headerView = new DraggableHeaderView(Qt::Horizontal, this);
setHorizontalHeader(headerView);
setAcceptDrops(true);
}
void CustomTableWidget::setTag(const int tag)
{
DraggableHeaderView *header = qobject_cast<DraggableHeaderView*> (horizontalHeader());
if (header)
{
header->setTag(tag);
}
}
void CustomTableWidget::setTableManager(ITableManager *manager)
{
DraggableHeaderView *header = qobject_cast<DraggableHeaderView*> (horizontalHeader());
if (header)
{
header->setTableManager(manager);
}
}
For converting table index to pointer I use ITableManager
class ITableManager
{
public:
virtual QTableWidget* getTableFromIndex(const int index) = 0;
};
And implement it in QMainWindow
class MainWindow : public QMainWindow, ITableManager
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QTableWidget* getTableFromIndex(const int index);
}
QTableWidget * MainWindow::getTableFromIndex(const int index)
{
switch (index)
{
case 1:
return ui->tableWidget;
case 2:
return ui->tableWidget_2;
default:
return nullptr;
}
}
Dont forget setup tags (indecies) and table manager for tables (in main window constructor)
ui->tableWidget->setTag(1);
ui->tableWidget_2->setTag(2);
ui->tableWidget->setTableManager(this);
ui->tableWidget_2->setTableManager(this);
EDIT: If you want change custom pixmap for dragging just set QDrag::setPixmap
void DraggableHeaderView::mouseMoveEvent(QMouseEvent *e)
{
if (e->buttons() & Qt::LeftButton)
{
int index = logicalIndexAt(e->pos());
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
QString mimeTxt = "MoveHeader;Table:" + QString::number(m_tag) +
";Index:" + QString::number(index);
mimeData->setText(mimeTxt);
drag->setMimeData(mimeData);
drag->setPixmap(pixmapForDrag(index));
Qt::DropAction dropAction = drag->exec();
}
}
And method for taking pixmap of column can be like this
QPixmap DraggableHeaderView::pixmapForDrag(const int columnIndex) const
{
QTableWidget *table = qobject_cast<QTableWidget*> (this->parentWidget());
if (!table)
{
return QPixmap();
}
//image for first 5 row
int height = table->horizontalHeader()->height();
for (int iRow = 0; iRow < 5 && iRow < table->rowCount(); ++iRow)
{
height += table->rowHeight(iRow);
}
//clip maximum size
if (height > 200)
{
height = 200;
}
QRect rect(table->columnViewportPosition(columnIndex) + table->verticalHeader()->width(),
table->rowViewportPosition(0),
table->columnWidth(columnIndex),
height);
QPixmap pixmap(rect.size());
table->render(&pixmap, QPoint(), QRegion(rect));
return pixmap;
}

Clipboard operation in Graphics View

I have different subclasses for my entities. The entities are drawn in GraphicsView, How can apply the Clipboard operations for Cut, Copy and Paste.
gEntity.h
#ifndef GENTITY_H
#define GENTITY_H
class gEntity :public QObject
{
public:
gEntity(QObject* parent=0) : QObject(parent) {}
virtual ~gEntity() {}
virtual gEntity* my_clone() { return 0; }
};
#endif // GENTITY_H
circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include <QPainter>
#include <QGraphicsItem>
#include <gentity.h>
#include "qmath.h"
class Circle : public QObject, public QGraphicsItem, public gEntity
{
Q_OBJECT
public:
Circle(QObject* parent=0) : gEntity(parent){
}
Circle(int, QPointF, QPointF);
Circle(int, QPointF, qreal);
QRectF boundingRect() const;
virtual void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget);
enum { Type = UserType + 3 };
int type() const;
int id;
QPointF center_p, end_p, move_p;
qreal radius;
void setRadius((const qreal &radius);
private:
QVector<QPointF> stuff;
};
#endif // CIRCLE_H
circle.cpp
#include "circle.h"
#include "gentity.h"
Circle::Circle(int i, QPointF p1, QPointF p2)
{
// assigns id
id = i;
/* set values of center point, end point
and calculate radius of circle */
center_p = p1;
end_p = p2;
radius = qSqrt(qPow((end_p.x()-center_p.x()), 2)
+ qPow((end_p.y()-center_p.y()), 2));
}
Circle::Circle(int i, QPointF p1, qreal rad)
{
// assigns id
id = i;
/* set values of center point
and radius of circle */
center_p = p1;
radius = rad;
}
int Circle::type() const
{
// Enable the use of qgraphicsitem_cast with circle item.
return Type;
}
QRectF Circle::boundingRect() const
{
// bounding rectangle for circle
return QRectF((center_p.x()-radius), (center_p.y()-radius),
(2*radius), (2*radius));
}
void Circle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
// draws/paints the path of circle
QPen paintpen(Qt::black);
paintpen.setWidth(1);
painter->setRenderHint(QPainter::Antialiasing);
if (isSelected())
{
// sets brush for center point
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
painter->drawEllipse(center_p, 2, 2);
// sets pen for circumference
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setBrush(Qt::NoBrush);
painter->setPen(paintpen);
painter->drawEllipse(center_p, radius, radius);
}
else
{ painter->save();
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawEllipse(center_p, 2, 2);
painter->setBrush(Qt::NoBrush);
painter->drawEllipse(center_p, radius, radius);
painter->restore();
}
}
gEntity* my_clone(){
Circle *c = new Circle();
c->setRadius(radius);
return c;
}
Clipboard.h
#include<QStack>
#include<QClipboard>
class MyClipBoard
{
public:
static MyClipBoard* instance()
{
if(!inst)
inst = new MyClipBoard;
return inst;
}
void push(gEntity* g) {
clips.push(g);
}
gEntity* last()
{
if(clips.count() == 0) return 0;
return clips.last();
}
gEntity* pop()
{
if(clips.count() == 0) return 0;
return clips.pop();
}
bool isempty() const { return clips.empty(); }
private:
QStack<gEntity*> clips;
static MyClipBoard* inst;
};
CadgraphicsScene.cpp
MyClipBoard* MyClipBoard::inst = 0;
CadGraphicsScene::CadGraphicsScene(QObject *parent, QUndoStack *undoStack)
: QGraphicsScene(parent)
{
setFlags();
id = 0;
mUndoStack = undoStack;
m_context = new QMenu;
m_context->addAction("Insert Circle");
a_cut = m_context->addAction("cut");
a_copy = m_context->addAction("copy");
a_paste = m_context->addAction("paste");
context_item = 0;
connect(m_context, SIGNAL(triggered(QAction*)), this, SLOT(contmenu(QAction*)));
}
void CadGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event){
m_context->exec(event->screenPos());
}
void CadGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// mousePressEvent in the graphicsScene
if(mouseEvent->button() == Qt::LeftButton)
{
switch (entityMode)
{
case NoMode:
qDebug() << "No Mode";
break;
case PointMode:
pointItem = new Point(++id);
pointItem->setPos(mouseEvent->scenePos());
itemList.append(pointItem);
mUndoStack->push(new CadCommandAdd(this, pointItem));
break;
case LineMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
end_p = mouseEvent->scenePos();
mPaintFlag = true;
mSecondClick = false;
}
if (mPaintFlag)
{
lineItem = new Line(++id, start_p, end_p);
lineItem->setLine(start_p.x(), start_p.y(), end_p.x(), end_p.y());
itemList.append(lineItem);
mUndoStack->push(new CadCommandAdd(this, lineItem));
setFlags();
}
break;
case CircleMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
end_p = mouseEvent->scenePos();
mPaintFlag = true;
mSecondClick = false;
}
if (mPaintFlag)
{
circleItem = new Circle(++id, start_p, end_p);
itemList.append(circleItem);
mUndoStack->push(new CadCommandAdd(this, circleItem));
setFlags();
}
break;
case EllipseMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
mid_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = false;
mThirdClick = true;
}
else if (!mSecondClick && mThirdClick)
{
end_p = mouseEvent->scenePos();
mThirdClick = false;
mPaintFlag = true;
}
if (mPaintFlag)
{
ellipseItem = new Ellipse(++id, start_p, mid_p, end_p);
itemList.append(ellipseItem);
mUndoStack->push(new CadCommandAdd(this, ellipseItem));
setFlags();
}
break;
case TextMode:
textItem = new mText(++id);
textItem->setPos(mouseEvent->scenePos());
itemList.append(textItem);
textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
mUndoStack->push(new CadCommandAdd(this, textItem));
connect(textItem, SIGNAL(lostFocus(mText*)),
this, SLOT(editorLostFocus(mText*)));
connect(textItem, SIGNAL(selectedChange(QGraphicsItem*)),
this, SIGNAL(itemSelected(QGraphicsItem*)));
setFlags();
default:
;
}
}else if(event->button() & Qt::RightButton)
{
context_item = itemAt(event->scenePos().toPoint(), QTransform());//base operand not a pointer
cpos = event->scenePos();//says invalid use of member function
if(!context_item)//Here it says all variables out of scope
{
a_cut->setEnabled(false);
a_copy->setEnabled(false);
if(MyClipBoard::instance()->isempty())
a_paste->setEnabled(false);
else a_paste->setEnabled(true);
}
else
{
a_cut->setEnabled(true);
a_copy->setEnabled(true);
a_paste->setEnabled(false);
}
}
QGraphicsScene::mousePressEvent(mouseEvent);
}
cadgraphicsscene.h
private:
QMenu* m_context;
QAction* a_cut;
QAction* a_copy;
QAction* a_paste;
QGraphicsItem* context_item;
QPointF cpos;
what are you mean of cutting a grahicsitem? (change its position or move to another view)
for copy and paste search for cloning a object in c++ it's not hard, and in paste just change position of new object and add that to your graphicsview or scene
update:
#ifndef MYSCENE_H
#define MYSCENE_H
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QGraphicsSceneContextMenuEvent>
#include <QMenu>
#include <QStack>
class gEntity : public QObject, public QGraphicsItem
{
public:
gEntity(QObject* parent=0) : QObject(parent) {}
virtual ~gEntity() {}
virtual gEntity* my_clone() { return 0; }
};
class Circle : public gEntity
{
public:
Circle(QObject* parent=0) : gEntity(parent) {
m_radius = 10;
}
qreal radius() const;
void setRadius(const qreal &radius);
gEntity* my_clone()
{
Circle* c = new Circle;
c->setRadius(m_radius);
return c;
}
QRectF boundingRect() const
{
return QRectF(-m_radius, -m_radius, 2 * m_radius, 2 * m_radius);
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->save();
painter->setBrush(Qt::yellow);
painter->drawEllipse(QPointF(0,0), m_radius, m_radius);
painter->restore();
}
private:
qreal m_radius;
};
class MyClipBoard
{
public:
static MyClipBoard* instance()
{
if(!inst)
inst = new MyClipBoard;
return inst;
}
void push(gEntity* g) {
clips.push(g);
}
gEntity* last()
{
if(clips.count() == 0) return 0;
return clips.last();
}
gEntity* pop()
{
if(clips.count() == 0) return 0;
return clips.pop();
}
bool isempty() const { return clips.empty(); }
private:
QStack<gEntity*> clips;
static MyClipBoard* inst;
};
class MyScene : public QGraphicsScene
{
Q_OBJECT
public:
MyScene(QObject* parent=0);
virtual ~MyScene()
{
delete m_context;
}
protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent* event);
void mousePressEvent(QGraphicsSceneMouseEvent* event);
public slots:
void insertCircle(const QPointF& pos)
{
Circle* mcircle = new Circle;
addItem(mcircle);
mcircle->setPos(pos);
}
void cut(gEntity* obj)
{
removeItem(obj);
MyClipBoard::instance()->push(obj);
}
void copy(gEntity* obj)
{
MyClipBoard::instance()->push(obj->my_clone());
}
void paste(const QPointF& pos)
{
gEntity* last = MyClipBoard::instance()->pop();
if(last)
{
addItem(last);
last->setPos(pos);
}
}
void contmenu(QAction* a)
{
if(a->text() == "Insert Circle")
{
insertCircle(cpos);
}
else if(a == a_cut)
{
cut(static_cast<gEntity*>(context_item));
}
else if(a == a_copy)
{
copy(static_cast<gEntity*>(context_item));
}
else if(a == a_paste)
{
paste(cpos);
}
}
private:
QMenu* m_context;
QAction* a_cut;
QAction* a_copy;
QAction* a_paste;
QGraphicsItem* context_item;
QPointF cpos;
};
#endif // MYSCENE_H
scene.cpp
#include "myscene.h"
#include <QGraphicsSceneMouseEvent>
MyClipBoard* MyClipBoard::inst = 0;
qreal Circle::radius() const
{
return m_radius;
}
void Circle::setRadius(const qreal &radius)
{
m_radius = radius;
}
MyScene::MyScene(QObject *parent) : QGraphicsScene(parent)
{
m_context = new QMenu;
m_context->addAction("Insert Circle");
a_cut = m_context->addAction("cut");
a_copy = m_context->addAction("copy");
a_paste = m_context->addAction("paste");
context_item = 0;
connect(m_context, SIGNAL(triggered(QAction*)), this, SLOT(contmenu(QAction*)));
}
void MyScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event){
m_context->exec(event->screenPos());
}
void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mousePressEvent(event);
if(event->button() & Qt::RightButton)
{
context_item = itemAt(event->scenePos().toPoint(), QTransform());
cpos = event->scenePos();
if(!context_item)
{
a_cut->setEnabled(false);
a_copy->setEnabled(false);
if(MyClipBoard::instance()->isempty())
a_paste->setEnabled(false);
else a_paste->setEnabled(true);
}
else
{
a_cut->setEnabled(true);
a_copy->setEnabled(true);
a_paste->setEnabled(false);
}
}
}
main.cpp
#include <QApplication>
#include "myscene.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsView w(new MyScene);
w.setSceneRect(0,0,500,500);
w.show();
return a.exec();
}

Text in GraphicsView

I have added text items in a graphics scene, in Qt, by assigning id to it, but I am unable to save the items; I am using XmlstreamWriter.
Following is my code snippet for adding the text:
cadtextitem.h
#ifndef cadtextitem_H
#define cadtextitem_H
#include <QGraphicsTextItem>
#include <QPen>
QT_BEGIN_NAMESPACE
class QFocusEvent;
class QGraphicsItem;
class QGraphicsScene;
class QGraphicsSceneMouseEvent;
QT_END_NAMESPACE
class cadtextitem:public QGraphicsTextItem
{
Q_OBJECT
public:
enum { Type = UserType + 3 };
cadtextitem( int, QGraphicsItem *parent=0);
int type() const{return Type;}
int id;
signals:
void lostFocus(cadtextitem *item);
void selectedChange(QGraphicsItem *item);
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void focusOutEvent(QFocusEvent *event);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
};
#endif // cadtextitem_H
cadtextitem.cpp
#include "cadtextitem.h"
cadtextitem::cadtextitem(int i, QGraphicsItem *parent)
: QGraphicsTextItem(parent)
{
//assigns id
id = i;
}
QVariant cadtextitem::itemChange(GraphicsItemChange change,
const QVariant &value)
{
if (change == QGraphicsItem::ItemSelectedHasChanged)
emit selectedChange(this);
return value;
}
void cadtextitem::focusOutEvent(QFocusEvent *event)
{
setTextInteractionFlags(Qt::NoTextInteraction);
emit lostFocus(this);
QGraphicsTextItem::focusOutEvent(event);
}
void cadtextitem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
if (textInteractionFlags() == Qt::NoTextInteraction)
setTextInteractionFlags(Qt::TextEditorInteraction);
QGraphicsTextItem::mouseDoubleClickEvent(event);
}
Following is the code to save the items:
mainwindow.cpp
void MainWindow::on_actionSave_triggered()
{
// save file dialog box
QString filename = QFileDialog::getSaveFileName(this,
tr("Save File"),
QString(),
tr("file Name(*.xml)"));
if(!filename.isEmpty())
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
}
else
{
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("SceneData");
xmlWriter.writeAttribute("version", "v1.0");
xmlWriter.writeStartElement("Entities");
view->scene->writeStream(&xmlWriter);
xmlWriter.writeEndElement(); //end of Entities
xmlWriter.writeEndElement(); //end of SceneData
QMessageBox::warning(this, "Saved",
QString("Saved Scene Data to '%1'").
arg(filename));
file.close();
}
}
cadgraphicsscene.cpp
void CadGraphicsScene::writeStream(QXmlStreamWriter *stream)
{
// write entities in a file
foreach (QGraphicsItem *item, itemList)
{
if (items().contains(item))
{
if (item->type() == Point::Type)
{
Point *myItem = dynamic_cast<Point *>(item);
stream->writeStartElement("Point");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("x", QString::number(myItem->x()));
stream->writeAttribute("y", QString::number(myItem->y()));
stream->writeEndElement(); //end of Point Item
}
else if (item->type() == Line::Type)
{
Line *myItem = dynamic_cast<Line *>(item);
stream->writeStartElement("Line");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("x1", QString::number(myItem->start_p.x()));
stream->writeAttribute("y1", QString::number(myItem->start_p.y()));
stream->writeAttribute("x2", QString::number(myItem->end_p.x()));
stream->writeAttribute("y2", QString::number(myItem->end_p.y()));
stream->writeEndElement(); //end of Line Item
}
else if (item->type() == Circle::Type)
{
Circle *myItem = dynamic_cast<Circle *>(item);
stream->writeStartElement("Circle");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("cx", QString::number(myItem->center_p.x()));
stream->writeAttribute("cy", QString::number(myItem->center_p.y()));
stream->writeAttribute("radius", QString::number(myItem->radius));
stream->writeEndElement(); //end of Circle Item
}
else if (item->type() == Ellipse::Type)
{
Ellipse *myItem = dynamic_cast<Ellipse *>(item);
stream->writeStartElement("Ellipse");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("cx", QString::number(myItem->p1.x()));
stream->writeAttribute("cy", QString::number(myItem->p1.y()));
stream->writeAttribute("majR", QString::number(myItem->majRadius));
stream->writeAttribute("minR", QString::number(myItem->minRadius));
stream->writeEndElement(); //end of Ellipse Item
}
else if (item->type() == mText::Type)
{
mText *myItem = dynamic_cast<mText *>(item);
stream->writeStartElement("Ellipse");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("textwidth", QString::number(myItem->textWidth()));
stream->writeEndElement(); //end of Text Item
}
}
}
}
From the code you've posted, you're missing a call to the stream writer's writeEndDocument function.

Qt Display tooltip after mouse hover on QGraphicsPixmapItem

I'm using QGraphicView to show game map that consist QGraphicsPixmapItems. I need to show tooltip on mouse hover at QGraphicsPixmapItem.
For saving QGraphicsPixmapItem position I using MazeItem:
#ifndef MAZEITEM_H
#define MAZEITEM_H
#include <QPoint>
#include <QGraphicsItem>
class MazeItem
{
private:
QPoint myPosition;
QString myToolTip;
public:
MazeItem();
QPoint position() const;
QString toolTip() const;
void setToolTip(const QString &toolTip);
void setPosition(const QPoint &position);
QPoint getPosition();
QGraphicsPixmapItem * pixmap;
};
#endif // MAZEITEM_H
I have widget class to display game map:
#include <QWidget>
#include <QtGui>
#include <QGraphicsView>
#include <QToolTip>
#include "mazeitem.h"
class MazeGUI : public QWidget
{
Q_OBJECT
private:
QGraphicsView * graphicsView;
QGraphicsScene * graphicsScene;
QString sceneString;
int imageSize;
QList<MazeItem> mazeItems;
void addItem(int x, int y, QPixmap picture);
bool event(QEvent *event);
int itemAt(const QPoint &pos);
public:
explicit MazeGUI(QWidget *parent = 0);
void setScene(QString sceneString);
signals:
public slots:
void redraw();
};
#endif // MAZEGUI_H
In constructor I set mouse tracking.
MazeGUI::MazeGUI(QWidget *parent) :
QWidget(parent)
{
setMouseTracking(true);
...
}
This is how I add new maze item.
void MazeGUI::addItem(int x, int y, QPixmap picture)
{
MazeItem mazeItem;
mazeItem.setPosition(QPoint(x, y));
mazeItem.setToolTip("text");
mazeItem.pixmap = this->graphicsScene->addPixmap(picture);
mazeItem.pixmap->setPos(y, x);
mazeItems.append(mazeItem);
}
And this I have from Qt tutorials,
bool MazeGUI::event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
// HERE - it never goes here!!
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), mazeItems[index].toolTip());
} else {
QToolTip::hideText();
event->ignore();
}
return true;
}
return QWidget::event(event);
}
int MazeGUI::itemAt(const QPoint &pos)
{
for (int i=0; i < mazeItems.size(); ++i)
{
if (mazeItems[i].getPosition() == pos)
return i;
}
return -1;
}
Was adding the tooltip on wrong object:
Instead of:
mazeItem.setToolTip("text");
It should be:
mazeItem.pixmap->setToolTip("text");

Qt drag & drop button; drop not detecting

I'm creating a 2D game in QT and i'm trying to implement a drag & drop into my program.
For some reason the drop is not registered: qDebug should print a message on dropping but this doesn't happen.
#include "dialog.h"
#include "ui_dialog.h"
#include "world.h"
#include <vector>
Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
MySquare *item;
QGraphicsRectItem *enemyItem;
World *myWorld = new World();
std::vector<Tile*> tiles = myWorld->createWorld(":/texture.jpg");
int count = 0;
foreach (Tile *tile, tiles){
count++;
item = new MySquare(tile->getXPos()*4,tile->getYPos()*4,4,4);
item->setBrush(QColor(tile->getValue()*255,tile->getValue()*255,tile->getValue()*255));
item->setAcceptDrops(true);
scene->addItem(item);
}
player = new MySquare(10,20,10,10);
player->setAcceptDrops(true);
scene->addItem(player);
//drag & drop part
QPushButton *pushButton = new QPushButton("Click Me",this);
connect(pushButton,SIGNAL(pressed()),this,SLOT(makeDrag()));
setAcceptDrops(true);
}
void Dialog::makeDrag()
{
QDrag *dr = new QDrag(this);
// The data to be transferred by the drag and drop operation is contained in a QMimeData object
QMimeData *data = new QMimeData;
data->setText("This is a test");
// Assign ownership of the QMimeData object to the QDrag object.
dr->setMimeData(data);
// Start the drag and drop operation
dr->start();
}
mysquare.cpp
#include "mysquare.h"
MySquare::MySquare(int _x,int _y, int _w, int _h)
{
isPlayer=false;
Pressed=false;
setFlag(ItemIsMovable);
setFlag(ItemIsFocusable);
setAcceptDrops(true);
color=Qt::red;
color_pressed = Qt::green;
x = _x;
y = _y;
w = _w;
h = _h;
}
QRectF MySquare::boundingRect() const
{
return QRectF(x,y,w,h);
}
void MySquare::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brush(color);
if (Pressed){
brush.setColor(color);
} else {
brush.setColor(color_pressed);
}
painter->fillRect(rec,brush);
painter->drawRect(rec);
}
void MySquare::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Pressed=true;
update();
QGraphicsItem::mousePressEvent(event);
qDebug() << "mouse Pressed";
}
void MySquare::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Pressed=false;
update();
QGraphicsItem::mousePressEvent(event);
qDebug() << "mouse Released";
}
void MySquare::keyPressEvent(QKeyEvent *event){
int x = pos().x();
int y = pos().y();
//key handling
QGraphicsItem::keyPressEvent(event);
}
void MySquare::dropEvent(QDropEvent *event)
{
qDebug("dropEvent - square");
// Unpack dropped data and handle it the way you want
qDebug("Contents: %s", event->mimeData()->text().toLatin1().data());
}
void MySquare::dragMoveEvent(QDragMoveEvent *event){
qDebug("dragMoveEvent - square ");
event->accept();
}
void MySquare::dragEnterEvent(QDragEnterEvent *event){
event->setAccepted(true);
qDebug("dragEnterEvent - square");
event->acceptProposedAction();
}
void MySquare::setBrush(QColor _color){
color = _color;
color_pressed = _color;
update(); //repaint
}
edit; there is no problem with qDebug() i'm just using it to test them i'm inside the drag events..which i'm not
In your mouseReleaseEvent, you pass to QGraphicsItem::mousePressEvent instead of QGraphicsItem::mouseReleaseEvent
Edit: I don't know if this matters, but initialize the QGraphicsItem in your constructor
MySquare::MySquare(int _x,int _y, int _w, int _h) : QGraphicsItem()