C++ 如何确定 QTableWidget 的正确大小?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8766633/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to determine the correct size of a QTableWidget?
提问by Joseph Quinsey
Is there anyway to set the "correct" size of a QTableWidget? (I'm a newbie) This test code is only 25 lines long, in two files, with the file Test.h:
有没有办法设置 QTableWidget 的“正确”大小?(我是新手)这个测试代码只有 25 行,在两个文件中,文件 Test.h:
#include <QtGui>
class Test : public QMainWindow {
Q_OBJECT
public:
Test();
};
and the file Test.cpp:
和文件 Test.cpp:
#include "Test.h"
Test::Test() : QMainWindow() {
QVBoxLayout *vbox = new QVBoxLayout;
QPushButton *btn = new QPushButton("Hello World etc etc etc etc etc");
QTableWidget *tbl = new QTableWidget(2, 2);
vbox->addWidget(btn);
vbox->addWidget(tbl);
QWidget *w = new QWidget;
setCentralWidget(w);
w->setLayout(vbox);
resize(1, 1);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Test test;
test.show();
app.exec();
}
Then the command:
然后命令:
qmake -project && qmake && make && ./Test
gives the window:
给出窗口:
But what we want of course is something more like:
但我们想要的当然更像是:
Using tbl->width()
seems to be useless, as it gives a default of 640
before test.show()
, and the unwanted value of 195
after. I've looked at the Qt Size Hints and Policies until my head spun, and I've tried setResizeMode(QHeaderView::Fixed)
and setStretchLastSection(false)
. Maybe I'm missing something obvious? This is with Qt 4.7.4 on CentOS 5, if this matters. Thank you for any help.
使用tbl->width()
似乎没用,因为它给出了默认值640
beforetest.show()
和不需要的值195
after 。我已经看过了Qt的大小提示和政策,直到我的头纺,我已经试过setResizeMode(QHeaderView::Fixed)
和setStretchLastSection(false)
。也许我错过了一些明显的东西?如果这很重要,这是在 CentOS 5 上的 Qt 4.7.4。感谢您的任何帮助。
Edit: In response to DK, ifthe line resize(1, 1);
is not present, there is the equaland oppositeproblem: the window is too large.
编辑:响应DK,如果该行resize(1, 1);
不存在,则存在相等和相反的问题:窗口太大。
And in response to Donotalo, adding:
并在回应 Donotalo 时补充说:
tbl->setMaximumWidth(222);
tbl->setMinimumWidth(222);
tbl->setMaximumHeight(88);
tbl->setMinimumHeight(88);
will give the desired window size (at least on my machine), but notin the desired way. How should we calculate the 'constants' 222
and 88?
将给出所需的窗口大小(至少在我的机器上),但不是以所需的方式。我们应该如何计算“常数”222
和88?
And Ton's answer to Qt: How to force a hidden widget to calculate its layout?doesn't seem to work here: the addition of tbl->setAttribute(Qt::WA_DontShowOnScreen); tbl->show();
left the value of tbl->width()
unchanged at 640.
Ton 对Qt的回答:如何强制隐藏的小部件计算其布局?在这里似乎不起作用:添加使640tbl->setAttribute(Qt::WA_DontShowOnScreen); tbl->show();
的值tbl->width()
保持不变。
采纳答案by Joseph Quinsey
The thread How to set a precise size of QTableWidget to prevent from having scroll bars? (Qt-interest Archive, June 2007)between Lingfa Yang and Susan Macchia seems to resolve my question. I will post more details shortly, if my testing works.
该线程如何设置 QTableWidget 的精确大小以防止出现滚动条?(Qt-interest Archive,2007 年 6 月)在 Lingfa Yang 和 Susan Macchia 之间似乎解决了我的问题。如果我的测试有效,我将很快发布更多详细信息。
Update #1: My test now generates the nice-looking window:
更新 #1:我的测试现在生成漂亮的窗口:
The complete test code for this, with Test.h unchanged, is:
在 Test.h 不变的情况下,完整的测试代码是:
#include "Test.h"
static QSize myGetQTableWidgetSize(QTableWidget *t) {
int w = t->verticalHeader()->width() + 4; // +4 seems to be needed
for (int i = 0; i < t->columnCount(); i++)
w += t->columnWidth(i); // seems to include gridline (on my machine)
int h = t->horizontalHeader()->height() + 4;
for (int i = 0; i < t->rowCount(); i++)
h += t->rowHeight(i);
return QSize(w, h);
}
static void myRedoGeometry(QWidget *w) {
const bool vis = w->isVisible();
const QPoint pos = w->pos();
w->hide();
w->show();
w->setVisible(vis);
if (vis && !pos.isNull())
w->move(pos);
}
Test::Test() : QMainWindow() {
QVBoxLayout *vbox = new QVBoxLayout;
QPushButton *btn = new QPushButton("Hello World etc etc etc etc etc");
QTableWidget *tbl = new QTableWidget(2, 2);
vbox->addWidget(btn);
vbox->addWidget(tbl);
setCentralWidget(new QWidget);
centralWidget()->setLayout(vbox);
layout()->setSizeConstraint(QLayout::SetMinimumSize); // or SetFixedSize
tbl->setVerticalHeaderItem(1, new QTableWidgetItem("two")); // change size
myRedoGeometry(this);
tbl->setMaximumSize(myGetQTableWidgetSize(tbl));
tbl->setMinimumSize(tbl->maximumSize()); // optional
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Test test;
test.show();
app.exec();
}
Some notes:
一些注意事项:
The above thread's inclusion of
verticalScrollBar()->width()
seems to be wrong. And, in my testing, this was always either a default value of 100, or the value 15, if the scrollbar had been displayed.Applying the
show(); hide();
sequence just to the QTableWidget was not sufficient to force Qt to recalculate the geometry, in this test. I needed to apply it to the whole window.Any suggestions for improvements would be welome. (I'll wait a bit before accepting my own answer, in case there are better solutions.)
上述线程的包含
verticalScrollBar()->width()
似乎是错误的。而且,在我的测试中,如果滚动条已经显示,这始终是默认值 100 或值 15。show(); hide();
在此测试中,仅将序列应用于 QTableWidget 不足以强制 Qt 重新计算几何。我需要将它应用到整个窗口。欢迎提出任何改进建议。(在接受我自己的答案之前,我会稍等片刻,以防有更好的解决方案。)
Update #2:
更新#2:
The Qt-interest thread may be wrong (or, at least, it disagrees with myversion of Qt running mymachine) regarding details on how to calculate the size: the +1 for each gridline is unnecessary, but an overall +4 is needed.
I'm still working through
layout()->invalidate()
vs. e.g. QT: How to preview sizes of widgets in layout BEFOREa show().
Qt-interest 线程可能是错误的(或者,至少,它不同意我运行我的机器的 Qt 版本)关于如何计算大小的细节:每个网格线的 +1 是不必要的,但整体 +4 是需要的.
我仍在研究
layout()->invalidate()
与例如QT:如何在show()之前预览布局中小部件的大小。
Update #3:
更新 #3:
This is my final version--but I'm not very happy with it. Any improvements would be verywelcome.
Things like
adjustSize()
andlayout()->invalidate()
andQt::WA_DontShowOnScreen
don't seem to help.The blog Shrinking Qt widgets to minimum needed sizeis interesting, but using
setSizeConstraint()
is just as good.The
setSizeConstraint()
andmove()
methods are needed for subsequent changes to the table, not shown here.There was an odd thing in my testing, done on CentOS 5 with Qt 4.6.3 and 4.7.4. For the
hide(); show();
sequence, the window position is saved/restored. But about 25% of the time (the patterning was irregular) the restored position would be 24 pixels higheron the screen, presumably the height of the window title. And about 10% of the time the value returned bypos()
would be null. The Qt sitesays for X11 it needsnifty heuristics and clever code
for this, but something seems to be broken somewhere.
这是我的最终版本——但我对它不是很满意。任何改进都会非常受欢迎。
喜欢的东西
adjustSize()
和layout()->invalidate()
和Qt::WA_DontShowOnScreen
似乎并没有帮助。将Qt 小部件缩小到最小所需大小的博客很有趣,但使用起来
setSizeConstraint()
也一样好。该
setSizeConstraint()
和move()
方法都需要后续变化表,这里没有显示。在我的测试中有一件奇怪的事情,它是在带有 Qt 4.6.3 和 4.7.4 的 CentOS 5 上完成的。对于
hide(); show();
序列,窗口位置被保存/恢复。但是大约 25% 的时间(图案不规则)恢复的位置会在屏幕上高出 24 个像素,大概是窗口标题的高度。大约 10% 的时间返回的值pos()
是null。在Qt的网站上说,对X11,它需要nifty heuristics and clever code
为这个事,但似乎被打破的地方。
回答by user6419667
Here is my (pythonic) solution to this problem:
这是我对这个问题的(pythonic)解决方案:
table.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
table.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
table.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
table.resizeColumnsToContents()
table.setFixedSize(table.horizontalHeader()->length() +
table.verticalHeader()->width(),
table.verticalHeader()->length() +
table.horizontalHeader()->height())
This gives me a table with a size perfectly wrapping all rows and columns.
这给了我一个大小完美包裹所有行和列的表格。
回答by Celdor
Recently, I found the same problem. I tested tens of functions found by Google in Qt Center, Qt Project but none of them gave me proper size. I made that function which I believe calculates the closest table size. The function gives a proper vertical but a bit greater horizontal size--it looks like it still cover for a vertical Scroll Bar. Also, I checked whether the table dimensions exceed a desktop size:
最近,我发现了同样的问题。我测试了谷歌在 Qt 中心、Qt 项目中找到的数十个函数,但没有一个给我合适的大小。我做了那个我相信计算最接近表大小的函数。该函数提供了适当的垂直尺寸,但水平尺寸稍大——看起来它仍然覆盖了垂直滚动条。另外,我检查了表格尺寸是否超过桌面尺寸:
const QRect MyApp::adjustTableSize(
QTableView* tv,
const QVBoxLayout* lay,
const int& maxRows,
const int& maxCols) {
// get Desktop size
using std::size_t;
QDesktopWidget desktop;
size_t desW = desktop.screen()->width();
size_t desH = desktop.screen()->height();
int leftM,rightM,topM,bottomM;
lay->getContentsMargins(&leftM,&topM,&rightM,&bottomM);
size_t extraTopHeight = topM + tv->frameWidth();
size_t extraBottomHeight = bottomM + tv->frameWidth();
size_t extraLeftWidth = leftM + tv->frameWidth();
size_t extraRightWidth = rightM + tv->frameWidth();
size_t w = tv->verticalHeader()->width() + extraLeftWidth + extraRightWidth;
size_t h = tv->horizontalHeader()->height() + extraTopHeight + extraBottomHeight;
for(size_t col = 0; col < maxCols; ++col) {
w += tv->columnWidth(col);
}
for(size_t row = 0; row < maxRows; ++row ) {
h += tv->rowHeight(row);
}
std::size_t x,y;
if((w - extraLeftWidth - extraRightWidth) > desW) {
x = 0;
w = desW - extraLeftWidth - extraRightWidth;
} else
x = (desW - w)/2;
if(h - extraTopHeight - extraBottomHeight - QStyle::PM_TitleBarHeight > desH) {
y = extraTopHeight + QStyle::PM_TitleBarHeight;
h = desH - (extraTopHeight + QStyle::PM_TitleBarHeight + extraBottomHeight);
} else
y = (desH - h)/2;
return QRect(x,y,w,h);
}
A few side notes:
一些旁注:
QTableView.
I used QTableView but I think it can also work with QTableWidget.
QTableView。
我使用 QTableView 但我认为它也可以与 QTableWidget 一起使用。
QVBoxLayout.
I am pretty positive that any of the layouts available in Qt can be used in this function instead.
QVBoxLayout。
我非常肯定 Qt 中可用的任何布局都可以在此函数中使用。
Hope, this function can help anybody.
希望这个功能可以帮助任何人。
回答by Ali
I was dealing with the same issue, and I tweaked previous answers to get a correct working code.
我正在处理同样的问题,我调整了以前的答案以获得正确的工作代码。
First, we get contents margins from QTableWidget
. If you just want to adjust its width, you only need to disable horizontal scroll bar.:
首先,我们从QTableWidget
. 如果你只是想调整它的宽度,你只需要禁用水平滚动条。:
int w = 0, h = 0;
ui->tableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
w += ui->tableWidget->contentsMargins().left()
+ ui->tableWidget->contentsMargins().right();
h += ui->tableWidget->contentsMargins().top()
+ ui->tableWidget->contentsMargins().bottom();
Then, we append width of vertical header to w
. The vertical header is a special column that contains rows indexes, and is enabled by default. we also append height of horizontal header to h
. The horizontal header is a special row that contains column titles.
然后,我们将垂直标题的宽度附加到w
. 垂直标题是一个包含行索引的特殊列,默认情况下启用。我们还将水平标题的高度附加到h
. 水平标题是包含列标题的特殊行。
w += ui->tableWidget->verticalHeader()->width();
h += ui->tableWidget->horizontalHeader()->height();
Then, we append width of each column to w
, and height of each row to h
.
然后,我们将每列的宽度附加到w
,并将每行的高度附加到h
。
for (int i=0; i<ui->tableWidget->columnCount(); ++i)
w += ui->tableWidget->columnWidth(i);
for (int i=0; i<ui->tableWidget->rowCount(); ++i)
h += ui->tableWidget->rowHeight(i);
Now, if w
or h
are too large to fit on window, we reduce them to fit in ui->centralWidget->contentsRect()
.
现在,如果w
或h
太大而不适合窗口,我们将它们缩小以适合ui->centralWidget->contentsRect()
.
if (w > ui->centralWidget->contentsRect().width())
w = ui->centralWidget->contentsRect().width();
if (h > ui->centralWidget->contentsRect().height())
h = ui->centralWidget->contentsRect().height();
Unfortunately, I don't know a better way of applying w
and h
to set width and height of QTableWidget
. If I use:
不幸的是,我不知道更好的应用w
和h
设置QTableWidget
. 如果我使用:
ui->tableWidget->setMinimumWidth(w);
ui->tableWidget->setMaximumWidth(w);
ui->tableWidget->setMinimumHeight(h);
ui->tableWidget->setMaximumHeight(h);
Then the user will not be able to resize the widget at all. I think we need to use some sort of manual layouting.
那么用户将根本无法调整小部件的大小。我认为我们需要使用某种手动布局。
It might seem a little off topic, but if you want your table to have more appealing view, use this command to resize columns to fit their data:
这似乎有点离题,但如果您希望您的表具有更吸引人的视图,请使用此命令调整列的大小以适合其数据:
ui->tableWidget->resizeColumnsToContents();
回答by Zbyněk Winkler
To get the width of the table sum the width of the vertical and horizontal headers and twice the frame width. The same goes for the height:
要获得表格的宽度,请将垂直和水平标题的宽度与框架宽度的两倍相加。高度也是如此:
w = verticalHeader()->width() + horizontalHeader()->length() + frameWidth()*2
h = horizontalHeader()->height() + verticalHeader()->length() + frameWidth()*2
There are multiple ways how to set them depending on your circumstances. The preferred probably would be to override sizeHint() to return your values. This way the table stays resizable but absent other requirements will be your size.
根据您的情况,有多种方法可以设置它们。首选可能是覆盖 sizeHint() 以返回您的值。这样桌子保持可调整大小,但没有其他要求将是您的尺寸。
The key to get this working is using the length()
method at the right places instead of just width()
or height()
. I am not exactly sure why but here it does the right thing ;-)
使这项工作发挥作用的关键是length()
在正确的位置使用该方法,而不仅仅是width()
或height()
。我不完全确定为什么,但在这里它做了正确的事情;-)
回答by Agustin Jesus Durand Diaz
Here's my solution (I'm hiding the vertical and horizontal header):
这是我的解决方案(我隐藏了垂直和水平标题):
m_table->resizeColumnsToContents();
m_table->resizeRowsToContents();
int w = 0; // verticalHeader()->width()
int h = 0; // horizontalHeader()->height()
for ( int i = 0; i < m_table->rowCount(); i++ )
{
h += m_table->rowHeight( i );
}
for ( int j = 0; j < m_table->columnCount(); j++ )
{
w += m_table->columnWidth( j );
}
m_table->setFixedSize( w, h );
回答by fabio
apparently there is --some bug maybe?-- in the horizontalHeader()->width() function; this solution worked for me:
显然有--一些错误吗?--在horizontalHeader()->width() 函数中;这个解决方案对我有用:
//given a QtableWidget* called x
int previous_width= x->horizontalHeader()->width();//get the width
//the width is relating to all the columns including the vertical headers
int previous_length=x->horizontalHeader()->length();//and the length
// the length is relating to all the columns excluding the size of the vertical headers
int vertical_headers_width=(previous_width-previous_length);
x->resizeColumnsToContents();//now we resize
x->resizeRowsToContents();
//if we call again x->horizontalHeader()->width();
// we get a number that looks to me not correct (maybe is my ignorance here)
x->setFixedWidth(x->horizontalHeader()->length()+vertical_headers_width);
//by adding to the length of the data columns the old width_of_verticla_headers_column we get the correct size;
回答by TimeS
I cannot comment to Joseph Qunesey's / Celdor's post, so I write it in here:
To retrieve true value of QStyle::PM_TitleBarHeight
, you should do it as follows:
我无法评论 Joseph Qunesey/Celdor 的帖子,所以我写在这里:要检索 的真实值QStyle::PM_TitleBarHeight
,您应该按如下方式进行:
QStyle *style;
if(tv->style())
{
style = tv->style();
}
else
{
style = QApplication::style();
}
int titleBarHeight = style->pixelMetric(QStyle::PM_TitleBarHeight));
That is because the enum does not have assigned exact values. I think, your misunderstanding of how it works was due to misleading Qt documentationwhere it looks like the enum directly represents the values, while it of course does not (as it is style dependent).
那是因为枚举没有分配确切的值。我认为,您对其工作方式的误解是由于误导了 Qt文档,其中枚举看起来像直接表示值,而它当然不是(因为它取决于样式)。