200分求解:超过1000000(或低于-1000000)的数个坐标点用CreatePolygonRgn创建区域句柄为什么失败!(200分)

  • 主题发起人 主题发起人 aizb
  • 开始时间 开始时间
A

aizb

Unregistered / Unconfirmed
GUEST, unregistred user!
procedure TForm1.Button1Click(Sender: TObject);
Var A:Array of TPoint;
Len:Integer;
rgn:THandle;
Buffer: array[0..255] of Char;
S: string;
begin
SetLength(a,4);
A[0].X:=-500000;
A[0].y:=-500000;
A[1].X:=-500000;
A[1].y:=500000;
A[2].X:=500000;
A[2].y:=-500000;
A[3].X:=500000;
A[3].y:=500000;
rgn:=CreatePolygonRgn(a,4,0);
//这里创建区域句柄失败!
//如果用PolygonRgn也会失败!
SetLength(S, 256);
Len:=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, GetLastError, 0, Buffer,
SizeOf(Buffer), nil);
while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
SetString(s, Buffer, Len);
ShowMessage(s+IntToStr(rgn));
//这里显示的是参数错误!
end;
 
不会吧,我在d5上通过的,返回的也是有效句柄啊
 
请试:
procedure TForm1.Button1Click(Sender: TObject);
Var
A:Array[0..128] of TPoint;

Len:Integer;
rgn:THandle;
Buffer: array[0..255] of Char;
S: string;
begin
//SetLength(a,4);
A[0].X:=-500000;
A[0].y:=-500000;

A[1].X:=-500000;
A[1].y:=500000;

A[2].X:=500000;
A[2].y:=-500000;

A[3].X:=500000;
A[3].y:=500000;

rgn:=CreatePolygonRgn(a,4,ALTERNATE);

SetLength(S, 256);
Len:=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, GetLastError, 0, Buffer,
SizeOf(Buffer), nil);
while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
SetString(s, Buffer, Len);
ShowMessage(s+IntToStr(rgn));
//这里显示的是:操作成功完成。3724806690

end;
注意:CreatePolygonRgn第一个参数必须是CONST,不能是变长数组;fnPolyFillMode
不能为0。
HRGN CreatePolygonRgn(
CONST POINT *lppt, // pointer to array of points
int cPoints, // number of points in array
int fnPolyFillMode // polygon-filling mode
);
 
to Huzzz:
不一定是定长数组:只要是指向定长数组的指针就可以了!用下面的方法应该也是对的,但是结果一样!
还有,有时返回正确,但用DeleteObject函数确无法删除句柄,所以当画的对象太多的时候,就会系统资源不足!
还有,在这种情况下,就算创建句柄成功也不能通过PaintRgn函数来绘出区域,也不能通过Canvas.Polygon来绘区域,
提示也是参数错误,或者绘出来是乱的!

procedure TForm1.Button1Click(Sender: TObject);
type
PPoints = ^TPoints;
TPoints = array[0..0] of TPoint;
Var A:Array of TPoint;
Len:Integer;
rgn:THandle;
Buffer: array[0..255] of Char;
S: string;
begin
SetLength(a,4);
A[0].X:=-500000;
A[0].y:=-500000;
A[1].X:=-500000;
A[1].y:=500000;
A[2].X:=500000;
A[2].y:=-500000;
A[3].X:=500000;
A[3].y:=500000;
rgn:=CreatePolygonRgn(PPoints(@a)^,4,0);
Canvas.Polygon();
try
//这里创建区域句柄失败!
//如果用PolygonRgn也会失败!
SetLength(S, 256);
Len:=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, GetLastError, 0, Buffer,
SizeOf(Buffer), nil);
while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
SetString(s, Buffer, Len);
ShowMessage(s+IntToStr(rgn));
//这里显示的是参数错误!
finally
DeleteObject(rgn);
end;
end;
 
>>不一定是定长数组:只要是指向定长数组的指针就可以了
这话我同意。

但PPoints(@a)^是没有用的,CONST常量参数本身传递的就是地址,最终还是把A传递
了。如果你常用指针你就会明白,对于指针操作,PPoints(@a)^是没有用的,指针跟
数据类型无关,你最终传递的仍是变长数组A的指针。
因此,你还是老老实实地声明:A:Array[0..3] of TPoint;
另外,我已经跟你说了(我不想再提):fnPolyFillMode 不能为0。

按理说变长数组应该也是可以的,但实践证明,WINDOWS API中CONST常量不能使用
DELPHI的变长数组(好像C++中也没有变长数组这一类型),如果用它也不会出错,
但结果往往是错误的(感觉上就只传了一个长度为0的数组)。

画的对象多当然会资源不足,要知道GDI资源是非常宝贵的,尽量省着用,用完立即
释放。
 
我认为不是PPoints(@a)^的问题,这个值是指向定长数组的第一个元素的指针,

而就算定义成定长数组,传递的也是这个定长数组的第一个元素的指针,只要把这个指针传递给API,
再传递一个元素个数n给API,就可以了,至于这第一个元素所在的数组是动态数组或者静态数组都不重要了,
因为API是从内存中从第一个元素开始n个数据,这个你看看Canvas的Polyrgn方法就知道了(这个方法是参数就是Const):
procedure TCanvas.Polygon(const Points: array of TPoint);
begin
Changing;
RequiredState([csHandleValid, csPenValid, csBrushValid]);
Windows.Polygon(FHandle, PPoints(@Points)^, High(Points) + 1);
Changed;
end;
好象在C中的确没有变长数组这个概念,在Delphi中有。
因为在C中的变量可以在代码中任何地方声明的,所以不需要变长数组,
如果Delphi也没有变长数组,那必须在每个单元的开始时声明一个
相当大的定长数组(不知道要耗多少资源)

画的对象多了,如果适时释放资源(每使用完一个资源就释放一个),就不应该造成资源不足。
 
我都懒得说你了。
 
我无法接受答案!
 
你自己试试就知道,TCanvas.Polygon如果你也那样传递数组,不会报错,但什么也
画不出来!
没有为什么,事实说明一切,你去试试吧。也许你应该去微软公司。
 
另:你可以请版主收回分数。
 
>注意:CreatePolygonRgn第一个参数必须是CONST,不能是变长数组;fnPolyFillMode不能为0。
>TCanvas.Polygon如果你也那样传递数组,不会报错,但什么也画不出来。

我同意huzzz朋友的观点,不知这位aizb朋友能否接受。

其实不就是定义一个静态数组的问题么?
 
to:卷起千堆雪tyn:
如果我有数千个区域需要画(我做的是GIS系统),而每个区域又都是不定长的,是不是需要按最长的点个数
创建一个静态数组?而且这个静态数组必须在程序中定死长度(如果是C也许就好了),因为必须预先定义。
如果我的程序用到一块地图的区域点数超过了这个长度怎么办?所以静态数组是满足不了我的要求。
其实上面的问题有两点:
第一:fnPolyFillMode不能为0。应该是1或2或3。我以为常量ALTERNATE是0,其实我在程
序中都是用ALTERNATE。
第二:的确象我所说的那样传递第一个元素的指针就可以了,不过PPoints(@a)^并不能达到要求,
而必须是PPoints(@a[0])^(在Windows98中两种都可以用)。请看下面的两段代码:
procedure TForm1.Button1Click(Sender: TObject);
Var A:Array of TPoint;
i,iCount:Integer;
begin
iCount:=100;
SetLength(a,iCount);
Randomize;
For i:=0 to iCount-1 do
begin
A.x:=random(Width);
A.y:=random(Height);
end;
windows.polygon(Canvas.Handle,PPoints(@a[0])^,iCount);
end;

procedure TForm1.Button2Click(Sender: TObject);
Var A:Array of TPoint;
i,iCount:Integer;
RGN:HRGN;
begin
Canvas.Brush.Color:=clRed;
iCount:=100;
SetLength(a,iCount);
Randomize;
For i:=0 to iCount-1 do
begin
A.x:=random(Width);
A.y:=random(Height);
end;
SetLastError(0);
RGN:=CreatePolygonRgn(PPoints(@a[0])^,iCount,ALTERNATE);
if GetLastError<>0 then
RaiseLastWin32Error;
try
if RGN<>0 then
PaintRgn(Canvas.Handle,RGN);
finally
DeleteObject(RGN);
end;
end;
这两段代码测试正确。
是该结束问题了。
不过问题还没有解决:坐标如果超大就会有问题。比如坐标超过1000000。如果有兴趣请继续讨论,我会在其他地方给分。
 
>>如果我的程序用到一块地图的区域点数超过了这个长度怎么办
超过了你也许要考虑优化点数据把不需要的点删除(如重叠点,肉眼看不出来的)

>>坐标如果超大就会有问题
哈哈,也许这个问题你可以看看:

http://www.delphibbs.com/delphibbs/dispq.asp?lid=566561
问题:矢量画多边形比例太大时出现异常
分类:图形图象 ( 版主:卷起千堆雪tyn, menxin )

另外我觉得你有点奇怪,你为什么要CreatePolygonRgn?直接用Polygon或PolyPolygon
不行吗?CreatePolygonRgn和 DeleteObject这不是多余浪费。
 
1、优化肯定是有!而且必要,问题是无法预知某个地图的元素的点个数的最大数。
2、CreatePolyRgn函数其实主要是用来作一些判断的,比如判断这个区域是否与屏幕有相交
,如果没有相交,就不画出来了。或者判断点是否在区域内。或者合并区域。
 
>>CreatePolyRgn函数其实主要是用来作一些判断的
奉劝你一句,不要用CreatePolyRgn来作判断,而是自己写判断函数,否则你可能会后悔的。
具体怎么做我不知道。坐标太大的问题也许只能裁剪,但难度较大,非一日之功。
 
后退
顶部