如何在控件中列出已经插入的控件?(100分)

  • 主题发起人 主题发起人 caowei
  • 开始时间 开始时间
C

caowei

Unregistered / Unconfirmed
GUEST, unregistred user!
我要编写一个控件,它有一个属性Associate,
对应一个下拉的列表框,可以列出当前的窗口上
已经放置的所有控件,就象TTreeView的Images
属性对应的下拉框可以列出已经有的ImageList一样.
请问应该如何实现?
 
procedure TForm1.Button1Click(Sender: TObject);
var I:Integer;
begin
ListBox1.Items.clear;
for I:=0 to ComponentCount-1 do
ListBox1.Items.Add(Components.Name);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var I:Integer;
begin
ListBox1.Items.clear;
for I:=0 to ComponentCount-1 do
ListBox1.Items.Add(Components.Name+'('+Components.ClassName+')');
end;
 
我的意思是**编写**一个控件,
使用时,在窗口中加入这个控件以后,属性编辑窗中会出现一个Associate的
属性,它对应的就是已经出现的其它控件列表,我可以从中选择一个.
不知道我释放解释清楚了,如果还没有,
请参考WIN32属性页上的TUpDown控件,它就有一个类似的属性.
试着加入一个TEdit,一个TMemo,一个TPageControl等等,然后再加入一个
TUpDown,它的Associate属性就是我所希望的.
另外,TTreeView的Images属性也类似,只不过它对应的仅仅是ImageList控件.
看了半天TUpDown的源码,没明白怎么回事,请指点!谢谢!
 
回答其实是没错的,
关键是Delphi已经在default property editor实现了你要的功能,
(方法同唐)不过加上两句
//controllist:TList;
for I:=0 to Parent.ControlCount-1 do
if Parent.Controls <> Self
controlList.AddObject(Parent.Controls.Name,Parent.Controls);


只需要将publish 设成TWincontrol 就可以实现你要的功能。
注意要加上接管函数Notification,当你关联的控件被删除时,你需要
对它做一些处理

TCustomUpDown = class(TWinControl)
private
FArrowKeys: Boolean;
FAssociate: TWinControl;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
...
property Associate: TWinControl read FAssociate write SetAssociate;
end;



procedure TCustomUpDown.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FAssociate) then
if HandleAllocated then
begin
SendMessage(Handle, UDM_SETBUDDY, 0, 0); //windows系统消息,解除updown
FAssociate := nil;
end;
end;
 
看来需要自己定义一个property editor了. 继承一个TSetProperty.
 
看来这个问题还是比较麻烦的.
我原来设计的目的是这样的:
我要做一个能够在鼠标移入时从左向右出现的按钮,
鼠标移出时它再慢慢的从右向左消失.按钮是用Image实现
我的初步方法是MouseEnter时,用CopyRect:
canvas.CopyRect(rect(intLeft,intTop,intRight,intBottom),
valBitmap.Canvas,
rect(0,0,valBitmap.Width,valBitmap.Height));
其中intLeft,intTop,intRight,intBottom是计算出来当前要显示的部分
比如对于一个120*40的图象,分12次显示,那么第一次显示宽度在110到120之间的图象,
第二次显示100到120之间的部分...
问题在于MouseLeave的时候,必须恢复原来的背景,我仍想用CopyRect函数,但是不行
canvas.CopyRect(rect(0,0,valBitmap.Width,valBitmap.Height),
valSaveBitmap.Canvas,
rect(0,0,valBitmap.Width,valBitmap.Height));
可以工作,但是valSaveBitmap怎么得到呢?我是用下面的代码:
valSaveBitmap.Canvas.CopyRect(rect(0,0,valBitmap.Width,valBitmap.Height),
TForm(Parent).canvas,rect(Left,Top,valSaveBitmap.Width,valBitmap.Height));
显然是有问题的. Parent不一定是TForm,可能是TPanel或者TImage等等,不一定有Canvas的属性.
所有运行时会出错.
后来我想在控件创建的时候,再new一个TImage,然后给它赋值,通过改变TImage的Left来实现
从左向右的显示.但这样要求TImage的Parent是我所创建的控件,可是它是从TGraphicControl
派生的. 之所以问如题的问题,是后来我实在没有办法了,就想干脆我找出已经有的控件
作为TImage的Parent算了. 真是一个其笨无比的方法.
请大家帮忙看看有什么办法可以解决这个问题吧! 我太笨了,呜呜....
谢谢大家帮忙了.....
 
你可以使用GetParentForm得到控件所在的Form,
这样就可以正确得到valsavebitmap
function GetParentForm(Control: TControl): TCustomForm;
begin
while Control.Parent <> nil do Control := Control.Parent;
Result := nil;
if Control is TCustomForm then Result := TCustomForm(Control);
end;
 
谢谢jiangtao和前面几位大侠!
可是如果我是在一个PANEL上放置的这个控件,即使得到了所在的Form也没有什么用啊!
因为最终的目的是要在背景上画完图以后还可以恢复出原来的背景.
有没有更好的办法呢?
 
你可以得到背景的HDC,

具体如下
aDC:HDC;
aCanvas:=TCanvas.Create;

aDC:=GetDC(control.Parent);
//aCanvas.Handle:=aDC;
//保存aCanvas的背景即可
//其实用BitBlt 更快,不需要用Canvas.CopyRect


bitblt(valSaveBitmap.Canvas.handle,0,0,valBitmap.Width,valBitmap.Height,
aDc,Parent.Left,Parent.Top,SRCCOPY);

//aCanvas.Free;
Realease(aDC);

function BitBlt(DestDC: HDC; X, Y, nWidth, Height: Integer; SrcDC: HDC;
XSrc, YSrc: Integer; Rop: LongInt): Bool;

 
我这有一个DELPHI的编译器的控件,(从新写了一遍DELPHI)
应该对你有用,要的话通知我!
 
不是控件,是DEMO,从哪拉回来的我给忘记了:)
 
哈, 和我的半透明控件有一样的功能, 可以慢慢拉出再慢慢缩回. 嘻嘻.

可我征求测试者到现在还没找到一个 :(

我就是用bitblt保存背景图象的. 不过为了防止背景图象中有动画成分, 我的控件
每次刷新时都重读背景再重新计算颜色再画上去. 自从我改了颜色计算的算法之后
刷新速度是达到要求了, 可还存在一些小bug, 最大的问题是两个半透明控件相交时
相交部分不正确.另一个问题是我设计的是panel, 可现在里面放不进其他东西 :(
不过作为一个弹出菜单来用效果还不错.

顺便说一句, 我是通过当前控件的Parent.PaintTo方法重画窗口来取得背景图象的.
(先用IntersectClipRect使paintto只重画被我控件遮住的背景图, 另外, 当然是
paintto到一个TBitmap中而不是当前屏幕上).

parent.paintto时当前控件的WM_PAINT事件中不做任何事直接返回, 这样就能得到
原始的背景图象了.(对了, 当前控件建立时一定要override createparams, 并在
params中加上EX_TRANSPARENT, 不然parent.paintto时会把这块区域擦空).

 
可以用一个TImage作, 选择你已有控件的parent作为Image的parent, 不要改变
Image的Left, 改变Image.width
 
多人接受答案了。
 
后退
顶部