qmenu基本用法_剖析QMenu Qt完全定制化菜单
贴张效果图:
定制包括:
1. 周边阴影
2. 菜单项的元素(分割符, 控制ICON大小, 文字显示位置与颜色, 子菜单指示符)
菜单内的效果, 部分可以使用stylesheet实现, 但要做到这样的定制化, stylesheet是做不到的
下面介绍如何实现这些效果:
1. 实现阴影效果
默认的Qt菜单QMenu的效果是这样的
1) 首先需要去除下拉阴影(Drop shadow)
Qt的菜单是继承QWidget然后自绘的, dropshadow不属于自绘范围, 是windows popup类型窗口默认的样式, 无法通过正常途径去除
可以从源码中看到调用过程大概是这样:
qmenu::popup -> qwidget::show() -> QWidgetPrivate::show_helper() -> show_sys();
而这时候, 还未调用qmenu::paintevent
而且不能去除QMenu的Popup 属性, 因为QMenu的实现依赖Popup属性, 例如:
QMenuPrivate::activateAction中使用QApplication::activePopupWidget()函数
在windows平台下:
menu.h
#ifndef MENU_H#define MENU_H#include
class Menu : publicQMenu
{
Q_OBJECTpublic:explicit Menu(QWidget *parent = 0);explicit Menu(const QString &title);protected:virtual bool event(QEvent *event);
signals:publicslots:
};#endif //MENU_H
menu.cpp
#include "menu.h"
Menu::Menu(QWidget*parent) :
QMenu(parent)
{
}
Menu::Menu(const QString &title) :
QMenu(title)
{
}bool Menu::event(QEvent *event)
{static bool class_amended = false;if (event->type() ==QEvent::WinIdChange)
{
HWND hwnd= reinterpret_cast(winId());if (class_amended == false)
{
class_amended= true;
DWORD class_style=::GetClassLong(hwnd, GCL_STYLE);
class_style&= ~CS_DROPSHADOW;
::SetClassLong(hwnd, GCL_STYLE, class_style);
}}return QWidget::event(event);
}
大概思路是: 在event中截获QEvent::WinIdChange事件, 然后获得窗口handle, 使用GetClassLong / SetClassLong 去除 CS_DROPSHADOW flags, 即可去除阴影
2) 使用dwm实现环绕阴影
优点:系统内置支持
缺点: 仅在vista以上并开启aero特效的情况, 使菜单有阴影环绕.
#pragma comment( lib, "dwmapi.lib" )#include"dwmapi.h"
bool Menu::event(QEvent *event)
{static bool class_amended = false;if (event->type() ==QEvent::WinIdChange)
{
HWND hwnd= reinterpret_cast(winId());if (class_amended == false)
{
class_amended= true;
DWORD class_style=::GetClassLong(hwnd, GCL_STYLE);
class_style&= ~CS_DROPSHADOW;
::SetClassLong(hwnd, GCL_STYLE, class_style);
}
DWMNCRENDERINGPOLICY val=DWMNCRP_ENABLED;
::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY,&val, sizeof(DWMNCRENDERINGPOLICY));//This will turn OFF the shadow//MARGINS m = {0};//This will turn ON the shadow
MARGINS m = {-1};
HRESULT hr= ::DwmExtendFrameIntoClientArea(hwnd, &m);if( SUCCEEDED(hr) )
{//do more things
}
}return QWidget::event(event);
}
简单地修改一下event的实现即可
3) 手动绘制阴影
1. CCustomMenu 继承 QMenu
voidCCustomMenu::_Init()
{//必须设置popup, 因为QMenuPrivate::activateAction中使用QApplication::activePopupWidget()函数
this->setWindowFlags(Qt::Popup |Qt::FramelessWindowHint);this->setAttribute(Qt::WA_TranslucentBackground);this->setObjectName("CustomMenu"); //以objectname 区分Qt内置菜单和CCustomMenu
}
设置菜单背景透明
objectname是为了在绘制时区分不同风格的菜单(比如原生Qmenu与CCustomMenu或者其他CCustomMenu2等)
2. 实现CCustomStyle (参考Qt的源码 QFusionStyle)
CCustomStyle继承自QProxyStyle, Qt控件中的基础元素都是通过style控制, style比stylesheet更底层, 可以做到更精细的控制
/**@brief 定制菜单style
@author lwh*/
class CCustomStyle : publicQProxyStyle
{
Q_OBJECTpublic:
CCustomStyle(QStyle*style = 0);void drawControl(ControlElement control, const QStyleOption *option,
QPainter*painter, const QWidget *widget) const;void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter*painter, const QWidget *widget) const;int pixelMetric ( PixelMetric pm, const QStyleOption * opt, const QWidget * widget) const;private:void _DrawMenuItem(const QStyleOption *option,
QPainter*painter, const QWidget *widget) const;
QPixmap _pixShadow ;//阴影图片
};
首先需要调整菜单项与边框的距离, 用于绘制阴影
在pixelMetric 中添加
if(pm ==PM_MenuPanelWidth)return 6; //调整边框宽度, 以绘制阴影
pixelMetric 中描述了像素公制可取的一些值,一个像素公制值是单个像素在样式中表现的尺寸.
然后再drawPrimitive实现阴影绘制
void CCustomStyle::drawPrimitive( PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget ) const{if(element ==PE_FrameMenu)
{
painter->save();
{if(_pixShadow.isNull()|| widget->objectName() != "CustomMenu") //fix bug: Qt的内置菜单显示不正常(如TextEdit右键菜单)
{
painter->restore();return__super::drawPrimitive(element, option, painter, widget);
}
QSize szThis= option->rect.size();
QPixmap pixShadowBg=_DrawNinePatch(szThis, _pixShadow);
painter->drawPixmap(option->rect, pixShadowBg);
}
painter->restore();return;
}
__super::drawPrimitive(element, option, painter, widget);
}
QStyle::PE_FrameMenu Frame for popup windows/menus; see also QMenu.
注意: 绘制完直接return
_DrawNinePatch是以九宫格形式绘制,
将这样一张小的阴影图绘制到窗口时, 如果直接拉伸, 会变得非常模糊.
而九宫格形式可以绘制出相对漂亮的背景, 这种技巧同样可以应用在其他控件上.
const QPixmap _DrawNinePatch( QSize szDst, const QPixmap &srcPix )
{//绘制背景图到, 以九宫格形式
QPixmap dstPix(szDst);
dstPix.fill(QColor(255, 255, 255, 0));
QPainter painter;
painter.begin(&dstPix);int nW =szDst.width();int nH =szDst.height();int nWBg =srcPix.width();int nHBg =srcPix.height();
QPoint m_ptBgLT(10, 10);
QPoint m_ptBgRB(19, 19);
QPoint ptDstLT(m_ptBgLT.x(), m_ptBgLT.y());
QPoint ptDstRB(nW-(nWBg-m_ptBgRB.x()), nH-(nHBg-m_ptBgRB.y()));//LT
painter.drawPixmap(QRect(0,0,ptDstLT.x(), ptDstLT.y()), srcPix, QRect(0,0,m_ptBgLT.x(), m_ptBgLT.y()));//MT
painter.drawPixmap(QRect(ptDstLT.x(),0, ptDstRB.x()-ptDstLT.x(), ptDstLT.y()), srcPix, QRect(m_ptBgLT.x(),0,m_ptBgRB.x()-m_ptBgLT.x(), m_ptBgLT.y()));//RT
painter.drawPixmap(QRect(ptDstRB.x(),0,nW-ptDstRB.x(), ptDstLT.y()), srcPix, QRect(m_ptBgRB.x(),0,nWBg-m_ptBgRB.x(), m_ptBgLT.y()));//LM
painter.drawPixmap(QRect(0,ptDstLT.y(),ptDstLT.x(), ptDstRB.y()-ptDstLT.y()), srcPix, QRect(0,m_ptBgLT.y(),m_ptBgLT.x(), m_ptBgRB.y()-m_ptBgLT.y()));//MM
painter.drawPixmap(QRect(ptDstLT.x(),ptDstLT.y(),ptDstRB.x()-ptDstLT.x(), ptDstRB.y()-ptDstLT.y()), srcPix, QRect(m_ptBgLT.x(),m_ptBgLT.y(),m_ptBgRB.x()-m_ptBgLT.x(), m_ptBgRB.y()-m_ptBgLT.y()));//RM
painter.drawPixmap(QRect(ptDstRB.x(),ptDstLT.y(), nW-ptDstRB.x(), ptDstRB.y()-ptDstLT.y()), srcPix, QRect(m_ptBgRB.x(),m_ptBgLT.y(), nWBg-m_ptBgRB.x(), m_ptBgRB.y()-m_ptBgLT.y()));//LB
painter.drawPixmap(QRect(0,ptDstRB.y(),ptDstLT.x(), nH-ptDstRB.y()), srcPix, QRect(0,m_ptBgRB.y(),m_ptBgLT.x(), nHBg-m_ptBgRB.y()));//MB
painter.drawPixmap(QRect(ptDstLT.x(),ptDstRB.y(),ptDstRB.x()-ptDstLT.x(), nH-ptDstRB.y()), srcPix, QRect(m_ptBgLT.x(),m_ptBgRB.y(),m_ptBgRB.x()-m_ptBgLT.x(), nHBg-m_ptBgRB.y()));//RB
painter.drawPixmap(QRect(ptDstRB.x(),ptDstRB.y(),nW-ptDstRB.x(), nH-ptDstRB.y()), srcPix, QRect(m_ptBgRB.x(),m_ptBgRB.y(),nWBg-m_ptBgRB.x(), nHBg-m_ptBgRB.y()));
painter.end();returndstPix;
}
2. 绘制菜单项
1) 控制ICON大小
在pixelMetric中:
if (pm ==QStyle::PM_SmallIconSize)return 12; //返回ICON的大小
2) 绘制菜单项内容
void CCustomStyle::drawControl( ControlElement control, const QStyleOption *option, QPainter *painter, const QWidget *widget ) const{switch(control )
{caseCE_MenuItem:
{
_DrawMenuItem(option, painter, widget);return; //直接返回, 否则会被super::drawcontrol覆盖
}
}
__super::drawControl(control, option, painter, widget);
}
1 void CCustomStyle::_DrawMenuItem(const QStyleOption *option, QPainter *painter, const QWidget *widget ) const
2 {3 painter->save();4
5 if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option))6 {7 //先绘制一层背景(否则在透明情况下, 会直接透过去);
8 painter->setPen(colItemBg);9 painter->setBrush(colItemBg);10 painter->drawRect(option->rect);11
12 if (menuItem->menuItemType ==QStyleOptionMenuItem::Separator) {13 int w = 0;14 if (!menuItem->text.isEmpty()) { //绘制分隔符文字
15 painter->setFont(menuItem->font);16 proxy()->drawItemText(painter, menuItem->rect.adjusted(5, 0, -5, 0), Qt::AlignLeft |Qt::AlignVCenter,17 menuItem->palette, menuItem->state & State_Enabled, menuItem->text,18 QPalette::Text);19 w = menuItem->fontMetrics.width(menuItem->text) + 5;20 }21 painter->setPen(colSeparator);22 bool reverse = menuItem->direction ==Qt::RightToLeft;23 painter->drawLine(menuItem->rect.left() + 5 + (reverse ? 0 : w), menuItem->rect.center().y(),24 menuItem->rect.right() - 5 - (reverse ? w : 0), menuItem->rect.center().y());25 painter->restore();26 return;27 }28 bool selected = menuItem->state & State_Selected && menuItem->state &State_Enabled;29 if(selected) {30 QRect r = option->rect;31 painter->fillRect(r, colItemHighlight);32 }33 bool checkable = menuItem->checkType !=QStyleOptionMenuItem::NotCheckable;34 bool checked = menuItem->checked;35 bool sunken = menuItem->state &State_Sunken;36 bool enabled = menuItem->state &State_Enabled;37
38 bool ignoreCheckMark = false;39 int checkcol = qMax(menuItem->maxIconWidth, 20);40
41 if (qobject_cast(widget))42 ignoreCheckMark = true; //ignore the checkmarks provided by the QComboMenuDelegate
43
44 if (!ignoreCheckMark) {45 //Check
46 QRect checkRect(option->rect.left() + 7, option->rect.center().y() - 6, 14, 14);47 checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect);48 if(checkable) {49 if (menuItem->checkType &QStyleOptionMenuItem::Exclusive) {50 //Radio button 未实现
51 if (checked ||sunken) {52 /*painter->setRenderHint(QPainter::Antialiasing);53 painter->setPen(Qt::NoPen);54
55 QPalette::ColorRole textRole = !enabled ? QPalette::Text:56 selected ? QPalette::HighlightedText : QPalette::ButtonText;57 painter->setBrush(option->palette.brush( option->palette.currentColorGroup(), textRole));58 painter->drawEllipse(checkRect.adjusted(4, 4, -4, -4));59 */
60 }61 } else{62 //Check box
63 if (menuItem->icon.isNull()) {64 QStyleOptionButton box;65 box.QStyleOption::operator=(*option);66 box.rect =checkRect;67 if (checked)68 box.state |=State_On;69 proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget);70
71 }72 }73 }74 } else { //ignore checkmark
75 if (menuItem->icon.isNull())76 checkcol = 0;77 else
78 checkcol = menuItem->maxIconWidth;79 }80
81 //Text and icon, ripped from windows style
82 bool dis = !(menuItem->state &State_Enabled);83 bool act = menuItem->state &State_Selected;84 const QStyleOption *opt =option;85 const QStyleOptionMenuItem *menuitem =menuItem;86
87 QPainter *p =painter;88 QRect vCheckRect = visualRect(opt->direction, menuitem->rect,89 QRect(menuitem->rect.x() + 4, menuitem->rect.y(),90 checkcol, menuitem->rect.height()));91 if (!menuItem->icon.isNull()) {92 QIcon::Mode mode = dis ?QIcon::Disabled : QIcon::Normal;93 if (act && !dis)94 mode =QIcon::Active;95 QPixmap pixmap;96
97 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize, option, widget);98 QSize iconSize(smallIconSize, smallIconSize);99 if (const QComboBox *combo = qobject_cast(widget))100 iconSize = combo->iconSize();101 if (checked)102 pixmap = menuItem->icon.pixmap(iconSize, mode, QIcon::On);103 else
104 pixmap = menuItem->icon.pixmap(iconSize, mode);105
106 int pixw =pixmap.width();107 int pixh =pixmap.height();108
109 QRect pmr(0, 0, pixw, pixh);110 pmr.moveCenter(vCheckRect.center());111 painter->setPen(colText);//menuItem->palette.text().color()
112 if (checkable && checked) {113 QStyleOption opt = *option;114 if(act) {115 QColor activeColor =mergedColors(116 colItemBg, //option->palette.background().color(),
117 colItemHighlight //option->palette.highlight().color());
118 );119 opt.palette.setBrush(QPalette::Button, activeColor);120 }121 opt.state |=State_Sunken;122 opt.rect =vCheckRect;123 proxy()->drawPrimitive(PE_PanelButtonCommand, &opt, painter, widget);124 }125 painter->drawPixmap(pmr.topLeft(), pixmap);126 }127 if(selected) {128 painter->setPen(colText);//menuItem->palette.highlightedText().color()
129 } else{130 painter->setPen(colText); //menuItem->palette.text().color()
131 }132 intx, y, w, h;133 menuitem->rect.getRect(&x, &y, &w, &h);134 int tab = menuitem->tabWidth;135 QColor discol;136 if(dis) {137 discol = colDisText; //menuitem->palette.text().color()
138 p->setPen(discol);139 }140 int xm = windowsItemFrame + checkcol + windowsItemHMargin + 2;141 int xpos = menuitem->rect.x() +xm;142
143 QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 *windowsItemVMargin);144 QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect);145 QString s = menuitem->text;146 if (!s.isEmpty()) { //draw text
147 p->save();148 int t = s.indexOf(QLatin1Char('\t'));149 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip |Qt::TextSingleLine;150 if (!__super::styleHint(SH_UnderlineShortcut, menuitem, widget))151 text_flags |=Qt::TextHideMnemonic;152 text_flags |=Qt::AlignLeft;153 if (t >= 0) {154 QRect vShortcutRect = visualRect(opt->direction, menuitem->rect,155 QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));156 if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {157 p->setPen(colText);//menuitem->palette.light().color()
158 p->drawText(vShortcutRect.adjusted(1, 1, 1, 1), text_flags, s.mid(t + 1));159 p->setPen(discol);160 }161 p->drawText(vShortcutRect, text_flags, s.mid(t + 1));162 s =s.left(t);163 }164 QFont font = menuitem->font;165 //font may not have any "hard" flags set. We override166 //the point size so that when it is resolved against the device, this font will win.167 //This is mainly to handle cases where someone sets the font on the window168 //and then the combo inherits it and passes it onward. At that point the resolve mask169 //is very, very weak. This makes it stonger.
170 font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF());171
172 if (menuitem->menuItemType ==QStyleOptionMenuItem::DefaultItem)173 font.setBold(true);174
175 p->setFont(font);176 if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {177 p->setPen(menuitem->palette.light().color());178 p->drawText(vTextRect.adjusted(1, 1, 1, 1), text_flags, s.left(t));179 p->setPen(discol);180 }181 p->drawText(vTextRect, text_flags, s.left(t));182 p->restore();183 }184
185 //Arrow 绘制子菜单指示符
186 if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu) {//draw sub menu arrow
187 int dim = (menuItem->rect.height() - 4) / 2;188 PrimitiveElement arrow;189 arrow = option->direction == Qt::RightToLeft ?PE_IndicatorArrowLeft : PE_IndicatorArrowRight;190 int xpos = menuItem->rect.left() + menuItem->rect.width() - 3 -dim;191 QRect vSubMenuRect = visualRect(option->direction, menuItem->rect,192 QRect(xpos, menuItem->rect.top() + menuItem->rect.height() / 2 - dim / 2, dim, dim));193 QStyleOptionMenuItem newMI = *menuItem;194 newMI.rect =vSubMenuRect;195 newMI.state = !enabled ?State_None : State_Enabled;196 if(selected)197 newMI.palette.setColor(QPalette::ButtonText, //此处futionstyle 有误, QPalette::Foreground改为ButtonText
198 colIndicatorArrow);//newMI.palette.highlightedText().color()
199 else
200 newMI.palette.setColor(QPalette::ButtonText,201 colIndicatorArrow);202
203 proxy()->drawPrimitive(arrow, &newMI, painter, widget);204 }205 }206 painter->restore();207 }
_DrawMenuItem
_DrawMenuItem的代码较长, 但比较简单, 都是一些条件判断加上绘图语句, 需要自己修改pallete的颜色
值得注意的是: 在透明情况下, 应先绘制一层menu item 的背景, 否则会直接透过去
3) 最后还要重写一下QMenu的addMenu
以使子菜单也生效
QAction * CCustomMenu::addMenu( CCustomMenu *menu )
{returnQMenu::addMenu(menu);
}
CCustomMenu* CCustomMenu::addMenu( const QString &title )
{
CCustomMenu*menu = new CCustomMenu(title, this);
addAction(menu->menuAction());returnmenu;
}
CCustomMenu* CCustomMenu::addMenu( const QIcon &icon, const QString &title )
{
CCustomMenu*menu = new CCustomMenu(title, this);
menu->setIcon(icon);
addAction(menu->menuAction());returnmenu;
}
编译需要VS2010+Qt5.
PS:
关于QMenu如何处理菜单消失, 参考我的另一篇blog Qt中QMenu的菜单关闭处理方法
qmenu基本用法_剖析QMenu Qt完全定制化菜单相关推荐
- qmenu基本用法_使用QProxyStyle定制QMenu (二)
显示一个还没定制的右键菜单 要在右键单击时显示弹出式的上下文菜单(a context menu)就要用到QWidget的contextMenuPolicy : Qt::ContextMenuPolic ...
- [SpringBoot2]web场景_静态资源规则与定制化
静态资源目录 只要静态资源放在类路径下: called /static (or /public or /resources or /META-INF/resources 访问 : 当前项目根路径/ + ...
- exdoll机器人_打造国内领先的定制化人工智能机器人品牌, EXDOLL新品惊艳亮相_TOM新闻...
原本只能在科幻电影中见到的人工智能,如今已越来越多的出现在我们的日常生活中,而随着AI技术和仿真技术的迅猛发展,人工智能机器人有望被大规模的应用于企业服务.医疗服务与生活服务中. AlphaGo和机器 ...
- challenge是什么意思_英语单词学习-challenge是什么意思_翻译_用法_例句
我们在学习英语这门科目的时候,不仅要重视听说读写,对于英语的基础知识也要重视,只有基础知识掌握到了,才能把英语这门科目学的更好.为了大家能够多学习一些英语单词,小编就带大家先了解一下英语单词学习-ch ...
- MATLAB中fix啥意思,matlab fix函数用法_常见问题解析,matlab
matlab syms什么意思_常见问题解析 matlab中syms的意思是定义多个变量,可以用来创建符号变量x和y,语法是"syms x y":也可以创建一些符号变量.函数和数组 ...
- matlab中的fix,matlab fix函数用法_常见问题解析
matlab syms什么意思_常见问题解析 matlab中syms的意思是定义多个变量,可以用来创建符号变量x和y,语法是"syms x y":也可以创建一些符号变量.函数和数组 ...
- qt 在点击菜单下的动作之后获取该菜单的名称
文章目录 qt 在点击菜单下的动作之后获取该菜单的名称 问题: 解决过程: qt 在点击菜单下的动作之后获取该菜单的名称 问题: QMenu 类下有4个信号: void aboutToHide() v ...
- Windows下Qt Creator设置IDE菜单字体样式
Windows下Qt Creator设置IDE菜单字体样式 本文为解决以下问题: IDE的菜单字体太小 IDE的菜单字体样式,可以更换为微软雅黑 创建样式文件 在Qt Creator目录下C:\Qt\ ...
- tkinter向文本框里加内容_给tkinter文本框添加右键菜单
给tkinter文本框添加右键菜单 需求:直接右键点击使用tkinter创建的文本框是不会弹出菜单的.我们需要实现右键点击tkinter框架下的Entry对象.Text对象后弹出右键菜单可复制.粘贴和 ...
最新文章
- Python之面向对象进阶
- 六大重点工程构筑兰州大数据产业
- 循环数组的最大子段和
- VTK:Filtering之Glyph2D
- 随时间的反向传播算法 BPTT
- 我的北京游戏开发总结【三】
- BZOJ3675 [APIO2014]序列分割
- GIT学习笔记2--基本使用
- Mysql学习总结(27)——Mysql数据库字符串函数
- 文件共享服务器灾备,搭建容灾性强、可管理的的文件共享服务器-windows server 2008 DFS续...
- hive内置函数_Hive Query生命周期 —— 钩子(Hook)函数篇
- 经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷
- SSM项目实战 —— 物流管理系统的实现
- LeetCode 刷题: Fizz Buzz
- Cisco switchport trunk encapsulation dot1q 详解
- 倪海厦天纪笔记16_倪海厦《天纪》——人间道听课笔记
- SQL面试必考——计算留存率
- 90后都开始养生了,你怎么能少了这本宝典丨钛空舱
- 数据分析过程中,发现数值缺失,怎么办?
- Python基础:函数的返回值return
热门文章
- 微信网页登录授权详解(前端)
- java indexof 子字符串_Java中字符串中子串的查找共有四种方法(indexof())
- 电脑开机时嘀嘀4声开不了机
- 「第三章」跨站脚本攻击(XSS)
- Java实现微信加密数据解密算法
- 案例式c语言程序设计彭文艺答案,彭文艺
- windows vue3 安装及搭建
- Android系统开发之烧录开发板
- doxygen教程-4-快速上手配置文件
- LeetCode第50题思悟——Pow(x, n)(powx-n)