WINAMP那样的界面如何实现:关于磁性窗体(50分)

  • 主题发起人 主题发起人 魏启明
  • 开始时间 开始时间

魏启明

Unregistered / Unconfirmed
GUEST, unregistred user!
问:
如何建立一个象 WINAMP 那样 副窗体 可跟随 副窗体 移动的窗体,
即当两个窗口靠近时自动合为一体;
拖动 副窗体 可使之脱离 副窗体 ;
具体请对照 WINAMP 试试看;
知道WINAMP吧,就是哪个mp3播放器;
 
前两天论坛刚刚有高手编写了这个控件
下载可以到这里:http://www.torry.net/vcl/forms/effects/zmagnetic.zip
 
魏启明:请自己提前或结束你的帖子,谢谢合作。
 
不好意思:
我这儿上不了国际网;包刮港澳台的站点;
 
国内站长主页:
http://mantousoft.51.net/delphi_work/work_tmagnetic.php
 
to:xk
不好意思,几天未上网!
我已下了http://mantousoft.51.net/delphi_work/work_tmagnetic.php
但没说明不会用;
请赐教!
谢谢
 
哦,这个问题我问过,
这是别人给我的答案:
资料我贴给你,美女在哪儿啊?
---------------------------
winamp的用户都知道,winamp的播放列表或均衡器在被移动的时候,仿佛会受到一股磁力,
每当靠近主窗口时就一下子被“吸附”过去,自动沿边对齐。我想让我的winamp插件也具备
这种奇妙特性,于是琢磨出了一种“磁化”窗口的方法。该法适用于delphi的各个版本。为
了演示这种技术,请随我来制作一个会被winamp“吸引”的样板程序。
  先新建一应用程序项目,把主窗口form1适当改小些,并将borderstyle设为bsnone。放
一个按钮元件,双击它并在onclick事件中写“close;”。待会儿就按它来结束程序。现在
切换到代码编辑区,定义几个全局变量
var
form1: tform1;
//“磁性”窗口
lastx, lasty: integer;
//记录前一次的坐标
winamprect:trect;
//保存winamp窗口的矩形区域
hwnd_winamp:hwnd;
//winamp窗口的控制句柄

接着编写form1的onmousedown和onmousemove事件。
procedure tform1.formmousedown(sender: tobject;
button:tmousebutton;
shift: tshiftstate;
x, y: integer);
const
classname = 'winamp v1.x';
//winamp主窗口的类名
//如果改成classname=‘tappbuilder’,你就会发现连delphi也有引力啦!
begin
//记录当前坐标
lastx := x;
lasty := y;
//查找winamp
hwnd_winamp := findwindow(classname,nil);
if hwnd_winamp>0 then
//找到的话,记录其窗口区域
getwindowrect(hwnd_winamp, winamprect);
end;

procedure tform1.formmousemove(sender: tobject;
shift:
tshiftstate;
x, y: integer);
var
nleft,ntop:integer;
//记录新位置的临时变量
begin
//检查鼠标左键是否按下
if hiword(getasynckeystate(vk_lbutton)) > 0 then
begin
//计算新坐标
nleft := left + x - lastx;
ntop := top + y - lasty;
//如果找到winamp,就修正以上坐标,产生“磁化”效果
if hwnd_winamp>0 then
magnetize(nleft,ntop);
//重设窗口位置
setbounds(nleft,ntop,width,height);
end;
end;
别急着,看magnetize()过程,先来了解一下修正坐标的原理。根据对winamp实现效果的观
察,我斗胆给所谓“磁化”下一个简单的定义,就是“在原窗口与目标窗口接近到某种预定
程度,通过修正原窗口的坐标,使两窗口处于同一平面且具有公共边的过程”。依此定义,
我设计了以下的“磁化”步骤。第一步,判断目标窗口(即winamp)和我们的form1在水平及
垂直方向上的投影线是否重叠。“某方向投影线有重叠”是“需要进行坐标修正”的必要
非充分条件。判断依据是两投影线段最右与最左边界的差减去它们宽度和的值的正负。第
二步,判断两窗口对应边界是否靠得足够近了。肯定的话就让它们合拢。
好了,下面便是“神秘”的magnetize过程了……
procedure tform1.magnetize(var nl,nt:integer);
//内嵌两个比大小的函数
function min(a,b:integer):integer;
begin
if a > b then
result:=b else
result:=a;
end;
function max(a,b:integer):integer;
begin
if a < b then
result:=b else
result:=a;
end;
var
h_overlapped,v_overlapped:boolean;
//记录投影线是否重叠
tw,ww,wh:integer;
//临时变量
const
magneticforce:integer=50;
//“磁力”的大小。
//准确的说,就是控制窗口边缘至多相距多少像素时需要修正坐标
//为了演示,这里用一个比较夸张的数字——50。
//一般可以用20左右,那样比较接近winamp的效果
begin
//判断水平方向是否有重叠投影
ww := winamprect.right - winamprect.left;
tw := max(winamprect.right,nl+width) - min(winamprect.left,nl);
h_overlapped := tw<=(width+ww);
//再判断垂直方向
wh := winamprect.bottom - winamprect.top;
tw := max(winamprect.bottom,nt + height) - min(winamprect.top,nt);
v_overlapped := tw<=(height + wh);
//足够接近的话就调整坐标
if h_overlapped then
begin
if abs(winamprect.bottom - nt)   
else
if abs(nt + height - winamprect.top)   
end;
if v_overlapped then
begin
if abs(winamprect.right - nl)   
else
if abs(nl + width - winamprect.left)   
end;
end;
  
 
我的控件,要不给我也来5分:)
我的源代码写了注释的呀,还有,那么完整的例子,不会看不懂吧,有什么真的不懂得,
问我,一点答复
mantousoft@sina.com
感谢!
 
多人接受答案了。
 
后退
顶部