Skip to content
  • 0 Votes
    5 Posts
    240 Views
    Pl45m4P

    @Axel-Spoerl said in QWidget Drag And Drop inside Layout. Is this a good way?:

    I have troubles to imagine what you mean by that. Colors aside, a widget is typically a rectangle. If I want to indicate a potential landing spot, I'd rather use a rectangle, than a line.

    I think @StudentScripter means the same behavior you see when adding widgets to a layout in QtDesigner.

    A "line" can be a thin rectangle :)

    You also see a rectangle when dragging QDockWidgets around showing the valid DockAreas.

    Maybe check the source code of QtCreator's Designer or QMainWindows dockarea.

  • 0 Votes
    11 Posts
    664 Views
    S

    @Pl45m4 I tried another thing now. Just using the group as way of organizing but setting a qgraphicsrectitem as parent of the qgraphicsitem group. On mouse release i position the qgraphicsrectitem above the groupitem:

    if(DragSelectionInProgress == true){ qDebug() << "SelectionInProgress" << GroupSelectionRect; //Erstelle eine Liste aller selecteten items die nicht das grouprect sind und füge alle items dieser Liste dem grouprect hinzu if(GroupSelectionRect){ QList<QGraphicsItem *> selectedItems = this->selectedItems(); QList<QGraphicsItem *> itemsToAdd; foreach(QGraphicsItem *item, selectedItems) { if(item != GroupSelectionRect && item != SelectionRectPixItem) { itemsToAdd.append(item); } } if(itemsToAdd.count() > 1){ foreach(QGraphicsItem *item, itemsToAdd) { // Check if the item is a pixmap item or a rect item ResizablePixmapItem *rectItem = qgraphicsitem_cast<ResizablePixmapItem *>(item); if(rectItem){ rectItem->setShouldDrawHandles(false); rectItem->drawHandlesIfNecessary(false); //rectItem->setParentItem(SelectionRectPixItem); } GroupSelectionRect->addToGroup(item); } GroupSelectionRect->setParentItem(SelectionRectPixItem); SelectionRectPixItem->setRect(GroupSelectionRect->boundingRect()); //GroupSelectionRect->setSelected(true); } } DragSelectionInProgress = false; }else{ } QGraphicsScene::mouseReleaseEvent(event); }

    I can calculate exactly how many pixel the qgraphicsrectitem is resized, but how do i apply this to the group? I want the graphicsitemgroup to mimic the proportions of the qgraphicsrectitem. It should only resize, but stay anchored in the corner that is not moved.

    The green outline below is the groupitem, the handles are from the qgraphicsrectitem laying above: f41f87da-3b8b-4e26-aee5-dcf1bf1d3da3-image.png cb6797e3-0bd4-4e9e-9f11-90d6cc8547e8-image.png

  • 0 Votes
    3 Posts
    273 Views
    S

    @Pl45m4 Worked like a charm, thank you very much. :)

  • 0 Votes
    1 Posts
    188 Views
    No one has replied
  • 0 Votes
    1 Posts
    160 Views
    No one has replied
  • 0 Votes
    8 Posts
    598 Views
    jsulmJ

    @Narutoblaze Please read again what @JonB wrote. Especially what he copied from Qt documentation...

  • 0 Votes
    12 Posts
    965 Views
    M

    AS @JonB said,
    Python is a dynamic language, C++ is not.
    So, you need to make an explicit cast to retreive the type of object you want.
    If you expect e->source() to return a QTabWidget, you need to do:

    QTabWidget* tabWidget=qobject_cast<QTabWidget*>(e->source()); if(tabWidget) // is a tab widget ? ( // indeed it is ) else { // is not }
  • 0 Votes
    9 Posts
    2k Views
    W

    Awesome, I will check that out, thank you very much!

  • Drag & Drop d'un Widget

    Solved French
    5
    0 Votes
    5 Posts
    738 Views
    M

    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; }
  • 0 Votes
    8 Posts
    953 Views
    Pl45m4P

    @sticky-thermos said in Receive Drag/Drop events for items in QGraphicsScene:

    void ChessBoard::mouseMoveEvent(QMouseEvent *event) {
    std::cout << FUNCTION << std::endl;
    QGraphicsView::mousePressEvent(event);
    QDrag *drag = new QDrag(this);
    QMimeData *mime = new QMimeData; // this is necessary even if nothing is set in the mime data
    drag->setMimeData(mime);
    drag->exec();
    }

    Looks good, but I would add a check to differenciate whether your mouseButton is down. Otherwise you are creating a lot of drags from just moving your mouse around on your chessBoard.

    Also, you are passing the ChessBoard::mouseMoveEvent(QMouseEvent *event) to QGraphicsView::mousePressEvent(event).
    QGraphicsView::mouseMoveEvent would be more fitting :)

  • 0 Votes
    1 Posts
    474 Views
    No one has replied
  • 0 Votes
    5 Posts
    1k Views
    O

    @SGaist @JonB With inspiration from QTableWidget sources my approach for internal reordering is now to override dropEvent and in there use moveRows.

    if (event->source() == this) { // It's an internal move, a solution based on overridden QAbstractItemModel::moveRows

    That works for internal reordering.

    It seems like QDrag::exec is supposed to return an action performed but I find no information on how the information about a successful drop shall get back to the source widget and also the call to QDrag::exec is buried deep within a mouse event handler for QAbstractItemView.

    My solution is to also implement copy-or-move in an overridden dropEvent. First let the base class process the drop event. If accepted then check keyboard modifers. If not ctrl modifier, i.e. if move, then use the event source to find the source widget and call remove on the source widget.

  • 0 Votes
    5 Posts
    486 Views
    SGaistS

    Good then please mark the thread as solved using the "Topic Tools" button so that other forum users may know a solution has been found.

  • 0 Votes
    2 Posts
    273 Views
    SGaistS

    Hi,

    Can you explain what exactly you are trying to achieve ?

  • 0 Votes
    26 Posts
    3k Views
    D

    @JKSH Yep I'm having a full run through the app now to ensure everything happens in GUI thread - that is widget/affects widget.

  • 0 Votes
    8 Posts
    1k Views
    SGaistS

    Hi @Sebastien-Leon and welcome to devnet,

    Can you post the link to the bug report / gerrit review you made ?

  • 0 Votes
    6 Posts
    823 Views
    Christian EhrlicherC

    Drag'n'Drop from a QListWidget to another QListWidget should work out-of-the-box if dragEnabled/acceptDrops is active - see documentation

  • 0 Votes
    1 Posts
    371 Views
    No one has replied
  • 1 Votes
    5 Posts
    4k Views
    M

    @Athius
    Sure it works, here my code for a bookmark tree:

    bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(column) if(action EQ Qt::IgnoreAction) return false; if(action EQ Qt::MoveAction) { QByteArray bytes=data->data(MIME_Bookmark); QDataStream stream(&bytes,QIODevice::QIODevice::ReadOnly); qintptr i; int r,c; stream>>i>>r>>c; QModelIndex index=createIndex(r,c,i); moveRow(index,index.row(),parent,row); } return true; }

    Of course you need to create and return your custom data in mimeData () as well.

  • 0 Votes
    2 Posts
    2k Views
    T

    By adding the line "property alias mouser: mouseArea" to the TreeView.qml of Qt, I can implement mouser.onPressed: {...} inside my TreeView code.
    This way both the selection and drag&drop work, but I actually don't like the idea of modifying Qt code.

    No one out there with an approach how to solve this a bit cleaner?