![]() |
Создание непрямоугольного окна с изменяемым размером (WinAPI)
Для получения окна произвольной формы с изменяемым размером обрабатываю WM_SIZE, но при уменьшении размера окна за правой и нижней границей тянется шлейф. Причем только за частями границы, которые отличаются от исходного прямоугольного региона (например за скругленными углами окна).
Самое забавное - есть замечательный пример написанный на MFC http://www.rsdn.ru/article/files/Classes/skindlg.xml и все прекрасно работает. А на WinAPI не получается :( Как можно решить данную проблему? Код:
case WM_SIZE: UpdateMainFrame - создается BITMAP BitmapToRegion - создается регион на основе BITMAP'а |
Вот попробуй етот код на Дельфяне, если что разберешся
unit Unit1;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Timer1: TTimer; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure buttonclick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure muve(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; kk:byte; xx,yy,xxl,yyl:integer; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var hwnd:longint; rgn:hrgn; poi:array[1..10] of tpoint; n,m,l,i,j:integer; begin m:=5; poi[1].x:=0; poi[1].y:=0; poi[2].x:=0; poi[2].y:=form1.Height div 2; poi[3].x:=form1.Width div 2; poi[3].y:=form1.Height; poi[4].x:=form1.Width; poi[4].y:=form1.Height div 2; poi[5].x:=form1.Width; poi[5].y:=0; rgn:=CreatePolygonRgn(poi,m,i); setwindowrgn(form1.Handle ,rgn,true); end; function BitmapToRegion(Bitmap: TBitmap; TransColor: TColor): HRGN; var X,Y: Integer; XStart: Integer; pb:pByteArray; begin Result:= 0; for Y:= 0 to Bitmap.Height - 1 do begin X:= 0; //with bitmap do pb:=bitmap.ScanLine[y]; while X <Bitmap.Width do begin while (X <Bitmap.Width) and (pb^[X] =TransColor) do inc(X); if X >=Bitmap.Width then Break; XStart := X; while (X <Bitmap.Width) and (pb^[x]<>TransColor) do Inc(X); if Result = 0 then Result := CreateRectRgn(XStart, Y, X, Y + 1) else CombineRgn(Result, Result,CreateRectRgn(XStart, Y, X, Y + 1), RGN_OR); end; {with bitmap do while X <Width do begin while (X <Width) and (Canvas.Pixels[X, Y] = TransColor) do Inc(X); if X >=Width then Break; XStart := X; while (X <Width) and (Canvas.Pixels[X, Y] <>TransColor) do Inc(X); if Result = 0 then Result := CreateRectRgn(XStart, Y, X, Y + 1) else CombineRgn(Result, Result, CreateRectRgn(XStart, Y, X, Y + 1), RGN_OR); end;} end; end; procedure TForm1.Button2Click(Sender: TObject); var rgn:hrgn; Bitmap: TBitmap; color:TColor; begin Bitmap := TBitmap.Create; Bitmap.LoadFromFile('c:\11.bmp'); color:=255; rgn:=BitmapToRegion(bitmap,color); setwindowrgn(form1.Handle ,rgn,true); form1.Canvas.Draw(-3,-24,bitmap); end; procedure TForm1.Button3Click(Sender: TObject); begin CLOSE end; procedure TForm1.buttonclick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if ord(button)=0 then if kk=0 then kk:=1 else kk:=0 else kk:=1; end; procedure TForm1.muve(Sender: TObject; Shift: TShiftState; X, Y: Integer); var c:cardinal; begin if kk=0 then begin xx:=xx-(xxl-x); yy:=yy-(yyl-y); xxl:=x; yyl:=y; form1.Caption:=inttostr(xx); SetWindowPos(form1.handle,form1.handle,xx,yy,form1.Width,form1.Height, c); timer1.Interval:=100; end else form1.Caption:='aaaaaaaaaa'; end; procedure TForm1.Timer1Timer(Sender: TObject); var c:cardinal; begin //SetWindowPos(form1.handle,getnextwindow(form1.handle,1),xx,yy,form1.Wi dth,form1.Height,c); end; procedure TForm1.FormCreate(Sender: TObject); begin kk:=12; end; end. |
thx конечно, но вопрос был не в способе реализации, а с какого перепуга отрисовка на DC'шке приводит к отрисовке последнего пикселя за границами региона (при ресайзе), при этом если уменьшить высоту и ширину на пиксель при BitBlt, то последний пиксель останется не отрисованым (хотя это изначально не вариант, так как с координатами все нормально).
А тут экзампл на дельфях помощник в последнюю очередь. |
В примере конкретно происходит ресайз, и нигде нету лишних пикселей, я даже тебе со вставкой картинок дал пример, для наглядности если у тебя последний пиксель прорисовывается :( , это у тебя скорее всего обновления не происходит либо скапливается мусор, попробуй очистить его перед тем как делать ресайз, сделай апдейт и потом ресайз.
|
Вложений: 1
Смотри, переносим код в обработку WM_ERASEBKGND (это к вопросу о том, что обновление не происходит):
Код:
case WM_ERASEBKGND: Код:
void UpdateMainFrame(int width, int height) Далее смотрим MSDN :contract: : The SetWindowRgn function sets the window region of a window. The window region determines the area within the window where the system permits drawing. The system does not display any portion of a window that lies outside of the window region. Иными словами говоря - не должно изображение за регион выходить. А что получается смотри во вложении. |
Вот наверное из-за того, что вынес изменение региона в WM_ERASEBKGND, такая фигня и получается... При изменении региона винда рекурсивно вызывает WM_ERASEBKGND ещё раз, тут то всё и происходит.
|
В WM_ERASEBKGND я вынес для примера, этого оно в WM_SIZE было, этот код хоть куда пихай (в тот же WM_NCPAINT) - результат один. Ну и вообще в SetWindowRgn третий параметр FALSE - указывает что перерисовка после изменения региона не требуется. Также, я могу в обработчике WM_ERASEBKGND ничего не перерисовывать, а просто return 0 делать - это не поможет, то бишь дело тут в другом. Ну и как видно на картинке - шлейф то только за частями, отличающимися от первоначального прямоугольного региона, а так был бы за всем окном.
Да к томуже FillRgn делается для того же региона, который установлен как регион окна :confused: . |
|
VeryLucky
Ну да, а из первого поста не заметно, что про эту статью я в курсе и под MFC все работает? |
Цитата:
SetWindowRgn там вызывается с bRepaint=TRUE!!! Попробуй... А ещё там Sleep(0) сразу после SetWindowRgn(). :contract: |
Gem Single
Похоже на правду, посмотрим ... |
Часовой пояс GMT +4, время: 04:05. |
Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.