ch2_1 模仿腾讯会议登录界面布局
1、添加各类控件布局登录界面
要注意最好要限制每一个控件的尺寸,然后再做水平垂直和栅格布局,否则可能会产生奇怪的编译结果。如果在修改完ui中的布局和控件尺寸,但是构建和编译后并没有更改,查看是否勾选了“shadow build”xuan”选项,要取消勾选重新编译效果就会改变。
2、运行结果
和原本的腾讯会议登录界面相比,模仿的界面多出了窗口标题,同时鼠标单击任务栏中的软件任务不能再显示和隐藏之间切换。
3、隐藏标题并添加切换显示和不显示设置
只需要在构造函数增加一行代码
#include "tencentmeetinglogin.h"
#include "ui_tencentmeetinglogin.h"
TencentMeetingLogin::TencentMeetingLogin(QWidget *parent)
: QDialog(parent)
, ui(new Ui::TencentMeetingLogin)
{
ui->setupUi(this);
//隐藏窗口标题,显示和不显示
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
}
TencentMeetingLogin::~TencentMeetingLogin()
{
delete ui;
}
ch1-2 优化腾讯会议登录界面
任务:
去掉窗口边框;
添加控件样式;
窗口移动
1、添加控件图标
2、设置控件样式
#include "tencentmeetinglogin.h"
#include "ui_tencentmeetinglogin.h"
TencentMeetingLogin::TencentMeetingLogin(QWidget *parent)
: QDialog(parent)
, ui(new Ui::TencentMeetingLogin)
{
ui->setupUi(this);
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
//为了凸显下面三个按钮的效果,可以设置全局样式为白色,这样会导致其他登陆方式这里的横线消失
//this->setStyleSheet("backfround-color:white; border:none");
ui->btnSet->setText(""); // 去除按钮上的文字
// 添加按钮样式,背景图标、无边界线、鼠标悬浮颜色加深
ui->btnSet->setStyleSheet("QPushButton{background-image:url(:/resource/set.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
ui->btnMin->setText("");
ui->btnMin->setStyleSheet("QPushButton{background-image:url(:/resource/min.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
ui->btnClose->setText("");
ui->btnClose->setStyleSheet("QPushButton{background-image:url(:/resource/close.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
// 去除标签上的文字
ui->labelLogo->clear();
//添加腾讯会议logo
QPixmap* pix = new QPixmap(":/resource/tencent-meeting.png");
ui->labelLogo->setPixmap(*pix);
ui->btnWeChat->setText("");
ui->btnWeChat->setStyleSheet("QPushButton{background-image:url(:/resource/weichatlogin.png); border:none} QPushButton::hover{background-color:rgb(10,100,100)}");
ui->btnPhoneLogin->setIcon(QIcon(":/resource/phonelogin.png"));
ui->btnPhoneLogin->setIconSize(QSize(40, 40));
ui->btnPhoneLogin->setText("手机号");
ui->btnPhoneLogin->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->btnPhoneLogin->setStyleSheet("background-color:white;border:none");
ui->btnEnpriseWX->setIcon(QIcon(":/resource/enpriseweichat.png"));
ui->btnEnpriseWX->setIconSize(QSize(40, 40));
ui->btnEnpriseWX->setText("企业微信");
ui->btnEnpriseWX->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->btnEnpriseWX->setStyleSheet("background-color:white;border:none");
ui->btnSSO->setIcon(QIcon(":/resource/sso.png"));
ui->btnSSO->setIconSize(QSize(40, 40));
ui->btnSSO->setText("SSO");
ui->btnSSO->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->btnSSO->setStyleSheet("background-color:white;border:none");
connect(ui->btnClose,&QPushButton::clicked,[=]{
close();
});
}
TencentMeetingLogin::~TencentMeetingLogin()
{
delete ui;
}
还可以在控件上右击选择改变样式表,添加样式内容来改变样式
ch2_3 代码创建布局,水平布局详解
手写代码布局的好处:
- 更好的控制布局
- 更好的设置qss
- 代码复用
//包含头文件
#include <QHBoxLayout>
//创建水平布局
QHBoxLayout* pHLay = new QHBoxLayout(父窗口指针,一般是this)
Qt布局的相关方法
- addWidget:在布局中添加一个控件
- addLayout:在布局里添加布局
- setMargin:(在6.3.1vs2022环境下报错没有这个函数)设置水平布局最外边界与相邻控件左上右下的间隙,这时左上右下的间隙相同,如果想设置成不同,可以使用setContentsMargins方法;
- setspacing:设置相邻控件之间的间隙,默认值大概是7
- addspacing:在setSpacing的基础上进行相加,例如addspacing(-7),相当于两个控件之间没有距离;addspacing(13)相当于setspacing(20);
- addStretch():在水平布局时添加一个水平的伸缩空间(QSpacerltem),在竖直布局时,添加一个竖直的伸缩空间
手写代码布局一个水平布局案例
#include "ch2_3_hLayout.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>
ch2_3_hLayout::ch2_3_hLayout(QWidget *parent)
: QWidget(parent)
{
QLabel* pPath = new QLabel(this);
pPath->setObjectName("pPath");
pPath->setFixedSize(40, 32);
pPath->setText("路径");
QLineEdit* pEdit = new QLineEdit(this);
pEdit->setObjectName("pEdit");
//pEdit->setFixedSize(100, 32);
pEdit->setMinimumWidth(50);
QPushButton* pBtn = new QPushButton(this);
pBtn->setObjectName("pBtn");
//pBtn->setFixedSize(50, 32);
pBtn->setText("打开");
添加一个水平布局
QHBoxLayout* pHlay = new QHBoxLayout(this);
//
pHlay->addStretch(); //在水平布局中这个函数用于添加水平弹簧,在垂直布局中添加垂直弹簧
pHlay->addWidget(pPath); //addWidget函数用于把控件添加到布局当中
pHlay->setSpacing(20); //在控件之间添加间隙,默认值为7
//pHlay->addStretch();
pHlay->addWidget(pEdit);
//pHlay->addStretch();
pHlay->addWidget(pBtn);
pHlay->addStretch();
pHlay->setContentsMargins(100, 100, 100, 100); //设置水平布局最外边界和相邻控件左上右下的间隙
}
ch2_3_hLayout::~ch2_3_hLayout()
{}
结果:
ch2_4 垂直布局
(1)包含头文件
#include
(2)创建竖直布局
QVBoxLayout* pMainVLay=new QVBoxLayout(this);
其他设置与水平布局类似
以下是手写代码垂直布局实例:
#include "ch2_4_vLayout.h"
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QDebug>
ch2_4_vLayout::ch2_4_vLayout(QWidget *parent)
: QWidget(parent)
{
//resize(400, 400); 设置窗口的大小
//创建一个新按钮
QPushButton* btn1 = new QPushButton(this);
//给按钮命名
btn1->setObjectName("btn1");
//设置按钮大小
btn1->setFixedSize(40, 32);
//编辑按钮上的文字内容
btn1->setText("按钮1");
QPushButton* btn2 = new QPushButton(this);
btn2->setObjectName("btn2");
btn2->setFixedSize(40, 32);
btn2->setText("按钮2");
QPushButton* btn3 = new QPushButton(this);
btn3->setObjectName("btn3");
btn3->setFixedSize(40, 32);
btn3->setText("按钮3");
//创建一个垂直布局
QVBoxLayout* pVLay = new QVBoxLayout(this);
pVLay->addWidget(btn1);
pVLay->setSpacing(30);
pVLay->addWidget(btn2);
pVLay->addSpacing(50);
pVLay->addWidget(btn3);
//pVLay->addSpacing(13);
pVLay->setContentsMargins(50, 60, 70, 80);
}
ch2_4_vLayout::~ch2_4_vLayout()
{}
结果:
ch2_5 栅格布局
(1)包含头文件#include
(2)创建栅格布局
QGridLayout* pGridLayout = new QGridLayout(this);
示例:
#include "widget.h"
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QCheckBox>
#include <QGridLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//去除窗口标题和缩放在任务栏
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
//头像
QLabel* pImageLabel = new QLabel(this);
QPixmap pixmap(":/user_image.png");
pImageLabel->setFixedSize(150, 150);
pImageLabel->setPixmap(pixmap);
pImageLabel->setScaledContents(true);
//用户名
QLineEdit* pUserNameLineEdit = new QLineEdit(this);
pUserNameLineEdit->setFixedSize(300, 40);
pUserNameLineEdit->setPlaceholderText("QQ号码/手机/邮箱");
QLineEdit* pPasswordLineEdit = new QLineEdit(this);
pPasswordLineEdit->setFixedSize(300, 40);
pPasswordLineEdit->setPlaceholderText("密码");
pPasswordLineEdit->setEchoMode(QLineEdit::Password);
QPushButton* pForgotButton = new QPushButton(this);
pForgotButton->setText("找回密码");
pForgotButton->setFixedWidth(80);
QCheckBox* pRememberCheckBox = new QCheckBox(this);
pRememberCheckBox->setText("记住密码");
QCheckBox* pAutoLoginCheckBox = new QCheckBox(this);
pAutoLoginCheckBox->setText("自动登录");
QPushButton* pLoginButton = new QPushButton(this);
pLoginButton->setFixedHeight(40);
pLoginButton->setText("登录");
QPushButton* pRegisterButton = new QPushButton(this);
pRegisterButton->setFixedHeight(40);
pRegisterButton->setText("注册账号");
QGridLayout* pGridLay = new QGridLayout(this);
//栅格布局添加控件时,widget函数参数
pGridLay->addWidget(pImageLabel, 0,0,3,1);
pGridLay->addWidget(pUserNameLineEdit, 0,1,1,2);
pGridLay->addWidget(pPasswordLineEdit, 1,1,1,2);
pGridLay->addWidget(pForgotButton, 2,1,1,1);
pGridLay->addWidget(pRememberCheckBox, 2,2,1,1, Qt::AlignHCenter | Qt::AlignVCenter);
pGridLay->addWidget(pAutoLoginCheckBox, 2,2,1,1, Qt::AlignRight | Qt::AlignVCenter);
pGridLay->addWidget(pLoginButton, 3,1,1,2);
pGridLay->addWidget(pRegisterButton, 4,1,1,2);
//pGridLay->setHorizontalSpacing(20);
//pGridLay->setVerticalSpacing(20);
pGridLay->setContentsMargins(20,20,20,20);
}
Widget::~Widget() {}
结果:
ch2_6 栅格布局中的一些调整
//就是上一节的代码中最后几行用于调整布局间距
pGridLay->setHorizontalSpacing(20);
pGridLay->setVerticalSpacing(20);
pGridLay->setContentsMargins(20,20,20,20);
ch2_7 分裂器布局代码实现
什么是分裂器?实际应用中的案例如下:
1、使用designer布局
2、C++代码实现分裂器
水平分裂器
QSplitter* pHSplitter = new QSplitter(Qt::Horizontal, this);
竖直分裂器
QSplitter* pVSplitter = new QSplitter(at::Vertical, pHSplitter);
分裂器也是Qwidget的子类,因此分裂器也有addwidget方法,而布局也可以使用addwidget往布局里添加分裂器
#include "ch2_7_splitter_code.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextBrowser>
#include <QSplitter>
ch2_7_splitter_code::ch2_7_splitter_code(QWidget *parent)
: QWidget(parent)
{
this->setWindowTitle("Qt分裂器布局_c++代码");
//整体用水平布局
QHBoxLayout* pHLay = new QHBoxLayout(this);
//整体水平分裂器
QSplitter* pHSplitter = new QSplitter(this);
QWidget* pLeftWdiget = new QWidget(this);
pLeftWdiget->setStyleSheet("background-color:rgb(54,54,54)");
pLeftWdiget->setMinimumWidth(200);
//分裂器添加widget
pHSplitter->addWidget(pLeftWdiget);
//右侧的竖直分裂器
//注意参数pHSplitter,表示父指针
QSplitter* pVSplitter = new QSplitter(Qt::Vertical, pHSplitter);
//在拖动到位后并谈起鼠标后再显示分隔条
pHSplitter->setOpaqueResize(true);
QWidget* pRightTopWidget = new QWidget(this);
pRightTopWidget->setStyleSheet("background-color:rgb(154,1,1)");
QTextBrowser* pRifghtBottom = new QTextBrowser(this);
pVSplitter->addWidget(pRightTopWidget);
pVSplitter->addWidget(pRifghtBottom);
pHSplitter->addWidget(pVSplitter);
//布局添加分裂器
pHLay->addWidget(pHSplitter);
//设置整体布局
setLayout(pHLay);
}
ch2_7_splitter_code::~ch2_7_splitter_code()
{}
ch2_8 setLayout使用说明
将此小部件的布局管理器设置为布局。如果这个小部件上已经安装了一个布局管理器,那么Qwidget不会让您安装另一个。您必须首先删除现有的布局管理器(由layout()返回),然后才能用新的布局调用setLayout()。
一般可以不写setLayout
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//不用加this
QPushButton* btn1 = new QPushButton;
btn1->setFixedSize(100, 100);
btn1->setText("btn1");
QPushButton* btn2 = new QPushButton;
btn2->setFixedSize(100, 100);
btn2->setText("btn2");
QHBoxLayout* hLay = new QHBoxLayout(this);
hLay->addWidget(btn1);
hLay->addWidget(btn2);
setLayout(hLay);
QPushButton* btn3 = new QPushButton(this);
btn3->setFixedSize(100, 100);
btn3->setText("btn3");
QPushButton* btn4 = new QPushButton;
btn4->setFixedSize(100, 100);
btn4->setText("btn4");
QVBoxLayout* vLay = new QVBoxLayout(this);
vLay->addWidget(btn3);
vLay->addWidget(btn4);
setLayout(vLay);
}
Widget::~Widget()
{
delete ui;
}
上面的代码中setLayout()
只会生效第一个,另外new后面是否加this,this表示父类指针,加上this则会在父窗口中显示,不加只显示setLayout以上的布局内容。
ch2_9 多重布局变化和布局删除
#include "ch2_9_rightMenu.h"
#include <QAction>
#include <QMessageBox>
ch2_9_rightMenu::ch2_9_rightMenu(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//设置菜单策略
this->setContextMenuPolicy(Qt::DefaultContextMenu);
initMenu();
}
ch2_9_rightMenu::~ch2_9_rightMenu()
{}
void ch2_9_rightMenu::contextMenuEvent(QContextMenuEvent* event)//这是一个事件处理函数,该函数不需要显式的调用,用于处理右键点击(上下文菜单)事件。Qt 框架会在适当的时候自动调用它。
{
m_pMenu->exec(QCursor::pos());
}
void ch2_9_rightMenu::initMenu()
{
m_pMenu = new QMenu(this);
QAction* pAc1 = new QAction("ac1");
QAction* pAc2 = new QAction("ac2");
QAction* pAc3 = new QAction("ac3");
QAction* pAc4 = new QAction("ac4");
QAction* pAc5 = new QAction("ac5");
m_pMenu->addAction(pAc1);
m_pMenu->addAction(pAc2);
m_pMenu->addAction(pAc3);
m_pMenu->addAction(pAc4);
m_pMenu->addAction(pAc5);
connect(pAc1, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac1");
});
connect(pAc2, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac2");
});
connect(pAc3, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac3");
});
connect(pAc4, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac4");
});
connect(pAc5, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac5");
});
}
另一个示例:
#pragma execution_character_set("utf-8")
#include "SwitchWidget.h"
#include <QGridLayout>
#include <QContextMenuEvent>
SwitchWidget::SwitchWidget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle("鍤欒笣钑�鍤欒笣钑�鍤欒珛槌磋暛鍤欒笣钑�鍤欒珝灏嶈暛");
initWidget();
this->resize(QSize(800, 500));
this->setContextMenuPolicy(Qt::DefaultContextMenu);
}
void SwitchWidget::initWidget()
{
initMenu();
for (int i = 0; i < 9; i++)
{
QLabel* label = new QLabel;
label->setStyleSheet(QString("QLabel{background-image:url(:/SwitchWidget/resources/%1.png); \
border:1px solid gray; \
background-position:center; \
background-repeat:no-repeat; \
}").arg(QString::number(i + 1)));
m_videoLabelList.append(label);
}
switchLayout(VideoLayoutType::OneVideo);
}
void SwitchWidget::initMenu()
{
m_switchMenu = new QMenu(this);
m_switchMenu->addAction("鐝ㄥ殭韪濊暛鍤欒笣钑�");
m_switchMenu->addAction("鍤欒�濈榾钑�鍤欒笣钑�");
m_switchMenu->addAction("鍤欒笣钑�鍤欒笣钑�鍤欙拷");
m_switchMenu->addAction("鍤欒笣钑�鍤欒笣钑�鍤欒笣钑�");
m_switchMenu->addAction("鍤欒�愮榾钑�鍤欒笣钑�");
QMap<QString, int> strTypeMap;
strTypeMap["鐝ㄥ殭韪濊暛鍤欒笣钑�"] = VideoLayoutType::OneVideo;
strTypeMap["鍤欒�濈榾钑�鍤欒笣钑�"] = VideoLayoutType::FourVideo;
strTypeMap["鍤欒笣钑�鍤欒笣钑�鍤欙拷"] = VideoLayoutType::FiveVideo;
strTypeMap["鍤欒笣钑�鍤欒笣钑�鍤欒笣钑�"] = VideoLayoutType::SixVideo;
strTypeMap["鍤欒�愮榾钑�鍤欒笣钑�"] = VideoLayoutType::NineVideo;
connect(m_switchMenu, &QMenu::triggered, this, [=](QAction* action) {
QString strText = action->text();
VideoLayoutType type = VideoLayoutType(strTypeMap[strText]);
switchLayout(type);
});
}
void SwitchWidget::contextMenuEvent(QContextMenuEvent* event)
{
m_switchMenu->exec(QCursor::pos());
}
void SwitchWidget::switchLayout(VideoLayoutType type)
{
QLayout* layout = this->layout();
if (layout)
{
QLayoutItem* child;
while ((child = layout->takeAt(0)) != 0)
{
if (child->widget())
{
child->widget()->setParent(NULL);
}
delete child;
}
delete layout;
}
switch (type)
{
case OneVideo:
{
QGridLayout* gLayout = new QGridLayout(this);
gLayout->addWidget(m_videoLabelList[0]);
gLayout->setMargin(0);
}
break;
case FourVideo:
{
QGridLayout* gLayout = new QGridLayout(this);
gLayout->setSpacing(0);
gLayout->setMargin(0);
for (int i = 0; i < 4; i++)
{
gLayout->addWidget(m_videoLabelList[i], i / 2, i % 2);
}
}
break;
case FiveVideo:
{
QVBoxLayout* pVLay = new QVBoxLayout(this);
pVLay->setSpacing(0);
QHBoxLayout* pHTopLay = new QHBoxLayout(this);
pHTopLay->setSpacing(0);
for (int i = 0; i < 3; i++)
{
pHTopLay->addWidget(m_videoLabelList[i]);
}
QHBoxLayout* pHBottomLay = new QHBoxLayout(this);
pHBottomLay->setSpacing(0);
for (int i = 3; i < 5; i++)
{
pHBottomLay->addWidget(m_videoLabelList[i]);
}
pVLay->addLayout(pHTopLay);
pVLay->addLayout(pHBottomLay);
}
break;
case SixVideo:
{
QGridLayout* gLayout = new QGridLayout(this);
gLayout->addWidget(m_videoLabelList[0], 0, 0, 2, 2);
gLayout->addWidget(m_videoLabelList[1], 0, 2);
gLayout->addWidget(m_videoLabelList[2], 1, 2);
gLayout->addWidget(m_videoLabelList[3], 2, 0);
gLayout->addWidget(m_videoLabelList[4], 2, 1);
gLayout->addWidget(m_videoLabelList[5], 2, 2);
gLayout->setSpacing(0);
gLayout->setMargin(0);
}
break;
case NineVideo:
{
QGridLayout* gLayout = new QGridLayout(this);
gLayout->setSpacing(0);
gLayout->setMargin(0);
for (int i = 0; i < 9; i++)
{
gLayout->addWidget(m_videoLabelList[i], i / 3, i % 3);
}
}
break;
default:
break;
}
}
ch2_10 手写代码实现腾讯会议登录界面
可以借鉴qt的designer布局自动生成的代码,然后这些代码复制过来做一些自己的修改。自动生成的代码为ui_tencentmeetinglogin.h,基于这个代码修改如下:
#include "ch2_10_logincode.h"
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
#include <QCoreApplication>
ch2_10_logincode::ch2_10_logincode(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout* verticalLayout_2;
QHBoxLayout* horizontalLayout;
QPushButton* btnSet;
QLabel* label;
QPushButton* btnMin;
QPushButton* btnClose;
QHBoxLayout* horizontalLayout_4;
QSpacerItem* horizontalSpacer;
QLabel* labelLogo;
QSpacerItem* horizontalSpacer_2;
QHBoxLayout* horizontalLayout_5;
QSpacerItem* horizontalSpacer_3;
QVBoxLayout* verticalLayout;
QPushButton* btnWeChat;
QPushButton* btnJoinMeeting;
QSpacerItem* horizontalSpacer_4;
QHBoxLayout* horizontalLayout_2;
QFrame* line;
QLabel* label_3;
QFrame* line_2;
QHBoxLayout* horizontalLayout_3;
QToolButton* btnPhoneLogin;
QToolButton* btnEnpriseWX;
QToolButton* btnSSO;
/*void setupUi(QDialog * this)
{
if (this->objectName().isEmpty())
this->setObjectName(QString::fromUtf8("this"));
this->resize(400, 600);*/
//将TencentMeetingLogin替换成this
this->setMinimumSize(QSize(400, 600));
this->setMaximumSize(QSize(400, 600));
verticalLayout_2 = new QVBoxLayout(this);
verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
horizontalLayout = new QHBoxLayout();
horizontalLayout->setSpacing(0);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setSizeConstraint(QLayout::SizeConstraint::SetDefaultConstraint);
horizontalLayout->setContentsMargins(-1, 0, -1, 61);
btnSet = new QPushButton(this);
btnSet->setObjectName(QString::fromUtf8("btnSet"));
btnSet->setMinimumSize(QSize(0, 32));
btnSet->setMaximumSize(QSize(32, 32));
horizontalLayout->addWidget(btnSet);
label = new QLabel(this);
label->setObjectName(QString::fromUtf8("label"));
label->setMinimumSize(QSize(284, 20));
label->setMaximumSize(QSize(350, 20));
label->setAlignment(Qt::AlignmentFlag::AlignCenter);
horizontalLayout->addWidget(label);
btnMin = new QPushButton(this);
btnMin->setObjectName(QString::fromUtf8("btnMin"));
btnMin->setMinimumSize(QSize(0, 32));
btnMin->setMaximumSize(QSize(32, 32));
horizontalLayout->addWidget(btnMin);
btnClose = new QPushButton(this);
btnClose->setObjectName(QString::fromUtf8("btnClose"));
btnClose->setMinimumSize(QSize(0, 32));
btnClose->setMaximumSize(QSize(32, 32));
horizontalLayout->addWidget(btnClose);
verticalLayout_2->addLayout(horizontalLayout);
horizontalLayout_4 = new QHBoxLayout();
horizontalLayout_4->setObjectName(QString::fromUtf8("horizontalLayout_4"));
horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout_4->addItem(horizontalSpacer);
labelLogo = new QLabel(this);
labelLogo->setObjectName(QString::fromUtf8("labelLogo"));
labelLogo->setMinimumSize(QSize(200, 200));
labelLogo->setMaximumSize(QSize(200, 200));
labelLogo->setAlignment(Qt::AlignmentFlag::AlignCenter);
horizontalLayout_4->addWidget(labelLogo);
horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout_4->addItem(horizontalSpacer_2);
verticalLayout_2->addLayout(horizontalLayout_4);
horizontalLayout_5 = new QHBoxLayout();
horizontalLayout_5->setObjectName(QString::fromUtf8("horizontalLayout_5"));
horizontalSpacer_3 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout_5->addItem(horizontalSpacer_3);
verticalLayout = new QVBoxLayout();
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
btnWeChat = new QPushButton(this);
btnWeChat->setObjectName(QString::fromUtf8("btnWeChat"));
btnWeChat->setMinimumSize(QSize(350, 40));
btnWeChat->setMaximumSize(QSize(350, 40));
verticalLayout->addWidget(btnWeChat);
btnJoinMeeting = new QPushButton(this);
btnJoinMeeting->setObjectName(QString::fromUtf8("btnJoinMeeting"));
btnJoinMeeting->setMinimumSize(QSize(350, 40));
btnJoinMeeting->setMaximumSize(QSize(350, 40));
btnJoinMeeting->setStyleSheet(QString::fromUtf8("QPushButton\n"
"{\n"
"/* \345\211\215\346\231\257\350\211\262 */\n"
"color:#0054E6;\n"
"/* \350\203\214\346\231\257\350\211\262 */\n"
"background-color:rgb(255,255,255);\n"
"/*\350\276\271\346\241\206\351\243\216\346\240\274 */\n"
"border-style:outset;\n"
"/* \350\276\271\346\241\206\345\256\275\345\272\246 */\n"
"border-width:0.5px;\n"
"/*\350\276\271\346\241\206\351\242\234\350\211\262*/\n"
"border-color:gray;\n"
"/*\350\276\271\346\241\206\345\200\222\350\247\222 */\n"
"border-radius:2px;\n"
"}\n"
"/*\351\274\240\346\240\207\346\202\254\346\265\256\346\227\266\347\232\204\346\225\210\346\236\234*/\n"
"QPushButton:hover\n"
"{\n"
"/* \350\276\271\346\241\206\351\242\234\350\211\262 */\n"
"border-color:blue\n"
"}"));
verticalLayout->addWidget(btnJoinMeeting);
horizontalLayout_5->addLayout(verticalLayout);
horizontalSpacer_4 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout_5->addItem(horizontalSpacer_4);
verticalLayout_2->addLayout(horizontalLayout_5);
horizontalLayout_2 = new QHBoxLayout();
horizontalLayout_2->setSpacing(6);
horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2"));
horizontalLayout_2->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize);
line = new QFrame(this);
line->setObjectName(QString::fromUtf8("line"));
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
horizontalLayout_2->addWidget(line);
label_3 = new QLabel(this);
label_3->setObjectName(QString::fromUtf8("label_3"));
label_3->setMinimumSize(QSize(150, 40));
label_3->setMaximumSize(QSize(150, 40));
label_3->setAlignment(Qt::AlignmentFlag::AlignCenter);
horizontalLayout_2->addWidget(label_3);
line_2 = new QFrame(this);
line_2->setObjectName(QString::fromUtf8("line_2"));
line_2->setFrameShape(QFrame::HLine);
line_2->setFrameShadow(QFrame::Sunken);
horizontalLayout_2->addWidget(line_2);
verticalLayout_2->addLayout(horizontalLayout_2);
horizontalLayout_3 = new QHBoxLayout();
horizontalLayout_3->setObjectName(QString::fromUtf8("horizontalLayout_3"));
horizontalLayout_3->setSizeConstraint(QLayout::SizeConstraint::SetDefaultConstraint);
btnPhoneLogin = new QToolButton(this);
btnPhoneLogin->setObjectName(QString::fromUtf8("btnPhoneLogin"));
btnPhoneLogin->setMinimumSize(QSize(68, 60));
btnPhoneLogin->setMaximumSize(QSize(68, 60));
horizontalLayout_3->addWidget(btnPhoneLogin);
btnEnpriseWX = new QToolButton(this);
btnEnpriseWX->setObjectName(QString::fromUtf8("btnEnpriseWX"));
btnEnpriseWX->setMinimumSize(QSize(68, 60));
btnEnpriseWX->setMaximumSize(QSize(68, 60));
horizontalLayout_3->addWidget(btnEnpriseWX);
btnSSO = new QToolButton(this);
btnSSO->setObjectName(QString::fromUtf8("btnSSO"));
btnSSO->setMinimumSize(QSize(68, 60));
btnSSO->setMaximumSize(QSize(68, 60));
horizontalLayout_3->addWidget(btnSSO);
verticalLayout_2->addLayout(horizontalLayout_3);
// retranslateUi(this);
QMetaObject::connectSlotsByName(this);
// } // setupUi
/* void retranslateUi(QDialog * this)
{*/
this->setWindowTitle(QCoreApplication::translate("this", "this", nullptr));
btnSet->setText(QCoreApplication::translate("this", "PushButton", nullptr));
label->setText(QCoreApplication::translate("this", "\350\247\206\351\242\221\344\274\232\350\256\256", nullptr));
btnMin->setText(QCoreApplication::translate("this", "PushButton", nullptr));
btnClose->setText(QCoreApplication::translate("this", "PushButton", nullptr));
labelLogo->setText(QCoreApplication::translate("this", "helloworld", nullptr));
btnWeChat->setText(QCoreApplication::translate("this", "\345\276\256\344\277\241\347\231\273\345\275\225", nullptr));
btnJoinMeeting->setText(QCoreApplication::translate("this", "\345\212\240\345\205\245\344\274\232\350\256\256", nullptr));
label_3->setText(QCoreApplication::translate("this", "\345\205\266\344\273\226\347\231\273\345\275\225\346\226\271\345\274\217", nullptr));
btnPhoneLogin->setText(QCoreApplication::translate("this", "...", nullptr));
btnEnpriseWX->setText(QCoreApplication::translate("this", "...", nullptr));
btnSSO->setText(QCoreApplication::translate("this", "...", nullptr));
// }
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
//为了凸显下面三个按钮的效果,可以设置全局样式为白色,这样会导致其他登陆方式这里的横线消失
//this->setStyleSheet("backfround-color:white; border:none");
btnSet->setText(""); // 去除按钮上的文字
// 添加按钮样式,背景图标、无边界线、鼠标悬浮颜色加深
btnSet->setStyleSheet("QPushButton{background-image:url(:/resources/set.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
btnMin->setText("");
btnMin->setStyleSheet("QPushButton{background-image:url(:/resources/min.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
btnClose->setText("");
btnClose->setStyleSheet("QPushButton{background-image:url(:/resources/close.png); border:none}"
"QPushButton::hover{background-color:rgb(200,200,200)}");
// 去除标签上的文字
labelLogo->clear();
//添加腾讯会议logo
QPixmap* pix = new QPixmap(":/resources/tencent-meeting.png");
labelLogo->setPixmap(*pix);
btnWeChat->setText("");
btnWeChat->setStyleSheet("QPushButton{background-image:url(:/resources/weichatlogin.png); border:none} QPushButton::hover{background-color:rgb(10,100,100)}");
/* btnPhoneLogin->setIcon(QIcon(":/resources/phonelogin.png"));
btnPhoneLogin->setIconSize(QSize(40, 40));
btnPhoneLogin->setText(u8"手机号");
btnPhoneLogin->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btnPhoneLogin->setStyleSheet("background-color:white;border:none");*/
btnEnpriseWX->setIcon(QIcon(":/resources/enpriseweichat.png"));
btnEnpriseWX->setIconSize(QSize(40, 40));
btnEnpriseWX->setText("企业微信");
btnEnpriseWX->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btnEnpriseWX->setStyleSheet("background-color:white;border:none");
btnSSO->setIcon(QIcon(":/resources/sso.png"));
btnSSO->setIconSize(QSize(40, 40));
btnSSO->setText("SSO");
btnSSO->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btnSSO->setStyleSheet("background-color:white;border:none");
connect(btnClose, &QPushButton::clicked, [=] {
close();
});
}
ch2_10_logincode::~ch2_10_logincode()
{}
运行的结果基本和ch2_1一致。
ch2_11 QTabWidget各种常见用法详解一
添加自定义tab
int insertTab(int index, QWidget *page, const QString &label)
int insertTab(int index, QWidget *page, const Qlcon &icon, const QString &label)
示例
#include "widget.h"
#include "ui_widget.h"
#include <QHBoxLayout>
#include <QTabWidget>
#include <QDebug>
#include <QTabBar>
#include "form.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//添加一个水平布局
QHBoxLayout* lay = new QHBoxLayout(this);
//添加一个标签widget
QTabWidget* pTabWidget = new QTabWidget(this);
//设置标签页可以被关闭
pTabWidget->setTabsClosable(true);
pTabWidget->setMovable(true);
pTabWidget->setTabShape(QTabWidget::Triangular);
pTabWidget->setTabPosition(QTabWidget::South);
//新建widget对象
QWidget *w1 = new QWidget;
w1->setStyleSheet("background-color:rgb(54,54,54)");
QWidget *w2 = new QWidget;
w2->setStyleSheet("background-color:rgb(154,54,54)");
QWidget *w3 = new QWidget;
w3->setStyleSheet("background-color:rgb(54,154,54)");
//把w1,w2,w3三个窗口添加到Tabwidget中
pTabWidget->insertTab(0, w1, "tab1");
pTabWidget->insertTab(1, w2, "tab2");
pTabWidget->insertTab(2, w3, "tab3");
//创建一个新的窗口类
Form* f = new Form;
pTabWidget->insertTab(3, f, "第四页");
//给标签添加提示信息,当鼠标放在标签上时显示
pTabWidget->setTabToolTip(2, "the tab id is 2");
//把pTabWidget添加到水平布局对象中
lay->addWidget(pTabWidget);
//测试几个QTabWidget的信号
/*
Q_SIGNALS:
void currentChanged(int index);
void tabCloseRequested(int index);
void tabBarClicked(int index);
void tabBarDoubleClicked(int index);
*/
connect(pTabWidget, &QTabWidget::currentChanged, [=](int index){
qDebug()<< "index = "<< index;
});
connect(pTabWidget, &QTabWidget::tabBarDoubleClicked, [=](int index){
qDebug() << "tabBarDoubleClicked index = " << index;
});
connect(pTabWidget, &QTabWidget::tabBarClicked, [=](int index){
qDebug() << "tabBarClicked index = " << index;
});
connect(pTabWidget, &QTabWidget::tabCloseRequested, [=](int index){
qDebug() << "tabCloseRequested index = " << index;
pTabWidget->removeTab(index); // 关闭tab
});
}
Widget::~Widget()
{
delete ui;
}
编译结果:
ch2_12 QTabWidget各种常见用法详解二
1、首先创建一个QWidget应用
2、添加Tab Widget控件
在Tab Widget控件上右击选择**“插入页”**,可以增加该控件的标签页面。然后在不同的页面可以选择一些控件添加进去。如下图:
3、在任意页面右击选择“改变样式表”对页面和控件进行样式修改
ch2_13 QListWidget用法一
QListWidget有两种显示模式如下
任务1:模仿一个选项窗口(列表模式)
1、添加控件
2、调整布局
3、添加图标资源文件
右击,选择添加现有文件,选择图标。
4、实例化QListWidgetItem,把图标选项添加到QListWidget中
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建item
QListWidgetItem* pItem1 = new QListWidgetItem(QIcon(":/resources/kits.png"), "kits");
QListWidgetItem* pItem2 = new QListWidgetItem(QIcon(":/resources/env.png"), "环境");
QListWidgetItem* pItem3 = new QListWidgetItem(QIcon(":/resources/editor.png"), "文本编辑");
QListWidgetItem* pItem4 = new QListWidgetItem(QIcon(":/resources/vim.png"), "FakeVim");
QListWidgetItem* pItem5 = new QListWidgetItem(QIcon(":/resources/help.png"), "帮助");
ui->listWidget->addItem(pItem1);
ui->listWidget->addItem(pItem2);
ui->listWidget->addItem(pItem3);
ui->listWidget->addItem(pItem4);
ui->listWidget->addItem(pItem5);
}
5、增加一个新的类并把它添加到ListWidget中
在useritem.ui中布局UserItem界面
在useritem.cpp中设置useritem布局的大小
把UserItem的头文件添加到Widget.cpp中,在Widget.cpp中添加自定义类UserItem,并放置在ListWidget中
调整widget.ui 的控件大小,适合useritem
编译结果是:
ch2_14 QListWidget用法二——左键菜单、item删除
项目管理小技巧
创建一个空项目,把里面的东西都删了,只保留.sln,然后把其他项目添加到空的解决方案里
QT6.3.1转VS方法
** List Item如何添加右键菜单**
//设置菜单策略,必须设置,不然无法显示菜单
ui.listWidget0->setContextMenuPolicy(Qt::CustomContextMenu);
//连接信号槽
connect(ui.listWidget0,&QListWidget::customContextMenuRequested, this&Widget::on PopupRightMenu);
QListWidget如何删除item
- 方式1:知道item的名字,根据名字删除,这种可用于用户掉线,信息丢失等,动态删除;
- 方式2:右键点击删除,或者选中删除
任务:在QListWidget下创建item,右击菜单,删除item
示例:
#pragma once
#include <QtWidgets/QWidget>
#include "ui_ch2_14_QListWidget.h"
#include <QMenu>
class ch2_14_QListWidget : public QWidget
{
Q_OBJECT
public:
ch2_14_QListWidget(QWidget *parent = nullptr);
~ch2_14_QListWidget();
private slots:
void on_PopupRightMenu(const QPoint& pos);
private:
void initRightMenu();
private:
Ui::ch2_14_QListWidgetClass ui;
QMenu* m_pRightMenu = nullptr;
};
#include "ch2_14_QListWidget.h"
#include <QListWidgetItem>
#include <QMessageBox>
ch2_14_QListWidget::ch2_14_QListWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
resize(600, 800);
QListWidgetItem* pItem1 = new QListWidgetItem(QIcon(":/ch2_14_QListWidget/resources/kits.png"), "Kits");
QListWidgetItem* pItem2 = new QListWidgetItem(QIcon(":/ch2_14_QListWidget/resources/env.png"), u8"环境");
QListWidgetItem* pItem3 = new QListWidgetItem(QIcon(":/ch2_14_QListWidget/resources/editor.png"), u8"编辑器");
QListWidgetItem* pItem4 = new QListWidgetItem(QIcon(":/ch2_14_QListWidget/resources/vim.png"), "FakeVim");
QListWidgetItem* pItem5 = new QListWidgetItem(QIcon(":/ch2_14_QListWidget/resources/help.png"), u8"帮助");
ui.listWidget->addItem(pItem1);
ui.listWidget->addItem(pItem2);
ui.listWidget->addItem(pItem3);
ui.listWidget->addItem(pItem4);
ui.listWidget->addItem(pItem5);
initRightMenu();
//设置菜单策略,必须设置,不然无法显示菜单
ui.listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
//连接信号槽
connect(ui.listWidget, &QListWidget::customContextMenuRequested,
this, &ch2_14_QListWidget::on_PopupRightMenu);
}
ch2_14_QListWidget::~ch2_14_QListWidget()
{}
void ch2_14_QListWidget::on_PopupRightMenu(const QPoint& pos)
{
/*使用listwidget中的itemAt方法,返回一个ListWidgetItem对象,
判断是否点击到了对象,如果是才弹出右击菜单*/
QListWidgetItem* pItem = ui.listWidget->itemAt(pos);
if (!pItem)
{
return;
}
m_pRightMenu->exec(QCursor::pos());
}
void ch2_14_QListWidget::initRightMenu()
{
m_pRightMenu = new QMenu(this);
QAction* pAc1 = new QAction("动作1", this);
QAction* pAc2 = new QAction("动作2", this);
QAction* pAc3 = new QAction("动作3", this);
QAction* pAc4 = new QAction("删除", this);
m_pRightMenu->addAction(pAc1);
m_pRightMenu->addAction(pAc2);
m_pRightMenu->addAction(pAc3);
m_pRightMenu->addAction(pAc4);
// 右击菜单中,选项1链接一个消息提示
connect(pAc1, &QAction::triggered, [=] {
QMessageBox::information(this, "title", "ac1");
});
connect(pAc4, &QAction::triggered, [=] {
// 动态删除
/*QList<QListWidgetItem*> list;
list = ui.listWidget->findItems("Kits", Qt::MatchCaseSensitive);
QListWidgetItem* sel = list[0];
int r = ui.listWidget->row(sel);
QListWidgetItem* item = ui.listWidget->takeItem(r);
ui.listWidget->removeItemWidget(item);
delete item;*/
QListWidgetItem* item = ui.listWidget->currentItem();
ui.listWidget->removeItemWidget(item);
delete item;
});
}
编译结果:
ch2_15 QListWidget用法三——图标模式+右侧滑动条样式
示例:
#include "ch2_15_QListWidget.h"
#include <QVBoxLayout>
#include <QListWidget>
ch2_15_QListWidget::ch2_15_QListWidget(QWidget *parent)
: QWidget(parent)
{
resize(600, 500);
QVBoxLayout* pMainVLayout = new QVBoxLayout(this);
QListWidget* pListWidget = new QListWidget(this);
pListWidget->setViewMode(QListView::IconMode);
pListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
pListWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
int vScrollBarWidth = 30;
QString qssLW = QString("QScrollBar{width:%1px;background:rgba(255, 255, 255,100%);margin:0px, 0px, 0px, 0px;}\
QScrollBar::handle:vertical{width:8px;background:rgba(162, 163, 165, 100%);border-radius:4px;min-height:60;}\
QScrollBar::handle:vertical:hover{width:8px;background:rgba(115,118,118, 100%);border-radius:4px;min-height:60;}\
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical{background:rgba(255, 255, 255, 100%);border-radius:4px;}\
QScrollBar::top-arrow:vertical,QScrollBar::bottom-arrow:vertical{border: none;background: none;color: none;}\
QScrollBar::add-line:vertical{border:none;background:none;}\
QScrollBar::sub-line:vertical{border:none;background:none;}\
QListWidget{background-color:rgb(255,255,255);border:none;} \
QListWidget::item{ \
/*background:blue;*/ \
margin-left:20px; \
margin-right:20px; \
margin-top:10px; \
} \
").arg(QString::number(vScrollBarWidth));
pListWidget->setStyleSheet(qssLW);
//180包括margin-left的值
//如果QListWidget::item没有写margin-right:20px,增加竖直滑动条和最后一列的间隙为margin-left的一半即可,这样看着美观
//如果QListWidget::item写了margin-right:20px, vScrollBarWidth + 1即可
pListWidget->setFixedWidth(180 * 3 + vScrollBarWidth + 1);
for (int i = 0; i < 15; i++)
{
QIcon icon(":/ch2_15_QListWidget/env.png");
QString name = QString(u8"用户%1").arg(QString::number(i));
QListWidgetItem* pItem = new QListWidgetItem(icon, name);
pItem->setSizeHint(QSize(180, 100));
pListWidget->addItem(pItem);
}
pMainVLayout->addWidget(pListWidget);
}
ch2_15_QListWidget::~ch2_15_QListWidget()
{}
编译结果:
ch2_16_17_18 模仿迅雷可以上下滑动的设置界面
任务1:搭建一个迅雷设置页面的主要结构
示例代码如下:
#pragma once
#include <QtWidgets/QWidget>
#include <QListWidget>
#include <QScrollArea>
#include <QStringList>
class ch2_16_ScrollAreaDemo : public QWidget
{
Q_OBJECT
public:
ch2_16_ScrollAreaDemo(QWidget *parent = nullptr);
~ch2_16_ScrollAreaDemo();
private:
//界面所要用到的所有控件,按照从上到下的顺序声明
QListWidget* m_pListWidget = nullptr;
QScrollArea* m_pScrollArea = nullptr;
QStringList m_textList;
};
注意查看代码中的注释,一些注意点写在了注释里
#include "ch2_16_ScrollAreaDemo.h"
#include <QHBoxLayout>
#include <string>
using namespace std;
ch2_16_ScrollAreaDemo::ch2_16_ScrollAreaDemo(QWidget *parent)
: QWidget(parent)
{
setFixedSize(150 + 1000 + 30 , 900);
this->setStyleSheet("background:rgb(26, 26, 26)");
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint); //隐藏窗口标题和任务栏控制最大最小化
//左边的ListWidget窗口
m_pListWidget = new QListWidget(this);
m_pListWidget->setFixedWidth(150);
m_pListWidget->setFrameShape(QFrame::NoFrame);
m_textList << "基本设置" << "云盘设置" << "下载设置" << "接管设置" << "任务管理" << "提醒" << "悬浮窗" << "高级设置";
m_pListWidget->addItems(m_textList);
string lw_qss = R"(QListWidget
{
/*border:1px solid gray; 使用R字符串优点是避免了一般字符串换行时重复增加反斜杠*/
background:rgb(26, 26, 26);
color:rgb(200, 200, 200);
font-size:15px;
border-radius:1px;
}
QListWidget::item
{
height:40px;
padding-left:10px; /*控制文本与left左边的距离*/
}
QListWidget::item:!active
{
background:rgb(26, 26, 26);
margin:5px 20px 1px 20px; /*上右下左,控制item与ListWidget的距离,这里好像有问题 */
}
QListWidget::item:hover
{
background:rgb(56, 56, 56);
/*padding-left:30px;*/
}
QListWidget::item:selected
{
border-radius:15px;
background:lightblue;
}
QListWidget::item:selected:!active
{
background:rgb(51,51,51);
color:#3F85FF;
})";
m_pListWidget->setStyleSheet(QString::fromStdString(lw_qss));
//右边的设置窗口,用QScrollArea控件来实现
m_pScrollArea = new QScrollArea(this);
m_pScrollArea->setFixedWidth(1000 + 30);
//添加一个水平布局,把上面创建的两个控件添加进去,setSpacing设置两个控件的间隙
QHBoxLayout* hlay = new QHBoxLayout(this);
hlay->addWidget(m_pListWidget);
hlay->setSpacing(0);
hlay->addWidget(m_pScrollArea);
}
ch2_16_ScrollAreaDemo::~ch2_16_ScrollAreaDemo()
{}
编译结果:
任务2:完善右边QScrollArea控件中的内容
右边的一个个单元设置可以认为是一个个widget窗口,分析第一个基本设置窗口的布局方法如下
添加一个Qwidget类,用于基本设置
ch2_16_ScrollAreaDemo.h
#pragma once
#include <QtWidgets/QWidget>
#include <QListWidget>
#include <QScrollArea>
#include <QStringList>
#include "CBaseSetWidget.h"
#include <vector>
#include "GaojiSetWidget.h"
using namespace std;
class ch2_16_ScrollAreaDemo : public QWidget
{
Q_OBJECT
public:
ch2_16_ScrollAreaDemo(QWidget *parent = nullptr);
~ch2_16_ScrollAreaDemo();
private slots:
void slotItemChlicked(QListWidgetItem* Item);
void slotValueChanged(int value);
private:
//界面所要用到的所有控件,按照从上到下的顺序声明
QListWidget* m_pListWidget = nullptr;
QScrollArea* m_pScrollArea = nullptr;
QStringList m_textList;
/*基本设置是创建了一个类来实现的,m_pYunpanSetWidget到m_pXuanfuWidget通过创建一个widget并在其中加入图片做的*/
CBaseSetWidget* m_pBaseSetWidget;
QWidget* m_pYunpanSetWidget;
QWidget* m_pDownloadWidget;
QWidget* m_pJieguanWidget;
QWidget* m_pRenwuWidget;
QWidget* m_pTixingWidget;
QWidget* m_pXuanfuWidget;
GaojiSetWidget* m_pGaojiWidget; //高级设置是用两个图片拼接起来的
vector<QWidget*> m_vecWidget; //申明一个容器类用于排列m_pScrollArea中要添加的widget
bool signFlag = false;
};
ch2_16_ScrollAreaDemo.cpp
#include "ch2_16_ScrollAreaDemo.h"
#include <QHBoxLayout>
#include <string>
#include <QScrollBar>
using namespace std;
ch2_16_ScrollAreaDemo::ch2_16_ScrollAreaDemo(QWidget *parent)
: QWidget(parent)
{
setFixedSize(150 + 1000 + 30 + 15 , 900); //主界面的大小
this->setStyleSheet("background:rgb(26, 26, 26)"); //主界面的颜色
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint); //隐藏窗口标题和任务栏控制最大最小化
m_pListWidget = new QListWidget(this); //创建一个QListWidget对象,this是他的父对象,这里就是ch2_16_ScrollAreaDemo
m_pListWidget->setFixedWidth(150);
m_pListWidget->setFrameShape(QFrame::NoFrame); //去除ListWidget的白色边框
m_pListWidget->setFocusPolicy(Qt::NoFocus); //去除聚焦策略,避免ListWidget中的Item偏移
m_textList << "基本设置" << "云盘设置" << "下载设置" << "接管设置" << "任务管理" << "提醒" << "悬浮窗" << "高级设置";
m_pListWidget->addItems(m_textList); //一次性添加多个Item
//QListWidget样式表
string lw_qss = R"(QListWidget
{
/*border:1px solid gray; 使用R字符串优点是避免了一般字符串换行时重复增加反斜杠*/
background:rgb(26, 26, 26);
color:rgb(200, 200, 200);
font-size:15px;
border-radius:1px;
}
QListWidget::item
{
height:40px;
padding-left:10px; /*控制文本与left左边的距离*/
}
QListWidget::item:!active
{
background:rgb(26, 26, 26);
margin:5px 20px 1px 20px; /*上右下左,控制item与ListWidget的距离,这里好像有问题 */
}
QListWidget::item:hover
{
background:rgb(56, 56, 56);
padding-left:30px; /*鼠标悬浮效果*/
}
QListWidget::item:selected
{
border-radius:15px;
background:lightblue;
}
QListWidget::item:selected:!active
{
background:rgb(51,51,51);
color:#3F85FF;
})";
m_pListWidget->setStyleSheet(QString::fromStdString(lw_qss));
m_pScrollArea = new QScrollArea(this);
m_pScrollArea->setFixedWidth(1000 + 30);
m_pScrollArea->setFrameShape(QFrame::NoFrame); //取消右边QScrollArea白色边框
m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //取消水平滑动条
//m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); //垂直滑动条在需要时显示
string verticalbar_qss = R"(
QScrollBar{width:15px;background:rgb(26, 26, 26);margin:0px, 0px, 0px, 0px;}
QScrollBar::handle:vertical{width:8px;background:rgba(162, 163, 165, 100%);border-radius:4px;min-height:40;}
QScrollBar::handle:vertical:hover{width:8px;background:rgba(115,118,118, 100%);border-radius:4px;min-height:40;}
QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical{background:rgb(26, 26, 26);border-radius:4px;}
QScrollBar::top-arrow:vertical,QScrollBar::bottom-arrow:vertical{border: none;background: none;color: none;}
QScrollBar::add-line:vertical{border:none;background:none;}
QScrollBar::sub-line:vertical{border:none;background:none;}
)";
m_pScrollArea->verticalScrollBar()->setStyleSheet(QString::fromStdString(verticalbar_qss));
m_pBaseSetWidget = new CBaseSetWidget;
m_vecWidget.push_back(m_pBaseSetWidget);
m_pYunpanSetWidget = new QWidget;
m_pYunpanSetWidget->setStyleSheet("background-image:url(:/ch2_16_ScrollAreaDemo/resources/YunPanSet.png);background-repeat:no-repeat;background-color:rgb(51,51,51)");
m_pYunpanSetWidget->setFixedSize(1000, 478);
m_vecWidget.push_back(m_pYunpanSetWidget);
m_pDownloadWidget = new QWidget;
m_pDownloadWidget->setStyleSheet("background-image:url(:/ch2_16_ScrollAreaDemo/resources/XiaZai.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
m_pDownloadWidget->setFixedSize(1000, 337);
m_vecWidget.push_back(m_pDownloadWidget);
m_pJieguanWidget = new QWidget;
m_pJieguanWidget->setStyleSheet("background-image:url(:/ch2_16_ScrollAreaDemo/resources/JieGuanSet.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
m_pJieguanWidget->setFixedSize(1000, 340);
m_vecWidget.push_back(m_pJieguanWidget);
m_pRenwuWidget = new QWidget;
m_pRenwuWidget->setStyleSheet("background-image:url(:/ch2_16_ScrollAreaDemo/resources/RenwuGuanli.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
m_pRenwuWidget->setFixedSize(1000, 413);
m_vecWidget.push_back(m_pRenwuWidget);
m_pTixingWidget = new QWidget;
m_pTixingWidget->setStyleSheet("background-image:url(:/ch2_16_ScrollAreaDemo/resources/TiXing.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
m_pTixingWidget->setFixedSize(1000, 728);
m_vecWidget.push_back(m_pTixingWidget);
m_pXuanfuWidget = new QWidget;
m_pXuanfuWidget->setStyleSheet("background-image:url(:/ScrollAreaDemo/resources/XuanFuChuang.png);background-repeat: no-repeat;background-color:rgb(51, 51, 51)");
m_pXuanfuWidget->setFixedSize(1000, 206);
m_vecWidget.push_back(m_pXuanfuWidget);
m_pGaojiWidget = new GaojiSetWidget;
m_vecWidget.push_back(m_pGaojiWidget);
QWidget* widget = new QWidget;
QVBoxLayout* pVLay = new QVBoxLayout(widget);
for (auto w : m_vecWidget)
{ //给每一个m_vecWidget的元素之间增加间隙
pVLay->addWidget(w);
pVLay->addSpacing(15);
}
pVLay->setContentsMargins(0, 5, 0, 5);
m_pScrollArea->setWidget(widget);
QHBoxLayout* hlay = new QHBoxLayout(this);
hlay->addWidget(m_pListWidget);
hlay->setSpacing(0);
hlay->addWidget(m_pScrollArea);
connect(m_pListWidget, &QListWidget::itemClicked, this, &ch2_16_ScrollAreaDemo::slotItemChlicked);
connect(m_pScrollArea->verticalScrollBar(), &QScrollBar::valueChanged, this, &ch2_16_ScrollAreaDemo::slotValueChanged);
}
//左侧Item点击的槽函数,点击标签在右侧显示对应设置
void ch2_16_ScrollAreaDemo::slotItemChlicked(QListWidgetItem* item)
{
signFlag = true;
QString itemText = item->text();
QPoint widgetPos;
int size = m_textList.size();
for (int i = 0; i < size; i++)
{
if (itemText == m_textList[i])
{
widgetPos = m_vecWidget[i]->pos();
}
}
m_pScrollArea->verticalScrollBar()->setValue(widgetPos.y());
}
//右边设置页面跟随滚动条变化
void ch2_16_ScrollAreaDemo::slotValueChanged(int value)
{
if (!signFlag)
{
int itemSize = m_vecWidget.size();
for (int i = 0; i < itemSize; i++)
{
if (!m_vecWidget[i]->visibleRegion().isEmpty())
{
m_pListWidget->item(i)->setSelected(true);
return;
}
else
{
m_pListWidget->item(i)->setSelected(false);
}
}
}
signFlag = false;
}
ch2_16_ScrollAreaDemo::~ch2_16_ScrollAreaDemo()
{}
基础设置,CBaseSetWidget.h
#include <QWidget>
#pragma once
class CBaseSetWidget:public QWidget
{
public:
CBaseSetWidget(QWidget* parent = nullptr);
~CBaseSetWidget();
};
CBaseSetWidget.cpp,根据基础设置布局手动代码布局
#include "CBaseSetWidget.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QRadioButton>
#include <QCheckBox>
CBaseSetWidget::CBaseSetWidget(QWidget* parent)
:QWidget(parent)
{
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_StyledBackground);
this->setStyleSheet("background-color:rgb(51, 51, 51);color:rgb(200,200,200);");
QLabel* pBaseSetLabel = new QLabel(this);
pBaseSetLabel->setText("基本设置");
QCheckBox* pCheckKaijiqidong = new QCheckBox(this);
pCheckKaijiqidong->setText("开机启动");
QCheckBox* pCheckMiandarao = new QCheckBox(this);
pCheckMiandarao->setFixedWidth(140);
pCheckMiandarao->setText("开启免打扰模式");
QLabel* p1 = new QLabel(this);
p1->setText("?");
QCheckBox* pCheckBosskey = new QCheckBox(this);
pCheckBosskey->setFixedWidth(105);
pCheckBosskey->setText("开启老板键");
QLineEdit* pLineEdit = new QLineEdit(this);
pLineEdit->setFixedWidth(100);
pLineEdit->setStyleSheet("bordor-style:solid;bordor-width:1px;bordor-color:rgb(79,79,79);");
QLabel* p2 = new QLabel(this);
p2->setText("?");
QCheckBox* pCheckNewShowMainUI = new QCheckBox(this);
pCheckNewShowMainUI->setText("新建时显示主界面");
QLabel* pXiazaimoshi = new QLabel(this);
pXiazaimoshi->setText("下载模式");
QRadioButton* pQuansuxiazai = new QRadioButton(this);
pQuansuxiazai->setText("全速下载");
QRadioButton* pXiansuxiazai = new QRadioButton(this);
pXiansuxiazai->setText("限速下载");
pXiansuxiazai->setFixedWidth(90);
QPushButton* pBtnModify = new QPushButton(this);
pBtnModify->setText("修改设置");
pBtnModify->setStyleSheet("background-color:#1A1A1A;color:#5F5F5F");
QLabel* label_cfginfo = new QLabel(this);
label_cfginfo->setText("限制时间段: 00:00-23:59 最大下载速度:不限速");
QVBoxLayout* pMainVlay = new QVBoxLayout(this);
pMainVlay->addWidget(pBaseSetLabel);
pMainVlay->addSpacing(20);
QHBoxLayout* pHlay1 = new QHBoxLayout(this);
pHlay1->addSpacing(35);
QVBoxLayout* pVlay1 = new QVBoxLayout(this);
pVlay1->addWidget(pCheckKaijiqidong);
pVlay1->addSpacing(20);
QHBoxLayout* pHlay2 = new QHBoxLayout(this);
pHlay2->addWidget(pCheckMiandarao);
pHlay2->addWidget(p1);
//把免打扰的水平布局添加到pVlay1中
pVlay1->addLayout(pHlay2);
pVlay1->addSpacing(20);
QHBoxLayout* pHlay3 = new QHBoxLayout(this);
pHlay3->addWidget(pCheckBosskey);
pHlay3->addWidget(pLineEdit);
pHlay3->addWidget(p1);
pVlay1->addLayout(pHlay3);
pVlay1->addSpacing(20);
pVlay1->addWidget(pCheckNewShowMainUI);
pVlay1->addSpacing(20);
//下载模式
pVlay1->addWidget(pXiazaimoshi);
pVlay1->addSpacing(20);
QHBoxLayout* pHlay4 = new QHBoxLayout(this);
pHlay4->addSpacing(30);
QVBoxLayout* pVlay2 = new QVBoxLayout(this);
QHBoxLayout* pHlay5 = new QHBoxLayout(this);
pHlay5->addWidget(pQuansuxiazai);
pHlay5->addWidget(p2);
pVlay2->addLayout(pHlay5);
pVlay2->addSpacing(20);
QHBoxLayout* pHlay6 = new QHBoxLayout(this);
pHlay6->addWidget(pXiansuxiazai);
pHlay6->addWidget(pBtnModify);
pHlay6->addWidget(label_cfginfo);
pHlay6->addStretch(); //增加一个弹簧
pVlay2->addLayout(pHlay6);
pHlay4->addLayout(pVlay2);
pVlay1->addLayout(pHlay4);
pHlay1->addLayout(pVlay1);
pMainVlay->addLayout(pHlay1);
pMainVlay->setContentsMargins(20, 20, 20, 20);
}
CBaseSetWidget::~CBaseSetWidget()
{
}
因为高级设置页面比较长,所以采取两种图片拼接的方式来显示,GaojiSetWidget.h
#pragma once
#include <QWidget>
class GaojiSetWidget:public QWidget
{
Q_OBJECT
public:
GaojiSetWidget(QWidget* parent = Q_NULLPTR);
~GaojiSetWidget();
private:
};
GaojiSetWidget.cpp
#include "GaojiSetWidget.h"
#include <QVBoxLayout>
#include <QLabel>
GaojiSetWidget::GaojiSetWidget(QWidget* parent)
: QWidget(parent)
{
QLabel* pLabel1 = new QLabel(this);
pLabel1->setFixedSize(1000, 541);
QPixmap* pixmap = new QPixmap(":/ch2_16_ScrollAreaDemo/resources/GaojiSet_1.png");
pixmap->scaled(pLabel1->size(), Qt::KeepAspectRatio);
pLabel1->setScaledContents(true);
pLabel1->setPixmap(*pixmap);
QLabel* pLabel2 = new QLabel(this);
pLabel2->setFixedSize(1000, 685);
pixmap = new QPixmap(":/ch2_16_ScrollAreaDemo/resources/GaojiSet_2.png");
pixmap->scaled(pLabel2->size(), Qt::KeepAspectRatio);
pLabel2->setScaledContents(true);
pLabel2->setPixmap(*pixmap);
QVBoxLayout* pVLay = new QVBoxLayout(this);
pVLay->addWidget(pLabel1);
pVLay->setSpacing(0);
pVLay->addWidget(pLabel2);
pVLay->setContentsMargins(0, 0, 0, 0);
}
GaojiSetWidget::~GaojiSetWidget()
{
}
编译结果:
还需要改进的地方: 基本设置中的问号离其他控件间距不正确;右边的界面在扩展显示器上图片显示不全;