用鼠标更改QTableView中的列宽

Change column width in QTableView with mouse

本文关键字:QTableView 鼠标      更新时间:2023-10-16

我需要QTableView中的行为,以便不仅在QHeaderView的帮助下,而且直接在QTableView区域本身上更改列宽。如果我可以在QTableView区域的单元格之间设置光标指针,并在QTableView区域上单击并拖动来更改列宽,那就太好了。

这里有一个部分答案,显示如何访问列分隔符

/** sense mouse position */
bool FreezeTableWidget::eventFilter(QObject *, QEvent *event) {
    if (event->type() == QEvent::MouseMove) {
        QMouseEvent *m = static_cast<QMouseEvent*>(event);
        QPoint p = m->pos();
        QRect r = visualRect(indexAt(p));
        if (abs(p.x() - r.x()) < 3) // || abs(p.x() - r.right()) < 3)
            setCursor(Qt::SplitHCursor);
        else
            unsetCursor();
    }
    return false;
}

eventFilter是一个虚拟函数,但必须注册它才能调用它。我在FreezeTableWidget构造函数中添加了:

qApp->installEventFilter(this);

edit:关于位置检查,来自eviruff的建议也有效(尽管计算效率的论点是不合理的),但总的来说,我认为你可以尝试一种替代的、更通用的方法:即使用horizontalHeader项作为代理处理程序,因为我们已经拥有了所有必需的、可工作的逻辑。

如果您想尝试(并了解)这些GUI细节,请尝试移动鼠标的垂直位置,并将事件赋予标题。。。我认为这是可行的,而且会比自己追踪状态更简单。

事实上,我认为这种行为没有任何问题。特别是对于只读表视图来说,它可能非常方便。

实现这一点的最快方法是安装事件处理程序,该程序将捕获鼠标事件并发出调整大小命令。显然,如果鼠标位于列分隔符上方/附近,则必须手动计算。

UPD:若要了解光标是否围绕垂直轴,可以使用以下方法:

/* Returns the x-coordinate in contents coordinates of the given column. */
int x = tableView->columnViewportPosition(int column); 

鼠标事件将为您提供鼠标位置,然后您可以很容易地看到它是否匹配任何列轴。

UPD2:我甚至会用一种更复杂的方式来实现它,在一个eventHandler中处理mousemove和header resize/scroll事件。。。缓存排序列表中的列位置,优化在mousemove处理程序中花费的时间。。因此,您将获得二进制搜索和距离检查。。但这当然取决于界面的重量。。

感谢大家!

以下是我对源代码的结果,它实现了问题中的行为(有点脏,但有总体想法):

#define DELTA_SPLIT 4
static bMouseBetweenCols= false;
static int nResizeColumn= -1;
void CHeaderTableView::mouseMoveEvent(QMouseEvent * event)
{
    QMouseEvent *m = static_cast<QMouseEvent*>(event);
    QPoint p = m->pos();
    QRect r = visualRect(indexAt(p));
    if (bMouseBetweenCols && nResizeColumn != -1)
    {
        QTableView* pT= dynamic_cast<QTableView*>(parent());
        if (pT)
        {
            Q_ASSERT(pT->horizontalHeader());
            int nMinSectionSize= pT->horizontalHeader()->minimumSectionSize();
            int nSectionSize= p.x() - columnViewportPosition(nResizeColumn);
            if (nSectionSize >= nMinSectionSize)
            {
                pT->horizontalHeader()->resizeSection(nResizeColumn, nSectionSize);
            }
        }
    }
    if (    abs(p.x() - r.right()) <= DELTA_SPLIT
        ||  abs(p.x() -  r.left()) <= DELTA_SPLIT)
    {
        setCursor(Qt::SplitHCursor);
        event->ignore();
        return;
    }
    else
        unsetCursor();
    QTableView::mouseMoveEvent(event);
}
void CHeaderTableView::mousePressEvent(QMouseEvent *event)
{
    QMouseEvent *m = static_cast<QMouseEvent*>(event);
    QPoint p = m->pos();
    QRect r = visualRect(indexAt(p));
    if (    abs(p.x() - r.right()) <= DELTA_SPLIT
        ||  abs(p.x() -  r.left()) <= DELTA_SPLIT)
    {
        QTableView* pT= dynamic_cast<QTableView*>(parent());
        if (pT)
        {
            nResizeColumn= pT->horizontalHeader()->visualIndex(indexAt(p).column());
            if (abs(p.x() - r.left()) <= DELTA_SPLIT) { nResizeColumn--; }
            nResizeColumn= pT->horizontalHeader()->logicalIndex(nResizeColumn);
            if (nResizeColumn >= 0)
                bMouseBetweenCols= true;
            event->ignore();
            return;
        }
    }
    QTableView::mousePressEvent(event);
}
void CHeaderTableView::mouseReleaseEvent(QMouseEvent *event)
{
    QMouseEvent *m = static_cast<QMouseEvent*>(event);
    QPoint p = m->pos();
    QRect r = visualRect(indexAt(p));
    if (    abs(p.x() - r.right()) <= DELTA_SPLIT
        ||  abs(p.x() -  r.left()) <= DELTA_SPLIT)
    {
        bMouseBetweenCols= false;
        nResizeColumn= -1;
        event->ignore();
        return;
    }
    bMouseBetweenCols= false;
    nResizeColumn= -1;
    QTableView::mouseReleaseEvent(event);
}
void CHeaderTableView::mouseDoubleClickEvent(QMouseEvent *event)
{
    QMouseEvent *m = static_cast<QMouseEvent*>(event);
    QPoint p = m->pos();
    QRect r = visualRect(indexAt(p));
    if (    abs(p.x() - r.right()) <= DELTA_SPLIT
        ||  abs(p.x() -  r.left()) <= DELTA_SPLIT)
    {
        QTableView* pT= dynamic_cast<QTableView*>(parent());
        if (pT)
        {
            int nDblClickColumn= pT->horizontalHeader()->visualIndex(indexAt(p).column());
            if (abs(p.x() - r.left()) <= DELTA_SPLIT) { nDblClickColumn--; }
            nDblClickColumn= pT->horizontalHeader()->logicalIndex(nDblClickColumn);
            pT->resizeColumnToContents(nDblClickColumn);
        }
        event->ignore();
        return;
    }
    QTableView::mouseDoubleClickEvent(event);
}