QTableWidget QTableView 选中虚框问题

本文介绍如何通过使用自定义项委托(item delegate)来隐藏PyQt中QTableWidget选中单元格周围的焦点矩形边框。通过重写paint方法,并在绘制前移除QStyle::State_HasFocus状态,可以实现这一效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原址:http://stackoverflow.com/questions/2055705/hide-the-border-of-the-selected-cell-in-qtablewidget-in-pyqt



3
down vote accepted

It looks like this dotted border around selected cell you're trying to hide is a focus rectangle. Any given cell can have focus and not be selected at the same time and vice-versa. If you want this border to not get painted use an item delegate. There you can remove State_HasFocus style from the item's state before painting it. Pls, see an example below on how to do this, it's c++, let me know if you have troubles converting it to python

// custom item delegate class
class NoFocusDelegate : public QStyledItemDelegate
{
protected:
    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
};

void NoFocusDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const
{
    QStyleOptionViewItem itemOption(option);
    if (itemOption.state & QStyle::State_HasFocus)
        itemOption.state = itemOption.state ^ QStyle::State_HasFocus;
    QStyledItemDelegate::paint(painter, itemOption, index);
}
...
// set the item delegate to your table widget
ui->tableView->setItemDelegate(new NoFocusDelegate());

<think>我们有两个目标:1.去除选中单元格时的线;2.设置整行的悬停和选中背景色(用户之前的问题)。但当前用户的问题聚焦在去除线,所以我们先解决这个问题,然后可以简要提及整行背景色的设置(因为之前已经回答过,这里可以引用之前的方法)。根据引用内容,去除线有三种方法:方法一(引用[1]):使用样式表设置全局样式:`QTableView {outline:0px; }`或针对QTableWidget设置:`tableWidget->setStyleSheet("QTableWidget {outline:0px; }");`方法二(引用[2]):使用代理样式(ProxyStyle)通过重载`drawPrimitive`函数,当绘制焦点矩形(PE_FrameFocusRect)时跳过绘制。方法三(引用[3]):使用自定义委托(Delegate)重写`paint`函数,在绘制时去掉焦点。下面分别给出三种方法的实现:###方法一:样式表(最简单) ```cpp//去除选中时的线tableWidget->setStyleSheet("QTableWidget {outline:0; }"); //或者更精确地针对item的选中线(有时样式表需要这样写) tableWidget->setStyleSheet("QTableWidget::item:focus {outline:none;}");```注意:有时可能需要同时设置`QTableView`,因为`QTableWidget`继承自`QTableView`,所以也可以:```cpptableWidget->setStyleSheet("QTableView{ outline:0;}");``` ###方法二:使用代理样式(ProxyStyle)步骤:1.创建一个继承自`QProxyStyle`的类,重写`drawPrimitive`函数,当绘制焦点矩形时跳过。2.将代理样式设置到表格控件上。代码示例: ```cppclassNoFocusProxyStyle :public QProxyStyle{public:usingQProxyStyle::QProxyStyle;voiddrawPrimitive(PrimitiveElement element, constQStyleOption *option,QPainter*painter,const QWidget *widget)const override{if (element ==PE_FrameFocusRect){//不绘制焦点矩形return;}QProxyStyle::drawPrimitive(element, option, painter, widget);} };//使用tableWidget->setStyle(newNoFocusProxyStyle); //注意:设置后样式由代理接管,原有的样式表可能被覆盖,需要重新设置样式表```注意:使用此方法后,如果之前设置了样式表,可能需要重新设置表格的样式表,因为设置新的样式对象会重置样式表。可以在设置代理样式后再设置样式表。###方法三:使用自定义委托(Delegate)步骤:1.创建一个继承自`QStyledItemDelegate`的类,重写`paint`函数,在绘制时去掉焦点。2.将委托设置到表格控件上。代码示例: ```cppclass NoFocusDelegate: publicQStyledItemDelegate{public:usingQStyledItemDelegate::QStyledItemDelegate;voidpaint(QPainter*painter,const QStyleOptionViewItem&option, constQModelIndex &index)const override{//复制option,去掉状态中的获得焦点状态QStyleOptionViewItem opt= option;if (opt.state& QStyle::State_HasFocus) {opt.state ^= QStyle::State_HasFocus; //移除焦点状态}QStyledItemDelegate::paint(painter, opt, index);} };//使用tableWidget->setItemDelegate(new NoFocusDelegate(tableWidget)); ```###推荐方法对于去除线,推荐使用方法一(样式表),因为它最简单,且不影响其他样式设置。但需要注意的是,用户之前还要求设置整行的悬停和选中背景色,我们之前已经通过自定义QTableWidget(HoverTableWidget)来实现。在自定义类中,我们使用了`setSelectionBehavior(QAbstractItemView::SelectRows)`来整行选择,并且设置了样式表来改变选中行的颜色(如:`setStyleSheet(QString("QTableWidget::item:selected{ background: %1;}").arg(m_selectedColor.name()));`)。在这种情况下,我们可以在同一个样式表中同时去除线。例如,在自定义类中设置样式表: ```cppsetStyleSheet("QTableWidget {outline:0; }""QTableWidget::item:selected{ background: #87CEFA;}"); ```这样既去除了线,又设置了选中行的背景色。另外,在自定义类中,我们通过鼠标事件设置了悬停行的背景色,所以悬停效果不受样式表影响。 ###总结1.去除线:在样式表中设置`outline:0`或`outline:none`是最简单的方法。2.整行选中背景色:通过样式表设置`QTableWidget::item:selected`的背景色。3.整行悬停背景色:通过自定义类中的`mouseMoveEvent`和`leaveEvent`动态设置行的背景色。因此,在之前的自定义类`HoverTableWidget`中,我们可以在构造函数中加入去除线的样式表设置: ```cppHoverTableWidget::HoverTableWidget(QWidget *parent):QTableWidget(parent) {setMouseTracking(true);setSelectionBehavior(QAbstractItemView::SelectRows);//设置样式表:去除线,并设置选中行背景色setStyleSheet("QTableWidget {outline:0; }");//注意:这里我们不在样式表中设置选中颜色,而是通过setSelectedColor函数设置,因为颜色是动态的//所以我们在setSelectedColor函数中设置选中颜色的样式表}```然后在`setSelectedColor`函数中,我们覆盖选中行的样式: ```cppvoid HoverTableWidget::setSelectedColor(constQColor&color) {m_selectedColor =color;//更新样式表(同时保留去除线的设置)setStyleSheet(QString("QTableWidget {outline:0; }QTableWidget::item:selected {background:%1; }").arg(m_selectedColor.name()));} ```这样,我们就同时实现了:-去除选中单元格的线-整行选中背景色-整行悬停背景色如果用户不需要自定义类,只是单独去除线,那么直接使用样式表设置即可。最后,关于用户之前的问题(整行背景色)和当前问题(去除线)的结合,我们已经给出了解决方案。</think>### 去除 QTableWidget 选中单元格的线边 以下是三种可靠方法,按实现复杂度排序: #### 方法一:使用样式表(推荐) ```cpp // 最简单有效的方式 tableWidget->setStyleSheet("QTableWidget { outline: none; }"); ``` 或更精确的写法: ```cpp tableWidget->setStyleSheet("QTableWidget::item:focus { outline: none; }"); ``` **优点**: - 一行代码即可解决问题 - 不改变原有选择行为 - 兼容性好[^1] **效果**:立即消除选中单元格时的线边 #### 方法二:自定义代理类(保持原有样式) ```cpp // 头文件 NoFocusDelegate.h #include <QStyledItemDelegate> class NoFocusDelegate : public QStyledItemDelegate { public: void paint(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { QStyleOptionViewItem opt = option; opt.state &= ~QStyle::State_HasFocus; // 移除焦点状态 QStyledItemDelegate::paint(painter, opt, index); } }; // 使用 tableWidget->setItemDelegate(new NoFocusDelegate(tableWidget)); ``` **优点**: - 精确控制绘制行为 - 保留其他选择状态(如背景色) - 不影响表格其他样式[^3] #### 方法三:自定义样式类(系统级修改) ```cpp // 头文件 NoFocusStyle.h #include <QProxyStyle> class NoFocusStyle : public QProxyStyle { public: void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override { if (element == PE_FrameFocusRect) return; // 跳过焦点绘制 QProxyStyle::drawPrimitive(element, option, painter, widget); } }; // 使用(应用后仍可单独设置表头样式) tableWidget->setStyle(new NoFocusStyle); tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section { background: skyblue; }"); ``` **适用场景**: - 需要全局移除所有焦点 - 与其他自定义样式配合使用[^2] ### 效果对比 | 方法 | 实现难度 | 保持选择色 | 表头独立样式 | 恢复默认样式 | |------------|----------|------------|--------------|--------------| | 样式表 | ⭐ | ✓ | ✓ | ✓ | | 自定义代理 | ⭐⭐ | ✓ | ✓ | ✓ | | 自定义样式 | ⭐⭐⭐ | ✓ | ✓ | 需手动恢复 | ### 最佳实践建议 1. **优先使用样式表方案**,代码简洁高效: ```cpp tableWidget->setStyleSheet("QTableView { outline: 0; }"); ``` 2. 如需保留选择背景色,配合整行选择使用: ```cpp tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); tableWidget->setStyleSheet( "QTableView { outline: none; }" "QTableView::item:selected { background: #87CEFA; }" ); ``` 3. **恢复默认样式**: ```cpp // 样式表方案 tableWidget->setStyleSheet(""); // 自定义代理方案 tableWidget->setItemDelegate(nullptr); // 自定义样式方案 tableWidget->setStyle(nullptr); // 恢复系统默认样式 ``` > **重要提示**:所有方法都需要配合 `setSelectionBehavior(QAbstractItemView::SelectRows)` 才能实现真正的整行选择效果[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值