当前位置: 首页 > news >正文

QT自定义无边框窗口(可移动控制和窗口大小调整)

         QT是一个功能强大的跨平台开发框架,它提供了丰富的界面设计工具和组件。在界面开发中,QT窗口自带的标题栏无法满足我们的需求。我们就需要自定义无边框窗口,包括自定义标题栏和窗口大小调整功能。本文将介绍如何在QT中实现这些功能。

一、简述

         本文介绍了如何使用Qt框架创建一个无边框窗口,并提供了详细的源码,包括窗口样式设置、移动区域控制和窗口大小调整功能。用于设置窗口为无边框窗口。可为窗口添加自定义标题栏、边框和系统菜单按钮。

二、 设计思路             

        首先,在QT中,我们可以通过设置窗口属性为Qt::FramelessWindowHint来实现无边框窗口BaseWindow(由于系统窗口被设置为Qt::FramelessWindowHint会导致窗口不能被拖动,需要通过捕获鼠标移动事件从而实现窗口移动。)。

        然后,我们可以通过一个自定义的QWidget来扮演标题栏的角色BaseTitleBar。在这个自定义的QWidget中,我们可以添加一些控件,比如窗口标题,关闭按钮等。我们通过自定义的标题栏和边框样式来实现无边框窗口的外观。使用titleBar类来定义标题栏的样式,其中包括标题文本和关闭按钮。通过重写QWidget的mousePressEventmouseMoveEventmouseReleaseEvent函数,我们可以实现拖动窗口的功能。

        最后,自定义FramelessHelper一个辅助类,我们可以自定义窗口的行为,如设置窗口的可移动和可缩放属性。

三、效果 

四、核心代码  
1、头文件

BaseWindow.h 

#ifndef BASEWINDOW_H
#define BASEWINDOW_H#include <QWidget>
#include <QMainWindow>
#include "BaseTitleBar.h"class BaseWindow : public QWidget
{Q_OBJECTpublic:BaseWindow(QWidget *parent = 0);~BaseWindow();private:void initTitleBar();void paintEvent(QPaintEvent *event);void loadStyleSheet(const QString &sheetName);private slots:void onButtonMinClicked();void onButtonRestoreClicked();void onButtonMaxClicked();void onButtonCloseClicked();protected:BaseTitleBar* m_titleBar;};#endif // BASEWINDOW_H

 BaseTitleBar.h

#ifndef BASETITLEBAR_H
#define BASETITLEBAR_H#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QTimer>enum ButtonType
{MIN_BUTTON = 0,			// 最小化和关闭按钮;MIN_MAX_BUTTON ,		// 最小化、最大化和关闭按钮;ONLY_CLOSE_BUTTON		// 只有关闭按钮;
};class BaseTitleBar : public QWidget
{Q_OBJECTpublic:BaseTitleBar(QWidget *parent = NULL);~BaseTitleBar();// 设置标题栏背景色;void setBackgroundColor(int r, int g, int b);// 设置标题栏图标;void setTitleIcon(QString filePath);// 设置标题内容;void setTitleContent(QString titleContent);// 设置标题栏长度;void setTitleWidth(int width);// 设置标题栏上按钮类型;void setButtonType(ButtonType buttonType);// 设置标题栏中的标题是否会滚动;具体可以看效果;void setTitleRoll();// 保存/获取 最大化前窗口的位置及大小;void saveRestoreInfo(const QPoint point, const QSize size);void getRestoreInfo(QPoint& point, QSize& size);private:void paintEvent(QPaintEvent *event);void mouseDoubleClickEvent(QMouseEvent *event);void mousePressEvent(QMouseEvent *event);void mouseMoveEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);// 初始化控件;void initControl();// 信号槽的绑定;void initConnections();// 加载样式文件;void loadStyleSheet(const QString &sheetName);signals:// 按钮触发的信号;void signalButtonMinClicked();void signalButtonRestoreClicked();void signalButtonMaxClicked();void signalButtonCloseClicked();private slots:// 按钮触发的槽;void onButtonMinClicked();void onButtonRestoreClicked();void onButtonMaxClicked();void onButtonCloseClicked();void onRollTitle();private:QLabel* m_pIcon;					// 标题栏图标;QLabel* m_pTitleContent;			// 标题栏内容;QPushButton* m_pButtonMin;			// 最小化按钮;QPushButton* m_pButtonRestore;		// 最大化还原按钮;QPushButton* m_pButtonMax;			// 最大化按钮;QPushButton* m_pButtonClose;		// 关闭按钮;// 标题栏背景色;int m_colorR;int m_colorG;int m_colorB;// 最大化,最小化变量;QPoint m_restorePos;QSize m_restoreSize;// 移动窗口的变量;bool m_isPressed;QPoint m_startMovePos;// 标题栏跑马灯效果时钟;QTimer m_titleRollTimer;// 标题栏内容;QString m_titleContent;// 按钮类型;ButtonType m_buttonType;
};#endif // BASETITLEBAR_H

 framelesshelper.h

#ifndef FRAMELESSHELPER_H
#define FRAMELESSHELPER_H#include <QtGui>
#include <QRubberBand>
#include <QStylePainter>
#include <QStyleOptionFocusRect>class WidgetData;
/****** FramelessHelperPrivate* 存储界面对应的数据集合,以及是否可移动、可缩放属性
*****/
class FramelessHelperPrivate
{
public:QHash<QWidget*, WidgetData*> m_widgetDataHash;bool m_bWidgetMovable        : true;bool m_bWidgetResizable      : true;bool m_bRubberBandOnResize   : true;bool m_bRubberBandOnMove     : true;
};class FramelessHelper : public QObject
{Q_OBJECTpublic:explicit FramelessHelper(QObject *parent = 0);~FramelessHelper();// 激活窗体void activateOn(QWidget *topLevelWidget);// 移除窗体void removeFrom(QWidget *topLevelWidget);// 设置窗体移动void setWidgetMovable(bool movable);// 设置窗体缩放void setWidgetResizable(bool resizable);// 设置橡皮筋移动void setRubberBandOnMove(bool movable);// 设置橡皮筋缩放void setRubberBandOnResize(bool resizable);// 设置边框的宽度void setBorderWidth(uint width);// 设置标题栏高度void setTitleHeight(uint height);bool widgetResizable();bool widgetMovable();bool rubberBandOnMove();bool rubberBandOnResisze();uint borderWidth();uint titleHeight();protected:// 事件过滤,进行移动、缩放等virtual bool eventFilter(QObject *obj, QEvent *event);private:FramelessHelperPrivate *d;
};class LinuxRubberBand : public QRubberBand
{
public:LinuxRubberBand(Shape s, QWidget * p = 0 ): QRubberBand( s, p ){QPalette palette;palette.setBrush( QPalette::WindowText, QBrush(Qt::lightGray) );setPalette(palette);repaint();}protected:virtual void paintEvent( QPaintEvent * ){QStylePainter painter(this);QStyleOptionFocusRect option;option.initFrom(this);QPen pen;pen.setStyle(Qt::DashLine);pen.setWidth(1);pen.setColor(QColor(Qt::red));painter.setPen(pen);painter.drawControl(QStyle::CE_FocusFrame, option);}};/****** CursorPosCalculator* 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
*****/
class CursorPosCalculator
{
public:explicit CursorPosCalculator();void reset();void recalculate(const QPoint &globalMousePos, const QRect &frameRect);public:bool m_bOnEdges              : true;bool m_bOnLeftEdge           : true;bool m_bOnRightEdge          : true;bool m_bOnTopEdge            : true;bool m_bOnBottomEdge         : true;bool m_bOnTopLeftEdge        : true;bool m_bOnBottomLeftEdge     : true;bool m_bOnTopRightEdge       : true;bool m_bOnBottomRightEdge    : true;static int m_nBorderWidth;static int m_nTitleHeight;
};/****** WidgetData* 更新鼠标样式、移动窗体、缩放窗体
*****/
class WidgetData
{
public:explicit WidgetData(FramelessHelperPrivate *d, QWidget *pTopLevelWidget);~WidgetData();QWidget* widget();// 处理鼠标事件-划过、厉害、按下、释放、移动void handleWidgetEvent(QEvent *event);// 更新橡皮筋状态void updateRubberBandStatus();private:// 更新鼠标样式void updateCursorShape(const QPoint &gMousePos);// 重置窗体大小void resizeWidget(const QPoint &gMousePos);// 移动窗体void moveWidget(const QPoint &gMousePos);// 处理鼠标按下void handleMousePressEvent(QMouseEvent *event);// 处理鼠标释放void handleMouseReleaseEvent(QMouseEvent *event);// 处理鼠标移动void handleMouseMoveEvent(QMouseEvent *event);// 处理鼠标离开void handleLeaveEvent(QEvent *event);// 处理鼠标进入void handleHoverMoveEvent(QHoverEvent *event);private:FramelessHelperPrivate *d;LinuxRubberBand *m_pRubberBand;QWidget *m_pWidget;QPoint m_ptDragPos;CursorPosCalculator m_pressedMousePos;CursorPosCalculator m_moveMousePos;bool m_bLeftButtonPressed;bool m_bCursorShapeChanged;bool m_bLeftButtonTitlePressed;Qt::WindowFlags m_windowFlags;
};#endif // FRAMELESSHELPER_H
2、实现代码

BaseWindow.cpp 

#include "BaseWindow.h"
#include <QDesktopWidget>
#include <QApplication>
#include <QPainter>
#include <QFile>BaseWindow::BaseWindow(QWidget *parent): QWidget(parent)
{// FramelessWindowHint属性设置窗口去除边框;// WindowMinimizeButtonHint 属性设置在窗口最小化时,点击任务栏窗口可以显示出原窗口;this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);// 设置窗口背景透明;setAttribute(Qt::WA_TranslucentBackground);// 初始化标题栏;initTitleBar();
}BaseWindow::~BaseWindow()
{}void BaseWindow::initTitleBar()
{m_titleBar = new BaseTitleBar(this);m_titleBar->move(0, 0);connect(m_titleBar, SIGNAL(signalButtonMinClicked()), this, SLOT(onButtonMinClicked()));connect(m_titleBar, SIGNAL(signalButtonRestoreClicked()), this, SLOT(onButtonRestoreClicked()));connect(m_titleBar, SIGNAL(signalButtonMaxClicked()), this, SLOT(onButtonMaxClicked()));connect(m_titleBar, SIGNAL(signalButtonCloseClicked()), this, SLOT(onButtonCloseClicked()));}void BaseWindow::paintEvent(QPaintEvent* event)
{//设置背景色;QPainter painter(this);QPainterPath pathBack;pathBack.setFillRule(Qt::WindingFill);pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()), 3, 3);painter.setRenderHint(QPainter::SmoothPixmapTransform, true);painter.fillPath(pathBack, QBrush(QColor(127, 127, 127)));return QWidget::paintEvent(event);
}void BaseWindow::loadStyleSheet(const QString &sheetName)
{QFile file(":/Resources/" + sheetName + ".css");file.open(QFile::ReadOnly);if (file.isOpen()){QString styleSheet = this->styleSheet();styleSheet += QLatin1String(file.readAll());this->setStyleSheet(styleSheet);}
}void BaseWindow::onButtonMinClicked()
{if (Qt::Tool == (windowFlags() & Qt::Tool)){hide();    //设置了Qt::Tool 如果调用showMinimized()则窗口就销毁了???}else{showMinimized();}
}void BaseWindow::onButtonRestoreClicked()
{QPoint windowPos;QSize windowSize;m_titleBar->getRestoreInfo(windowPos, windowSize);this->setGeometry(QRect(windowPos, windowSize));
}void BaseWindow::onButtonMaxClicked()
{m_titleBar->saveRestoreInfo(this->pos(), QSize(this->width(), this->height()));QRect desktopRect = QApplication::desktop()->availableGeometry();QRect FactRect = QRect(desktopRect.x() - 3, desktopRect.y() - 3, desktopRect.width() + 6, desktopRect.height() + 6);setGeometry(FactRect);
}void BaseWindow::onButtonCloseClicked()
{close();
}

BaseTitleBar.cpp

#include "BaseTitleBar.h"
#include <QHBoxLayout>
#include <QPainter>
#include <QFile>
#include <QMouseEvent>#define BUTTON_HEIGHT 30		// 按钮高度;
#define BUTTON_WIDTH 30			// 按钮宽度;
#define TITLE_HEIGHT 30			// 标题栏高度;BaseTitleBar::BaseTitleBar(QWidget *parent): QWidget(parent), m_colorR(153), m_colorG(153), m_colorB(153), m_isPressed(false), m_buttonType(MIN_MAX_BUTTON)
{// 初始化;initControl();initConnections();loadStyleSheet("MyTitle");
}BaseTitleBar::~BaseTitleBar()
{}// 初始化控件;
void BaseTitleBar::initControl()
{m_pIcon = new QLabel;m_pTitleContent = new QLabel;m_pButtonMin = new QPushButton;m_pButtonRestore = new QPushButton;m_pButtonMax = new QPushButton;m_pButtonClose = new QPushButton;m_pButtonMin->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));m_pButtonRestore->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));m_pButtonMax->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));m_pButtonClose->setFixedSize(QSize(BUTTON_WIDTH, BUTTON_HEIGHT));m_pTitleContent->setObjectName("TitleContent");m_pButtonMin->setObjectName("ButtonMin");m_pButtonRestore->setObjectName("ButtonRestore");m_pButtonMax->setObjectName("ButtonMax");m_pButtonClose->setObjectName("ButtonClose");QHBoxLayout* mylayout = new QHBoxLayout(this);mylayout->addWidget(m_pIcon);mylayout->addWidget(m_pTitleContent);mylayout->addWidget(m_pButtonMin);mylayout->addWidget(m_pButtonRestore);mylayout->addWidget(m_pButtonMax);mylayout->addWidget(m_pButtonClose);mylayout->setContentsMargins(5, 0, 0, 0);m_pTitleContent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);this->setFixedHeight(TITLE_HEIGHT);this->setWindowFlags(Qt::FramelessWindowHint);
}// 信号槽的绑定;
void BaseTitleBar::initConnections()
{connect(m_pButtonMin, SIGNAL(clicked()), this, SLOT(onButtonMinClicked()));connect(m_pButtonRestore, SIGNAL(clicked()), this, SLOT(onButtonRestoreClicked()));connect(m_pButtonMax, SIGNAL(clicked()), this, SLOT(onButtonMaxClicked()));connect(m_pButtonClose, SIGNAL(clicked()), this, SLOT(onButtonCloseClicked()));
}// 设置标题栏背景色,在paintEvent事件中进行绘制标题栏背景色;
//在构造函数中给了默认值,可以外部设置颜色值改变标题栏背景色;
void BaseTitleBar::setBackgroundColor(int r, int g, int b)
{m_colorR = r;m_colorG = g;m_colorB = b;// 重新绘制(调用paintEvent事件);update();
}// 设置标题栏图标;
void BaseTitleBar::setTitleIcon(QString filePath)
{QPixmap titleIcon(filePath);m_pIcon->setPixmap(titleIcon.scaled(25 , 25));
}// 设置标题内容;
void BaseTitleBar::setTitleContent(QString titleContent)
{m_pTitleContent->setText(titleContent);m_titleContent = titleContent;
}// 设置标题栏长度;
void BaseTitleBar::setTitleWidth(int width)
{this->setFixedWidth(width);
}// 设置标题栏上按钮类型;
// 由于不同窗口标题栏上的按钮都不一样,所以可以自定义标题栏中的按钮;
// 这里提供了四个按钮,分别为最小化、还原、最大化、关闭按钮,如果需要其他按钮可自行添加设置;
void BaseTitleBar::setButtonType(ButtonType buttonType)
{m_buttonType = buttonType;switch (buttonType){case MIN_BUTTON:{m_pButtonRestore->setVisible(false);m_pButtonMax->setVisible(false);}break;case MIN_MAX_BUTTON:{m_pButtonRestore->setVisible(false);}break;case ONLY_CLOSE_BUTTON:{m_pButtonMin->setVisible(false);m_pButtonRestore->setVisible(false);m_pButtonMax->setVisible(false);}break;default:break;}
}// 设置标题栏中的标题是否会自动滚动,跑马灯的效果;
// 一般情况下标题栏中的标题内容是不滚动的,但是既然自定义就看自己需要嘛,想怎么设计就怎么搞O(∩_∩)O!
void BaseTitleBar::setTitleRoll()
{connect(&m_titleRollTimer, SIGNAL(timeout()), this, SLOT(onRollTitle()));m_titleRollTimer.start(200);
}// 保存窗口最大化前窗口的位置以及大小;
void BaseTitleBar::saveRestoreInfo(const QPoint point, const QSize size)
{m_restorePos = point;m_restoreSize = size;
}// 获取窗口最大化前窗口的位置以及大小;
void BaseTitleBar::getRestoreInfo(QPoint& point, QSize& size)
{point = m_restorePos;size = m_restoreSize;
}// 绘制标题栏背景色;
void BaseTitleBar::paintEvent(QPaintEvent *event)
{//设置背景色;QPainter painter(this);QPainterPath pathBack;pathBack.setFillRule(Qt::WindingFill);pathBack.addRoundedRect(QRect(0, 0, this->width(), this->height()), 3, 3);painter.setRenderHint(QPainter::SmoothPixmapTransform, true);painter.fillPath(pathBack, QBrush(QColor(m_colorR, m_colorG, m_colorB)));// 当窗口最大化或者还原后,窗口长度变了,标题栏的长度应当一起改变;if (this->width() != this->parentWidget()->width()){this->setFixedWidth(this->parentWidget()->width());}QWidget::paintEvent(event);
}// 双击响应事件,主要是实现双击标题栏进行最大化和最小化操作;
void BaseTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{// 只有存在最大化、还原按钮时双击才有效;if (m_buttonType == MIN_MAX_BUTTON){// 通过最大化按钮的状态判断当前窗口是处于最大化还是原始大小状态;// 或者通过单独设置变量来表示当前窗口状态;if (m_pButtonMax->isVisible()){onButtonMaxClicked();}else{onButtonRestoreClicked();}}	return QWidget::mouseDoubleClickEvent(event);
}// 以下通过mousePressEvent、mouseMoveEvent、mouseReleaseEvent三个事件实现了鼠标拖动标题栏移动窗口的效果;
void BaseTitleBar::mousePressEvent(QMouseEvent *event)
{return QWidget::mousePressEvent(event);if (m_buttonType == MIN_MAX_BUTTON){// 在窗口最大化时禁止拖动窗口;if (m_pButtonMax->isVisible()){m_isPressed = true;m_startMovePos = event->globalPos();}}else{m_isPressed = true;m_startMovePos = event->globalPos();}//	return QWidget::mousePressEvent(event);
}void BaseTitleBar::mouseMoveEvent(QMouseEvent *event)
{if (m_isPressed){QPoint movePoint = event->globalPos() - m_startMovePos;QPoint widgetPos = this->parentWidget()->pos();m_startMovePos = event->globalPos();this->parentWidget()->move(widgetPos.x() + movePoint.x(), widgetPos.y() + movePoint.y());}return QWidget::mouseMoveEvent(event);
}void BaseTitleBar::mouseReleaseEvent(QMouseEvent *event)
{m_isPressed = false;return QWidget::mouseReleaseEvent(event);
}// 加载本地样式文件;
// 可以将样式直接写在文件中,程序运行时直接加载进来;
void BaseTitleBar::loadStyleSheet(const QString &sheetName)
{QFile file(":/TitleBarRc/" + sheetName + ".css");file.open(QFile::ReadOnly);if (file.isOpen()){QString styleSheet = this->styleSheet();styleSheet += QLatin1String(file.readAll());this->setStyleSheet(styleSheet);}
}// 以下为按钮操作响应的槽;
void BaseTitleBar::onButtonMinClicked()
{emit signalButtonMinClicked();
}void BaseTitleBar::onButtonRestoreClicked()
{m_pButtonRestore->setVisible(false);m_pButtonMax->setVisible(true);emit signalButtonRestoreClicked();
}void BaseTitleBar::onButtonMaxClicked()
{m_pButtonMax->setVisible(false);m_pButtonRestore->setVisible(true);emit signalButtonMaxClicked();
}void BaseTitleBar::onButtonCloseClicked()
{emit signalButtonCloseClicked();
}// 该方法主要是让标题栏中的标题显示为滚动的效果;
void BaseTitleBar::onRollTitle()
{static int nPos = 0;QString titleContent = m_titleContent;// 当截取的位置比字符串长时,从头开始;if (nPos > titleContent.length())nPos = 0;m_pTitleContent->setText(titleContent.mid(nPos));nPos++;
}

 framelesshelper.cpp

#include "framelesshelper.h"int CursorPosCalculator::m_nBorderWidth = 5;
int CursorPosCalculator::m_nTitleHeight = 30;
/***** CursorPosCalculator *****/
CursorPosCalculator::CursorPosCalculator()
{reset();
}void CursorPosCalculator::reset()
{m_bOnEdges = false;m_bOnLeftEdge = false;m_bOnRightEdge = false;m_bOnTopEdge = false;m_bOnBottomEdge = false;m_bOnTopLeftEdge = false;m_bOnBottomLeftEdge = false;m_bOnTopRightEdge  = false;m_bOnBottomRightEdge = false;
}void CursorPosCalculator::recalculate(const QPoint &gMousePos, const QRect &frameRect)
{int globalMouseX = gMousePos.x();int globalMouseY = gMousePos.y();int frameX = frameRect.x();int frameY = frameRect.y();int frameWidth = frameRect.width();int frameHeight = frameRect.height();m_bOnLeftEdge = (globalMouseX >= frameX &&globalMouseX <= frameX + m_nBorderWidth );m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth &&globalMouseX <= frameX + frameWidth);m_bOnTopEdge = (globalMouseY >= frameY &&globalMouseY <= frameY + m_nBorderWidth );m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth &&globalMouseY <= frameY + frameHeight);m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge;m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge;m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge;m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge;m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge;
}/***** WidgetData *****/
WidgetData::WidgetData(FramelessHelperPrivate *_d, QWidget *pTopLevelWidget)
{d = _d;m_pWidget = pTopLevelWidget;m_bLeftButtonPressed = false;m_bCursorShapeChanged = false;m_bLeftButtonTitlePressed = false;m_pRubberBand = NULL;m_windowFlags = m_pWidget->windowFlags();m_pWidget->setMouseTracking(true);m_pWidget->setAttribute(Qt::WA_Hover, true);updateRubberBandStatus();
}WidgetData::~WidgetData()
{m_pWidget->setMouseTracking(false);m_pWidget->setWindowFlags(m_windowFlags);m_pWidget->setAttribute(Qt::WA_Hover, false);delete m_pRubberBand;m_pRubberBand = NULL;
}QWidget* WidgetData::widget()
{return m_pWidget;
}void WidgetData::handleWidgetEvent(QEvent *event)
{switch (event->type()){default:break;case QEvent::MouseButtonPress:handleMousePressEvent(static_cast<QMouseEvent*>(event));break;case QEvent::MouseButtonRelease:handleMouseReleaseEvent(static_cast<QMouseEvent*>(event));break;case QEvent::MouseMove:handleMouseMoveEvent(static_cast<QMouseEvent*>(event));break;case QEvent::Leave:handleLeaveEvent(static_cast<QMouseEvent*>(event));break;case QEvent::HoverMove:handleHoverMoveEvent(static_cast<QHoverEvent*>(event));break;}
}void WidgetData::updateRubberBandStatus()
{if (d->m_bRubberBandOnMove || d->m_bRubberBandOnResize){if (NULL == m_pRubberBand) {m_pRubberBand = new LinuxRubberBand(QRubberBand::Rectangle);}}else{delete m_pRubberBand;m_pRubberBand = NULL;}
}void WidgetData::updateCursorShape(const QPoint &gMousePos)
{if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()){if (m_bCursorShapeChanged){m_pWidget->unsetCursor();}return;}m_moveMousePos.recalculate(gMousePos, m_pWidget->frameGeometry());if(m_moveMousePos.m_bOnTopLeftEdge || m_moveMousePos.m_bOnBottomRightEdge){m_pWidget->setCursor( Qt::SizeFDiagCursor );m_bCursorShapeChanged = true;}else if(m_moveMousePos.m_bOnTopRightEdge || m_moveMousePos.m_bOnBottomLeftEdge){m_pWidget->setCursor( Qt::SizeBDiagCursor );m_bCursorShapeChanged = true;}else if(m_moveMousePos.m_bOnLeftEdge || m_moveMousePos.m_bOnRightEdge){m_pWidget->setCursor( Qt::SizeHorCursor );m_bCursorShapeChanged = true;}else if(m_moveMousePos.m_bOnTopEdge || m_moveMousePos.m_bOnBottomEdge){m_pWidget->setCursor( Qt::SizeVerCursor );m_bCursorShapeChanged = true;}else{if (m_bCursorShapeChanged){m_pWidget->unsetCursor();m_bCursorShapeChanged = false;}}
}void WidgetData::resizeWidget(const QPoint &gMousePos)
{QRect origRect;if (d->m_bRubberBandOnResize)origRect = m_pRubberBand->frameGeometry();elseorigRect = m_pWidget->frameGeometry();int left = origRect.left();int top = origRect.top();int right = origRect.right();int bottom = origRect.bottom();origRect.getCoords(&left, &top, &right, &bottom);//int minWidth = m_pWidget->minimumWidth();//int minHeight = m_pWidget->minimumHeight();int minWidth = 40;int minHeight = 40;if (m_pressedMousePos.m_bOnTopLeftEdge){left = gMousePos.x();top = gMousePos.y();}else if (m_pressedMousePos.m_bOnBottomLeftEdge){left = gMousePos.x();bottom = gMousePos.y();}else if (m_pressedMousePos.m_bOnTopRightEdge){right = gMousePos.x();top = gMousePos.y();}else if (m_pressedMousePos.m_bOnBottomRightEdge){right = gMousePos.x();bottom = gMousePos.y();}else if (m_pressedMousePos.m_bOnLeftEdge){left = gMousePos.x();}else if (m_pressedMousePos.m_bOnRightEdge){right = gMousePos.x();}else if (m_pressedMousePos.m_bOnTopEdge){top = gMousePos.y();}else if (m_pressedMousePos.m_bOnBottomEdge){bottom = gMousePos.y();}QRect newRect(QPoint(left, top), QPoint(right, bottom));if (newRect.isValid()){if (minWidth > newRect.width()){if (left != origRect.left())newRect.setLeft(origRect.left());elsenewRect.setRight(origRect.right());}if (minHeight > newRect.height()){if (top != origRect.top())newRect.setTop(origRect.top());elsenewRect.setBottom(origRect.bottom());}if (d->m_bRubberBandOnResize){m_pRubberBand->setGeometry(newRect);}else{m_pWidget->setGeometry(newRect);}}
}void WidgetData::moveWidget(const QPoint& gMousePos)
{if (d->m_bRubberBandOnMove){m_pRubberBand->move(gMousePos - m_ptDragPos);}else{m_pWidget->move(gMousePos - m_ptDragPos);}
}void WidgetData::handleMousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){m_bLeftButtonPressed = true;m_bLeftButtonTitlePressed = event->pos().y() < m_moveMousePos.m_nTitleHeight;QRect frameRect = m_pWidget->frameGeometry();QRect moveRect(frameRect.x(), frameRect.y(), frameRect.width(), 30);m_pressedMousePos.recalculate(event->globalPos(), frameRect);m_ptDragPos = event->globalPos() - frameRect.topLeft();if (m_pressedMousePos.m_bOnEdges){if (d->m_bRubberBandOnResize){m_pRubberBand->setGeometry(frameRect);m_pRubberBand->show();}}else if (d->m_bRubberBandOnMove){if (moveRect.contains(event->globalPos())) {m_pRubberBand->setGeometry(frameRect);m_pRubberBand->show();}}}
}void WidgetData::handleMouseReleaseEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){m_bLeftButtonPressed = false;m_bLeftButtonTitlePressed = false;m_pressedMousePos.reset();if (m_pRubberBand && m_pRubberBand->isVisible()){m_pRubberBand->hide();m_pWidget->setGeometry(m_pRubberBand->geometry());}}
}void WidgetData::handleMouseMoveEvent(QMouseEvent *event)
{if (m_bLeftButtonPressed){if (d->m_bWidgetResizable && m_pressedMousePos.m_bOnEdges){resizeWidget(event->globalPos());}else if (d->m_bWidgetMovable && m_bLeftButtonTitlePressed){moveWidget(event->globalPos());}}else if (d->m_bWidgetResizable){updateCursorShape(event->globalPos());}
}void WidgetData::handleLeaveEvent(QEvent *event)
{Q_UNUSED(event)if (!m_bLeftButtonPressed){m_pWidget->unsetCursor();}
}void WidgetData::handleHoverMoveEvent(QHoverEvent *event)
{if (d->m_bWidgetResizable){updateCursorShape(m_pWidget->mapToGlobal(event->pos()));}
}/*****FramelessHelper*****/
FramelessHelper::FramelessHelper(QObject *parent): QObject(parent),d(new FramelessHelperPrivate())
{d->m_bWidgetMovable = true;d->m_bWidgetResizable = true;d->m_bRubberBandOnResize = false;d->m_bRubberBandOnMove = false;
}FramelessHelper::~FramelessHelper()
{QList<QWidget*> keys = d->m_widgetDataHash.keys();int size = keys.size();for (int i = 0; i < size; ++i) {delete d->m_widgetDataHash.take(keys[i]);}delete d;
}bool FramelessHelper::eventFilter(QObject *obj, QEvent *event)
{switch (event->type()){case QEvent::MouseMove:case QEvent::HoverMove:case QEvent::MouseButtonPress:case QEvent::MouseButtonRelease:case QEvent::Leave:{WidgetData *data = d->m_widgetDataHash.value(static_cast<QWidget*>(obj));if (data){data->handleWidgetEvent(event);return true;}}}return QObject::eventFilter(obj, event);
}void FramelessHelper::activateOn(QWidget *topLevelWidget)
{if (!d->m_widgetDataHash.contains(topLevelWidget)){WidgetData *data = new WidgetData(d, topLevelWidget);d->m_widgetDataHash.insert(topLevelWidget, data);topLevelWidget->installEventFilter(this);}
}void FramelessHelper::removeFrom(QWidget *topLevelWidget)
{WidgetData *data = d->m_widgetDataHash.take(topLevelWidget);if (data){topLevelWidget->removeEventFilter(this);delete data;}
}void FramelessHelper::setRubberBandOnMove(bool movable)
{d->m_bRubberBandOnMove = movable;QList<WidgetData*> list = d->m_widgetDataHash.values();foreach (WidgetData *data, list){data->updateRubberBandStatus();}
}void FramelessHelper::setWidgetMovable(bool movable)
{d->m_bWidgetMovable = movable;
}void FramelessHelper::setWidgetResizable(bool resizable)
{d->m_bWidgetResizable = resizable;
}void FramelessHelper::setRubberBandOnResize(bool resizable)
{d->m_bRubberBandOnResize = resizable;QList<WidgetData*> list = d->m_widgetDataHash.values();foreach (WidgetData *data, list){data->updateRubberBandStatus();}
}void FramelessHelper::setBorderWidth(uint width)
{if (width > 0){CursorPosCalculator::m_nBorderWidth = width;}
}void FramelessHelper::setTitleHeight(uint height)
{if (height > 0){CursorPosCalculator::m_nTitleHeight = height;}
}bool FramelessHelper::widgetMovable()
{return d->m_bWidgetMovable;
}bool FramelessHelper::widgetResizable()
{return d->m_bWidgetResizable;
}bool FramelessHelper::rubberBandOnMove()
{return d->m_bRubberBandOnMove;
}bool FramelessHelper::rubberBandOnResisze()
{return d->m_bRubberBandOnResize;
}uint FramelessHelper::borderWidth()
{return CursorPosCalculator::m_nBorderWidth;
}uint FramelessHelper::titleHeight()
{return CursorPosCalculator::m_nTitleHeight;
}

        通过以上代码,我们可以实现一个具有自定义标题栏、窗口大小调整和可移动、可缩放属性的无边框窗口。这段代码提供了一种简单而有效的方法来实现自定义外观和交互方式的无边框窗口。可以根据自己的需求进行修改和定制,以满足不同应用程序的需要。

五、使用示例

以下是一个简单的示例代码,演示了如何在Qt中使用此控件:

CustomMainWindow.h
#ifndef CUSTOMMAINWINDOW_H
#define CUSTOMMAINWINDOW_H#include <QWidget>#include "BaseWindow.h"
#include "framelesshelper.h"namespace Ui {
class CustomMainWindow;
}class CustomMainWindow : public BaseWindow
{Q_OBJECTpublic:explicit CustomMainWindow(QWidget *parent = 0);~CustomMainWindow();private:void initTitleBar();void framelesshelperInit();Ui::CustomMainWindow *ui;
};#endif // CUSTOMMAINWINDOW_H
CustomMainWindow.cpp
#include "CustomMainWindow.h"
#include "ui_CustomMainWindow.h"CustomMainWindow::CustomMainWindow(QWidget *parent) :BaseWindow(parent),ui(new Ui::CustomMainWindow)
{initTitleBar();framelesshelperInit();ui->setupUi(this);
}CustomMainWindow::~CustomMainWindow()
{delete ui;
}void CustomMainWindow::initTitleBar()
{m_titleBar->setBackgroundColor(71,76,78);m_titleBar->setTitleIcon(":/TitleBarRc/icon.png");m_titleBar->setTitleContent(QStringLiteral("这是一个可以滚动的标题!"));m_titleBar->setTitleRoll();m_titleBar->setButtonType(MIN_MAX_BUTTON);m_titleBar->setTitleWidth(this->width());
}void CustomMainWindow::framelesshelperInit()
{//this指的是要处理的窗体FramelessHelper *pHelper = new FramelessHelper(this);pHelper->activateOn(this);  //激活当前窗体pHelper->setWidgetMovable(true);  //设置窗体可移动pHelper->setWidgetResizable(true);  //设置窗体可缩放pHelper->setRubberBandOnMove(false);  //设置橡皮筋效果-可移动pHelper->setRubberBandOnResize(true);  //设置橡皮筋效果-可缩放
}

        现在,我们可以编译和运行该项目。当窗口显示出来时,您将会看到一个自定义的无边框窗口,包含自定义的标题栏和窗口大小调整按钮。您可以尝试拖动标题栏或点击窗口大小调整按钮来调整窗口的大小和位置。需要注意的是,使用自定义标题栏时需留够空间,不要被窗口内控件遮挡。

        通过以上步骤,我们成功地实现了在QT中创建自定义无边框窗口的目标,包括自定义标题栏和窗口大小调整功能。这使得我们可以根据自己的需要创建独特和个性化的窗口界面。

        谢谢您的阅读,希望本文能为您带来一些帮助和启发。如果您有任何问题或意见,请随时与我联系。祝您度过美好的一天!

六、源代码下载

相关文章:

QT自定义无边框窗口(可移动控制和窗口大小调整)

QT是一个功能强大的跨平台开发框架&#xff0c;它提供了丰富的界面设计工具和组件。在界面开发中&#xff0c;QT窗口自带的标题栏无法满足我们的需求。我们就需要自定义无边框窗口&#xff0c;包括自定义标题栏和窗口大小调整功能。本文将介绍如何在QT中实现这些功能。 一、简…...

Typora 【最新1.8.6】版本安装下载教程 (轻量级 Markdown 编辑器),图文步骤详解,免费领取(软件可激活使用)

文章目录 软件介绍软件下载安装步骤激活步骤 软件介绍 Typora 是一款专为 Markdown 爱好者设计的文本编辑器&#xff0c;它结合了简洁的界面设计与强大的 Markdown 渲染能力&#xff0c;为用户提供了一个流畅、高效的写作环境。以下是对 Typora 更详细的介绍&#xff1a; 核心特…...

RxJava 面试题及其答案

以下是一个全面的 RxJava 面试题及其答案&#xff0c;涵盖了 RxJava 的各个方面&#xff0c;包括基本概念、操作符、线程管理、错误处理、背压处理等&#xff1a; 基本概念 1. RxJava 的基本概念和原理是什么&#xff1f; 答案&#xff1a; RxJava 是一个用于响应式编程的库…...

【Rust】所有权OwnerShip

什么是所有权 rust使用由编译器检查的一些规则构成的所有权系统来管理内存。且这不会影响程序的运行效率。 所有权规则 rust中每一个每一个值都有一个owner。在同一时刻&#xff0c;只能有一个owner。当这个owner超过范围&#xff0c;则该值会被丢弃。 String类型 为什么需…...

qt总结--翻金币案例

完成了一个小项目的在qt5.15.2环境下的运行,并使用NSIS editNSIS打包完成.有待改进之处:增加计时功能,随机且能通关功能,过关后选择下一关功能.打包后仅仅有安装包有图标 安装后应用图标并未改变 在qt .pro中有待改进对qt的基本操作和帮助文档有了基本的认识.对C制作小游戏有了…...

最清楚的 BIO、NIO、AIO 详解!

一、什么是 I/O&#xff1f; I/O 描述了计算机系统与外部设备&#xff08;磁盘&#xff09;之间通信的过程。 为了保证操作系统的稳定性和安全性&#xff0c;一个进程的地址空间划分为 用户空间&#xff08;User space&#xff09; 和 内核空间&#xff08;Kernel space &…...

八股文学习第二天| HTTP请求报文和响应报文是怎样的,有哪些常见的字段?,HTTP有哪些请求方式?,GET请求和POST请求的区别?

1、HTTP请求报文和响应报文是怎样的&#xff0c;有哪些常见的字段&#xff1f; 答&#xff1a; HTTP报文分为请求报文和响应报文。 &#xff08;1&#xff09; 请求报文 请求报文主要由请求行、请求头、空行、请求体构成。 请求行包括如下字段&#xff1a; 方法&#xff08…...

C++初阶学习第四弹——类与对象(中)

目录 一. 类的默认成员函数 二.六种默认成员函数 1、构造函数 1.1 构造函数的作用 1.2 特性 1.3 默认构造函数 2、析构函数 2.1 析构函数的作用 2.2 析构函数的用法 3、拷贝构造函数 3.1 拷贝构造函数的作用 3.2 特征 3.3 默认拷贝构造函数 三.总结 类与对象&…...

【计算机网络】期末实验答辩

注意事项&#xff1a; 1&#xff09;每位同学要在下面做过的实验列表中选取三个实验进行答辩准备&#xff0c;并将自己的姓名&#xff0c;学号以及三个实验序号填入共享文档"1&#xff08;2&#xff09;班答辩名单"中。 2&#xff09;在答辩当日每位同学由老师在表…...

一步步教你学会如何安装VMare虚拟机(流程参考图)

前言&#xff1a;一步步教你安装VMare虚拟机&#xff08;此版本为17.5。2版本&#xff09;。 1、安装 2、确认协议 3、选择位置存放 4、选择第二个 5、都不选。 6、都选提供便捷操作 7、点击许可证&#xff0c;将密钥输入&#xff08;可以在网络寻找自己版本的密钥&#xff…...

WebGoC题解(14) 151.(2017dloi小乙)第5题 巧克力甜度(sweet)

题目描述 妈妈买了n颗甜度不同的巧克力&#xff0c;规定小C只能吃最大甜度之和是S。 例如&#xff1a;有5颗巧克力&#xff0c;s6&#xff0c;每个的甜度分别为&#xff1a; 4 2 3 1 1&#xff0c;那么小C最多可以吃3颗。 请问你能帮小C计算一下最多能吃多少颗巧克力吗? 输入格…...

深入探索PHP框架:Symfony框架全面解析

1. 引言 在现代Web开发领域&#xff0c;PHP作为一种广泛使用的服务器端脚本语言&#xff0c;其框架的选择对于项目的成功至关重要。PHP框架不仅能够提高开发效率&#xff0c;还能确保代码的质量和可维护性。本文将深入探讨Symfony框架&#xff0c;这是一个功能强大且灵活的PHP…...

内卷的利与弊

“内卷”原指一类文化模式达到了某种最终的形态以后&#xff0c;既没有办法稳定下来&#xff0c;也没有办法转变为新的形态&#xff0c;而只能不断地在内部变得更加复杂的现象。经网络流传&#xff0c;很多大学生用其来指代非理性的内部竞争或“被自愿”竞争。现指同行间竞相付…...

用Java手写jvm之实现查找class

写在前面 完成类加载器加载class的三阶段&#xff0c;加载&#xff0c;解析&#xff0c;初始化中的加载&#x1f600;&#x1f600;&#x1f600; 源码 。 jvm想要运行class&#xff0c;是根据类全限定名称来从特定的位置基于类加载器来查找的&#xff0c;分别如下&#xff1a;…...

【React】组件:全面解析现代前端开发的基石

文章目录 一、什么是组件&#xff1f;二、组件的类型三、组件的生命周期四、状态管理五、属性传递六、组合与继承七、最佳实践 在现代前端开发中&#xff0c;React 已成为开发者构建用户界面的首选框架之一。React 的强大之处在于其组件化设计&#xff0c;允许开发者将 UI 拆分…...

java学习--包装类

包装类 Boolean的关系图 Character关系图 其他关系图 包装类和基本数据转换 Debug进入之后可以看到底层代码如下 例题&#xff1a; 三元运算符是一个整体返回的数的类型看其中所含类型最高的那个是谁就会转成哪个 想要掌握这个这个知识&#xff0c;就要多看源码&#xff0c;直接…...

Python Django功能强大的扩展库之channels使用详解

概要 随着实时 web 应用程序的兴起,传统的同步 web 框架已经无法满足高并发和实时通信的需求。Django Channels 是 Django 的一个扩展,旨在将 Django 从一个同步 HTTP 框架转变为一个支持 WebSockets、HTTP2 和其他协议的异步框架。它不仅能够处理传统的 HTTP 请求,还可以处…...

推荐3款将相片变为动漫风格的免费AI工具推荐

toonme ToonMe是一款功能强大的在线和移动端应用&#xff0c;专门用于将照片转换成卡通风格图像。该工具利用先进的AI技术&#xff0c;能够快速识别照片中的面部特征&#xff0c;并进行智能处理&#xff0c;生成高清晰度的卡通肖像。 功能特点 ToonMe通过其内置的人工智能算法…...

【职业学习】高效工作法

文章目录 01 时间拳击02 非同步沟通03 批量处理04. 80/20法则05. 一次只做一件事 01 时间拳击 时间拳击&#xff08;Time Boxing&#xff09;核心是给每项任务创造一个时间限制&#xff0c;然后在固定的时间段内专注地完成这个任务。 不同于传统的待办事项清单&#xff1a;8点…...

【iOS】Tagged Pointer

目录 前言什么是Tagged Pointer&#xff1f;引入Tagged Pointer技术之前引入Tagged Pointer之后总结 Tagged Pointer原理&#xff08;TagData分析&#xff09;关闭数据混淆MacOS分析NSNumberNSString iOS分析 判断Tagged PointerTagged Pointer应用Tagged Pointer 注意点 Tagge…...

Mysql explain 优化解析

explain 解释 select_type 效率对比 MySQL 中 EXPLAIN 语句的 select_type 列描述了查询的类型,不同的 select_type 类型在效率上会有所差异。下面我们来比较一下各种 select_type 的效率: SIMPLE: 这是最简单的查询类型,表示查询不包含子查询或 UNION 操作。 这种查询通常是…...

wget下载github文件得到html文件

从github/gitee下载源文件&#xff0c;本来是22M下载下来只有11k 原因&#xff1a; Github会提供html页面&#xff0c;包括指定的文件、上下文与相关操作。通过wget或者curl下载时&#xff0c;会下载该页面 解决方式&#xff1a; github点击Code一栏的raw按钮&#xff0c;获得源…...

【es】elasticsearch 自定义排序-按关键字位置排序

一 背景 要求es查询的结果按关键字位置排序&#xff0c;位置越靠前优先级越高。 es版本7.14.0&#xff0c;项目是thrift&#xff0c;也可以平替springboot&#xff0c;使用easyes连接es。 二 easyes使用 配easyes按官方文档就差不多了 排序 | Easy-Es 主要的一个问题是easy…...

堆的相关知识点

目录 大小堆 堆的实现 堆的创建 堆的销毁 交换 向上调整 向下调整 弹出首个元素 取出首个元素 判空 堆插入 大小堆 大堆&#xff1a;最上面的数字是最小的&#xff0c;越往下越大 小堆&#xff1a;最上面的数字是最大的&#xff0c;越往下越小 堆的复杂程度&#…...

【Sass】常用全局sass高级函数,可使用原子化CSS减轻代码量,方便快速开发

文章目录 前言一、安装二、样式custom.scssflex.scsscolor.scssmargin-padding.scssorther 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 针对style的预编译器为scss 转载自git前端知识库 原博主是B站up程序员郑清&#xff0c;可以看他的v3教程…...

MYSQL 第四次作业

任务要求&#xff1a; 具体操作&#xff1a; 新建数据库&#xff1a; mysql> CREATE DATABASE mydb15_indexstu; Query OK, 1 row affected (0.01 sec) mysql> USE mydb15_indexstu; Database changed 新建表&#xff1a; mysql> CREATE TABLE student( ->…...

depcheck 前端依赖检查

介绍 depcheck 是一款用于检测项目中 未使用依赖项 的工具。 depcheck 通过扫描项目文件&#xff0c;帮助你找出未被引用的依赖&#xff0c;从而优化项目。 优势&#xff1a; 简单易用: 仅需几个简单的命令&#xff0c;就能够扫描并列出未使用的依赖项&#xff0c;让你快速了…...

Qt/C++音视频开发79-采集websocket视频流/打开ws开头的地址/音视频同步/保存到MP4文件/视频回放

一、前言 随着音视频的爆发式的增长,各种推拉流应用场景应运而生,基本上都要求各个端都能查看实时视频流,比如PC端、手机端、网页端,在网页端用websocket来接收并解码实时视频流显示,是一个非常常规的场景,单纯的http-flv模式受限于最大6个通道同时显示,一般会选择ws-f…...

网络安全等级保护制度1.0与2.0的演进与变革

等保1.0概述 等保1.0是我国在网络安全领域迈出的重要一步&#xff0c;它于2008年正式发布。该版本的等保制度以《信息安全技术 信息系统安全等级保护基本要求》为核心标准&#xff0c;主要聚焦于信息系统的物理安全、网络安全、主机安全、应用安全和数据安全等方面的基础防护。…...

多线程优化API请求:CountDownLatch与PriorityBlockingQueue的应用

目录 前言 CountDownLatch是什么&#xff1f; PriorityBlockingQueue是什么&#xff1f; 场景描述 解决方案 定义统一工厂制造类 定义制造厂 定义客户请求实现 定义控制器 定义启动类 结果呈现 启动项目 请求制造操作 总结 前言 写这篇文章的缘由是因为之前在面…...

谷粒商城实战笔记-54-商品服务-API-三级分类-拖拽效果

文章目录 一&#xff0c;54-商品服务-API-三级分类-修改-拖拽效果1&#xff0c;el-tree控件加上允许拖拽的属性2&#xff0c;是否允许拖拽3&#xff0c;完整代码 一&#xff0c;54-商品服务-API-三级分类-修改-拖拽效果 本节的主要内容是给三级分类树形结构加上拖拽功能&#…...

AI大模型学习必备十大网站

随着人工智能技术的快速发展&#xff0c;AI大模型&#xff08;如GPT-3、BERT等&#xff09;在自然语言处理、计算机视觉等领域取得了显著的成果。对于希望深入学习AI大模型的开发者和研究者来说&#xff0c;找到合适的学习资源至关重要。本文将为大家推荐十大必备网站&#xff…...

Elasticsearch:Golang ECS 日志记录 - zap

ECS 记录器是你最喜欢的日志库的格式化程序/编码器插件。它们可让你轻松地将日志格式化为与 ECS 兼容的 JSON。 编码器以 JSON 格式记录日志&#xff0c;并在可能的情况下依赖默认的 zapcore/json_encoder。它还处理 ECS 错误格式的错误字段记录。 默认情况下&#xff0c;会添…...

关于线性代数(考研)

1.AE的特征值的问题 若λ是A的特征值&#xff0c;对应的特征向量是x&#xff0c;则Axλx&#xff0c;所以(AE)xAxExλxx(λ1)x&#xff0c;所以λ1是AE的特征值。所以若A的特征值是1&#xff0c;1&#xff0c;0&#xff0c;则AE的特征值就是11&#xff0c;11&#xff0c;01&am…...

【java基础】spring springMVC springboot 的区别

Spring, Spring MVC, 和 Spring Boot 是三个紧密相关的技术&#xff0c;它们都是由 Pivotal 团队&#xff08;原SpringSource&#xff09;开发的&#xff0c;主要用于构建企业级的Java应用程序。尽管它们在功能上有所交集&#xff0c;但各自也有独特的定位和用途。 Spring Fra…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 开源项目热度排行榜(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 93 分 最新华为OD机试目录…...

大模型算法面试题(十一)

本系列收纳各种大模型面试题及答案。 1、说一下目前主流或前沿的预训练模型&#xff0c;包括nlp&#xff08;百度ERNIE3.0&#xff0c;华为NEZHA&#xff0c;openAI gpt-3&#xff0c;nvidia MegatronLM&#xff0c;macrosoft T5&#xff09;和cv&#xff08;我只知道CLIP&…...

CSS 基础知识

CSS(级联样式表)是设置 Web 内容样式的代码。CSS 基础知识将介绍入门所需的内容。我们将回答以下问题:如何将文本设置为红色?如何使内容显示在(网页)布局中的某个位置?如何用背景图片和颜色装饰我的网页? 什么是CSS? 像HTML一样,CSS不是一种编程语言。它也不是一种标…...

IntelliJ IDEA 和 Eclipse的区别

IntelliJ IDEA 和 Eclipse 是两个非常流行的 Java 集成开发环境&#xff08;IDE&#xff09;&#xff0c;它们各自具有不同的特点和优势。下面是它们之间的一些主要对比&#xff1a; 性能和资源使用 IntelliJ IDEA 被认为在某些方面更加智能&#xff0c;能够提供更好的代码分…...

Ansible之playbook剧本编写(二)

tags 模块 可以在一个playbook中为某个或某些任务定义“标签”&#xff0c;在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。 playbook还提供了一个特殊的tags为always。作用就是当使用always作为tags的task时&#xff0c;无论执行哪一个t…...

力扣第二十九题——两数相除

内容介绍 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#xff0c;-…...

解析三款热门的文献翻译工具:优势与使用指南

今儿咱们来聊聊那些让咱们头疼又不得不面对的事儿——文献翻译。在浩瀚的学术海洋里遨游时&#xff0c;遇到外文文献那是家常便饭&#xff0c;但语言障碍就像海上的迷雾&#xff0c;一不小心就能让你偏离航向。别担心&#xff0c;我这不就带着几款亲测好用的文献翻译神器来了嘛…...

git 过滤LFS文件下载

git config --global filter.lfs.smudge "git-lfs smudge --skip -- %f" git config --global filter.lfs.process "git-lfs filter-process --skip" 恢复下载 git config --global filter.lfs.smudge "git-lfs smudge -- %f" git config --g…...

内存泄漏详解

文章目录 什么是内存泄漏内存泄漏的原因排查及解决内存泄漏避免内存泄漏及时释放资源设置合理的变量作用域及时清理不需要的对象避免无限增长避免内部类持有外部类引用使用弱引用 什么是内存泄漏 内存泄漏是指不使用的对象持续占有内存使得内存得不到释放&#xff0c;从而造成…...

多角度解析高防CDN防御DDOS及CC攻击

网络攻击的形式也日益多样化&#xff0c;其中DDoS&#xff08;分布式拒绝服务&#xff09;和CC&#xff08;Challenge Collapsar&#xff09;攻击尤为突出&#xff0c;给网站和企业带来了巨大的安全威胁。高防CDN&#xff08;Content Delivery Network&#xff09;作为一种专业…...

(7) cmake 编译C++程序(二)

文章目录 概要整体代码结构整体代码小结 概要 在ubuntu下&#xff0c;通过cmake编译一个稍微复杂的管理程序 整体代码结构 整体代码 boss.cpp #include "boss.h"Boss::Boss(int id, string name, int dId) {this->Id id;this->Name name;this->DeptId …...

C语言系统调用linux文件系统

在C语言中&#xff0c;open、write和read函数是系统调用&#xff08;system calls&#xff09;&#xff0c;它们直接由操作系统提供&#xff0c;用于底层的文件操作。这些函数是UNIX和类UNIX系统&#xff08;如Linux&#xff09;中的标准接口&#xff0c;不同于C标准库中的文件…...

LeetCode142 环形链表 II

前言 题目&#xff1a; 142. 环形链表 II 文档&#xff1a; 代码随想录——环形链表 II 编程语言&#xff1a; C 解题状态&#xff1a; 思路错误&#xff0c;链表不允许被修改 思路 两步走&#xff0c;第一步&#xff0c;判断有没有环&#xff0c;第二步&#xff0c;判断入环口…...

逆向案例二十八——某高考志愿网异步请求头参数加密,以及webpack

网址&#xff1a;aHR0cDovL3d3dy54aW5nYW9rYW90Yi5jb20vY29sbGVnZXMvc2VhcmNo 抓包分析&#xff0c;发现请求头有参数u-sign是加密的&#xff0c;载荷没有进行加密&#xff0c;直接跟栈分析。 进入第二个栈&#xff0c;打上断点&#xff0c;分析有没有加密位置。 可以看到参数…...

WebKit的文本装饰艺术:CSS Text Decoration全解析

WebKit的文本装饰艺术&#xff1a;CSS Text Decoration全解析 CSS文本装饰&#xff08;Text Decoration&#xff09;是一组用于美化和增强网页文本表现的属性&#xff0c;它们可以为文本添加下划线、上划线、线删除和强调标记等效果。WebKit作为许多现代浏览器的渲染引擎&…...