- 浏览: 199807 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
hao3721:
dsfasd
ehcache 使用 -
nihaokid:
方法是不会存在在对象内存中的,它存在于方法区,建议看看jvm的 ...
Java 深层理解 父类引用指向子类对象 -
vissalan:
有一点没看明白Father f1 = (Father)s;这时 ...
Java 深层理解 父类引用指向子类对象 -
咖啡舞者:
非常感谢这种分享精神.
在BREW中实现自己的GUI(8)-IWEB的封装 -
咖啡舞者:
这是创建的代码。
在设备上调的。
界面在手机和模拟器上显示的差异
今天讨论关于GUI的另一个话题:如何在两个界面切换中表现出比较炫一点的效果,比如渐变、缩放等等。同样我们还是用组件的方式来做。IGSlider,负责管理两个IControl切换的动态效果,它的使用比较简单:
static void loadMenu(DisplayFavt * pMe,uint16 wParam)
...{
TItemData *pData;
IControl * p1,*p2;
uint16 style;
pData=NULL;
//加载第一个IControl,即起始界面
if(pMe->pCurrentTabOpt && pMe->pCurrentTabOpt->pMenu)
...{
ICONTROL_SetActive(pMe->pCurrentTabOpt->pMenu,FALSE);
p1=pMe->pCurrentTabOpt->pMenu;
}
//得到第二个IControl,即结束界面
pMe->currentTab=IGTABPANECTL_GetSel(pMe->pApp->pMenuTab);
MainItemQueue_FindById(pMe->pApp->pTabList,pMe->currentTab,&pData);
if(pData==NULL)
return;
IGTABPANECTL_GetItemData(pMe->pApp->pMenuTab,pMe->currentTab,(uint32*)&pMe->pCurrentTabOpt);
p2=pMe->pCurrentTabOpt->pMenu;
//设置切换效果的风格
//style =(wParam==0)?0:((wParam==AVK_LEFT)?SLIDER_STYLE_RTOL:SLIDER_STYLE_LTOR);
style=(wParam==0)?0:SLIDER_STYLE_DTOB;
if(p1 && p2 && style!=0)
...{
AEERect rec;
SET_CTL_RECT(&rec);
//两个界面应该同样大小
IGSLIDER_SetRect(pMe->pApp->pSlider,&rec);
//将两个界面IControl加入IGSlider
if(IGSLIDER_AddControls(pMe->pApp->pSlider,p1,p2))
...{
//初始化,设置回调、风格、动态效果显示时长
IGSLIDER_Init(pMe->pApp->pSlider,style,3,(PFNNOTIFY)loadMenuDone,(void*)pMe);
//启动
IGSLIDER_Start(pMe->pApp->pSlider);
return;
}
}
...{
ICONTROL_SetActive((IControl*)pMe->pCurrentTabOpt->pMenu,TRUE);
ICONTROL_Redraw(pMe->pCurrentTabOpt->pMenu);
pMe->pApp->state=STATE_COMMAND;
}
}
...{
TItemData *pData;
IControl * p1,*p2;
uint16 style;
pData=NULL;
//加载第一个IControl,即起始界面
if(pMe->pCurrentTabOpt && pMe->pCurrentTabOpt->pMenu)
...{
ICONTROL_SetActive(pMe->pCurrentTabOpt->pMenu,FALSE);
p1=pMe->pCurrentTabOpt->pMenu;
}
//得到第二个IControl,即结束界面
pMe->currentTab=IGTABPANECTL_GetSel(pMe->pApp->pMenuTab);
MainItemQueue_FindById(pMe->pApp->pTabList,pMe->currentTab,&pData);
if(pData==NULL)
return;
IGTABPANECTL_GetItemData(pMe->pApp->pMenuTab,pMe->currentTab,(uint32*)&pMe->pCurrentTabOpt);
p2=pMe->pCurrentTabOpt->pMenu;
//设置切换效果的风格
//style =(wParam==0)?0:((wParam==AVK_LEFT)?SLIDER_STYLE_RTOL:SLIDER_STYLE_LTOR);
style=(wParam==0)?0:SLIDER_STYLE_DTOB;
if(p1 && p2 && style!=0)
...{
AEERect rec;
SET_CTL_RECT(&rec);
//两个界面应该同样大小
IGSLIDER_SetRect(pMe->pApp->pSlider,&rec);
//将两个界面IControl加入IGSlider
if(IGSLIDER_AddControls(pMe->pApp->pSlider,p1,p2))
...{
//初始化,设置回调、风格、动态效果显示时长
IGSLIDER_Init(pMe->pApp->pSlider,style,3,(PFNNOTIFY)loadMenuDone,(void*)pMe);
//启动
IGSLIDER_Start(pMe->pApp->pSlider);
return;
}
}
...{
ICONTROL_SetActive((IControl*)pMe->pCurrentTabOpt->pMenu,TRUE);
ICONTROL_Redraw(pMe->pCurrentTabOpt->pMenu);
pMe->pApp->state=STATE_COMMAND;
}
}
原理比较简单:
1、我们要将两个 IControl绘入两个IBitmap中,然后才能进行各种图像操作(渐变、淡化、缩放等)。
2、用一个定时器来控制这个切换时的效果显示。
3、需要一个回调函数,在完成切换时需要调一下它,来处理善后事项。
先看看这个组件包含的成员,如上所述,除了两个ICotrol和两个IBitmap以外,还要那个回调m_cbDone、风格m_style、时间控制m_delay等等。
struct _IGSlider ...{
const AEEVTBL(IGSlider) * pvt;
uint32 m_nRefs;
IShell *m_pIShell;
IDisplay *m_pIDisplay;
IModule *m_pIModule;
IControl *m_pFirst;
IControl *m_pSecond;
int m_delay;
int m_style;
boolean m_isActive;
PFNNOTIFY m_cbDone;
void *m_pNotifyData;
AEERect m_Rect;
IBitmap *pFirst;
IBitmap *pSecond;
int tick;
uint8 flag;
IBitmap *pTemp;
};
const AEEVTBL(IGSlider) * pvt;
uint32 m_nRefs;
IShell *m_pIShell;
IDisplay *m_pIDisplay;
IModule *m_pIModule;
IControl *m_pFirst;
IControl *m_pSecond;
int m_delay;
int m_style;
boolean m_isActive;
PFNNOTIFY m_cbDone;
void *m_pNotifyData;
AEERect m_Rect;
IBitmap *pFirst;
IBitmap *pSecond;
int tick;
uint8 flag;
IBitmap *pTemp;
};
然后需要声明的接口函数包括以下几个:
AEEINTERFACE(IGSlider)
...{
DECLARE_IBASE(IGSlider)
boolean (*Redraw) (IGSlider * po);
void (*SetRect) (IGSlider * po, const AEERect *);
boolean (*AddControls) (IGSlider * po, IControl * p1,IControl * p2);
boolean (*AddControlsD) (IGSlider * po, IControl * p1,IControl * p2);
boolean (*AddControlFrom) (IGSlider * po,IControl * p1);
boolean (*AddControlTo) (IGSlider * po,IControl * p2);
boolean (*AddControlFromBitmap) (IGSlider * po,IBitmap * p1);
boolean (*AddControlToBitmap) (IGSlider * po,IBitmap * p2);
IBitmap* (*GetBitmapFirst) (IGSlider * po);
IBitmap* (*GetBitmapSecond) (IGSlider * po);
boolean (*IsActive) (IGSlider * po);
void (*Init) (IGSlider * po, uint16 style,uint32 delay,PFNNOTIFY cbDone,void * pUser);
void (*Start) (IGSlider * po);
void (*Stop) (IGSlider * po);
};
...{
DECLARE_IBASE(IGSlider)
boolean (*Redraw) (IGSlider * po);
void (*SetRect) (IGSlider * po, const AEERect *);
boolean (*AddControls) (IGSlider * po, IControl * p1,IControl * p2);
boolean (*AddControlsD) (IGSlider * po, IControl * p1,IControl * p2);
boolean (*AddControlFrom) (IGSlider * po,IControl * p1);
boolean (*AddControlTo) (IGSlider * po,IControl * p2);
boolean (*AddControlFromBitmap) (IGSlider * po,IBitmap * p1);
boolean (*AddControlToBitmap) (IGSlider * po,IBitmap * p2);
IBitmap* (*GetBitmapFirst) (IGSlider * po);
IBitmap* (*GetBitmapSecond) (IGSlider * po);
boolean (*IsActive) (IGSlider * po);
void (*Init) (IGSlider * po, uint16 style,uint32 delay,PFNNOTIFY cbDone,void * pUser);
void (*Start) (IGSlider * po);
void (*Stop) (IGSlider * po);
};
实现方面主要是这个addControls函数,在加入两个ICotrol同时,将它绘制到IBitmap上去。
static boolean IGSlider_AddControls(IGSlider * pMe,IControl * p1,IControl * p2)
...{
AEERect r;
if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pFirst))
return FALSE;
SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy);
ICONTROL_SetRect(p1,&r);
ICONTROL_Redraw(p1);
IDISPLAY_Update(pMe->m_pIDisplay);
ICONTROL_SetRect(p1,&pMe->m_Rect);
if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pSecond))
return FALSE;
SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy);
ICONTROL_SetRect(p2,&r);
ICONTROL_Redraw(p2);
IDISPLAY_Update(pMe->m_pIDisplay);
ICONTROL_SetRect(p2,&pMe->m_Rect);
IDISPLAY_SetDestination(pMe->m_pIDisplay,NULL);
return TRUE;
}
...{
AEERect r;
if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pFirst))
return FALSE;
SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy);
ICONTROL_SetRect(p1,&r);
ICONTROL_Redraw(p1);
IDISPLAY_Update(pMe->m_pIDisplay);
ICONTROL_SetRect(p1,&pMe->m_Rect);
if(SUCCESS!=IDISPLAY_SetDestination(pMe->m_pIDisplay,pMe->pSecond))
return FALSE;
SETAEERECT(&r,0,0,pMe->m_Rect.dx,pMe->m_Rect.dy);
ICONTROL_SetRect(p2,&r);
ICONTROL_Redraw(p2);
IDISPLAY_Update(pMe->m_pIDisplay);
ICONTROL_SetRect(p2,&pMe->m_Rect);
IDISPLAY_SetDestination(pMe->m_pIDisplay,NULL);
return TRUE;
}
启动效果切换的工作是根据当前设置的风格调用不同的图像处理函数,还要提供一个停止函数来随时中止效果变化(其实就是Cancel掉定时器罢了)。
static void IGSlider_Start(IGSlider * pMe)
...{
pMe->tick = 0;
pMe->flag=0;
pMe->m_isActive=TRUE;
if(pMe->m_style==SLIDER_STYLE_RTOL)
drawRTOL(pMe);
else if(pMe->m_style==SLIDER_STYLE_LTOR)
drawLTOR(pMe);
else if(pMe->m_style==SLIDER_STYLE_DARK)
drawDARK(pMe);
else if(pMe->m_style==SLIDER_STYLE_BRIT)
drawBRIT(pMe);
else if(pMe->m_style==SLIDER_STYLE_SIZE)
drawSize(pMe);
else if(pMe->m_style==SLIDER_STYLE_GRID)
drawGRID(pMe);
else if(pMe->m_style==SLIDER_STYLE_SIZE2)
drawSize2(pMe);
else if(pMe->m_style==SLIDER_STYLE_LTORD)
drawLTORD(pMe);
else if(pMe->m_style==SLIDER_STYLE_RTOLD)
drawRTOLD(pMe);
else if(pMe->m_style==SLIDER_STYLE_BTOT)
drawBTOT(pMe);
else if(pMe->m_style==SLIDER_STYLE_TTOB)
drawTTOB(pMe);
else if(pMe->m_style==SLIDER_STYLE_DTOB)
drawDTOB(pMe);
}
static void IGSlider_Stop(IGSlider * pMe)
...{
pMe->m_isActive=FALSE;
ISHELL_CancelTimer(pMe->m_pIShell,NULL,(void*)pMe);
}
...{
pMe->tick = 0;
pMe->flag=0;
pMe->m_isActive=TRUE;
if(pMe->m_style==SLIDER_STYLE_RTOL)
drawRTOL(pMe);
else if(pMe->m_style==SLIDER_STYLE_LTOR)
drawLTOR(pMe);
else if(pMe->m_style==SLIDER_STYLE_DARK)
drawDARK(pMe);
else if(pMe->m_style==SLIDER_STYLE_BRIT)
drawBRIT(pMe);
else if(pMe->m_style==SLIDER_STYLE_SIZE)
drawSize(pMe);
else if(pMe->m_style==SLIDER_STYLE_GRID)
drawGRID(pMe);
else if(pMe->m_style==SLIDER_STYLE_SIZE2)
drawSize2(pMe);
else if(pMe->m_style==SLIDER_STYLE_LTORD)
drawLTORD(pMe);
else if(pMe->m_style==SLIDER_STYLE_RTOLD)
drawRTOLD(pMe);
else if(pMe->m_style==SLIDER_STYLE_BTOT)
drawBTOT(pMe);
else if(pMe->m_style==SLIDER_STYLE_TTOB)
drawTTOB(pMe);
else if(pMe->m_style==SLIDER_STYLE_DTOB)
drawDTOB(pMe);
}
static void IGSlider_Stop(IGSlider * pMe)
...{
pMe->m_isActive=FALSE;
ISHELL_CancelTimer(pMe->m_pIShell,NULL,(void*)pMe);
}
各种效果的实现并不复杂,去google一下就能得到很多图像处理方法了。下面给出两个典型的处理,一是由暗变亮的实现,即第一个界面由亮变暗而第二个界面由暗变亮。
static void drawDTOB(IGSlider * pMe)
...{
ITransform *pTransform;
AEEBitmapInfo inf;
IBitmap *bmp;
AEETransformMatrix matrix;
int x,y;
pMe->tick++;
IBITMAP_SetTransparencyColor(pMe->pFirst,MAKE_RGB(0,0,0));
if(pMe->flag==0)
...{
IBITMAP_GetInfo(pMe->pFirst,&inf,sizeof(AEEBitmapInfo));
for(x=0;x<inf.cx;x++)
for(y=0;y<inf.cy;y++)
...{
NativeColor tc;
RGBVAL ocolor,ncolor;
IBITMAP_GetPixel(pMe->pFirst,x,y,&tc);
ocolor=IBITMAP_NativeToRGB(pMe->pFirst,tc);
ncolor = __transColor(pMe,ocolor,-50);
tc= IBITMAP_RGBToNative(pMe->pFirst,ncolor);
IBITMAP_DrawPixel(pMe->pFirst,x,y,tc,AEE_RO_COPY);
}
IDISPLAY_BitBlt(pMe->m_pIDisplay,pMe->m_Rect.x,pMe->m_Rect.y,pMe->m_Rect.dx,pMe->m_Rect.dy,pMe->pFirst,0,0,AEE_RO_TRANSPARENT);
IDISPLAY_Update(pMe->m_pIDisplay);
if(pMe->tick<pMe->m_delay)
ISHELL_SetTimer(pMe->m_pIShell,5,(PFNNOTIFY)drawDTOB,(void*)pMe);
else
...{
pMe->flag=1;
pMe->tick=1;
}
}
if(pMe->flag==1)
...{
IBITMAP_GetInfo(pMe->pSecond,&inf,sizeof(AEEBitmapInfo));
if(pMe->pTemp)
IBITMAP_Release(pMe->pTemp);
IBITMAP_CreateCompatibleBitmap(pMe->pSecond,&pMe->pTemp,inf.cx,inf.cy);
for(x=0;x<inf.cx;x++)
for(y=0;y<inf.cy;y++)
...{
NativeColor tc;
RGBVAL ocolor,ncolor;
IBITMAP_GetPixel(pMe->pSecond,x,y,&tc);
al
...{
ITransform *pTransform;
AEEBitmapInfo inf;
IBitmap *bmp;
AEETransformMatrix matrix;
int x,y;
pMe->tick++;
IBITMAP_SetTransparencyColor(pMe->pFirst,MAKE_RGB(0,0,0));
if(pMe->flag==0)
...{
IBITMAP_GetInfo(pMe->pFirst,&inf,sizeof(AEEBitmapInfo));
for(x=0;x<inf.cx;x++)
for(y=0;y<inf.cy;y++)
...{
NativeColor tc;
RGBVAL ocolor,ncolor;
IBITMAP_GetPixel(pMe->pFirst,x,y,&tc);
ocolor=IBITMAP_NativeToRGB(pMe->pFirst,tc);
ncolor = __transColor(pMe,ocolor,-50);
tc= IBITMAP_RGBToNative(pMe->pFirst,ncolor);
IBITMAP_DrawPixel(pMe->pFirst,x,y,tc,AEE_RO_COPY);
}
IDISPLAY_BitBlt(pMe->m_pIDisplay,pMe->m_Rect.x,pMe->m_Rect.y,pMe->m_Rect.dx,pMe->m_Rect.dy,pMe->pFirst,0,0,AEE_RO_TRANSPARENT);
IDISPLAY_Update(pMe->m_pIDisplay);
if(pMe->tick<pMe->m_delay)
ISHELL_SetTimer(pMe->m_pIShell,5,(PFNNOTIFY)drawDTOB,(void*)pMe);
else
...{
pMe->flag=1;
pMe->tick=1;
}
}
if(pMe->flag==1)
...{
IBITMAP_GetInfo(pMe->pSecond,&inf,sizeof(AEEBitmapInfo));
if(pMe->pTemp)
IBITMAP_Release(pMe->pTemp);
IBITMAP_CreateCompatibleBitmap(pMe->pSecond,&pMe->pTemp,inf.cx,inf.cy);
for(x=0;x<inf.cx;x++)
for(y=0;y<inf.cy;y++)
...{
NativeColor tc;
RGBVAL ocolor,ncolor;
IBITMAP_GetPixel(pMe->pSecond,x,y,&tc);
al
发表评论
-
手机开发平台指南、教程和资料介绍(转载)
2009-05-13 15:58 2621欢迎转载,转载请注明出处。作者:手机即信息 博客:http:/ ... -
Brew中的Module的实现方法
2009-05-13 14:36 1248Brew中的Module的实现方法: 【原创作者:sho ... -
Brew常见错误整理
2009-05-07 16:26 12881.用户是否可以将信息上传到开发商的服务器上来?用户传上来 ... -
BREW-教你设计用户界面
2009-04-24 16:14 1994这个书高通下的pdf, ... -
AppLoader的使用
2009-04-24 16:12 2696AppLoader是Brew Tools Suite3.0. ... -
程序在模拟器中的调试
2009-04-24 16:11 1247通过高通的FAQ知道:DBGPRINTF可以在vc的调试窗口和 ... -
程序在手机上的调试
2009-04-24 16:11 1106仍然通过高通的FAQ知道:DBGPRINTF的内容,当 ... -
浅谈ISocket的使用
2009-04-24 16:10 1822环境:brew sdk3.0中文版 + vc6.0 ... -
WEBOPT中http代理的设置
2009-04-24 16:09 1214原代码如下: awo[i].nId = WEBOPT_ ... -
强大的IWEB接口
2009-04-24 16:08 2127概述 本文着重介绍了在1.1SDK中引入的IWEB接口,以及 ... -
关于音频的播放
2009-04-24 16:06 1485先了解一下brew中可以 ... -
关于文件的读写
2009-04-24 16:05 2284brew中对文件操作需要 ... -
界面在手机和模拟器上显示的差异
2009-04-24 16:04 1756高通告诫我们:程序一定要多多在手机上调试。 刚入门时 ... -
在BREW中实现自己的GUI(8)-IWEB的封装
2009-04-13 17:43 2059封装IWeb其实并不算是GUI的范畴,但是一并说了罢。在BRE ... -
在BREW中实现自己的GUI(6)-单选框与复选框的实现
2009-04-13 17:40 1572还有一个常用的UI控件是单选框与复选框。可惜BREW也不提供, ... -
在BREW中实现自己的GUI(5)-滚动条的实现
2009-04-13 17:38 1296前面做IGStatic时我们用到了一个滚动条组件IGScrol ... -
在BREW中实现自己的GUI(4)-IGStatic的实现
2009-04-13 17:37 1615BREW中的IStatic可以方便地显示一个文本,但是它没有背 ... -
在BREW中实现自己的GUI(3)-做一个跑马灯的效果
2009-04-13 17:37 1685有时如果我们在应用中需要提供一个滚动的信息提示条(类似于页面上 ... -
在BREW中实现自己的GUI(2)-TabPane的实现
2009-04-13 17:35 1303同样是定义一下几个实体结构: //自定义菜单项type ... -
在BREW中实现自己的GUI(1)-图形化菜单的实现
2009-04-13 17:34 2245要实现的菜单比较简单,只支持列表视图,也就是IMenuCtl中 ...
相关推荐
在《BREW开发-海信(王宏兵).pdf》这本书中,作者深入探讨了BREW平台的游戏开发技术,包括如何使用BREW API进行图形、声音、输入控制等关键模块的编程,以及如何优化性能以适应有限的移动设备资源。 Wordware....
多态性在C语言中主要通过函数指针的动态绑定实现。当`RunPig`实例调用`eat`方法时,实际上执行的是`RunPig_eat`而不是`Pig_eat`,这是因为`pfn_eat`函数指针在构造函数`RunPig_Ctor`中被重定向到了`RunPig_eat`: `...
此外,线程同步对于多任务环境中的程序设计至关重要,书中的内容将指导读者如何在BREW中实现线程安全的代码。 3. BREW底层原理: BREW的底层实现涉及到操作系统接口、硬件抽象层以及设备驱动。书中的剖析部分会讲解...
深入BREW开发(1-8)+深度剖析BREW实现原理 BREW,全称为Binary Runtime Environment for Wireless,是由高通公司开发的一种操作系统平台,主要用于移动设备,尤其是早期的CDMA网络手机。它提供了一个用于开发和运行...
- **动态加载**:应用程序的部分代码和数据仅在需要时加载到内存中,以节省空间。 - **内存保护**:通过设置内存访问权限,防止应用程序之间或应用程序与系统之间的非法访问。 #### 四、BREW的应用程序生命周期管理...
在调试过程中,使用BREW模拟器可以快速测试应用功能和性能,调整代码优化用户体验。 8. 进阶开发: 高级BREW开发者还可以利用扩展API(如Multimedia、Location等)实现更多功能,如多媒体播放、位置服务等。此外,...
- 该应用程序利用了BREW平台提供的图形显示和用户输入功能,展示了Java应用程序在BREW平台上的运行效果。 #### 3. 技术细节 - **虚拟机的实现**: - 选择合适的内存管理策略,如堆空间的动态调整,以减少内存碎片...
Brew 3.1.5全套开发库安装文件,包括Brew SDK 3.1.5、SDK Tools、Tool Suite、Brew Addins
【BrewMP Windowed实现】是关于在Brew MP平台上构建具有窗口化界面的应用程序的知识点。Brew MP,全称Binary Runtime Environment for Wireless Mobile Platform,是由高通公司开发的一个强大的移动操作系统,主要...
在这个项目中,“基于brew开发的小程序-电话本”是一个毕业生的设计作品,它利用Brew技术创建了一个简单的电话本应用。虽然这个应用的界面可能不够美观,但其核心功能——电话本的保存和排序——已经实现,对于初学...
7. **自动化与脚本**:API文档还涵盖了如何在脚本和自动化流程中使用Homebrew,这对于系统管理员和开发者来说特别重要,他们可能需要批量安装或更新软件。 8. **安全与权限**:在Homebrew 3.0中,安全性得到了...
docker-brew-ubuntu-core, 在 Docker 中,官方导入的Ubuntu核心tarball用于使用 ;dr: git clone --single-branch https://github.com/tianon/docker-brew-ubuntu-core.git不打开请求来更新图像用于准备Ubuntu官方 ...
在实际开发过程中,BREW平台还提供了一些其他工具和库,如图形渲染库、音频处理库等,用于提升游戏的视觉和听觉效果。开发者可以利用这些工具来绘制飞机和障碍物的图像,创建背景音乐和音效,进一步增强游戏体验。 ...
在这个名为“brew的简单代码”的项目中,我们似乎有一个包含多个工程的压缩包,这可能是一个学习或实践`brew`使用的小型项目集合。 1. **什么是Homebrew(Brew)**: Homebrew是用于Mac OS X的开源包管理器,由Max...