关于CreatePolygonRgn函数(200分)

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

cAkk

Unregistered / Unconfirmed
GUEST, unregistred user!
请看下面的代码,应该在窗口上画出一个正方形出来,但是却画满了整个窗口:
procedure TForm1.Button1Click(Sender: TObject);
var pary:array of tpoint;
i:integer;
rgn:hrgn;
type
PPoints = ^TPoints;
TPoints = array[0..0] of TPoint;
begin
canvas.brush.color:=clred;
setlength(pary,4);
pary[0]:=point(0,0);
pary[1]:=point(180,0);
pary[2]:=point(180,180);
pary[3]:=point(0,180);
try
//rgn:=CreatePolygonRgn(Pary, 3, WINDING);
rgn:=CreatePolygonRgn(PPoints(@Pary)^, High(Pary) + 1, ALTERNATE );
if rgn<&gt0 then
fillrgn(canvas.handle,rgn,canvas.brush.handle)
else
showmessage('invalid region');
finally
deleteobject(rgn);
end;

end;

问题何在? 如果改用静态数组就一点问题没有,但是我看了很多控件的源代码也是这样做的.
 
>>rgn:=CreatePolygonRgn(PPoints(@Pary)^, High(Pary) + 1, ALTERNATE)
这句话错了,改成就对了
rgn:=CreatePolygonRgn(PPoints(Pary)^, High(Pary) + 1, ALTERNATE)
 
hubdog说的对,Pary本身就是指针,不需@
 
hotdog好像说对了,但是我的用法是借鉴RxLib的代码的,
你们可以看看RxHints.pas这个文件,里面的用法和我一模一样啊!

另外,在问一句:WINDING和ALTERNATE有什么不同?
 
还有问题:
我在程序里面定义了一个全局的Region,然后在运行时可以通过按钮来
切换是否需要改变形状,如果取消改变形状,我就用:
SetWindowRgn(0,0,width,height)来恢复整个形状.

现在的问题是恢复整个形状之后,再想Region就不行了,好像是那个全局
变量的Region失效乐.怎么回事?

这个问题再添100分.
 
似乎只有临时Create的region才有效,怎么回事?
 
SelectObject(Canvas.Handle, Rgn) ? 我没有试过,Just 猜想
 
好像不行.
 
好像没有问题

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

var
Rgn: HRgn;

procedure TForm1.Button1Click(Sender: TObject);
var pary:array of tpoint;
i:integer;
type
PPoints = ^TPoints;
TPoints = array[0..0] of TPoint;
begin
canvas.brush.color:=clred;
setlength(pary,4);
pary[0]:=point(0,0);
pary[1]:=point(180,0);
pary[2]:=point(180,180);
pary[3]:=point(0,180);
try
//rgn:=CreatePolygonRgn(Pary, 3, WINDING);
rgn:=CreatePolygonRgn(PPoints(Pary)^, High(Pary) + 1, ALTERNATE );
if rgn<>0 then
//fillrgn(canvas.handle,rgn,canvas.brush.handle)
else
showmessage('invalid region');
finally
//deleteobject(rgn);
end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
fillrgn(canvas.handle,rgn,canvas.brush.handle);
deleteobject(rgn);
end;

end.
 
不是fillrgn,而是setwindowrgn,我看API帮助上说,一旦SetWindowRgn之后,
操作系统就拥有这个region,并且不做备份,所以以后不应该再操作这个region...

意思是不是说: 一旦setwindowrgn之后,这个rgn就不能再用了? 那么我怎样实现
我的功能呢? 是不是我需要自己做一个备份? 我怎样备份呢?
 
It also tell you that "call the GetWindowRgn function."
但这样所得到的是 Rgn 和 Window 原来的 Region 的交集,
有可能不是你所指定的 Rgn。

要不先把 Rgn 画到一个 Mask 上,
需要时,再由 Mask 转换回来。
 
第三个 Region ( Rgn3)

然后: CombineRgn(Rgn3, Rgn1, RGN_COPY);

(Sorry, 我要回家了!)
 
Sorry,

----> CombineRgn(Rgn3, Rgn1, 0, RGN_COPY); ?
 
谢谢! 我试一试.
路上小心.
 
搞定了没?

unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
Panel2: TPanel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

var
Rgn, Rgn2: HRgn;

procedure TForm1.Button1Click(Sender: TObject);
var pary:array of tpoint;
i:integer;
type
PPoints = ^TPoints;
TPoints = array[0..0] of TPoint;
begin
canvas.brush.color:=clred;
setlength(pary,4);
pary[0]:=point(0,0);
pary[1]:=point(180,0);
pary[2]:=point(180,180);
pary[3]:=point(0,180);
try
//rgn:=CreatePolygonRgn(Pary, 3, WINDING);
rgn:=CreatePolygonRgn(PPoints(Pary)^, High(Pary) + 1, ALTERNATE );
if rgn<>0 then
begin
//fillrgn(canvas.handle,rgn,canvas.brush.handle);
Rgn2 := CreateRectRgn(0, 0, 10, 10);
CombineRgn(Rgn2, Rgn, 0, RGN_COPY);
SetWindowRgn(Panel1.Handle, Rgn, True);
end
else
showmessage('invalid region');
finally
//deleteobject(rgn);
end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
fillrgn(canvas.handle,rgn2,canvas.brush.handle);
deleteobject(rgn);
end;

end.
 
>另外,在问一句:WINDING和ALTERNATE有什么不同?
帮助里有解释的呀?

主要是用来指定是否填充相交区域的,
如果你的 Region 来自于一个汉字,
再 FillRgn 一下,
那么可以很清楚的看到,
ALTERNATE :汉字笔画相交(一次)的区域,没有填充色,字被打断了;
WINDING:和平时一样,所有封闭区域均被填充;
 
多谢! 昨晚就搞定了,CombineRgn的确管用.

不过我不知道这是不是标准的解决办法? 是不是复制一个region的备份
只能用CombineRgn? 我看到有一个ExtCreateRegion函数,似乎能够
做到从已存在的Region里面生成一个新的Region,但是用法没太明白.
 
我自己也没有用过,看来是更加麻烦,
下面有一个例子,我也没有仔细读过
(Copy From SkinForm.pas(Author: Xue Huai Qing [xhq@writeme.com]))

// This function programmed by Eddie Shipman
function Bitmap2Region( hBmp: TBitmap; TransColor: TColor; Tolerance: TColor): HRGN;
const
ALLOC_UNIT = 100;
var
MemDC, DC: HDC;
BitmapInfo: TBitmapInfo;
hbm32, holdBmp, holdMemBmp: HBitmap;
pbits32 : Pointer;
bm32 : BITMAP;
maxRects: DWORD;
hData: HGLOBAL;
pData: PRgnData;
b, LR, LG, LB, HR, HG, HB: Byte;
p32: pByte;
x, x0, y: integer;
p: pLongInt;
pr: PRect;
h: HRGN;

function MinByte(B1, B2: byte): byte;
begin
if B1 < B2 then
Result := B1
else
Result := B2;
end;

begin
Result := 0;
if hBmp <> nil then
begin
{ Create a memory DC inside which we will scan the bitmap contents }
MemDC := CreateCompatibleDC(0);
if MemDC <> 0 then
begin
{ Create a 32 bits depth bitmap and select it into the memory DC }
with BitmapInfo.bmiHeader do
begin
biSize := sizeof(TBitmapInfoHeader);
biWidth := hBmp.Width;
biHeight := hBmp.Height;
biPlanes := 1;
biBitCount := 32;
biCompression := BI_RGB; { (0) uncompressed format }
biSizeImage := 0;
biXPelsPerMeter := 0;
biYPelsPerMeter := 0;
biClrUsed := 0;
biClrImportant := 0;
end;
hbm32 := CreateDIBSection(MemDC, BitmapInfo, DIB_RGB_COLORS, pbits32,0, 0);
if hbm32 <> 0 then
begin
holdMemBmp := SelectObject(MemDC, hbm32);
{
Get how many bytes per row we have for the bitmap bits
(rounded up to 32 bits)
}
GetObject(hbm32, SizeOf(bm32), @bm32);
while (bm32.bmWidthBytes mod 4) > 0 do
inc(bm32.bmWidthBytes);
DC := CreateCompatibleDC(MemDC);
{ Copy the bitmap into the memory DC }
holdBmp := SelectObject(DC, hBmp.Handle);
BitBlt(MemDC, 0, 0, hBmp.Width, hBmp.Height, DC, 0, 0, SRCCOPY);
{
For better performances, we will use the ExtCreateRegion() function
to create the region. This function take a RGNDATA structure on
entry. We will add rectangles by
amount of ALLOC_UNIT number in this structure
}
maxRects := ALLOC_UNIT;
hData := GlobalAlloc(GMEM_MOVEABLE, sizeof(TRgnDataHeader) +
SizeOf(TRect) * maxRects);
pData := GlobalLock(hData);
pData^.rdh.dwSize := SizeOf(TRgnDataHeader);
pData^.rdh.iType := RDH_RECTANGLES;
pData^.rdh.nCount := 0;
pData^.rdh.nRgnSize := 0;
SetRect(pData^.rdh.rcBound, MaxInt, MaxInt, 0, 0);
{ Keep on hand highest and lowest values for the "transparent" pixel }
LR := GetRValue(ColorToRGB(TransColor));
LG := GetGValue(ColorToRGB(TransColor));
LB := GetBValue(ColorToRGB(TransColor));
{ Add the value of the tolerance to the "transparent" pixel value }
HR := MinByte($FF, LR + GetRValue(ColorToRGB(Tolerance)));
HG := MinByte($FF, LG + GetGValue(ColorToRGB(Tolerance)));
HB := MinByte($FF, LB + GetBValue(ColorToRGB(Tolerance)));
{
Scan each bitmap row from bottom to top,
the bitmap is inverted vertically
}
p32 := bm32.bmBits;
inc(PChar(p32), (bm32.bmHeight - 1) * bm32.bmWidthBytes);
for y := 0 to hBmp.Height-1 do
begin
{ Scan each bitmap pixel from left to right }
x := -1;
while x+1 < hBmp.Width do
begin
inc(x);
{ Search for a continuous range of "non transparent pixels" }
x0 := x;
p := PLongInt(p32);
inc(PChar(p), x * SizeOf(LongInt));
while x < hBmp.Width do
begin
b := GetBValue(p^); // Changed from GetRValue(p^)
if (b >= LR) and (b <= HR) then
begin
b := GetGValue(p^); // Left alone
if (b >= LG) and (b <= HG) then
begin
b := GetRValue(p^); // Changed from GetBValue(p^)
if (b >= LB) and (b <= hb) then
{ This pixel is "transparent" }
break;
end;
end;
inc(PChar(p), SizeOf(LongInt));
inc(x);
end;
if x > x0 then
begin
{
Add the pixels (x0, y) to (x, y+1) as a new rectangle in
the region
}
if pData^.rdh.nCount >= maxRects then
begin
GlobalUnlock(hData);
inc(maxRects, ALLOC_UNIT);
hData := GlobalReAlloc(hData, SizeOf(TRgnDataHeader) +
SizeOf(TRect) * maxRects, GMEM_MOVEABLE);
pData := GlobalLock(hData);
Assert(pData <> NIL);
end;
pr := @pData^.Buffer[pData^.rdh.nCount * SizeOf(TRect)];
SetRect(pr^, x0, y, x, y+1);
if x0 < pData^.rdh.rcBound.Left then
pData^.rdh.rcBound.Left := x0;
if y < pData^.rdh.rcBound.Top then
pData^.rdh.rcBound.Top := y;
if x > pData^.rdh.rcBound.Right then
pData^.rdh.rcBound.Left := x;
if y+1 > pData^.rdh.rcBound.Bottom then
pData^.rdh.rcBound.Bottom := y+1;
inc(pData^.rdh.nCount);
{
On Windows98, ExtCreateRegion() may fail if the number of
rectangles is too large (ie: > 4000). Therefore, we have to
create the region by multiple steps
}
if pData^.rdh.nCount = 2000 then
begin
h := ExtCreateRegion(NIL, SizeOf(TRgnDataHeader) +
(SizeOf(TRect) * maxRects), pData^);
Assert(h <> 0);
if Result <> 0 then
begin
CombineRgn(Result, Result, h, RGN_OR);
DeleteObject(h);
end else
Result := h;
pData^.rdh.nCount := 0;
SetRect(pData^.rdh.rcBound, MaxInt, MaxInt, 0, 0);
end;
end;
end;
{
Go to next row (remember, the bitmap is inverted vertically)
that is why we use DEC!
}
Dec(PChar(p32), bm32.bmWidthBytes);
end;
{ Create or extend the region with the remaining rectangle }
h := ExtCreateRegion(NIL, SizeOf(TRgnDataHeader) +
(SizeOf(TRect) * maxRects), pData^);
Assert(h <> 0);
if Result <> 0 then
begin
CombineRgn(Result, Result, h, RGN_OR);
DeleteObject(h);
end else
Result := h;
{ Clean up }
GlobalFree(hData);
SelectObject(DC, holdBmp);
DeleteDC(DC);
DeleteObject(SelectObject(MemDC, holdMemBmp));
end;
end;
DeleteDC(MemDC);
end;
end;
 
哎!太麻烦了,不如CombineRgn.就这样吧!

Big_Z,你有没有RxLib? 你看看上面最先讨论的那个问题,为什么这个用法:
rgn:=CreatePolygonRgn(PPoints(@Pary)^, High(Pary) + 1, ALTERNATE)

在RxLib的RxHints.pas里面可以,而我的程序不行?
 
后退
顶部