imho.ws |
![]() |
![]() |
|
Сообщения:
Перейти к новому /
Последнее
|
Опции темы |
![]() |
# 1 |
Member
Регистрация: 18.04.2002
Адрес: Ф туманах Новосибирска...
Сообщения: 378
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Создание непрямоугольного окна с изменяемым размером (WinAPI)
Для получения окна произвольной формы с изменяемым размером обрабатываю WM_SIZE, но при уменьшении размера окна за правой и нижней границей тянется шлейф. Причем только за частями границы, которые отличаются от исходного прямоугольного региона (например за скругленными углами окна).
Самое забавное - есть замечательный пример написанный на MFC http://www.rsdn.ru/article/files/Classes/skindlg.xml и все прекрасно работает. А на WinAPI не получается ![]() Как можно решить данную проблему? Код:
case WM_SIZE: { RECT clientRect, wndRect; GetClientRect(hWnd, &clientRect); UpdateMainFrame(((int)(short)LOWORD(lParam)), ((int)(short)HIWORD(lParam))); WindowRgn = BitmapToRegion(MainFrame, RGB(255, 0, 255)); SetWindowRgn(hWnd, WindowRgn, FALSE); hdc = GetDC(hWnd); HDC MainFrameDC; MainFrameDC = CreateCompatibleDC(NULL); SelectObject(MainFrameDC, MainFrame); BitBlt(hdc, 0, 0, clientRect.right, clientRect.bottom, MainFrameDC, 0, 0, SRCCOPY); ReleaseDC(hWnd, hdc); DeleteDC(MainFrameDC); return 0; } UpdateMainFrame - создается BITMAP BitmapToRegion - создается регион на основе BITMAP'а Последний раз редактировалось Gunslinger; 15.09.2004 в 17:23. |
![]() |
![]() |
# 2 |
Guest
Сообщения: n/a
|
Вот попробуй етот код на Дельфяне, если что разберешся
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 ![]() 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. |
![]() |
# 3 |
Member
Регистрация: 18.04.2002
Адрес: Ф туманах Новосибирска...
Сообщения: 378
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
thx конечно, но вопрос был не в способе реализации, а с какого перепуга отрисовка на DC'шке приводит к отрисовке последнего пикселя за границами региона (при ресайзе), при этом если уменьшить высоту и ширину на пиксель при BitBlt, то последний пиксель останется не отрисованым (хотя это изначально не вариант, так как с координатами все нормально).
А тут экзампл на дельфях помощник в последнюю очередь. |
![]() |
![]() |
# 4 |
Guest
Сообщения: n/a
|
В примере конкретно происходит ресайз, и нигде нету лишних пикселей, я даже тебе со вставкой картинок дал пример, для наглядности если у тебя последний пиксель прорисовывается
![]() |
![]() |
# 5 |
Member
Регистрация: 18.04.2002
Адрес: Ф туманах Новосибирска...
Сообщения: 378
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Смотри, переносим код в обработку WM_ERASEBKGND (это к вопросу о том, что обновление не происходит):
Код:
case WM_ERASEBKGND: { GetWindowRect(hWnd, &windowRect); UpdateMainFrame(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top); frameRegion = BitmapToRegion(MainFrame, RGB(255, 0, 255)); SetWindowRgn(hWnd, frameRegion, FALSE); HBRUSH brush; brush = CreatePatternBrush(MainFrame); FillRgn(hdc, frameRegion, brush); DeleteObject(brush); return 0; } Код:
void UpdateMainFrame(int width, int height) { HDC MainFrameDC; if(MainFrame != NULL) DeleteObject(MainFrame); MainFrame = CreateBitmap(width, height, 1, 32, NULL); MainFrameDC = CreateCompatibleDC(NULL); SelectObject(MainFrameDC, MainFrame); //собираем BITMAP из кусочков BitBlt(MainFrameDC, 0, 0, bitmap11info.bmWidth, bitmap11info.bmHeight, bitmap11hdc, 0, 0, SRCCOPY); StretchBlt(MainFrameDC, bitmap11info.bmWidth, 0, width-bitmap13info.bmWidth-bitmap11info.bmWidth, bitmap12info.bmHeight, bitmap12hdc, 0, 0, bitmap12info.bmWidth, bitmap12info.bmHeight, SRCCOPY); BitBlt(MainFrameDC, width-bitmap13info.bmWidth, 0, bitmap13info.bmWidth, bitmap13info.bmHeight, bitmap13hdc, 0, 0, SRCCOPY); StretchBlt(MainFrameDC, 0, bitmap11info.bmHeight, bitmap21info.bmWidth, height-bitmap11info.bmHeight-bitmap31info.bmHeight, bitmap21hdc, 0, 0, bitmap21info.bmWidth, bitmap21info.bmHeight, SRCCOPY); StretchBlt(MainFrameDC, bitmap21info.bmWidth, bitmap11info.bmHeight, width-bitmap23info.bmWidth-bitmap21info.bmWidth, height-bitmap12info.bmHeight-bitmap32info.bmHeight, bitmap22hdc, 0, 0, bitmap22info.bmWidth, bitmap22info.bmHeight, SRCCOPY); StretchBlt(MainFrameDC, width-bitmap23info.bmWidth, bitmap11info.bmHeight, bitmap23info.bmWidth, height-bitmap11info.bmHeight-bitmap31info.bmHeight, bitmap23hdc, 0, 0, bitmap23info.bmWidth, bitmap23info.bmHeight, SRCCOPY); BitBlt(MainFrameDC, 0, height-bitmap31info.bmHeight, bitmap31info.bmWidth, bitmap31info.bmHeight, bitmap31hdc, 0, 0, SRCCOPY); StretchBlt(MainFrameDC, bitmap31info.bmWidth, height-bitmap32info.bmHeight, width-bitmap33info.bmWidth-bitmap31info.bmWidth, bitmap32info.bmHeight, bitmap32hdc, 0, 0, bitmap32info.bmWidth, bitmap32info.bmHeight, SRCCOPY); BitBlt(MainFrameDC, width-bitmap33info.bmWidth, height-bitmap33info.bmHeight, bitmap33info.bmWidth, bitmap33info.bmHeight, bitmap33hdc, 0, 0, SRCCOPY); DeleteDC(MainFrameDC); GetObject(MainFrame, sizeof(MainFrameInfo), &MainFrameInfo); } ![]() Далее смотрим MSDN ![]() 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. Иными словами говоря - не должно изображение за регион выходить. А что получается смотри во вложении. |
![]() |
![]() |
# 6 |
Newbie
Регистрация: 21.07.2004
Адрес: Брест
Сообщения: 26
![]() |
Вот наверное из-за того, что вынес изменение региона в WM_ERASEBKGND, такая фигня и получается... При изменении региона винда рекурсивно вызывает WM_ERASEBKGND ещё раз, тут то всё и происходит.
__________________
Spel chekers, hoo neeeds em? ![]() |
![]() |
![]() |
# 7 |
Member
Регистрация: 18.04.2002
Адрес: Ф туманах Новосибирска...
Сообщения: 378
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
В WM_ERASEBKGND я вынес для примера, этого оно в WM_SIZE было, этот код хоть куда пихай (в тот же WM_NCPAINT) - результат один. Ну и вообще в SetWindowRgn третий параметр FALSE - указывает что перерисовка после изменения региона не требуется. Также, я могу в обработчике WM_ERASEBKGND ничего не перерисовывать, а просто return 0 делать - это не поможет, то бишь дело тут в другом. Ну и как видно на картинке - шлейф то только за частями, отличающимися от первоначального прямоугольного региона, а так был бы за всем окном.
Да к томуже FillRgn делается для того же региона, который установлен как регион окна ![]() |
![]() |
![]() |
# 10 | |
Newbie
Регистрация: 21.07.2004
Адрес: Брест
Сообщения: 26
![]() |
Цитата:
SetWindowRgn там вызывается с bRepaint=TRUE!!! Попробуй... А ещё там Sleep(0) сразу после SetWindowRgn(). ![]()
__________________
Spel chekers, hoo neeeds em? ![]() Последний раз редактировалось Gem Single; 26.09.2004 в 00:58. |
|
![]() |