You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt QTableView悬停显示垂直表头完整文本弹窗问题求助

修正方案

根因说明

  • 弹窗默认带窗口边距,且未添加布局管理内部控件,导致尺寸计算偏移
  • QLabel 手动设置的位置超出了弹窗可视区域,所以设置同尺寸时文本消失
  • 坐标映射误用了表格主视口的转换逻辑,垂直表头本身是独立视口,坐标体系不匹配

修正后完整代码

#ifndef TABLEVIEW_H
#define TABLEVIEW_H

#include <QDialog>
#include <QEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QTableView>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QTimer>
#include <QFontMetrics>

class TableView : public QTableView {
    Q_OBJECT
    QDialog* popup;
    QLabel* popupLabel;
    int editor_index ;

public:
    TableView(QWidget* parent = nullptr) :QTableView(parent) {
        viewport()->installEventFilter(this);
        horizontalHeader()->viewport()->installEventFilter(this);
        verticalHeader()->viewport()->installEventFilter(this);
        setMouseTracking(true);
        
        popup = new QDialog(this, Qt::Popup | Qt::ToolTip | Qt::FramelessWindowHint);
        // 移除弹窗默认边距
        popup->setContentsMargins(0,0,0,0);
        auto* layout = new QVBoxLayout(popup);
        layout->setContentsMargins(0,0,0,0);
        layout->setSpacing(0);
        
        popupLabel = new QLabel(popup);
        popupLabel->setWordWrap(false);
        popupLabel->setTextFormat(Qt::RichText);
        //  label 边距可根据需要调整
        popupLabel->setContentsMargins(2,0,2,0);
        layout->addWidget(popupLabel);
        
        popup->installEventFilter(this);
        popup->hide();
    }

    bool eventFilter(QObject* watched, QEvent* event) override{
        if ((watched == horizontalHeader()->viewport() || watched == verticalHeader()->viewport())) 
        {
            if (event->type() == QEvent::MouseMove) 
            {
                QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);                
                QHeaderView* header = static_cast<QHeaderView*>(watched->parent());
                int mouse_pos = header->orientation() == Qt::Horizontal ? mouseEvent->x() : mouseEvent->y();
                int logical_index = header->logicalIndex(header->visualIndexAt(mouse_pos));
                                
                if (logical_index >= 0) 
                {               
                    showPopup(logical_index, watched);                    
                }                
                else 
                {
                    popup->hide();
                }
            }
            else if (event->type() == QEvent::Leave) {
                popup->hide();
            }
        }
        else if (popup == watched) 
        {
            if (event->type() == QEvent::Leave) 
            {
                popup->hide();
            }
        }
        return QTableView::eventFilter(watched, event);
    }

private:
    void showPopup(const int & logical_index, QObject* watched) const 
    {
        if (logical_index < 0) {
            popup->hide();
            return;
        }
        QHeaderView* header = static_cast<QHeaderView*>(watched->parent());
        QRect rect;
        if (header->orientation() == Qt::Horizontal) {
            rect.setLeft(header->sectionViewportPosition(logical_index));
            rect.setWidth(header->sectionSize(logical_index));
            rect.setTop(0);
            rect.setHeight(header->height());
        }
        else {
            rect.setTop(header->sectionViewportPosition(logical_index));
            rect.setHeight(header->sectionSize(logical_index));
            rect.setLeft(0);
            rect.setWidth(header->width());
        }
        // 获取表头文本
        QString text = header->model()->headerData(logical_index, header->orientation()).toString();
        popupLabel->setText(text);
        // 计算文本实际宽度,也可以固定为表头宽度按需调整
        QFontMetrics fm(popupLabel->font());
        int textWidth = fm.horizontalAdvance(text) + 4; // 加边距补偿
        // 弹窗尺寸设置:高度和表头项一致,宽度适配文本
        popup->setFixedSize(textWidth, rect.height());
        // 坐标映射修正:用当前表头的viewport做全局转换
        QPoint globalPos = static_cast<QWidget*>(watched)->mapToGlobal(rect.topLeft());
        // 垂直表头默认在左侧,弹窗右移避免挡住表头,不需要可以直接用globalPos
        popup->move(globalPos + QPoint(header->width(), 0));
        popup->show();
    }
};

#endif // TABLEVIEW_H

效果说明

  • 弹窗尺寸自动适配文本宽度,不会出现尺寸偏大或文本消失问题
  • 弹窗位置固定在当前hover的表头项右侧,不会随索引偏移
  • 垂直表头宽度可以单独设置为只适配序号尺寸,不影响完整文本显示

内容的提问来源于stack exchange,提问作者ahmed allam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:54:04