!!!!!!winamp播放列表的拖放!!!(200分)

  • 主题发起人 YuanGuo2001
  • 开始时间
Y

YuanGuo2001

Unregistered / Unconfirmed
GUEST, unregistred user!
winamp那个播放列表的拖放是怎么实现的?
任意选择列表中的文件(shift 和ctrl),
开始向下拉,就马上可以使‘已经选择的文件’
的位置发生变化。
我研究了一下,它与一般的listbox的拖放不太一样,
我参考以前的代码,这些代码是通过获取当前节点的位置,
和目标节点的位置来实现拖放的,跟winamp不太一样,
因为winamp被拖放的文件可以多个,而且”即拉即可以看见效果“。
我不知道winamp是怎么实现的?或者winamp本来就不用拖放的,可能是通过
mousedown,move,up事件来实现的。
誰做过类似功能的???添代码讲原理都行!!!!!!!
 
大家讲讲思路啊,如果可行,马上给分。
 
呵呵,是不是我讲的不清楚??
 
用listbox可以

拖动时,swap位置,一层一层顶
 
to windea:
这个我也知道啊,请看清题目。谢谢
在线等候……………………
 
应该是mousedown记录下所选的item,
MouseMove的时候就swapItem.
 
用spy++可以看到winamp中并没有真正的列表框,都是画出来的。
位置都要自己计算,用FormMouseUp/FormMouseDown
 
同意月满西楼, WinAmp应该是自己画的
其实用下面的代码也可以用ListBox来摸拟这样的操作, 但是拖动快了的时候
界面闪动就比较明显了。
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
ListBox1: TListBox;
procedure ListBox1MouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure ListBox1MouseUp(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure ListBox1MouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
private
{ Private declarations }
Fbegin
Move: Boolean;
FSelected: Integer;
public
{ Public declarations }
end;


var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ListBox1MouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
begin

Fbegin
Move := True;
FSelected := ListBox1.ItemIndex;
end;


procedure TForm1.ListBox1MouseUp(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
begin

Fbegin
Move := False;
end;


procedure TForm1.ListBox1MouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
var
FCurIndex: Integer;
procedure SwapIndex(A, B: Integer);
begin

if A <> B then

ListBox1.Items.Exchange(A, B);
end;

begin

if Fbegin
Move then

begin

FCurIndex := ListBox1.ItemAtPos(Point(X, Y), True);
if FCurIndex >= 0 then

begin

SwapIndex(FSelected, FCurIndex);
FSelected := FCurIndex;
ListBox1.ItemIndex := FSelected;
end;

end;

end;


end.

 
拖动一个没问题,拖动多个应该也差不多吧? 只是算法复杂一些,要考虑的东西也多了
另外,上面的代码只是随手写的,没作充分测试,刚刚乱拖一气发现其他ITEM也变了
 
to 月满西楼:谢谢,自己重画难度太大了吧??有代码吗?
to xianjun:
代码有点用处,跟我原先写的实现拖放功能的代码差不多!(贴出来),
我觉得实现多个文件就不是那么简单了,您看代码里都是真的当前选中的项目(ListBox1.ItemIndex )
不知道您能否解决多个文件??
procedure TFrmList.LBPlayListMouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
begin

LBPlayList.begin
drag(false);
end;


procedure TFrmList.LBPlayListDragOver(Sender, Source: TObject;
X,
Y: Integer;
State: TDragState;
var Accept: Boolean);
var
aPoint:TPoint;
begin

aPoint.x:=x;
aPoint.y:=y;
if (source=Sender) and (LBPlayList.ItemAtPos(apoint,true)<>-1)
and (LBPlayList.itematpos(apoint,true)<>LBPlayList.itemindex) then

accept:=true
else
accept:=false;
end;


procedure TFrmList.LBPlayListDragDrop(Sender, Source: TObject;
X,
Y: Integer);
var
aPoint:TPoint;
begin

aPoint.x:=x;
aPoint.y:=y;
LBPlayList.items.Exchange(LBPlayList.itemindex,LBPlayList.itematpos(aPoint,true));
end;
 
选中多个也可以用下面的代码实现,但效果不太好, 闪动比较厉害:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
ListBox1: TListBox;
CheckBox1: TCheckBox;
procedure ListBox1MouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
procedure CheckBox1Click(Sender: TObject);
private
{ Private declarations }
FSelected: array of Integer;
procedure GetSelected;
public
{ Public declarations }
end;


var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.GetSelected;
var
I: Integer;
begin

for I := 0 to ListBox1.Count - 1do

begin

if ListBox1.Selected then

begin

SetLength(FSelected, Length(FSelected) + 1);
FSelected[High(FSelected)] := I;
end;

end;

end;


procedure TForm1.ListBox1MouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
var
I: Integer;
FCurIndex: Integer;
procedure SwapIndex(A, B: Integer);
begin

if A <> B then

ListBox1.Items.Exchange(A, B);
end;

begin

if CheckBox1.Checked then

begin

FCurIndex := ListBox1.ItemAtPos(Point(X, Y), True);
if FCurIndex < FSelected[0] then

begin

for I := High(FSelected)do
wnto 0 do

begin

ListBox1.Items.Exchange(FCurIndex, FSelected);
FSelected := FSelected - (FSelected[0] - FCurIndex);
end;

end
else
if FCurIndex > FSelected[High(FSelected)] then

begin

for I := 0 to High(FSelected)do

begin

ListBox1.Items.Exchange(FCurIndex, FSelected);
FSelected := FSelected + (FCurIndex - FSelected[High(FSelected)]);
end;

end;

for I := 0 to High(FSelected)do

ListBox1.Selected[FSelected] := True;
end;

end;


procedure TForm1.CheckBox1Click(Sender: TObject);
begin

if CheckBox1.Checked then

GetSelected;
end;


end.

 
to xianjun:
有几个错误,1.如果已经选择了多个文件,想拖动的时候又只选中一个文件,
2. listout of index
在这个语句FSelected := FSelected - (FSelected[0] - FCurIndex);
我回头再仔细看看,现在我对数组都有点忘了,水平不行了。
总体感觉效果不好,哈哈。
 
不使用ListBox的方法,总之为了不闪烁必须增加不少工作量。实在写的累,不加注解了,
应该没有大的问题。
interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Math;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure FormMouseUp(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
procedure FormMouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
private
{ Private declarations }
FMouseDown : Boolean;
FFocused : integer;
function GetSelected(Index: integer): Boolean;
procedure SetSelected(Index: integer;
const Value: Boolean);
public
{ Public declarations }
FStrings : TStringList;
property Selected[Index: integer]: Boolean read GetSelected write SetSelected;
end;


var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin

FStrings := TStringList.Create;
FMouseDown := False;
FFocused := -1;
with FStringsdo
begin

AddObject('红藕香残玉簟秋', TObject(0));
AddObject('轻解罗裳', TObject(0));
AddObject('独上兰洲', TObject(0));
AddObject('云中谁寄锦书来', TObject(0));
AddObject('雁字回时', TObject(0));
AddObject('月满西楼', TObject(0));
AddObject('花自飘零水自流', TObject(0));
AddObject('一种相思', TObject(0));
AddObject('两处闲愁', TObject(0));
AddObject('此情无计可消除', TObject(0));
AddObject('才下眉头', TObject(0));
AddObject('却上心头', TObject(0));
end;

end;



procedure TForm1.FormDestroy(Sender: TObject);
begin

FreeAndNil(FStrings);
end;



procedure TForm1.FormPaint(Sender: TObject);
var
i : integer;
begin

with Canvasdo
begin

Brush.Color := clBlack;
Font.Color := clGreen;
FillRect(ClientRect);
for i:=0 to FStrings.Count-1do
begin

if Integer(FStrings.Objects)=0 then

Brush.Color := clBlack
else

Brush.Color := clBlue;
FillRect(Rect(0,i*40,ClientWidth,(i+1)*40));

TextOut(0, i*40, FStrings);
end;

end;

end;



procedure TForm1.FormMouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
var
i, Index : integer;
rc : TRect;
begin

if Button<>mbLeft then
Exit;
Index := Y div 40;
if Index>=FStrings.Count then
Exit;
FMouseDown := True;
if ssCtrl in Shift then
begin

Selected[Index] := not Selected[Index];
rc := Rect(0, Index*40, ClientWidth, (Index+1)*40);
InvalidateRect(Handle, @rc, False);
FFocused := Index;
end
else
if ssShift in Shift then
begin

for i:=0 to FStrings.Count-1do

if Selected then
begin

Selected := False;
rc := Rect(0, i*40, ClientWidth, (i+1)*40);
InvalidateRect(Handle, @rc, False);
end;

if FFocused<0 then
begin

for i:=0 to Indexdo

Selected := True;
rc := Rect(0, 0, ClientWidth, (Index+1)*40);
InvalidateRect(Handle, @rc, False);
end
else
begin

if Index>=FFocused then
begin

for i:=FFocused to Indexdo

Selected := True;
rc := Rect(0, FFocused*40, ClientWidth, (Index+1)*40);
end
else
begin

for i:=FFocuseddo
wnto Indexdo

Selected := True;
rc := Rect(0, Index*40, ClientWidth, (FFocused+1)*40);

end;

InvalidateRect(Handle, @rc, False);
end;

FFocused := Index;
end
else
begin

if Selected[Index]=False then
begin

for i:=0 to FStrings.Count-1do

if Selected then
begin

Selected := False;
rc := Rect(0, i*40, ClientWidth, (i+1)*40);
InvalidateRect(Handle, @rc, False);
end;

Selected[Index] := True;
rc := Rect(0, Index*40, ClientWidth, (Index+1)*40);
InvalidateRect(Handle, @rc, False);
end;

FFocused := Index;
end;

end;


function TForm1.GetSelected(Index: integer): Boolean;
begin

if Index>=FStrings.Count then

Raise Exception.Create('Error:Index out of bounds');
Result := (Integer(FStrings.Objects[Index])<>0);
end;



procedure TForm1.SetSelected(Index: integer;
const Value: Boolean);
begin

if Index>=FStrings.Count then

Raise Exception.Create('Error:Index out of Bounds');
if Value then

FStrings.Objects[Index] := TObject(1)
else

FStrings.Objects[Index] := TObject(0);

end;



procedure TForm1.FormMouseUp(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState;
X, Y: Integer);
var
i, NewFocus : integer;
rc : TRect;
begin

FMouseDown := False;
NewFocus := Y div 40;
if NewFocus>=FStrings.Count then
Exit;
if (NewFocus=FFocused) and not(ssCtrl in Shift) and
not(ssShift in Shift) then
begin

for i:=0 to FStrings.Count-1do

if (Selected) and (i<>FFocused) then
begin

Selected := False;
rc := Rect(0, i*40, ClientWidth, (i+1)*40);
InvalidateRect(Handle, @rc, False);
end;

FFocused := NewFocus;
Selected[FFocused] := True;
rc := Rect(0, NewFocus*40, ClientWidth, (NewFocus+1)*40);
InvalidateRect(Handle, @rc, False);
end;


end;



procedure TForm1.FormMouseMove(Sender: TObject;
Shift: TShiftState;
X,
Y: Integer);
var
NewFocus, i, Delta : integer;
rc : TRect;
begin

if not FMouseDown then
Exit;
NewFocus := Y div 40;
if NewFocus=FFocused then
Exit;
Delta := NewFocus - FFocused;
if Delta<0 then
begin

for i:=0 to FStrings.Count-1do

if Selected then
begin

Delta := Max(-i,Delta);
Break;
end;

if Delta=0 then
Exit;

for i:=0 to FStrings.Count-1do

if Selected then
begin

FStrings.Move(i, i+Delta);
rc := Rect(0, i*40, ClientWidth, (i+1)*40);
InvalidateRect(Handle, @rc, False);
rc := Rect(0, (i+Delta)*40, ClientWidth, (i+Delta+1)*40);
InvalidateRect(Handle, @rc, False);
end;

end
else
begin

for i:=FStrings.Count-1do
wnto 0do

if Selected then
begin

Delta := Min(FStrings.Count-1-i, Delta);
end;

if Delta=0 then
Exit;

for i:= FStrings.Count-1do
wnto 0do

if Selected then
begin

FStrings.Move(i, i+Delta);
rc := Rect(0, i*40, ClientWidth, (i+1)*40);
InvalidateRect(Handle, @rc, False);
rc := Rect(0, (i+Delta)*40, ClientWidth, (i+Delta+1)*40);
InvalidateRect(Handle, @rc, False);
end;

end;

FFocused := FFocused + Delta;
end;


end.

 
1、是因为按下CheckBox时就把各个选中的ITEM记录了,此时再加减ITEM并不反应到数组
里面,所以可能会出错。
2、出错的原因就是1所说的
效果确实不好,特别是要经常操作的话,建议不用LISTBOX,闪得太厉害了
而且跟winamp的操作也有所不同
 
to 月满西楼:
的确精彩,高手啊。
代码能够实现了,回头慢慢看,以后我写出类似winamp的播放列表的操作功能
我再把全部代码贴上来。
to xianjun:我以后解决了这个问题再把代码贴上来。谢谢了。
感谢所以回答本题的朋友,给分了。
 
我也看过了,高手! 谢谢!
 
顶部