J'ai fini par réussir à partir de l'exemple cité ci-dessu.
Voici le code :
mainwidget.h
#ifndef WIDGETPARENT_H
#define WIDGETPARENT_H
#include <QObject>
#include <QtWidgets>
#include <QPainter>
#include <QPen>
QT_BEGIN_NAMESPACE
class QDragEnterEvent;
class QDropEvent;
QT_END_NAMESPACE
class MainWidget : public QWidget
{
Q_OBJECT
public:
explicit MainWidget(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
void dropEvent(QDropEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
signals:
public slots:
};
#endif // WIDGETPARENT_H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QObject>
#include <QWidget>
class MainWindow : public QWidget
{
public:
explicit MainWindow(QWidget *parent = nullptr);
protected:
};
#endif // MAINWINDOW_H
movable_child_widget.h
#ifndef MOVABLE_CHILD_WIDGET_H
#define MOVABLE_CHILD_WIDGET_H
#include <QtWidgets>
#include <QLabel>
class Movable_Child_Widget : public QLabel
{
public:
Movable_Child_Widget(const QString &text, QWidget *parent);
QString labelText() const;
private:
QString m_labelText;
};
#endif // MOVABLE_CHILD_WIDGET_H
main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
#ifdef QT_KEYPAD_NAVIGATION
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
#endif
MainWindow window;
bool smallScreen = QApplication::arguments().contains(QStringLiteral("-small-screen"));
if (smallScreen)
window.showFullScreen();
else
window.show();
return app.exec();
}
mainwidget.cpp
#include "mainwidget.h"
#include "movable_child_widget.h"
static inline QString MemeFamilleDeProgrammes() { return QStringLiteral("application/x-ceTypeDeProgramme"); }
// MemeFamilleDeProgrammes définit un type personnalisé de données à transmettre au presse papier.
// Si deux occurences de ce même programme sont lancées, il sera ainsi possible de passer des widgets
// d'un programme à l'autre.
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
this->setFixedWidth(1000);
this->setFixedHeight(100);
Movable_Child_Widget *newChild = new Movable_Child_Widget("Child widget", this);
newChild->setAttribute(Qt::WA_DeleteOnClose);
QPalette pal = QPalette();
this->setGeometry(0, 0, 600, 100);
pal.setColor(QPalette::Window, QColor("#CC773C")); this->setAutoFillBackground(true); this->setPalette(pal);
setAcceptDrops(true); // <------------------------ Important de le mettre dans le parent du widget à déplacer
}
void MainWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setPen(Qt::blue);
//painter.setBrush(QBrush("#539e47"));
painter.drawRect(0, 0, this->width()-1, this->height()-1);
// on place les quarts d'heures
QPen pen0(Qt::green);
pen0.setWidth(1);
pen0.setStyle(Qt::DashDotLine);
painter.setPen(pen0);
for (int i=0; i<=24*4; i++){
painter.drawLine(int (i*this->width()/96),int (0.5*this->height()-10), int (i*this->width()/96), int (0.5*this->height()+10));
}
// on place les heures
QPen pen1(Qt::blue);
pen1.setWidth(3);
painter.setPen(pen1);
//painter.setPen(Qt::blue);
for (int i=0; i<=24; i++){
painter.drawLine(int (i*this->width()/24), int (0.5*this->height()-10), int (i*this->width()/24), int (0.5*this->height()+10));
}
//updateGeometry();
}
void MainWidget::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat(MemeFamilleDeProgrammes())) {
if (children().contains(event->source())) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
event->acceptProposedAction();
}
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void MainWidget::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasFormat(MemeFamilleDeProgrammes())) {
if (children().contains(event->source())) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
event->acceptProposedAction();
}
} else if (event->mimeData()->hasText()) {
event->acceptProposedAction();
} else {
event->ignore();
}
}
void MainWidget::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(MemeFamilleDeProgrammes())) {
const QMimeData *mime = event->mimeData();
QByteArray itemData = mime->data(MemeFamilleDeProgrammes());
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
QString text;
QPoint offset;
dataStream >> text >> offset;
Movable_Child_Widget *newChild = new Movable_Child_Widget(text, this);
newChild->move(event->pos() - offset);
newChild->show();
newChild->setAttribute(Qt::WA_DeleteOnClose);
if (event->source() == this) {
event->setDropAction(Qt::MoveAction);
event->accept();
} else {
event->acceptProposedAction();
}
} else if (event->mimeData()->hasText()) {
QStringList pieces = event->mimeData()->text().split(QRegularExpression(QStringLiteral("\\s+")));
QPoint position = event->pos();
for (const QString &piece : pieces) {
Movable_Child_Widget *newChild = new Movable_Child_Widget(piece, this);
newChild->move(position);
newChild->show();
newChild->setAttribute(Qt::WA_DeleteOnClose);
position += QPoint(newChild->width(), 0);
}
event->acceptProposedAction();
} else {
event->ignore();
}
}
void MainWidget::mousePressEvent(QMouseEvent *event)
{
Movable_Child_Widget *child = static_cast<Movable_Child_Widget*>(childAt(event->pos()));
if (!child)
return;
QPoint hotSpot = event->pos() - child->pos();
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << child->labelText() << QPoint(hotSpot);
QMimeData *mimeData = new QMimeData;
mimeData->setData(MemeFamilleDeProgrammes(), itemData);
mimeData->setText(child->labelText());
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
const QPixmap *ch = child->pixmap(); drag->setPixmap(*ch);
drag->setHotSpot(hotSpot);
child->hide();
//if (drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction) == Qt::MoveAction)
if (drag->exec(Qt::MoveAction))
child->close();
else
child->show();
}
mainwindow.cpp
#include "movable_child_widget.h"
#include "mainwindow.h"
#include "mainwidget.h"
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
setWindowTitle(tr("Fenêtre principale")); //
QPalette newPalette = palette(); // Fenêtre principale
newPalette.setColor(QPalette::Window, Qt::gray); //
setPalette(newPalette); //
this->setWindowState(Qt::WindowMaximized); //
this->setFixedSize(2000, 1000); //
MainWidget *Widget1 = new MainWidget(this); // Création d'un premier widget
Widget1->move(200, 200); //
MainWidget *Widget2 = new MainWidget(this); // Création d'un second widget
Widget2->move(200, 400); //
}
movable_child_widget.cpp
#include "movable_child_widget.h"
Movable_Child_Widget::Movable_Child_Widget(const QString &text, QWidget *parent)
: QLabel(parent)
{
QFontMetrics metric(font());
QSize size = metric.size(Qt::TextSingleLine, text);
QImage image(size.width() + 12, size.height() + 12, QImage::Format_ARGB32_Premultiplied);
image.fill(qRgba(0, 0, 0, 0));
QFont font;
font.setStyleStrategy(QFont::ForceOutline);
QLinearGradient gradient(0, 0, 0, image.height()-1);
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(0.2, QColor(200, 200, 255));
gradient.setColorAt(0.8, QColor(200, 200, 255));
gradient.setColorAt(1.0, QColor(127, 127, 200));
QPainter painter;
painter.begin(&image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(gradient);
painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1), 25, 25, Qt::RelativeSize);
painter.setFont(font);
painter.setBrush(Qt::black);
painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
painter.end();
QPushButton *bt = new QPushButton ("bt", this);
bt->move(this->width()/2, 0);
setPixmap(QPixmap::fromImage(image));
m_labelText = text;
}
QString Movable_Child_Widget::labelText() const
{
return m_labelText;
}