Qt,C++开发炫酷圆形扇形菜单面板
一如既往,先上图
动画效果参考下面的是视频
20220316-182247
摘要描述:
1、支持嵌入面板和弹出按钮两种,目前仅完成嵌入面板,后期会实现弹出实现
2、支持非常多的自定义功能,有关自定义功能定义参考下面的风格数据结构体代码,结构体中的功能均支持自定义
风格数据结构体代码如下:
/// 圆形菜单控件风格样式数据结构///typedef struct LNCFROUNDMENU_STYLE_{QList<DGRADIENTCOLOR_DATA> vMenuCtlBkgClr; //菜单渐变背景颜色集合列表QColor cMenuCtlBkgClr = QColor(88,88,88,44); //菜单控件背景颜色QColor cMenuBtnBkgClr = QColor(77,77,77,44); //菜单按钮默认背景色QColor cMenuBtnHovers = QColor(192,192,192,144);//菜单按钮悬停背景色QColor cMenuBtnTxtClr = QColor(202,202,202); //菜单按钮文字颜色QColor cMenuTextHover = QColor(255,255,255); //菜单按钮文字悬停颜色QColor cSwicthBnColor = QColor(144,133,227); //切换按钮默认颜色QColor cSwicthExpands = QColor(250,142,85); //切换按钮菜单展开时背景颜色QColor cSwicthBnHover = QColor(250,85,101); //切换按钮鼠标悬停颜色QColor cBkgBorderClrs = QColor(11,11,21,99); //背景边框颜色QColor cItemBorderClr = QColor(11,11,21,99); //菜单项边框颜色qreal dFrameOutScale = 0.75; //菜单外边框距离窗口边界比例qreal dFrameInnScale = 0.40; //菜单内边框距离窗口边界比例qreal dCenterBnScale = 1.5; //菜单中心按钮大小比例,相对于菜单窗口大小的缩小比例qreal dItemsBtnScale = 2.0; //菜单按钮图标大小比例,相对于菜单按钮扇形区域大小缩放比例qreal dItemsBkgScale = 1.25; //菜单按钮圆形背景大小比例,相对于菜单按钮扇形区域大小缩放比例qreal dItemBorderWid = 1; //菜单按钮边框宽度qreal dBnRoundRadius = 0.5; //菜单按钮圆角比例,0-0.5之间qreal dBkgBordersWid = 1; //菜单背景宽度qreal dStartDrawAngle = 180.0; //起始绘制角度uint uCenterBtnSize = 64; //菜单中心按钮绝对大小尺寸uint uAnimatedTimer = 400; //菜单展开和关闭动画周期时长bool bShowCtrlBkgnd = false; //是否显示控件背景bool bShowItemsLine = false; //是否绘制分割线bool bRoundMenuItem = true; //是否绘制圆形菜单项,默认是,否则显示扇形bool bDrawCenterBtn = true; //绘制中心按钮bool bMenuBtnsScale = true; //中心按钮大小比例类型,true表示绝对比例,false绝对大小bool bHasRandomClrs = false; //是否使用随机按钮背景颜色bool bRotateAnimate = true; //是否启用旋转动画,如果使用旋转动画至少将菜单展开和关闭周期设置到400或以上bool bShowBkgBorder = false; //是否显示背景边框bool bHasItemBorder = false; //是否显示菜单按钮边框bool bNoIcoFullName = true; //无图标按钮是否显示菜单全名bool operator == (const LNCFROUNDMENU_STYLE_& rhs) // == 操作运算符重载{if(vMenuCtlBkgClr.count()!= rhs.vMenuCtlBkgClr.count())return false;if(vMenuCtlBkgClr.count()== rhs.vMenuCtlBkgClr.count()&&rhs.vMenuCtlBkgClr.count()>0){for(int i=0;i<rhs.vMenuCtlBkgClr.count();i++){if(QString("%1").arg(vMenuCtlBkgClr[i].fBkgndAngleVal) !=QString("%1").arg(rhs.vMenuCtlBkgClr[i].fBkgndAngleVal))return false;if(vMenuCtlBkgClr[i].cBkgndAngleClr != rhs.vMenuCtlBkgClr[i].cBkgndAngleClr)return false;}}return (cMenuCtlBkgClr == rhs.cMenuCtlBkgClr)&& (cMenuBtnBkgClr == rhs.cMenuBtnBkgClr)&& (cMenuBtnHovers == rhs.cMenuBtnHovers)&& (cMenuBtnTxtClr == rhs.cMenuBtnTxtClr)&& (bHasRandomClrs == rhs.bHasRandomClrs)&& (cMenuTextHover == rhs.cMenuTextHover)&& (cSwicthBnColor == rhs.cSwicthBnColor)&& (cSwicthExpands == rhs.cSwicthExpands)&& (cSwicthBnHover == rhs.cSwicthBnHover)&& (QString("%1").arg(dFrameOutScale) == QString("%1").arg(rhs.dFrameOutScale))&& (QString("%1").arg(dFrameInnScale) == QString("%1").arg(rhs.dFrameInnScale))&& (QString("%1").arg(dCenterBnScale) == QString("%1").arg(rhs.dCenterBnScale))&& (QString("%1").arg(dItemsBtnScale) == QString("%1").arg(rhs.dItemsBtnScale))&& (QString("%1").arg(dItemsBkgScale) == QString("%1").arg(rhs.dItemsBkgScale))&& (QString("%1").arg(dStartDrawAngle) == QString("%1").arg(rhs.dStartDrawAngle))&& (uCenterBtnSize == rhs.uCenterBtnSize)&& (uAnimatedTimer == rhs.uAnimatedTimer)&& (bShowCtrlBkgnd == rhs.bShowCtrlBkgnd)&& (bShowItemsLine == rhs.bShowItemsLine)&& (bRoundMenuItem == rhs.bRoundMenuItem)&& (bDrawCenterBtn == rhs.bDrawCenterBtn)&& (bMenuBtnsScale == rhs.bMenuBtnsScale)&& (bHasRandomClrs == rhs.bHasRandomClrs)&& (bRotateAnimate == rhs.bRotateAnimate)&& (cBkgBorderClrs == rhs.cBkgBorderClrs)&& (bShowBkgBorder == rhs.bShowBkgBorder)&& (cItemBorderClr == rhs.cItemBorderClr)&& (QString("%1").arg(dItemBorderWid) == QString("%1").arg(rhs.dItemBorderWid))&& (bHasItemBorder == rhs.bHasItemBorder)&& (dBnRoundRadius == rhs.dBnRoundRadius)&& (QString("%1").arg(dBkgBordersWid) == QString("%1").arg(rhs.dBkgBordersWid))&& (bNoIcoFullName == rhs.bNoIcoFullName); //无图标按钮是否显示菜单全名}bool operator != (const LNCFROUNDMENU_STYLE_& rhs) // != 操作运算符重载{return !(*this == rhs);}}LNCFROUNDMENU_STYLE,*PLNCFROUNDMENU_STYLE;
除了风格自定义还支持自定义图标等功能,参考下面的变量
///菜单展开图标路径std::u16string sExpandImgPath;///菜单闭合图标路径std::u16string sClosedImgPath;
头文件主要代码
//默认构造函数explicit Lncf_QRoundMenuCtl(QWidget *parent = nullptr);/// 标准构造函数/// \brief Lncf_QRoundMenuCtl/// \param bPopup :是否为popup模式/// \param uBtnSize :中心按钮尺寸/// \param uItemType :菜单项类型,0圆角矩形,1扇形/// \param parent :父窗口句柄///explicit Lncf_QRoundMenuCtl(bool bPopup,uint uBtnSize,uint uItemType = 0,QWidget *parent = nullptr);//标准析构~Lncf_QRoundMenuCtl();private:/// 初始化圆形菜单控件/// \brief InitRoundMenuCtl///void InitRoundMenuCtl();protected:// 重写系统事件bool event(QEvent *ev) override;// 重写系统绘制事件void paintEvent(QPaintEvent *event) override;/// 绘制控件圆形背景/// \brief DrawBackgroundCtl/// \param painter///void DrawBackgroundCtl(QPainter *painter);/// 绘制菜单项圆形外边框/// \brief DrawItemOutBorder/// \param painter///void DrawItemOutBorder(QPainter *painter);/// 绘制菜单项圆形内边框/// \brief DrawItemsInBorder/// \param painter///void DrawItemsInBorder(QPainter *painter);/// 绘制菜单中心按钮/// \brief DrawSwitchsButton/// \param painter///void DrawSwitchsButton(QPainter *painter);/// 绘制菜单项按钮/// \brief DrawMenuCtlButton/// \param painter///void DrawMenuCtlButton(QPainter *painter);// 重写系统鼠标松开事件void mouseReleaseEvent(QMouseEvent *event) override;
private:/// 初始化菜单动画/// \brief InitMenuAnimation///void InitMenuAnimation();/// 获取菜单项外圆半径/// \brief GetItemsOutRadius/// \return///qreal GetItemsOutRadius();/// 获取菜单项内圆半径/// \brief GetItemsInnRadius/// \return///qreal GetItemsInnRadius();/// 获取菜单项目绘制开始角度/// \brief GetItemStartAngle/// \return///qreal GetItemStartAngle();/// 获取菜单控件绘制弧度/// \brief GetFrmStartRadian/// \return///qreal GetFrmStartRadian();/// 获取菜单切换按钮菜单绘图路径/// \brief GetSwitchBtnsPath/// \return///QPainterPath GetSwitchBtnsPath();/// 获取菜单按钮绘图路径/// \brief GetMenuButtonPath/// \param index/// \param hover/// \return///QPainterPath GetMenuButtonPath(int index, bool hover = false);private slots:/// 切换菜单按钮单击/// \brief MenuSwitchClicked///void MenuSwitchClicked();/// 菜单项展开或收起/// \brief MenuItemBtnExpand/// \param bExpand///void MenuItemBtnExpand(const bool& bExpand);/// 菜单项单击槽函数/// \brief MenuItemsBtnClick/// \param uIndex///void MenuItemsBtnClick(const uint& uIndex);public:/// 添加菜单按钮项/// \brief AddMenuButtonItem/// \param tMenuItem/// 注意在插入和添加菜单时图标和title必须提供一个///void AddMenuButtonItem(const LQROUNDMENUBTN_ITEM& tMenuItem);void AddMenuButtonItem(const QPixmap &icon, const QString &title, const QString &tooltip);void AddMenuButtonItem(const QPixmap &icon, const QString &title, const QString &tooltip,const QColor &background);void AddMenuButtonItem(const QPixmap &icon, const std::u16string &title, const std::u16string &tooltip,const QColor &background);/// 插入一个菜单按钮/// \brief InsertMenuBtnItem/// \param index/// \param tMenuItem///void InsertMenuBtnItem(int index,LQROUNDMENUBTN_ITEM tMenuItem);/// 插入一个按钮项目/// \brief InsertMenuBtnItem/// \param index/// \param icon/// \param title/// \param tooltip/// \param background///void InsertMenuBtnItem(int index, const QPixmap &icon, const QString &title, const QString &tooltip,const QColor &background = QColor());void InsertMenuBtnItem(int index, const QPixmap &icon, const std::u16string &title, const std::u16string &tooltip,const QColor &background = QColor());/// 获取菜单展开图标路径/// \brief GetExpandImgPath/// \return///std::u16string GetExpandImgPath() const;/// 获取菜单闭合图标路径/// \brief GetClosedImgPath/// \return///std::u16string GetClosedImgPath() const;/// 设置菜单展开图标路径/// \brief SetExpandImgPath/// \param sImage///void SetExpandImgPath(const std::u16string& sImage);/// 设置菜单闭合图标路径/// \brief SetClosedImgPath/// \param sImage///void SetClosedImgPath(const std::u16string& sImage);
核心绘图代码如下
// 重写系统绘制事件void Lncf_QRoundMenuCtl::paintEvent(QPaintEvent *event){QWidget::paintEvent(event);QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);//绘制背景if(this->tMenuCtrlStyles.bShowCtrlBkgnd)DrawBackgroundCtl(&painter);//绘制菜单按钮DrawMenuCtlButton(&painter);//绘制中心按钮if(this->tMenuCtrlStyles.bDrawCenterBtn)DrawSwitchsButton(&painter);}/// 绘制控件圆形背景/// \brief DrawBackgroundCtl/// \param painter///void Lncf_QRoundMenuCtl::DrawBackgroundCtl(QPainter *painter){painter->setPen(this->tMenuCtrlStyles.bShowBkgBorder?QPen(tMenuCtrlStyles.cBkgBorderClrs,tMenuCtrlStyles.dBkgBordersWid):Qt::NoPen);if(this->tMenuCtrlStyles.vMenuCtlBkgClr.count()>0){QLinearGradient gradient(QPoint(0, 0), QPoint(width(), height()));for(int i=0;i<tMenuCtrlStyles.vMenuCtlBkgClr.count();i++)gradient.setColorAt(tMenuCtrlStyles.vMenuCtlBkgClr[i].fBkgndAngleVal, tMenuCtrlStyles.vMenuCtlBkgClr[i].cBkgndAngleClr);painter->setBrush(gradient);}else{painter->setBrush(this->tMenuCtrlStyles.cMenuCtlBkgClr);}QRectF rect = this->rect();uint uRectMinVal = qMin(this->width(),this->height());rect.setSize(QSize(uRectMinVal*tMenuCtrlStyles.dFrameOutScale,uRectMinVal*tMenuCtrlStyles.dFrameOutScale));rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));painter->drawEllipse(rect);}/// 绘制菜单项圆形外边框/// \brief DrawItemOutBorder/// \param painter///void Lncf_QRoundMenuCtl::DrawItemOutBorder(QPainter *painter){QRectF rect(0.0, 0.0, 2.0 * GetItemsOutRadius(), 2.0 * GetItemsOutRadius());rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));painter->save();painter->setPen(QPen(QBrush(this->tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dItemBorderWid));painter->drawEllipse(rect);painter->restore();}/// 绘制菜单项圆形内边框/// \brief DrawItemsInBorder/// \param painter///void Lncf_QRoundMenuCtl::DrawItemsInBorder(QPainter *painter){QRectF rect(0.0, 0.0, 2.0 * GetItemsInnRadius(), 2.0 * GetItemsInnRadius());rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));painter->save();painter->setPen(QPen(QBrush(this->tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dItemBorderWid));painter->drawEllipse(rect);painter->restore();}int imageRotate =0;/// 绘制菜单中心按钮/// \brief DrawSwitchsButton/// \param painter///void Lncf_QRoundMenuCtl::DrawSwitchsButton(QPainter *painter){auto path = GetSwitchBtnsPath();painter->setBrush(bSwitchBnHover?tMenuCtrlStyles.cSwicthBnHover:(bHasExpandMenu ? tMenuCtrlStyles.cSwicthExpands : tMenuCtrlStyles.cSwicthBnColor));painter->setPen(tMenuCtrlStyles.bHasItemBorder?QPen(tMenuCtrlStyles.cItemBorderClr,tMenuCtrlStyles.dItemBorderWid):Qt::NoPen);painter->drawPath(path);auto pixmap = bHasExpandMenu ? QPixmap(QString::fromStdU16String(sClosedImgPath)) :QPixmap(QString::fromStdU16String(sExpandImgPath));auto rect = path.boundingRect();if(!pixmap.isNull()){rect = rect.marginsRemoved(QMargins(rect.width() / 4.0,rect.height() / 4.0,rect.width() / 4.0,rect.height() / 4.0));painter->drawPixmap(rect, pixmap, pixmap.rect());}else{rect = rect.marginsRemoved(QMargins(rect.width() / 4.0,rect.height() / 4.0,rect.width() / 4.0,rect.height() / 4.0));std::u16string sSwicthText = bHasExpandMenu ? u"MENU":u"CLOSE";QFont fontObj = this->font();fontObj.setPointSizeF(rect.height()/4.0);painter->setFont(fontObj);painter->setPen(bSwitchBnHover?tMenuCtrlStyles.cMenuBtnTxtClr:tMenuCtrlStyles.cMenuTextHover);painter->drawText(rect, Qt::AlignCenter|Qt::TextWordWrap,QString::fromStdU16String(sSwicthText));}}/// 绘制菜单项按钮/// \brief DrawMenuCtlButton/// \param painter///void Lncf_QRoundMenuCtl::DrawMenuCtlButton(QPainter *painter){if(pMenuAnimeGroup->state() != QAbstractAnimation::Running){if(!bHasExpandMenu||vMenuButtonList.count()<=0){return;}}if(this->tMenuCtrlStyles.bShowItemsLine&&!this->tMenuCtrlStyles.bRoundMenuItem){DrawItemOutBorder(painter);DrawItemsInBorder(painter);}auto count = vMenuButtonList.count();if(count == 0) return;auto radian = 2 * PI / count;auto outer_radius = GetItemsOutRadius();auto inner_radius = GetItemsInnRadius();QFont fontObj = this->font();for (int i = 0 ; i< count; ++i){auto path = GetMenuButtonPath(i);//绘制背景auto bgColor = this->tMenuCtrlStyles.bHasRandomClrs?QColor::fromHsl(rand()%360,rand()%256,rand()%200):vMenuButtonList.at(i)->cCustomBkgClr;if(!bgColor.isValid()){bgColor = this->tMenuCtrlStyles.cMenuBtnBkgClr;}auto iconRectWidth = outer_radius - inner_radius;if(!this->tMenuCtrlStyles.bRoundMenuItem){painter->fillPath(path,vMenuButtonList.at(i)->bIsHoverState?this->tMenuCtrlStyles.cMenuBtnHovers:bgColor);}else{QRectF rectBtnBkg(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBkgScale, iconRectWidth / this->tMenuCtrlStyles.dItemsBkgScale);rectBtnBkg.moveCenter(path.boundingRect().center());painter->setBrush(vMenuButtonList.at(i)->bIsHoverState?this->tMenuCtrlStyles.cMenuBtnHovers:bgColor);painter->setPen(tMenuCtrlStyles.bHasItemBorder?QPen(tMenuCtrlStyles.cItemBorderClr,tMenuCtrlStyles.dItemBorderWid):Qt::NoPen);painter->drawRoundedRect(rectBtnBkg,rectBtnBkg.width()*tMenuCtrlStyles.dBnRoundRadius,rectBtnBkg.height()*tMenuCtrlStyles.dBnRoundRadius);}auto pixmapIcon = vMenuButtonList.at(i)->pMenuItemIcon;if(!pixmapIcon.isNull()){QRectF rectIcon(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale);rectIcon.moveCenter(path.boundingRect().center());painter->drawPixmap(rectIcon, pixmapIcon, pixmapIcon.rect());}else{QRectF rectText(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale*0.95, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale*0.95);rectText.moveCenter(path.boundingRect().center());fontObj.setPointSizeF(rectText.height()/4.0);painter->setFont(fontObj);painter->setPen(vMenuButtonList.at(i)->bIsHoverState?tMenuCtrlStyles.cMenuTextHover:tMenuCtrlStyles.cMenuBtnTxtClr);painter->drawText(rectText, Qt::AlignCenter|Qt::TextWordWrap, QString::fromStdU16String(vMenuButtonList.at(i)->uItemTitleVal));}/**************************** draw seperator* */if(this->tMenuCtrlStyles.bShowItemsLine&&!this->tMenuCtrlStyles.bRoundMenuItem){QPointF point1(width() / 2.0 + outer_radius * std::cos(radian * i + GetFrmStartRadian()),height() / 2.0 - outer_radius * std::sin(radian * i + GetFrmStartRadian()));QPointF point2(width() / 2.0 + inner_radius * std::cos(radian * i + GetFrmStartRadian()),height() / 2.0 - inner_radius * std::sin(radian * i + GetFrmStartRadian()));painter->save();painter->setPen(QPen(QBrush(tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dBkgBordersWid));painter->drawLine(point1, point2);painter->restore();}}}
大半夜刚封装完,困的实在类,先写到这。
有关详细信息和技术交流,移步QQ群:717743458。
Qt,C++开发炫酷圆形扇形菜单面板相关推荐
- android 扇形切换,Android 一个炫酷的扇形菜单
效果演示 效果展示 如何使用 1.布局 android:id="@+id/sector_menu" android:layout_width="wrap_content& ...
- html的悬停图片圆形,css3炫酷圆形图片鼠标滑过特效
这是一款纯css3炫酷圆形图片鼠标滑过特效插件.在插件中,所有的缩略图都被用css3 border-radius制作成圆形,然后再在其上做各种鼠标滑过特效. HTML 所有demo的html结构都如下 ...
- html img 圆头像_纯CSS3炫酷圆形头像图片过滤特效
这是一款效果非常酷的纯CSS3炫酷圆形头像图片过滤特效.该特效将图片制作为圆形图片,以网格形式布局,带点击相应的分类按钮后,该类别的图片被放大显示,其它类别的图片被缩小,效果非常的不错. 制作方法 H ...
- 新一代嵌入式UI框架 HaaS UI 使用JS在嵌入式开发炫酷前端
HaaS UI 是一款面向AIoT 领域的渐进式JS应用开发框架,以移动开发理念有效降低开发者研发AIoT带屏应用难度. 理念 移动开发模式,全面拥抱JavaScritp开源生态,且系统服务通过统一的 ...
- BOLT.NET 学习笔记(一) 开篇 用.net winform 快速开发 炫酷的界面
BOLT.NET 学习笔记(一) 开篇 用.net winform 快速开发 炫酷的界面 bolt 基本介绍 Bolt界面引擎是迅雷公司从2009年开始开发的第四代界面库.迅雷7是首个采用该引擎成功开 ...
- 纯css3炫酷科技感菜单
下载地址 一款样式炫酷的旋转导航菜单,纯css3代码实现的炫酷科技感菜单,带css3旋转动画特效. dd:
- 安卓炫酷的抽屉菜单——JPSpringMenu
一个炫酷的抽屉菜单--JPSpringMenu GitHub地址:传送门 看到这个,本来想搜搜它的穿件方式,就是应用,结果查找了一番,都是github的那一点解释 看到这,决定还是自己动手一番吧 具体 ...
- android开发炫酷背景图片,12 个炫酷背景特效库
作者:lindelof 译者:前端小智 来源:github点赞再看,微信搜索GitHub https://github.com/qq44924588... 上已经收录,文章的已分类,也整理了很多我的文 ...
- 76.qt qml-QianWindow开源炫酷界面框架(支持白色暗黑渐变自定义控件均以适配)
界面介绍 界面支持: 透明 白色 黑色 渐变 单色 静态图 动态图 侧边栏支持:抽屉.带折叠.多模式场景 控件已集成: 暗黑风格 高亮风格.并附带个人自定义控件及开源demo 白色场景如下所示: 单色 ...
最新文章
- POSA2:Wrapper Facade模式
- python数据分析常见面试题_python数据分析方向,面试题解答
- keil c语言表用什么数据类型,面向51单片机的Keil uVision4基本数据类型简介
- html判断是安卓还是苹果手机,网页能够自己判断是pc端首页还是手机android和苹果。...
- 文末送书 | Facebook:易于解释的神经元可能会阻碍神经网络的学习
- pytorch中调整学习率: torch.optim.lr_scheduler
- OpenGL.Vertex Array Object (VAO).
- 前端电子时钟字体引入
- 掷骰子python代码_掷骰子游戏,,游戏规则:玩家投掷两个骰
- 悼念512汶川大地震遇难同胞
- services.msc 无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动
- 华为云CentOS7.6云耀服务器Python环境基本配置
- 在一张表里实现省市区镇村五级联动
- php设置pst时区,PHP时区标识符含义
- java写接口给前端_看看人家那后端API接口写得,那叫一个优雅!
- 校验输入的拼音是否符合声母韵母搭配规则(不是根据汉字生成拼音)
- py 网站实时监控+可手动回溯回放网站数据的实现
- SCAPE、BlendSCAPE、SMPL、SMPL-H、SMPL-X、STAR等都是什么?请分别仔细介绍一下
- Codeforces Round #652 div2 总结 端午节前小结
- 边工作边学习的现实选择