本文通过多个案例,详细说明关于Qt窗体尺寸的一些重要问题
默认尺寸
对于一个Qt的窗口(继承于QWidget),获取其窗体尺寸的方法size();
以一个Qt创建Qt Widgets Application项目的默认生成代码为基础,做如下测试
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
qDebug()<<"MainWindow::MainWindow:"<<this->size();
this->resize(1200,800);
qDebug()<<"MainWindow::MainWindow:"<<this->size();
}
第一个this->size()输出QSize(640, 480),即MainWindow具有默认的尺寸640*480
第二个this->size()输出QSize(1200, 800)
实际上,继承于QWidget的控件,例如QPushButton,QLineEdit等也会获得默认的尺寸640*480
QWidget* page=new QWidget;
qDebug()<<".."<<page->size();
QPushButton* btn=new QPushButton;
qDebug()<<".."<<btn->size();
QLineEdit* edt=new QLineEdit;
qDebug()<<".."<<edt->size();
以上输出都是QSize(640, 480)
布局之后的尺寸
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
qDebug()<<"MainWindow::MainWindow:"<<this->size();
this->resize(1200,800);
QWidget* page=new QWidget;
qDebug()<<".."<<page->size();
QVBoxLayout* layout=new QVBoxLayout(page);
QPushButton* btn=new QPushButton;
qDebug()<<".."<<btn->size();
QLineEdit* edt=new QLineEdit;
qDebug()<<".."<<edt->size();
layout->addWidget(btn);
layout->addWidget(edt);
this->setCentralWidget(page);
qDebug()<<".."<<page->size();
qDebug()<<".."<<btn->size();
qDebug()<<".."<<edt->size();
qDebug()<<"MainWindow::MainWindow:"<<this->size();
//当界面显示出来之后,点击按钮查看控件尺寸
connect(btn,&QPushButton::clicked,[=]{
qDebug()<<".."<<page->size();
qDebug()<<".."<<btn->size();
qDebug()<<".."<<edt->size();
});
}
以上代码this->setCentralWidget(page);之后的三个打印对应的尺寸应该是多少?
依然还是 QSize(640, 480)
而connect()方法中的三个打印对应的值则分别为
.. QSize(1200, 800)
.. QSize(1178, 28)
.. QSize(1178, 24)
以上代码说明两个问题:
(1)将控件加入到布局,然后放入了父窗体中,则控件的尺寸会根据父窗体的布局重新设置
(2)控件尺寸的重新设置发生在窗体显示出来后(绘制时)
固定尺寸
以下代码实现在主窗体上布局多个按钮和子窗体,实现点击按钮切换每个子窗体的隐藏和可见。
但是存在问题:
(1)4个子窗体平分了主窗体的尺寸;
(2)隐藏一个子窗体后,其他的子窗体尺寸被更改(窗体重绘时会重新设置尺寸)
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
qDebug()<<"MainWindow::MainWindow:"<<this->size();
this->resize(1200,800);
QWidget* page=new QWidget;
QVBoxLayout* layout=new QVBoxLayout(page);
QScrollArea* contentArea=new QScrollArea;
contentArea->setWidgetResizable(true);
contentArea->setWidget(page);
for(int i=0;i<4;i++)
{
QWidget* p=new QWidget;
//设置窗体背景色,使得区分背景,可见
p->setStyleSheet("background-color:green");
QPushButton* b=new QPushButton;
layout->addWidget(b);
layout->addWidget(p);
connect(b,&QPushButton::clicked,[p]{
//点击按钮后窗体切换显示和隐藏效果
p->setVisible(!p->isVisible());
});
}
this->setCentralWidget(contentArea);
}
如果需要设置子窗体在重绘时不改变尺寸,那么需要设置其尺寸
例如在QWidget* p=new QWidget;下方增加 p->setFixedHeight(300);
这样隐藏和显示一个子窗体不会对任意其他的子窗体的尺寸造成影响。
更改后会发现,当隐藏完所有的子窗体后,所有的按钮被均匀布局在了主窗体,如果想要的效果是按钮从主窗体从上往下紧密排列,可以在layout添加完所有的控件和窗口后,添加一个stretch,即在this->setCentralWidget(contentArea);上一行添加layout->addStretch();
窗体实际尺寸
如果MainWindow设置的高度为600,而它的中心窗体高度为800,该怎样显示?
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
qDebug()<<"MainWindow::MainWindow:"<<this->size();
this->resize(800,600);
qDebug()<<"MainWindow::MainWindow:"<<this->size();
//默认情况下MainWindow没有centralWidget
QWidget* center=new QWidget;
qDebug()<<"center:"<<center->size();
QVBoxLayout* layout=new QVBoxLayout(center);
QWidget* page1=new QWidget;
page1->setStyleSheet("background-color:green");
page1->setFixedHeight(400);
QWidget* page2=new QWidget;
page2->setFixedHeight(400);
page2->setStyleSheet("background-color:yellow");
layout->addWidget(page1);
layout->addWidget(page2);
qDebug()<<"center:"<<center->size();
this->setCentralWidget(center);
//此时输出QSize(800, 600)
qDebug()<<"MainWindow::MainWindow:"<<this->size();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
qDebug()<<"w size:"<<w.size();
return a.exec();
}
以上代码执行时,MainWindow构造函数中的输出mainwindow的窗体高度为600,但是在窗口显示(执行了w.show())之后,它的高度却是829
给窗体设置某个尺寸,实际显示的时候窗体根据布局,不一定恰好按照给定的尺寸来显示
尺寸不够引起重叠的窗体
如果主窗体设置了固定高度600,而它的中心窗体设置固定高度1200?
此时,肯定主窗体显示不全page1和page2
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
qDebug()<<"MainWindow::MainWindow:"<<this->size();
this->resize(800,600);
this->setFixedHeight(600);
qDebug()<<"MainWindow::MainWindow:"<<this->size();
//默认情况下MainWindow没有centralWidget
QWidget* center=new QWidget;
center->resize(800,500);
qDebug()<<"center:"<<center->size();
QVBoxLayout* layout=new QVBoxLayout(center);
QWidget* page1=new QWidget;
page1->setStyleSheet("background-color:green");
page1->setFixedHeight(600);
QWidget* page2=new QWidget;
page2->setFixedHeight(600);
page2->setStyleSheet("background-color:yellow");
layout->addWidget(page1);
layout->addWidget(page2);
qDebug()<<"center:"<<center->size();
this->setCentralWidget(center);
//此时输出QSize(800, 600)
qDebug()<<"MainWindow::MainWindow:"<<this->size();
QTimer::singleShot(1000,[=](){
//为什么page1和page2的高度是600,而实际显示的界面没有600?
//事实上page1和page2的高度都是600,界面上也是600,但是page1和page2重叠了一部分
qDebug()<<"page1:"<<page1->size();
qDebug()<<"page2:"<<page2->size();
qDebug()<<"center:"<<center->size();
qDebug()<<"sizeHint:"<<layout->sizeHint();
qDebug()<<"MainWindow::MainWindow:"<<this->size();
});
}
这里输出了layout的sizeHit(),为1229,layout上放置了page1和page2,他们的高度600+600=1200,29是布局周边留下的空白部分。
最小高度限制
这里展示了一个实际项目中遇到的问题,需要在一个页面中放置多个表格,并且每个表格要直接显示至少5行,更多行的时候滚动条显示。
以下代码是从项目中抽取的问题特征部分:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->resize(800,600);
QWidget* page=new QWidget;
QVBoxLayout* layout=new QVBoxLayout(page);
QScrollArea* contentArea=new QScrollArea;
contentArea->setWidgetResizable(true);
contentArea->setWidget(page);
for(int i=0;i<4;i++)
{
TableWidget* p=new TableWidget;
QPushButton* b=new QPushButton;
layout->addWidget(b);
layout->addWidget(p);
connect(b,&QPushButton::clicked,[p]{
//点击按钮后窗体切换显示和隐藏效果
p->setVisible(!p->isVisible());
qDebug()<<"p size:"<<p->size();
});
}
layout->addStretch();
this->setCentralWidget(contentArea);
}
TableWidget只是一个平凡的QTableWidget实例,它设置了默认表格有6行8列,
TableWidget::TableWidget()
{
this->setRowCount(6);
this->setColumnCount(8);
}
上述代码的效果:
目前的问题是每个表格高度都被挤压了,只显示了一行。
一种解决问题的思路是,在表格初始化时,设置最小高度限制:
TableWidget::TableWidget()
{
this->setMinimumHeight(250);
this->setRowCount(6);
this->setColumnCount(8);
}