Qt总结(十三)--布局 && QSplitter

一直没涉及布局,学习一波


2.25

QLayout

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)); // 绘制不规则背景
}

QSplitter

UI设计界面实现

(1)选中子控件,点击工具栏的Lay out Vertically in Splitter,就会自动生成一个QSplitter。
(2)如果想要QSplitter充满这个界面,可以点击其它空白部分,点击工具栏Lay out Vertically

代码实现

(1)设置布局
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);

(2)addWidget()

因为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

QDockWidget嵌套布局详解-实现Visual Studio布局

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值