Qt C++ 在表格之间拖动 QHeaderView。

huangapple go评论116阅读模式
英文:

Qt C++ Drag QHeaderView between tables

问题

我想复制QTableWidget的选定列到另一个表格。

所以我尝试通过添加以下代码使选定列可拖动:

void makeDraggable(QTableWidget *table)
{
    table->setDragEnabled(true);
    table->setAcceptDrops(true);
    table->setSelectionBehavior(QAbstractItemView::SelectColumns);
}

我得到的结果:

Qt C++ 在表格之间拖动 QHeaderView。

但我想要通过仅点击标题来拖动整列(水平和垂直标题),并将其数据复制到另一个表格,包括标题文本。

英文:

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:

Qt C++ 在表格之间拖动 QHeaderView。

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.

答案1

得分: 0

在一个应用程序内,可以通过重新实现自定义的 QHeaderViewQTableWidget 来在不同表格之间进行拖动。在我的示例中,我生成了包含表格和列的索引的文本以进行拖动事件。自定义头部:

#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;  // 表格的内部索引
    ITableManager *m_tableManager;  // 管理器将表格索引转换为指针
};

自定义头部 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;
        // 自定义拖动文本,包含索引
        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 - "Table:" 的长度
    QTableWidget* tableSrc = m_tableManager->getTableFromIndex(tableIndex);
    if (!tableSrc)
    {
        event->ignore();
        return;
    }

    // 目标表格作为头部视图的父级
    QTableWidget *tableDst = qobject_cast<QTableWidget*> (this->parentWidget());
    if (!tableDst)
    {
        event->ignore();
        return;
    }

    // 移动列:根据您的需要进行修改
    // 现在只移动项目文本
    int columnIndex = logicalIndexAt(event->pos());
    int srcColumnIndex = dragText.at(2).mid(6).toInt(); // 6 - "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;
}

现在创建带有 DraggableHeaderView 的自定义 QTableWidget

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);
    }
}

为了将表格索引转换为指针,我使用了 ITableManager

class ITableManager
{
public:
    virtual QTableWidget* getTableFromIndex(const int index) = 0;
};

并在 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;
    }
}

不要忘记在表格(在主窗口构造函数中)中设置标签(索引)和表格管理器:

ui->tableWidget->setTag(1);
ui->tableWidget_2->setTag(2);
ui->tableWidget->setTableManager(this);
ui->tableWidget_2->setTableManager(this);

编辑: 如果您想更改拖动的自定义图像,只需设置 QDrag::setPixmap

void

<details>
<summary>英文:</summary>

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 &lt;QHeaderView&gt;
    
    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 &lt;QMouseEvent&gt;
    #include &lt;QDrag&gt;
    #include &lt;QMimeData&gt;
    #include &lt;QDebug&gt;
    #include &lt;QTableWidget&gt;
    
    #include &lt;ITableManager.h&gt;
    
    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-&gt;buttons() &amp; Qt::LeftButton)
        {
            int index = logicalIndexAt(e-&gt;pos());
            QDrag *drag = new QDrag(this);
            QMimeData *mimeData = new QMimeData;
            //custom drag text with indecies inside
            QString mimeTxt = &quot;MoveHeader;Table:&quot; + QString::number(m_tag) +
                    &quot;;Index:&quot; + QString::number(index);
            mimeData-&gt;setText(mimeTxt);
            drag-&gt;setMimeData(mimeData);
            Qt::DropAction dropAction = drag-&gt;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-&gt;ignore();
            return;
        }
    
        QString dragText = event-&gt;mimeData()-&gt;text();
        int index = dragText.indexOf(&quot;MoveHeader;&quot;);
        if (index == 0)
        {
            event-&gt;accept();
        }
        else
        {
            event-&gt;ignore();
        }
    }
    
    void DraggableHeaderView::dropEvent(QDropEvent *event)
    {
        if (!m_tableManager)
        {
            event-&gt;ignore();
            return;
        }
    
        QStringList dragText = event-&gt;mimeData()-&gt;text().split(&#39;;&#39;);
        if (dragText.count() &lt; 3 || dragText.at(0) != &quot;MoveHeader&quot;)
        {
            event-&gt;ignore();
            return;
        }
    
        int tableIndex = dragText.at(1).mid(6).toInt();//6 - length &#39;Table:&#39;
        QTableWidget* tableSrc = m_tableManager-&gt;getTableFromIndex(tableIndex);
        if (!tableSrc)
        {
            event-&gt;ignore();
            return;
        }

        //dst table as parent for header view
        QTableWidget *tableDst = qobject_cast&lt;QTableWidget*&gt; (this-&gt;parentWidget());
        if (!tableDst)
        {
            event-&gt;ignore();
            return;
        }
    
        //move column: modify for your needs
        //now moves only items text
        int columnIndex = logicalIndexAt(event-&gt;pos());
        int srcColumnIndex = dragText.at(2).mid(6).toInt(); //6 - length of &#39;Index:&#39;
        tableDst-&gt;insertColumn(columnIndex);
        for (int iRow = 0; iRow &lt; tableDst-&gt;rowCount() &amp;&amp; iRow &lt; tableSrc-&gt;rowCount(); ++iRow)
        {
            if (tableSrc-&gt;item(iRow, srcColumnIndex))
            {
                tableDst-&gt;setItem(iRow, columnIndex,
                                  new QTableWidgetItem(tableSrc-&gt;item(iRow, srcColumnIndex)-&gt;text()));
            }
            else
            {
                tableDst-&gt;setItem(iRow, columnIndex, new QTableWidgetItem());
            }
        }
        tableSrc-&gt;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&lt;DraggableHeaderView*&gt; (horizontalHeader());
        if (header)
        {
            header-&gt;setTag(tag);
        }
    }
    
    void CustomTableWidget::setTableManager(ITableManager *manager)
    {
        DraggableHeaderView *header = qobject_cast&lt;DraggableHeaderView*&gt; (horizontalHeader());
        if (header)
        {
            header-&gt;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-&gt;tableWidget;
        case 2:
            return ui-&gt;tableWidget_2;
        default:
            return nullptr;
        }
    }

Dont forget setup tags (indecies) and table manager for tables (in main window constructor)

    ui-&gt;tableWidget-&gt;setTag(1);
    ui-&gt;tableWidget_2-&gt;setTag(2);
    ui-&gt;tableWidget-&gt;setTableManager(this);
    ui-&gt;tableWidget_2-&gt;setTableManager(this);

**EDIT:** If you want change custom pixmap for dragging just set `QDrag::setPixmap`

    void DraggableHeaderView::mouseMoveEvent(QMouseEvent *e)
    {
        if (e-&gt;buttons() &amp; Qt::LeftButton)
        {
            int index = logicalIndexAt(e-&gt;pos());
            QDrag *drag = new QDrag(this);
            QMimeData *mimeData = new QMimeData;
            QString mimeTxt = &quot;MoveHeader;Table:&quot; + QString::number(m_tag) +
                    &quot;;Index:&quot; + QString::number(index);
            mimeData-&gt;setText(mimeTxt);
            drag-&gt;setMimeData(mimeData);
            drag-&gt;setPixmap(pixmapForDrag(index));
            Qt::DropAction dropAction = drag-&gt;exec();
        }
    }

And method for taking pixmap of column can be like this

    QPixmap DraggableHeaderView::pixmapForDrag(const int columnIndex) const
    {
        QTableWidget *table = qobject_cast&lt;QTableWidget*&gt; (this-&gt;parentWidget());
        if (!table)
        {
            return QPixmap();
        }
    
        //image for first 5 row
        int height = table-&gt;horizontalHeader()-&gt;height();
        for (int iRow = 0; iRow &lt; 5 &amp;&amp; iRow &lt; table-&gt;rowCount(); ++iRow)
        {
            height += table-&gt;rowHeight(iRow);
        }
    
        //clip maximum size
        if (height &gt; 200)
        {
            height = 200;
        }
    
        QRect rect(table-&gt;columnViewportPosition(columnIndex) + table-&gt;verticalHeader()-&gt;width(),
                     table-&gt;rowViewportPosition(0),
                     table-&gt;columnWidth(columnIndex),
                     height);
        QPixmap pixmap(rect.size());
        table-&gt;render(&amp;pixmap, QPoint(), QRegion(rect));
        return pixmap;
    }

</details>



huangapple
  • 本文由 发表于 2020年1月6日 23:18:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/59614591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定