よく使いそうな機能なので、ChatGPTといろいろやりとりしながら、BugFixして完成したものです。グリッド内のボタンをDrag&Dropで動かせるので、対応関係の設定などに利用すると便利そうです。
DraggableButton.h #pragma once #include #include #include #include #include class DraggableButton : public QPushButton { Q_OBJECT public: explicit DraggableButton(const QString &text, QWidget *parent = nullptr) : QPushButton(text, parent), m_row(0), m_col(0) { setAcceptDrops(false); } int row() const { return m_row; } int col() const { return m_col; } void setCell(int r, int c) { m_row = r; m_col = c; } protected: void mousePressEvent(QMouseEvent *event) override { dragStartPos = event->pos(); QPushButton::mousePressEvent(event); } void mouseMoveEvent(QMouseEvent *event) override { if (!(event->buttons() & Qt::LeftButton)) return; if ((event->pos() - dragStartPos).manhattanLength() < 5) return; QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << m_row << m_col; auto *mime = new QMimeData; mime->setData("application/x-griditem", data); auto *drag = new QDrag(this); drag->setMimeData(mime); drag->exec(Qt::MoveAction); } private: QPoint dragStartPos; int m_row; int m_col; };
DraggableGridWidget.h #pragma once #include #include "DraggableButton.h" class DraggableGridWidget : public QWidget { Q_OBJECT public: explicit DraggableGridWidget(int rows, int cols, QWidget *parent = nullptr); void addButton(DraggableButton *btn, int row, int col); protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; void dropEvent(QDropEvent *event) override; private: int m_rows; int m_cols; QPoint cellTopLeft(int row, int col) const; DraggableButton* buttonAtCell(int row, int col) const; };
DraggableGridWidget.cpp #include "DraggableGridWidget.h" #include #include #include #include DraggableGridWidget::DraggableGridWidget(int rows, int cols, QWidget *parent) : QWidget(parent), m_rows(rows), m_cols(cols) { setAcceptDrops(true); } void DraggableGridWidget::addButton(DraggableButton *btn, int row, int col) { btn->setParent(this); btn->setCell(row, col); btn->resize(width()/m_cols, height()/m_rows); btn->move(cellTopLeft(row, col)); btn->show(); } QPoint DraggableGridWidget::cellTopLeft(int row, int col) const { int w = width() / m_cols; int h = height() / m_rows; return QPoint(col * w, row * h); } DraggableButton* DraggableGridWidget::buttonAtCell(int row, int col) const { for (auto btn : findChildren()) { if (btn->row() == row && btn->col() == col) return btn; } return nullptr; } void DraggableGridWidget::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); QPainter painter(this); painter.setPen(QPen(Qt::gray, 1)); int w = width() / m_cols; int h = height() / m_rows; for (int r = 1; r < m_rows; ++r) painter.drawLine(0, r*h, width(), r*h); for (int c = 1; c < m_cols; ++c) painter.drawLine(c*w, 0, c*w, height()); } void DraggableGridWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); int cellW = width() / m_cols; int cellH = height() / m_rows; for (auto btn : findChildren()) { int row = btn->row(); int col = btn->col(); btn->resize(cellW, cellH); btn->move(cellTopLeft(row, col)); } } void DraggableGridWidget::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-griditem")) event->acceptProposedAction(); } void DraggableGridWidget::dragMoveEvent(QDragMoveEvent *event) { if (event->mimeData()->hasFormat("application/x-griditem")) event->acceptProposedAction(); } void DraggableGridWidget::dropEvent(QDropEvent *event) { if (!event->mimeData()->hasFormat("application/x-griditem")) return; QByteArray data = event->mimeData()->data("application/x-griditem"); QDataStream stream(&data, QIODevice::ReadOnly); int fromRow, fromCol; stream >> fromRow >> fromCol; int cellW = width()/m_cols; int cellH = height()/m_rows; int toCol = event->position().x() / cellW; int toRow = event->position().y() / cellH; auto *fromBtn = buttonAtCell(fromRow, fromCol); auto *toBtn = buttonAtCell(toRow, toCol); if (!fromBtn) return; if (toBtn) { // 交換 fromBtn->move(cellTopLeft(toRow, toCol)); toBtn->move(cellTopLeft(fromRow, fromCol)); fromBtn->setCell(toRow, toCol); toBtn->setCell(fromRow, fromCol); } else { fromBtn->move(cellTopLeft(toRow, toCol)); fromBtn->setCell(toRow, toCol); } event->acceptProposedAction(); }
mainwindow内のダイアログ起動コード void MainWindow::on_actionimport_triggered() { QDialog dlg(this); dlg.setWindowTitle("Draggable Grid"); dlg.resize(400, 400); auto *grid = new DraggableGridWidget(3, 3, &dlg); QVBoxLayout *vbox = new QVBoxLayout(&dlg); vbox->addWidget(grid); for (int r = 0; r < 3; ++r) for (int c = 0; c < 3; ++c) { if(c>0&&r>0){ auto btn = new DraggableButton(QString("B%1%2").arg(r).arg(c), grid); grid->addButton(btn, r, c); } } dlg.exec(); }
0 件のコメント:
コメントを投稿