一个非常酷的悬浮球菜单特效。
同时可以参考本例代码,学习一下怎么处理适应不同的dpi。
所有影响dpi显示的常数值,都做 *dpi 处理,以在不同的dpi下,显示对应的正确尺寸。

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=299;bottom=299;max=false;min=false;mode="popup";sysmenu=false;title=false;topmost=1)
winform.add({})
/*}}*/
import win.ui.layered
win.ui.layered(winform);
winform.show()
import godking.paint
var dpi = godking.paint.getDpi();
import inet.http
//下载图标,并缩小、切割到合适大小,保证图片质量的同时,加快渲染速度。
var imgs = inet.http.get("https://aardio.online/upload/files/20250207/1738894054.png");
var bmp = godking.paint.fromBitmap(imgs);
imgs = bmp.getThumbnailBuffer("*.png",100/*JPG质量*/,32*6/*宽度*/,32*6/*高度*/,true/*按比例*/,/*参数*/);
bmp.close();
var imgs = godking.paint.splitImage(imgs,6/*列数*/,6/*行数*/);
//处理菜单
var centerX,centerY = winform.width/2,winform.height/2; //logo中心点坐标
var popitem = false; // 是否已弹出项目
var mousepos = 0; // 用于记录当前鼠标位置处于哪个位置(0:项目圈外;1:项目圈内但未在项目上;2:logo圈内;其他:项目上)
var mouseitem = 0; // 用于记录当前鼠标位置处于哪个项目;0:未在项目上。其他:在项目上
var items = {}; //项目列表
for(i=1;12;1){ //项目数量,创建项目信息
..table.push(items,{
id = 200+i; //项目ID
text = "项目"++i; //项目文本
img = imgs[i]; //项目图片
path = null; //项目圆圈路径
x=0; //项目中心点坐标
y=0; //项目中心点坐标
trans=0; //透明度
})
}
var logo = {
r = 40*dpi; //圆圈半径
img = imgs[35]; //图片
imgsize = 60*dpi; //图片大小
}
var item = {
r = 26*dpi; //圆圈半径
distance = math.floor(11*dpi)*10; //项目中心点到logo中心点的距离
imgsize = 24*dpi; //图片大小
font = ::LOGFONT(name="宋体";h=12*dpi;color=0xFF888888 ); //项目文本字体
}
var getlen = function(x1,y1,x2,y2){
return math.sqrt((x1-x2)**2+(y1-y2)**2);
}
var paint = godking.paint(winform.width,winform.height,false/*自动刷新*/,false/*重绘背景*/);
paint.textAntiAlias = 0;
var drawitems = function(rotate){
paint.clear();
mouseitem = 0;
if popitem { //画项目
if items[[1]].trans===1 and items[[1]][["path"]] {
var maxlen = item.distance + item.r + 10*dpi ;
paint.fillEllipseF(centerX-maxlen ,centerY-maxlen ,maxlen*2/*宽度*/,maxlen*2/*高度*/,0x05FFFFFF);
}
for(n=1;#items;1){
if items[n].trans {
var color = gdi.ARGB(200,200,200,items[n].trans*255);
var px,py = items[n].x,items[n].y;
paint.drawLine(centerX,centerY,px,py,color,1/*线宽*/,1/*线型*/);
paint.drawLine(centerX,centerY,px+5,py+5,0x66DDDDDD,1/*线宽*/,1/*线型*/);
if items[n].path { //只有完全显示的情况下,透明度为1,才有path,才绘制阴影和填充颜色
// 画item阴影
var rectf = ::RECTF(px-item.r+5*dpi,py-item.r+5*dpi,item.r*2+5*dpi,item.r*2+5*dpi);
var path = paint.path(1/*0:交叉填充 1:全填充*/);
path.addEllipse(rectf.x,rectf.y,rectf.width,rectf.height);
var brush = paint.brush.pathGradientBrush(path /*路径对象*/);
brush.setCenterColor(0xFF000000);
brush.setSurroundColors({0x00000000});
brush.setCenterPoint(rectf.x+item.r,rectf.y+item.r);
paint.fillEllipseF(rectf /*绘制范围RECTF*/,brush);
brush.delete();
path.delete();
// 填充item
if mousepos === items[n].id {
mouseitem = n;
paint.fillPath(items[n].path /*路径*/,0xFFB0E0E6/*填充颜色或brush对象*/);
} else {
paint.fillPath(items[n].path /*路径*/,0xFFFFFAF0/*填充颜色或brush对象*/);
}
}
paint.drawEllipse(px-item.r,py-item.r,px+item.r,py+item.r,color,/*线宽*/,/*线型*/);
paint.drawImageCenter(px,py-8*dpi,item.imgsize,item.imgsize,items[n].img/*图片*/,items[n].trans/*透明度或图片属性*/,true/*保持比例*/);
paint.drawText(px-item.r,py+2*dpi,px+item.r,py+item.r,items[n].text,item.font,0/*格式*/,1/*水平*/,1/*垂直*/,false/*截短*/)
}
}
}
// 画logo阴影
var rectf = ::RECTF(centerX-logo.r-5*dpi,centerY-logo.r-5*dpi,logo.r*2+20*dpi,logo.r*2+20*dpi);
var path = paint.path(1/*0:交叉填充 1:全填充*/);
path.addEllipse(rectf.x,rectf.y,rectf.width,rectf.height);
var brush = paint.brush.pathGradientBrush(path /*路径对象*/);
brush.setCenterColor(0xFF000000);
brush.setSurroundColors({0x00000000});
brush.setCenterPoint(rectf.x+item.r,rectf.y+item.r);
paint.fillEllipseF(rectf /*绘制范围RECTF*/,brush);
brush.delete();
path.delete();
// 画logo
paint.fillEllipse(centerX-logo.r,centerY-logo.r,centerX+logo.r,centerY+logo.r,0xFFFFFAF0);
paint.drawEllipse( centerX-logo.r,centerY-logo.r,centerX+logo.r,centerY+logo.r,0xFFCCCCCC,/*线宽*/,/*线型*/);
paint.rotateCenter(rotate); //旋转画布角度
paint.drawImageCenter(centerX,centerY,logo.imgsize,logo.imgsize,logo.img/*图片*/,/*透明度或图片属性*/,true/*保持比例*/);
paint.resetTransform(); //恢复画布角度
winform.redrawBackground();//绘制窗口背景
}
var openitem = function(){
popitem = true;
var itemcount = #items;
var itemangle = 360/itemcount;
for(itemr=10;item.distance;10){
var offsetangle = 45*itemr/item.distance;
var trans = itemr/item.distance;
for(n=1;itemcount;1){
var angle = (offsetangle+n*itemangle)*3.1415926/180;
var lenx = itemr*math.cos(angle);
var leny = itemr*math.sin(angle);
items[n].x,items[n].y = centerX+lenx,centerY+leny;
items[n].trans = trans;
if itemr==item.distance {
var path = paint.path(1/*0:交叉填充 1:全填充*/);
path.addEllipse(items[n].x-item.r,items[n].y-item.r,item.r*2,item.r*2);
items[n].path = path;
} else {
if items[n].path {
items[n].path.delete();
items[n].path = null;
}
}
}
drawitems(itemr*360/item.distance);
win.delay(0);
}
}
var closeitem = function(){
var itemcount = #items;
var itemangle = 360/itemcount;
for(itemr=item.distance-10;0;-10){
var offsetangle = 45*itemr/item.distance;
var trans = itemr/item.distance;
for(n=1;itemcount;1){
var angle = (offsetangle+n*itemangle)*3.1415926/180;
var lenx = itemr*math.cos(angle);
var leny = itemr*math.sin(angle);
items[n].x,items[n].y = centerX+lenx,centerY+leny;
items[n].trans = trans;
if items[n].path {
items[n].path.delete();
items[n].path = null;
}
}
drawitems(itemr*360/item.distance);
win.delay(0);
}
popitem = false;
}
var tagTRACKMOUSEEVENT_leave = {
int cbSize=16;
int dwFlags=0x2; //_TME_LEAVE
int hwndTrack=winform.hwnd;
int dwHoverTime=0;
};
winform.wndproc = function(hwnd,message,wParam,lParam){
if (message== 0x201/*_WM_LBUTTONDOWN*/) {
if mousepos===2 { //拖动logo移动窗口
return winform.postMessage(0xA1/*_WM_NCLBUTTONDOWN*/,2,0);
} elseif mouseitem {
var n = mouseitem;
closeitem();
if winform.onMenuClick winform.onMenuClick(n);
}
} elseif (message == 0x2A3 /*_WM_MOUSELEAVE*/){
winform.TrackMouseEvent_LEAVE = false;
..win.peekPumpInputMessage();
if mousepos!==0 {
mousepos=0;
if popitem {
closeitem();
}
}
} elseif message == 0x200/*_WM_MOUSEMOVE*/ {
if !winform.TrackMouseEvent_LEAVE {
winform.TrackMouseEvent_LEAVE = true;
::Comctl32._TrackMouseEvent(tagTRACKMOUSEEVENT_leave);
}
var x,y = win.getMessagePos(lParam);
var len = getlen(x,y,centerX,centerY);
if len<logo.r {
if mousepos!==2 {//进入logo圈
mousepos=2;
if !popitem { //弹出项目
openitem();
}
} else {/*在logo圈内移动*/}
} elseif len<(item.distance+item.r) {
var pos = 1;
if len>(item.distance-item.r) {//进入项目范围,判断是否在项目上
if popitem {
for(i=1;#items;1){
if items[i].path {
if paint.isInPath( x,y, items[i].path/*path*/) {
pos = items[i].id;
break;
}
}
}
}
}
if mousepos!==pos { //进入项目圈
mousepos = pos;
drawitems(0);
} else {/*在项目圈内移动*/}
} else {
if mousepos!==0 {
mousepos=0;
if popitem {
closeitem();
}
}
}
}
}
winform.onDrawBackground = function(hdc,rc){
var gra = gdip.graphics(hdc);
gra.drawImageRect(paint.bitmap,0,0,winform.width,winform.height);
gra.delete();
}
drawitems(0);
winform.show();
winform.onMenuClick = function(n){
winform.msgbox("您点击了第"++n++"个按钮");
}
win.loopMessage();