QT学习笔记三

ch3_1 查看QWidget类源码了解其使用方法

Qt所有的窗口、控件以及布局都是派生于Qwidget,Qt很多问题都可以从Qwidget类找到答案,学习Qt大部分就是在与QWidget打交道。

ch3_2 无边框窗口的基本实现

直接看代码:
MainWidget.h

#pragma once

#include <QtWidgets/QWidget>

class MainWidget : public QWidget
{
   Q_OBJECT

public:
   MainWidget(QWidget *parent = nullptr);
   ~MainWidget();

private:
   void mouseMoveEvent(QMouseEvent* event) override;
   void mousePressEvent(QMouseEvent* event) override;

private:
   QPoint diff_pos;  
   QPoint window_pos;
   QPoint mouse_pos;
};

MainWidget.cpp

#include "MainWidget.h"
#include <QMouseEvent>

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
}

MainWidget::~MainWidget()
{}

void MainWidget::mousePressEvent(QMouseEvent * event)
{
    mouse_pos = event->globalPosition().toPoint();	//这句QT5和QT6方法有所不同,在5版本中,使用globalPos,6版本是globalPosition返回值是一个QPointF类型
    window_pos = this->pos();
    diff_pos = mouse_pos - window_pos;
}

void MainWidget::mouseMoveEvent(QMouseEvent* event)
{
    QPoint pos = event->globalPosition().toPoint();
    //this->move(pos);
    this->move(pos - diff_pos);
}

编译结果:
在这里插入图片描述

ch3_3 给无边框窗口添加自定义标题栏并实现拖拽拉伸

本小节的文件结构如下:
在这里插入图片描述
MainWidget类:主窗口
CTitleBar类:标题栏类
CFrameLessWidgetBase类:无边框窗口类,当需要使用创建无边框窗口时,可以使用该类派生子类,拥有基本的无边框窗口的方法属性

任务1:代码实现无边框窗口布局

单独写写一个标题栏类,标题栏布局如下:
在这里插入图片描述
CTitleBar.h

#pragma once
#include <QWidget>
#include <QPushbutton>
#include <QLabel>
#include <QMouseEvent>

class CTitlebar : public QWidget
{
	Q_OBJECT

public:
	CTitlebar(QWidget* p = nullptr);
	~CTitlebar();
	
private:
	void initUI();
	void mousePressEvent(QMouseEvent* event) override;

private:
	QLabel* m_pLogo;
	QLabel* m_pTitleTextLabel;

	QPushButton* m_pSetBtn;
	QPushButton* m_pMinBtn;
	QPushButton* m_pMaxBtn;
	QPushButton* m_pCloseBtn;
};

CTitlebar.cpp

#include "CTitlebar.h"
#include <QHBoxLayout>
#pragma warning(disable:4996)	//为了避免出现C4996报错添加此句
#include <qt_windows.h>

CTitlebar::CTitlebar(QWidget* p) : QWidget(p)
{
	initUI();
}

CTitlebar::~CTitlebar()
{
}

void CTitlebar::initUI()
{
	//禁止父窗口影响子窗口样式
	setAttribute(Qt::WA_StyledBackground);
	this->setFixedHeight(40);
	this->setStyleSheet("background-color:rgb(100,100,100)");

	m_pLogo = new QLabel(this);
	m_pLogo->setFixedSize(32, 32);
	m_pLogo->setStyleSheet("background-color:rgb(200,10,10)");

	m_pTitleTextLabel = new QLabel(this);
	m_pTitleTextLabel->setText("我是标题");
	m_pTitleTextLabel->setFixedWidth(120);

	m_pSetBtn = new QPushButton(this);
	m_pSetBtn->setFixedSize(32, 32);

	m_pMinBtn = new QPushButton(this);
	m_pMinBtn->setFixedSize(32, 32);

	m_pMaxBtn = new QPushButton(this);
	m_pMaxBtn->setFixedSize(32, 32);
	
	m_pCloseBtn = new QPushButton(this);
	m_pCloseBtn->setFixedSize(32, 32);

	QHBoxLayout* pHlay = new QHBoxLayout(this);
	pHlay->addWidget(m_pLogo);
	pHlay->addWidget(m_pTitleTextLabel);
	pHlay->addStretch();
	pHlay->addWidget(m_pSetBtn);
	pHlay->addWidget(m_pMinBtn);
	pHlay->addWidget(m_pMaxBtn);
	pHlay->addWidget(m_pCloseBtn);

	pHlay->setContentsMargins(5, 5, 5, 5);
}

//拖拽无边框窗口更好的解决办法
void CTitlebar::mousePressEvent(QMouseEvent* event)
{
	if (ReleaseCapture())
	{
		QWidget* pWindow = this->window();
		if (pWindow->isTopLevel())
		{
			SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
		}
	}
}

CFrameLessWidgetBase.h

#pragma once
#include <QWidget>

class CFrameLessWidgetBase :
    public QWidget
{
public:
    CFrameLessWidgetBase(QWidget* p = nullptr);
    ~CFrameLessWidgetBase() {};
    
protected:
    bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;

private:
    int m_nBorderWidth = 6; //m_nBorder表示鼠标位于边框缩放范围的宽度
};

CFrameLessWidgetBase.cpp

#include "CFrameLessWidgetBase.h"
#include <qt_windows.h>
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib, "user32.lib")

CFrameLessWidgetBase::CFrameLessWidgetBase(QWidget* p)
	:QWidget(p)
{
	this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
	setAttribute(Qt::WA_Hover);
}

//这个函数的作用是实现窗口的拉伸缩放的功能
bool CFrameLessWidgetBase::nativeEvent(const QByteArray& eventType, void* message, qintptr* result)
{
	MSG* param = static_cast<MSG*>(message);

	switch (param->message)
	{
	case WM_NCHITTEST:
	{
		int nX = GET_X_LPARAM(param->lParam) - this->geometry().x();
		int nY = GET_Y_LPARAM(param->lParam) - this->geometry().y();

		/*if (childAt(nX, nY) != nullptr)
			return QWidget::nativeEvent(eventType, message, result);*/

		if (nX > m_nBorderWidth && nX < this->width() - m_nBorderWidth &&
			nY > m_nBorderWidth && nY < this->height() - m_nBorderWidth)
		{
			if (childAt(nX, nY) != nullptr)
				return QWidget::nativeEvent(eventType, message, result);
		}

		if ((nX > 0) && (nX < m_nBorderWidth))
			*result = HTLEFT;

		if ((nX > this->width() - m_nBorderWidth) && (nX < this->width()))
			*result = HTRIGHT;

		if ((nY > 0) && (nY < m_nBorderWidth))
			*result = HTTOP;

		if ((nY > this->height() - m_nBorderWidth) && (nY < this->height()))
			*result = HTBOTTOM;

		if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0)
			&& (nY < m_nBorderWidth))
			*result = HTTOPLEFT;

		if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
			&& (nY > 0) && (nY < m_nBorderWidth))
			*result = HTTOPRIGHT;

		if ((nX > 0) && (nX < m_nBorderWidth)
			&& (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
			*result = HTBOTTOMLEFT;

		if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
			&& (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
			*result = HTBOTTOMRIGHT;

		return true;
	}
	}

	return false;
}

MainWidgetPro.h

#pragma once

#include <QtWidgets/QWidget>
#include "CTitlebar.h"
#include "CFrameLessWidgetBase.h"

//把无边框窗口抽象成 CFrameLessWidgetBase类,让主窗口从无边框窗口类派生出来
class MainWidgetPro : public CFrameLessWidgetBase
{
    Q_OBJECT

public:
    MainWidgetPro(QWidget *parent = Q_NULLPTR);
    ~MainWidgetPro();

private:
    void initUI();
    
private:
    CTitlebar* m_pTitleBar = nullptr;
};

MainWidgetPro.cpp

#include "MainWidgetPro.h"

#include "CTitlebar.h"
#include <QVBoxLayout>

MainWidgetPro::MainWidgetPro(QWidget *parent)
    : CFrameLessWidgetBase(parent)
{
    
    // 背景透明,防止黑影
    //setAttribute(Qt::WA_TranslucentBackground);

    initUI();
}

MainWidgetPro::~MainWidgetPro()
{}

void MainWidgetPro::initUI()
{
    m_pTitleBar = new CTitlebar(this);

    QWidget* w = new QWidget(this);
    w->setMinimumSize(800, 600);
    QVBoxLayout* pVlay = new QVBoxLayout(this);
    pVlay->addWidget(m_pTitleBar);
    pVlay->addWidget(w);

    pVlay->setContentsMargins(0, 0, 0, 0);  //把标题栏不要留有间隙
    setLayout(pVlay);
}

//下面实现无边框窗口缩放拉伸借鉴的其他人

/*
 * 拖动,缩放实现
*/
//bool MainWidgetPro::nativeEvent(const QByteArray& eventType, void* message, qintptr* result) {
//    Q_UNUSED(eventType);
//#ifdef Q_OS_WIN
//    MSG* param = static_cast<MSG*>(message);
//    switch (param->message) {
//    case WM_NCCALCSIZE: {
//        // 使用window默认布局,不加这一段代码,系统无法正确进行最大化
//        *result = 0;
//        return true;
//    }
//    case WM_NCHITTEST: {
//        int nX = cursor().pos().x() - x();
//        int nY = cursor().pos().y() - y();
//        // 如果鼠标位于子控件上,则不进行处理
//        if (childAt(nX, nY) != nullptr) {
//            return QWidget::nativeEvent(eventType, message, result);
//        }
//        // 默认情况下,将鼠标视为在标题栏上
//        *result = HTCAPTION;
//        // 鼠标区域位于窗体边框,进行缩放
//        // 左边框
//        if ((nX > 0) && (nX < m_nBorderWidth))
//            *result = HTLEFT;
//        // 右边框
//        if (nX > (this->width() - m_nBorderWidth))
//            *result = HTRIGHT;
//        // 左上边框
//        if ((nY > 0) && (nY < m_nBorderWidth))
//            *result = HTTOP;
//        // 下边框
//        if ((nY > this->height() - m_nBorderWidth) && (nY < this->height()))
//            *result = HTBOTTOM;
//        // 左上角
//        if ((nX > 0) && (nX < m_nBorderWidth) && (nY > 0)
//            && (nY < m_nBorderWidth))
//            *result = HTTOPLEFT;
//        // 右上角
//        if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
//            && (nY > 0) && (nY < m_nBorderWidth))
//            *result = HTTOPRIGHT;
//        // 左下角
//        if ((nX > 0) && (nX < m_nBorderWidth)
//            && (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
//            *result = HTBOTTOMLEFT;
//        // 右下角
//        if ((nX > this->width() - m_nBorderWidth) && (nX < this->width())
//            && (nY > this->height() - m_nBorderWidth) && (nY < this->height()))
//            *result = HTBOTTOMRIGHT;
//        return true;
//    }
//    }
//#endif
//
//    return QWidget::nativeEvent(eventType, message, result);
//}

编译结果:
在这里插入图片描述

问题:
1、按照上面贴出来的代码,只能实现拖动窗口,但是不能实现缩放拉伸,如何解决待后续研究;
2、在重写nativeEvent函数时,发现qt6和qt5在函数参数上有所区别,qt6是qintptr* result,qt5是long* result
3、qt6在pWindow->isTopLevel()这句会报c4996错误,要在头文件处加上#pragma warning(disable:4996)

任务2:补充标题栏图标并实现按钮功能

代码是在前一个任务上的补充

#pragma once
#include <QWidget>
#include <QPushbutton>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>

class CTitlebar : public QWidget
{
	Q_OBJECT

public:
	CTitlebar(QWidget* p = nullptr);
	~CTitlebar();
	
private:
	void initUI();
	void mousePressEvent(QMouseEvent* event) override;
	
private slots:
	void onClicked();

signals:
	void sig_close();


private:
	QLabel* m_pLogo;
	QLabel* m_pTitleTextLabel;

	QPushButton* m_pSetBtn;
	QPushButton* m_pMinBtn;
	QPushButton* m_pMaxBtn;
	QPushButton* m_pCloseBtn;
};
----------------------------------------------------------
#include "CTitlebar.h"
#include <QHBoxLayout>
#pragma warning(disable:4996)	//为了避免出现C4996报错添加此句
#include <qt_windows.h>

CTitlebar::CTitlebar(QWidget* p) : QWidget(p)
{
	initUI();
}

CTitlebar::~CTitlebar()
{
}

void CTitlebar::initUI()
{
	/*QLabel* m_pLogo;
	QLabel* m_pTitleTextLabel;

	QPushButton* m_pSetBtn;
	QPushButton* m_pMinBtn;
	QPushButton* m_pMaxBtn;
	QPushButton* m_pCloseBtn;*/
	/*禁止父窗口影响子窗口样式,通过启用 Qt::WA_StyledBackground 属性,
	控件的背景可以使用 Qt 样式表(Style Sheet) 进行渲染。如果没有启用此属性,
		即使你通过样式表设置背景样式(如 background-color),也可能不会生效。*/
	setAttribute(Qt::WA_StyledBackground);
	this->setFixedHeight(40);
	this->setStyleSheet("background-color:rgb(100,100,100)");

	m_pLogo = new QLabel(this);
	m_pLogo->setFixedSize(32, 32);
	m_pLogo->setStyleSheet("background-image:url(:/MainWidgetPro/resources/titlebar/title_icon.png);border:none");
	  
	m_pTitleTextLabel = new QLabel(this);
	m_pTitleTextLabel->setText("我是标题");
	m_pTitleTextLabel->setFixedWidth(120);
	m_pTitleTextLabel->setStyleSheet("QLabel{font-family: Microsoft YaHei; font-size:18px; color:#BDC8E2; background-color:rgb(54,54,54);}");

	m_pSetBtn = new QPushButton(this);
	m_pSetBtn->setFixedSize(32, 32);
	m_pSetBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/set.svg);border:none}" \
		"QPushButton:hover{background-color:rgb(99,99,99);"  \
		"background-image:url(:/MainWidgetPro/resources/titlebar/set_hover.svg);border:none}");

	m_pMinBtn = new QPushButton(this);
	m_pMinBtn->setFixedSize(32, 32);
	m_pMinBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/min.svg);border:none}" \
		"QPushButton:hover{background-color:rgb(99,99,99);"  \
		"background-image:url(:/MainWidgetPro/resources/titlebar/min_hover.svg);border:none}");

	m_pMaxBtn = new QPushButton(this);
	m_pMaxBtn->setFixedSize(32, 32);
	m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/normal.svg);border:none}" \
		"QPushButton:hover{background-color:rgb(99,99,99);"  \
		"background-image:url(:/MainWidgetPro/resources/titlebar/normal_hover.svg);border:none}");
	
	m_pCloseBtn = new QPushButton(this);
	m_pCloseBtn->setFixedSize(32, 32);
	m_pCloseBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/close.svg);border:none}" \
		"QPushButton:hover{background-color:rgb(99,99,99);"  \
		"background-image:url(:/MainWidgetPro/resources/titlebar/close_hover.svg);border:none}");

	QHBoxLayout* pHlay = new QHBoxLayout(this);
	pHlay->addWidget(m_pLogo);
	pHlay->addWidget(m_pTitleTextLabel);
	pHlay->addStretch();
	pHlay->addWidget(m_pSetBtn);
	QSpacerItem* pItem1 = new QSpacerItem(20, 20, QSizePolicy::Fixed);
	pHlay->addSpacerItem(pItem1);

	pHlay->addWidget(m_pMinBtn);
	QSpacerItem* pItem2 = new QSpacerItem(20, 20, QSizePolicy::Fixed);
	pHlay->addSpacerItem(pItem2);

	pHlay->addWidget(m_pMaxBtn);
	QSpacerItem* pItem3 = new QSpacerItem(20, 20, QSizePolicy::Fixed);
	pHlay->addSpacerItem(pItem3);	 // 弹簧每次使用时得new出来,不能重复使用

	pHlay->addWidget(m_pCloseBtn);

	pHlay->setContentsMargins(5, 5, 5, 5);	//设置布局的内容边距(即子控件与布局容器边框之间的距离)
	//pHlay->setContentsMargins(0,0,0,0);

	connect(m_pCloseBtn, &QPushButton::clicked, this, &CTitlebar::onClicked);
	connect(m_pMinBtn, &QPushButton::clicked, this, &CTitlebar::onClicked);
	connect(m_pMaxBtn, &QPushButton::clicked, this, &CTitlebar::onClicked);
	
}

//拖拽无边框窗口更好的解决办法
void CTitlebar::mousePressEvent(QMouseEvent* event)
{
	if (ReleaseCapture())
	{
		QWidget* pWindow = this->window();
		if (pWindow->isTopLevel())
		{
			SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
		}
	}
}

void CTitlebar::onClicked()
{
	QPushButton* pButton = qobject_cast<QPushButton*>(sender());	/*获取当前槽函数的触发者(通常是信号的发送者)的指针。
																	尝试将该指针转换为 QPushButton* 类型。
																	如果转换成功,将结果赋值给变量 pButton,否则 pButton 为 nullptr。*/
	QWidget* pWidget = this->window();		//获取当前窗口部件(QWidget)的指针,即当前控件所属的顶层窗口。

	if (pButton == m_pMinBtn)
	{
		pWidget->showMinimized();
	}
	else if (pButton == m_pMaxBtn)
	{
		if (pWidget->isMaximized())
		{
			pWidget->showNormal();
			m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/normal.svg);border:none}" \
				"QPushButton:hover{background-color:rgb(99,99,99);"  \
				"background-image:url(:/MainWidgetPro/resources/titlebar/normal_hover.svg);border:none}");
		}
		else
		{
			pWidget->showMaximized();
			m_pMaxBtn->setStyleSheet("QPushButton{background-image:url(:/MainWidgetPro/resources/titlebar/max.svg);border:none}" \
				"QPushButton:hover{background-color:rgb(99,99,99);"  \
				"background-image:url(:/MainWidgetPro/resources/titlebar/max_hover.svg);border:none}");
		}
	}
	else if (pButton == m_pCloseBtn)
	{
		emit sig_close();
	}

}

--------------------------------------------------------------
#pragma once
#include <QWidget>

class CFrameLessWidgetBase :
    public QWidget
{
public:
    CFrameLessWidgetBase(QWidget* p = nullptr);
    ~CFrameLessWidgetBase() {};
    
protected:
    //bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override;

private:
    int m_nBorderWidth = 5; //m_nBorder表示鼠标位于边框缩放范围的宽度
};

--------------------------------------------------------------------
#include "CFrameLessWidgetBase.h"
#include <qt_windows.h>
#include <windows.h>
#include <windowsx.h>
#pragma comment(lib, "user32.lib")

CFrameLessWidgetBase::CFrameLessWidgetBase(QWidget* p)
	:QWidget(p)
{
	this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
	setAttribute(Qt::WA_Hover); 

}

---------------------------------------------------------------------------
#pragma once

#include <QtWidgets/QWidget>
#include "CTitlebar.h"
#include "CFrameLessWidgetBase.h"

class MainWidgetPro : public CFrameLessWidgetBase
{
    Q_OBJECT

public:
    MainWidgetPro(QWidget *parent = Q_NULLPTR);
    ~MainWidgetPro();

private:
    void initUI();

private slots:
    void on_closeSlot();

private:
    CTitlebar* m_pTitleBar = nullptr;  
};

--------------------------------------------------------------------------------------------------------
#include "MainWidgetPro.h"

#include "CTitlebar.h"
#include <QVBoxLayout>

MainWidgetPro::MainWidgetPro(QWidget *parent)
    : CFrameLessWidgetBase(parent)
{
    
    // 背景透明,防止黑影
    //setAttribute(Qt::WA_TranslucentBackground);

    initUI();
}

MainWidgetPro::~MainWidgetPro()
{}

void MainWidgetPro::initUI()
{
    m_pTitleBar = new CTitlebar(this);

    QWidget* w = new QWidget(this);
    w->setMinimumSize(800, 600);
    QVBoxLayout* pVlay = new QVBoxLayout(this);
    pVlay->addWidget(m_pTitleBar);
    pVlay->addWidget(w);

    pVlay->setContentsMargins(0, 0, 0, 0);  //设置布局的内容边距(即子控件与布局容器边框之间的距离);这里设置为 0,表示布局的子控件与布局边框之间没有任何间距
    setLayout(pVlay);

    connect(m_pTitleBar, &CTitlebar::sig_close, this, &MainWidgetPro::on_closeSlot);
}

void MainWidgetPro::on_closeSlot()
{
    close();
}

编译结果:
在这里插入图片描述

ch3_7 Qt实现窗口阴影

任务1:给登录窗口添加阴影

预期效果:
在这里插入图片描述
窗口阴影的设置需要两层窗口
//设置窗体透明
this->setAttribute(Qt::WA TranslucentBackground, true);
//设置无边框
this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
//给顶层widget设置背景颜色,不然看不见,因为底层widget已经透明了
pRealWidget->setStyleSheet(“background-color:rgb(255,254,253)”);
Qt窗囗阴影类 QGraphicsDropshadowEffect
QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(this);
//设置阴影距离
shadow->setoffset(0,0);
//设置阴影颜色
shadow->setColor(QColor(“#00FF00”));
//设置阴影区域
shadow->setBlurRadius(30);
//给顶层awidget设置阴影
pRealWidget->setGraphicsEffect(shadow);

#pragma once

#include <QtWidgets/QDialog>


class CLoginDlg : public QDialog
{
    Q_OBJECT

public:
    CLoginDlg(QWidget *parent = nullptr);
    ~CLoginDlg();

private:
    void mousePressEvent(QMouseEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;

private:
    QPointF windowPos;
    QPointF mousePos;
    QPointF dPos;
    
};
-------------------------------------------
#include "CLoginDlg.h"
#include <CLoginRealWidget.h>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QGraphicsDropShadowEffect>

CLoginDlg::CLoginDlg(QWidget *parent)
    : QDialog(parent)
{
    //设置窗体透明
    this->setAttribute(Qt::WA_TranslucentBackground, true);
    //设置无边框
    this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);

    QVBoxLayout* pMainLay = new QVBoxLayout(this);
    CLoginRealWidget* pRealWidget = new CLoginRealWidget(this);
    pMainLay->addWidget(pRealWidget);
    pMainLay->setContentsMargins(30,30,30,30);
    //setLayout(pMainLay);

    //给顶层widget设置背景色,不然看不见,因为底层widget是透明的
    pRealWidget->setStyleSheet("background-color:rgb(255,254,253)");

    //创建一个阴影对象
    QGraphicsDropShadowEffect* shadow = new QGraphicsDropShadowEffect(this);
    //设置阴影偏移量
    shadow->setOffset(0, 0);
    //设置阴影颜色
    shadow->setColor(QColor("#00ff00"));
    //设置阴影区域
    shadow->setBlurRadius(30);
    //给顶层widget设置阴影
    pRealWidget->setGraphicsEffect(shadow);

}

CLoginDlg::~CLoginDlg()
{}

void CLoginDlg::mousePressEvent(QMouseEvent * event)
{
    this->windowPos = this->pos();
    this->mousePos = event->globalPosition();
    this->dPos = mousePos - windowPos;
}

void CLoginDlg::mouseMoveEvent(QMouseEvent* event)
{
    this->move((event->globalPosition() - this->dPos).toPoint());
}
-------------------------------------------
#pragma once
#include <QWidget>


class CLoginRealWidget : public QWidget
{
	Q_OBJECT

public:
	CLoginRealWidget(QWidget* p = nullptr);
	~CLoginRealWidget();

private:

};
----------------------------------------
#include "CLoginRealWidget.h"
#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QPushButton>
#include <QHBoxLayout>
#include <QGridLayout>

CLoginRealWidget::CLoginRealWidget(QWidget* p)
	:QWidget(p)
{
	//禁止父窗口影响子窗口样式
	setAttribute(Qt::WA_StyledBackground);
	setWindowFlags(Qt::FramelessWindowHint);

	//头像
	QLabel* pImageLabel = new QLabel(this);
	QPixmap pixmap(":/CLoginDlg/resource/user_image.png");
	pImageLabel->setFixedSize(150, 150);
	pImageLabel->setPixmap(pixmap);
	pImageLabel->setScaledContents(true);

	//用户名
	QLineEdit* pUserNameLineEdit = new QLineEdit(this);
	pUserNameLineEdit->setFixedSize(300, 50);
	pUserNameLineEdit->setPlaceholderText(QStringLiteral("QQ号码/手机/邮箱"));

	//密码
	QLineEdit* pPasswordLineEdit = new QLineEdit(this);
	pPasswordLineEdit->setFixedSize(300, 50);
	pPasswordLineEdit->setPlaceholderText(QStringLiteral("密码"));
	pPasswordLineEdit->setEchoMode(QLineEdit::Password);

	QPushButton* pForgotButton = new QPushButton(this);
	pForgotButton->setText(QStringLiteral("找回密码"));
	pForgotButton->setFixedWidth(80);

	QCheckBox* pRememberCheckBox = new QCheckBox(this);
	pRememberCheckBox->setText(QStringLiteral("记住密码"));

	QCheckBox* pAutoLoginCheckBox = new QCheckBox(this);
	pAutoLoginCheckBox->setText(QStringLiteral("自动登录"));

	QPushButton* pLoginButton = new QPushButton(this);
	pLoginButton->setFixedHeight(48);
	pLoginButton->setText(QStringLiteral("登录"));

	QPushButton* pRegisterButton = new QPushButton(this);
	pRegisterButton->setFixedHeight(48);
	pRegisterButton->setText(QStringLiteral("注册账号"));

	QHBoxLayout* pMainLay = new QHBoxLayout(this);

	QSpacerItem* pHSpacer = new QSpacerItem(25, 20, QSizePolicy::Fixed, QSizePolicy::Fixed);
	pMainLay->addSpacerItem(pHSpacer);

	QGridLayout* pGridLayout = new QGridLayout(this);

	// 头像 第0行,第0列开始,占3行1列
	pGridLayout->addWidget(pImageLabel, 0, 0, 3, 1);

	// 用户名输入框 第0行,第1列开始,占1行2列
	pGridLayout->addWidget(pUserNameLineEdit, 0, 1, 1, 2);
	
	// 密码输入框 第1行,第1列开始,占1行2列
	pGridLayout->addWidget(pPasswordLineEdit, 1, 1, 1, 2);

	// 忘记密码 第2行,第1列开始,占1行1列
	pGridLayout->addWidget(pForgotButton, 2, 1, 1, 1);
	
	// 记住密码 第2行,第2列开始,占1行1列 水平居中 垂直居中
	pGridLayout->addWidget(pRememberCheckBox, 2, 2, 1, 1, Qt::AlignLeft | Qt::AlignVCenter);

	// 自动登录 第2行,第2列开始,占1行1列 水平居右 垂直居中
	pGridLayout->addWidget(pAutoLoginCheckBox, 2, 2, 1, 1, Qt::AlignRight | Qt::AlignVCenter);

	// 登录按钮 第3行,第1列开始,占1行2列
	pGridLayout->addWidget(pLoginButton, 3, 1, 1, 2);

	// 注册按钮 第4行,第1列开始,占1行2列
	pGridLayout->addWidget(pRegisterButton, 4, 1, 1, 2);

	// 设置水平间距
	pGridLayout->setHorizontalSpacing(10);

	// 设置垂直间距
	pGridLayout->setVerticalSpacing(10);

	pMainLay->addLayout(pGridLayout);
	pMainLay->addSpacerItem(pHSpacer);

	pMainLay->setContentsMargins(5, 5, 5, 5);
	setLayout(pMainLay);
}

CLoginRealWidget::~CLoginRealWidget()
{
}

ch3_8 实现圆角窗口

实现圆角窗口通常有两种方法:
1、重写paintEvent方法
2、qss样式表

#pragma once

#include <QtWidgets/QWidget>


class MainWidget : public QWidget
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = nullptr);
    ~MainWidget();

private:
    void paintEvent(QPaintEvent* event) override;
};

------------------------------------------------
#include "MainWidget.h"
#include <QPainter>
#include <QStyleOption>

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    resize(600, 400);

    setAttribute(Qt::WA_TranslucentBackground);
    setWindowFlags(Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);

    this->setStyleSheet("QWidget{background-color:#ffFFFF;  \
        border-top-left-radius:15px;   \
        border-bottom-right-radius:15px; \
        }");
}

MainWidget::~MainWidget()
{}
//方法1重写paintEvent方法

//void MainWidget::paintEvent(QPaintEvent * event)
//{
//    QPainter painter(this);
//    painter.setRenderHint(QPainter::Antialiasing);  //反锯齿
//    painter.setBrush(QBrush(QColor(255, 255, 255)));    //设置窗口颜色
//    painter.setPen(Qt::transparent);                        //设置窗口边框颜色
//    QRect rect = this->rect();
//    painter.drawRoundedRect(rect, 15, 15);      //设置窗口圆角 15px
//
//}

//方法2使用qss样式表,然后因为窗口被设置了透明,还需要重写paintEvent方法,否则无法显示窗口
void MainWidget::paintEvent(QPaintEvent* event)
{
    QStyleOption opt;
    opt.initFrom(this);		//qt5中这个方法是init
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}


方法1实现效果:
在这里插入图片描述
方法2实现效果:
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值