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
相关产品推荐
相关产品推荐

