一直没涉及布局,学习一波
QLayout 和 QLayoutItem 这两个类是抽象类,当设计自定义的布局管理器时才会使用到。
通常使用的是由 Qt 实现的 QLayout 的几个子类
由于没设置布局,所以调整窗口大小时会出现下面情况,故setFixedSize(830,780),固定窗口大小
出现上面现象的原因是为了圆角窗体效果,设置了窗体遮罩。
QBitmap bmp(this->size());
bmp.fill(Qt::white); //生成遮罩图片,得填充白色,其它色都无效
QPainter p(&bmp);
p.setPen(Qt::NoPen);
p.setBrush(Qt::black);
p.drawRoundedRect(bmp.rect(),12,12);
setMask(bmp);
也可使用下面方法。可以设置好背景图片,自制的标题栏背景设透明,只负责显示文字和拖动、关闭等功能
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);//背景设透明
void MainWindow::paintEvent(QPaintEvent*)
{
QPixmap pixmap;
pixmap.load(":/image/image/圆角.png");
QPainter painter(this);
painter.drawPixmap(0,0,pixmap.scaled(this->size(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); // 绘制不规则背景
}
(1)选中子控件,点击工具栏的Lay out Vertically in Splitter,就会自动生成一个QSplitter。
(2)如果想要QSplitter充满这个界面,可以点击其它空白部分,点击工具栏Lay out Vertically
splitter = new QSplitter(Qt::Horizontal,this);
QLabel *lb = new QLabel("CCC");
QLabel *lb1 = new QLabel("DDD");
//设置布局
QVBoxLayout *VBox = new QVBoxLayout();
VBox->addWidget(lb);
VBox->addWidget(lb1);
//设置布局
splitter->setLayout(VBox);
//设置拉伸因子,以调整初始显示时各子部件间的位置 2:1
splitter->setStretchFactor(0,2);
splitter->setStretchFactor(1,1);
splitter->setGeometry(0,0,200,100);
//设置边框
splitter->setFrameShadow(QFrame::Raised);splitter->setFrameShape(QFrame::Box);splitter->setLineWidth(3);
//设置分界线Handle颜色
splitter->setStyleSheet("QSplitter::handle{background-color: transparent}");
splitter->setHandleWidth(10);
因为splitter不能直接设置多个布局,所以先设置两个布局,再分别添加到两个groupBox中,再splitter->addWidget(groupBox)
QPushButton *bt = new QPushButton("AAA");
QPushButton *bt1 = new QPushButton("BBB");
QLabel *lb = new QLabel("CCC");
QLabel *lb1 = new QLabel("DDD");
lb->setFrameShape (QFrame::Box);//边框
lb1->setFrameShape (QFrame::Box);
//设置布局
QVBoxLayout *VBox = new QVBoxLayout();
VBox->addWidget(bt);
VBox->addWidget(bt1);
QVBoxLayout *VBox1 = new QVBoxLayout();
VBox1->addWidget(lb);
VBox1->addWidget(lb1);
//布局中设置显示比例 1:2
VBox->setStretchFactor(bt,1);
VBox->setStretchFactor(bt1,3);
VBox1->setStretchFactor(lb,1);
VBox1->setStretchFactor(lb1,2);
QGroupBox* group1 = new QGroupBox(this);
QGroupBox* group2 = new QGroupBox(this);
group1->setStyleSheet("QGroupBox {border-color: rgb(133, 100, 250);border-width: 1px;"
"border-style: solid;margin-top: 0.5ex;}");
group2->setStyleSheet("QGroupBox {border-color: rgb(233, 100, 250);border-width: 1px;"
"border-style: solid;margin-top: 0.5ex;}");
group1->setLayout(VBox);
group2->setLayout(VBox1);
splitter->addWidget(group1);
splitter->addWidget(group2);
splitter->setOpaqueResize(true);
splitter->setChildrenCollapsible(true); //子部件不可折叠
splitter->setGeometry(0,0,200,100);
//设置边框
splitter->setFrameShadow(QFrame::Raised);splitter->setFrameShape(QFrame::Box);splitter->setLineWidth(3);
//设置分界线Handle颜色
splitter->setStyleSheet("QSplitter::handle{background-color: blue}");
splitter->setHandleWidth(10);
上面垂直布局中两按钮已通过setStretchFactor()
设置显示比例为1:3,但实际仍显示为1:1。原因是:
默认情况下部件是可以拉伸的,对于按钮、 QLineEdit、 QSpinBox 这种水平方向的部件,默认策略是可以水平拉伸,垂直固定。
可以通过setSizePolicy()
改变
//水平 和 垂直
bt->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
bt1->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
splitter垂直和水平布局不能相邻,否则之后子控件大小不能恢复
要实现如下效果
先在窗口里放一个QSplitter,左边放视频widge和一个按钮,右边放列表,点按钮隐藏或者显示列表,自己决定下面的控制按钮和视频widget在一起,还是独立的放在窗口最下面,QQ是独立的放到最下面。
(1)设置一个按钮QPushButton *moveBt,当点击按钮时执行hide()
或show()
,同时moveBt->move()改变按钮的位置实现附着在分界线的效果,或者直接固定按钮位置。
我用一个int group2Width
,在group2没被隐藏时,在resizeEvent()
和splitterMovedSlot()
中记录group2->width()
,方便group2恢复后将按钮移回分界线上。
但存在一个问题就是如果group2隐藏后,窗体宽度被改变,但是此时group2Width还是原来的,那点击恢复后按钮就会回到原来的位置,可分界条会在新的位置。
根本原因是在按钮点击槽函数里,group2->show()
之后就是移动按钮,但此时group2位置还没更新,group2->width()
还是0,所以得用之前记录的group2Width
。那就干脆开一个定时器,延时1ms再移动按钮。成功解决
(2)继承原来的QSplitter,QSplitterHandle,将按钮布局到QSplitterHandle上去。未尝试
QDockWidget嵌套布局详解-实现Visual Studio布局