英文:
How to make table view corner items corners round?
问题
I have a QTableWidget
(alternatively, a QListWidget
) which I want to style in the following way:
-
The "selected" color of the cells should be a certain fixed color. I am able to do this by using the following stylesheet:
QTableWidget::item:selected { background-color: #FF0000 }
-
The "unselected" color of the cells should be set individually, according to a vector of colors that I have within my code. I am able to do this by assigning a
QBrush
to eachQTableWidgetItem
, when created:QColor col = color_vector.value(i); QBrush brush(col); item->setData(Qt::BackgroundRole, QVariant(brush));
-
The entire table should have rounded corners (essentially "clipping" the borders of the corner items in the table).
The last part I have not been able to achieve.
I have tried the following approaches:
- Set the stylesheet:
I can round the corners of the table using this stylesheet:
QTableWidget
{
border: 1px solid;
background: transparent;
border-radius: 5px;
}
Even though this draws a rounded border around the table, the background of the individual cells still "pokes out" at the corners.
I can set the same border-radius
for QTableWidget::item
, but then all corners of all cells will be rounded, and not just at the edges of the table. Since QTableWidgetItem
is itself not a QWidget
, I don't think I can assign the styling to specific items.
- Create a
QDelegate
:
I tried to subclass the QStyledItemDelegate
and override the paint()
function. But it doesn't seem to do much. Maybe I'm making an error (still very new to Qt, so very possible), or maybe the changes are overridden by the options I already set in the stylesheet/setData?
This is what I tried for the paint(painter, option, index)
implementation:
painter->setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(option.rect, 5, 5);
painter->fillPath(path, option.backgroundBrush);
QStyledItemDelegate::paint(painter, option, index);
Then added it to the table widget object:
table->setItemDelegateForRow(0, new RoundedCornerDelegate(table));
This would not even be the final desired outcome yet (I'd still have to figure out a way to draw only one rounded corner), but it doesn't seem to work: the item's background is still drawn as a pure rectangle. Even if I change the brush in the above code to something different, I don't see a different-color rounded rectangle being drawn on top (maybe below?).
- Put the table inside a
QFrame
:
I haven't used QFrame
before, so I'm not sure if this is the intended use. But I created a QFrame
in the UI editor, and added the table as a child. Then I tried:
ui->frame->setStyleSheet("* { border: 1px solid; border-radius: 5 }");
QWidget* child = qobject_cast<QWidget*>(ui->frame->children().at(0));
ui->frame->setFixedSize(child->size());
But this just gives weird results: the border around the QFrame
only seems to exist where the child does not, and the child is not fully visible.
英文:
I have a QTableWidget
(alternatively, a QListWidget
) which I want to style in the following way:
-
The "selected" color of the cells should be a certain fixed color. I am able to do this by using the following stylesheet:
QTableWidget::item:selected { background-color: #FF0000 }
-
The "unselected" color of the cells should be set individually, according to a vector of colors that I have within my code. I am able to do this by assigning a
QBrush
to eachQTableWidgetItem
, when created:QColor col = color_vector.value(i); QBrush brush(col); item->setData(Qt::BackgroundRole, QVariant(brush));
-
The entire table should have rounded corners (essentially "clipping" the borders of the corner items in the table).
The last part I have not been able to achieve.
I have tried the following approaches:
- Set the stylesheet:
I can round the corners of the table using this stylesheet:
QTableWidget
{
border: 1px solid;
background: transparent;
border-radius: 5px
}
Even though this draws a rounded border around the table, the background of the individual cells still "pokes out" at the corners.
I can set the same border-radius
for QTableWidget::item
, but then all corners of all cells will be rounded, and not just at the edges of the table. Since QTableWidgetItem
is itself not a QWidget
, I don't think I can assign the styling to specific items.
- Create a
QDelegate
:
I tried to subclass the QStyledItemDelegate
and override the paint()
function. But it doesn't seem to do much. Maybe I'm making an error (still very new to Qt, so very possible), or maybe the changes are overridden by the options I already set in the stylesheet/setData?
This is what I tried for the paint(painter, option, index)
implementation:
painter->setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(option.rect, 5, 5);
painter->fillPath(path, option.backgroundBrush);
QStyledItemDelegate::paint(painter, option, index);
Then added it to the table widget object:
table->setItemDelegateForRow(0, new RoundedCornerDelegate(table));
This would not even be the final desired outcome yet (I'd still have to figure out a way to draw only one rounded corner), but it doesn't seem to work: the item's background is still drawn as a pure rectangle. Even if I change the brush in the above code to something different, I don't see a different-color rounded rectangle being drawn on top (maybe below?).
- Put the table inside a
QFrame
:
I haven't used QFrame
before, so I'm not sure if this is the intended use. But I created a QFrame
in the UI editor, and added the table as a child. Then I tried:
ui->frame->setStyleSheet("* { border: 1px solid; border-radius: 5 }");
QWidget* child = qobject_cast<QWidget*>(ui->frame->children().at(0));
ui->frame->setFixedSize(child->size());
But this just gives weird results: the border around the QFrame
only seems to exist where the child does not, and the child is not fully visible.
答案1
得分: 1
Solution
sigma 说道:
>看起来你可以通过构建一个带有圆角矩形形状的 QRegion 并使用 QWidget::setMask(QRegion const&) 来实现这个目标。
这使我找到了这个 答案:如何实现QWidget的圆角,并基于它,我制作了以下的最小可重现示例:
#include <QApplication>
#include <QTableWidget>
#include <QHeaderView>
#include <QPainterPath>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
//以下只是我的设置
//只是一个容器窗口
QWidget* w = new QWidget();
QTableWidget* table = new QTableWidget(w);
table->setGeometry(100, 100, 200, 90);
table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//填充表格
table->insertColumn(0);
table->insertColumn(1);
table->insertRow(0);
table->insertRow(1);
table->insertRow(2);
table->setItem(0, 0, new QTableWidgetItem("item1"));
table->item(0, 0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(1, 0, new QTableWidgetItem("item2"));
table->item(1, 0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(2, 0, new QTableWidgetItem("item3"));
table->item(2, 0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(0, 1, new QTableWidgetItem("item4"));
table->item(0, 1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(1, 1, new QTableWidgetItem("item5"));
table->item(1, 1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(2, 1, new QTableWidgetItem("item6"));
table->item(2, 1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
//移除表头
table->verticalHeader()->setVisible(false);
table->horizontalHeader()->setVisible(false);
//表格和其项的样式表
table->setStyleSheet("QTableWidget"
"{"
"background: rgb(4, 104, 38);"
"border: 1px solid white;"
"border-radius: 10px;"
"color: black;"
"selection-background-color: transparent;"
"}"
"QTableWidget::item"
"{"
"border: 1px solid white;"
"border-radius: 0px;"
"}");
table->viewport()->setStyleSheet("background: rgb(4, 104, 38);"
"border: 1px solid white;"
"border-radius: 10px;"
"color: black;");
//解决方法
//在表格视图上设置掩码
//获取视图的矩形
QRect rect = table->viewport()->rect();
QPainterPath path;
//我必须调整它以隐藏突出的角
//只是让它变小
rect.adjust(+1, +1, -1, -1);
//将矩形添加到路径中,以便我们可以将其绘制为圆角矩形
path.addRoundedRect(rect, 7, 7);
//将圆角矩形提供给我们将用作掩码的区域
QRegion mask = QRegion(path.toFillPolygon().toPolygon());
//设置视图的掩码
table->viewport()->setMask(mask);
w->setMaximumSize(800, 600);
w->show();
return a.exec();
}
这是它的外观,你可以看到一些边缘和边框是粗糙的,但这是我能做到的最好的,看看是否可以调整样式表以使其看起来更好:
关于你的方法的解释
第一种方法:
在这种情况下,样式表不起作用,因为 QTableWidgetItem
不是从 QWidget
派生的。
你唯一可以样式化它的方式是通过 ::item 子控件,但没有办法在没有状态的情况下获取单个项目。
第二种方法:
你没有指定你如何使用 QStyledItemDelegate::paint
,所以我猜你没有正确覆盖它,看看这个 答案 上的信息:Qt subclassed QStyledItemDelegate paint method is never called。
即使你修复了这个问题,你仍然需要绘制仅具有特定圆角的矩形。看看这个,了解如何做到:在Qt中绘制仅有2个角是圆角的矩形
我尝试过这种方法,我不建议使用它,因为为了获得所需的结果需要太多工作和混乱。
第三种方法:
使用 QFrame
作为容器只会增加另一层,这会导致表格
英文:
Solution
sigma said:
>It looks like you might be able to achieve this by constructing a QRegion with a rounded rectangular shape and using QWidget::setMask(QRegion const&).
That allowed me to find this answer on: How to round QWidget corners, and based on it, I made the following minimal reproducible example:
#include <QApplication>
#include <QTableWidget>
#include <QHeaderView>
#include <QPainterPath>
int main(int argc,char*argv[])
{
QApplication a(argc, argv);
//the following is just my setup
//just a container widget
QWidget *w = new QWidget();
QTableWidget *table = new QTableWidget(w);
table->setGeometry(100,100,200,90);
table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//filling the table
table->insertColumn(0);
table->insertColumn(1);
table->insertRow(0);
table->insertRow(1);
table->insertRow(2);
table->setItem(0,0,new QTableWidgetItem("item1"));
table->item(0,0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(1,0,new QTableWidgetItem("item2"));
table->item(1,0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(2,0,new QTableWidgetItem("item3"));
table->item(2,0)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(0,1,new QTableWidgetItem("item4"));
table->item(0,1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(1,1,new QTableWidgetItem("item5"));
table->item(1,1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
table->setItem(2,1,new QTableWidgetItem("item6"));
table->item(2,1)->setData(Qt::BackgroundRole, QVariant(QBrush(Qt::green)));
//removing headers
table->verticalHeader()->setVisible(false);
table->horizontalHeader()->setVisible(false);
//stylesheet of table and its items
table->setStyleSheet("QTableWidget"
"{"
"background: rgb(4, 104, 38);"
"border: 1px solid white;"
"border-radius: 10px;"
"color: black;"
"selection-background-color: transparent;"
"}"
"QTableWidget::item"
"{"
"border: 1px solid white;"
"border-radius: 0px;"
"}");
table->viewport()->setStyleSheet("background: rgb(4, 104, 38);"
"border: 1px solid white;"
"border-radius: 10px;"
"color: black;");
//SOLUTION
//setting mask on the table's viewport
//get the viewport's rect
QRect rect = table->viewport()->rect();
QPainterPath path;
//I had to adjust it so it hides the corners that were poking out
//just made it smaller
rect.adjust(+1,+1,-1,-1);
//add the rect to the path so we can draw it as a rounded one
path.addRoundedRect(rect, 7, 7);
//feed the rounded rect to a region that we'll use as a mask
QRegion mask = QRegion(path.toFillPolygon().toPolygon());
//set the viewport's mask
table->viewport()->setMask(mask);
w->setMaximumSize(800,600);
w->show();
return a.exec();
}
Here's how it looks, you can see that some of the edges and border are rough, but this is as good as I could make it, see if you can tweak the style sheets to make it look better:
Explanation regarding your methods
First Method:
Style sheets won't work in this case, because QTableWidgetItem
is not derived from QWidget
.
The only way you could style it is through ::item sub-control, but no way to get a single item without a state.
Second Method:
You haven't specified how exactly you're using QStyledItemDelegate::paint
, so my guess is that you're not overriding it correctly, see this answer on Qt subclassed QStyledItemDelegate paint method is never called.
And event if you fix that, you'll then need to draw a rectangle with only specific corners round. Take a look at this to see how: Drawing Rectangle with only 2 corners rounded in Qt
I tried this method, and I advise against it, too much work and mess for the desired result.
Third Method:
Using a QFrame
as a container would only add another layer, it would cause the same problem between the table widget and its viewport.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论