英文:
Qt C++ Drag QHeaderView between tables
问题
我想复制QTableWidget
的选定列到另一个表格。
所以我尝试通过添加以下代码使选定列可拖动:
void makeDraggable(QTableWidget *table)
{
table->setDragEnabled(true);
table->setAcceptDrops(true);
table->setSelectionBehavior(QAbstractItemView::SelectColumns);
}
我得到的结果:
但我想要通过仅点击标题来拖动整列(水平和垂直标题),并将其数据复制到另一个表格,包括标题文本。
英文:
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.
答案1
得分: 0
在一个应用程序内,可以通过重新实现自定义的 QHeaderView
和 QTableWidget
来在不同表格之间进行拖动。在我的示例中,我生成了包含表格和列的索引的文本以进行拖动事件。自定义头部:
#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 <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;
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论