Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Полупрозрачные окна


Автор: bems 14.6.2006, 00:23
Хочу поизвращаться с дизайном окна. Я просто замечательно придумал как это должно выглядеть, но не имею понятия как это сделать. Идея такова: полупрзрачное окно неправильной формы. На нем область с другим AlphaBlend, и тоже неправильной формы. и в этой области и в остальной части окна больше чем один цвет. Сделать это нужно только на апи. Подскажите какой-нить изврат, пожалуйста... 

Автор: ~FoX~ 14.6.2006, 13:49
Неправильная форма - работа с регионами.
Полупрозрачность - SetLayeredWindowAttributes
Юзаем поиск и ФАК, темы поднимались не однократно! 

Автор: bems 15.6.2006, 00:36
Цитата(~FoX~ @  14.6.2006,  13:49 Найти цитируемый пост)
Полупрозрачность - SetLayeredWindowAttributes
Для больше, чем одного значения прозрачности на одном окне, не знаю как преминять. И поиск и MSDN не дают ответа на вопрос.
 

Автор: Snowy 15.6.2006, 08:18
Не. На всё окно одна прозрачность.
А для раздельной ничего стандартного нет.
Тут уже идут глючные извращения. 

Автор: Romikgy 15.6.2006, 09:04
bems, имхо нужно создать не одно окно , а несколько smile 

Автор: bems 15.6.2006, 10:20
Цитата(Romikgy @  15.6.2006,  09:04 Найти цитируемый пост)
 имхо нужно создать не одно окно , а несколько 

да, буду извращаться таким образом.
Цитата(Snowy @  15.6.2006,  08:18 Найти цитируемый пост)
Тут уже идут глючные извращения.  

А как сделать это безглючно?

В большом окне сделаю дырку для маленького. Как сделать чтобы оно всегда оставалось в этой дырке и в Z - порядке всегда было рядом?
WM_WINDOWPOSCHANGED вроде не всегда получаю. Хотя в оконной процедуре у меня не без боков...


  

Автор: Snowy 15.6.2006, 11:00
Цитата(bems @  15.6.2006,  10:20 Найти цитируемый пост)
А как сделать это безглючно?
Этого еще никому не удавалось...
Во всех реализациях имеются свои недостатки...

Цитата(bems @  15.6.2006,  10:20 Найти цитируемый пост)
Как сделать чтобы оно всегда оставалось в этой дырке и в Z - порядке всегда было рядом?
Прибить намертво к десктопу.
Иначе всё равно будет эффект отставания при перетаскивании. 

Автор: urix 15.6.2006, 14:24
можете глянуть это:
http://urixsoft.nm.ru/ru/index.htm?soft-ScrMon&frameleft_s
и это
http://urixsoft.nm.ru/ru/index.htm?soft-StartPPC&frameleft_s

(с исходниками).

Всё нехватает времени засесть за оптимизацию скорости, потому что работает значительно медленнее, чем я предполагаю возможно. Ну, и конечно же - как же без глюков...
(в висте, например, эта реализация не работает, в XP - дефекты, когда друг над другом,...) 

Автор: bems 18.6.2006, 09:40
А вот теперь - ДА!

UpdateLayeredWindow рулит 

Автор: bems 19.6.2006, 10:16
Цитата(Snowy @  15.6.2006,  08:18 Найти цитируемый пост)
Не. На всё окно одна прозрачность.
А для раздельной ничего стандартного нет.
Тут уже идут глючные извращения.  

Есть функция UpdateLayeredWindow. Но разобраться с ней на 100% не выходит. 
В теории все выглядит так: нужно создать контекст устройства, битмап, выбрать битмап в контекст и в битмап напрямую (не в ДиСи) записывать значения прозрачности для каждой точки. Потом вызвать UpdateLayeredWindow с этим контекстом и общим значением прозрачности для всего окна. Реальная прозрачность в каждой точке должна быть результирующей между индивидуальной и общей. Это в теории.
А на практике:из теории делаю вывод что одинаковое значение прозрачности для каждой точки($30 к примеру) и полная непрозрачность всего окна должны дать тот же результат, что и отсутствующая прозрачность точек со значением $30 для всего окна. Но не сходиться! я написал такой вот код:
Код

program Alpha;
uses windows,messages;

const
 sCaption='UpdateLayeredWindow test program';
 width=500;height=500;
 GWL_LAYEREDDC=0;clBack=$0000FF00;
 PerPixelAlpha=$FF;//прозрачность каждого пикселя
 ConstantAlpha=$30;//прозрачность всего окна

type TRGBA=packed record
           Blue,Green,
           Red,Alpha:byte
           end;//Как RGBQuad, только теперь мы знаем что такое Reserved
     pRGBA=^TRGBA;

function AppWndProc(wnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
begin
result:=DefWindowProc(wnd,uMsg,wParam,lParam);
end;

function InitLayeredDC:HDC;
var hBMP:HBITMAP;
    x,y:integer;bi:BITMAPINFO;
    bits:pointer;rgba:pRGBA;
begin
result:=CreateCompatibleDC(0);
bi.bmiHeader.biSize:=SizeOF(bi.bmiHeader);
bi.bmiHeader.biWidth:=width;
bi.bmiHeader.biHeight:=-height;
bi.bmiHeader.biPlanes:=1;
bi.bmiHeader.biBitCount:=32;
bi.bmiHeader.biCompression:=BI_RGB;
bi.bmiHeader.biSizeImage:=0;
bi.bmiHeader.biXPelsPerMeter:=0;
bi.bmiHeader.biYPelsPerMeter:=0;
bi.bmiHeader.biClrUsed:=0;
bi.bmiHeader.biClrImportant:=0;
hBMP:=CreateDIBSection(result,bi,DIB_RGB_COLORS,bits,0,0);
SelectObject(result,hBMP);
SelectObject(result,CreateSolidBrush(clBack));
RoundRect(result,0,0,width-1,height-1,50,50);
for y:=0 to height-1 do
 for x:=0 to width-1 do
  begin
  rgba:=pRGBA(DWORD(bits)+(x+y*width)*4);
  rgba.alpha:=PerPixelAlpha; //у всего окна ставим одинаковою прозрачность
  end;
end;

procedure FreeLayeredDC(DC:HDC);
begin
DeleteDC(DC)
end;

function MonitorWndProc(wnd:HWND;uMsg:UINT;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
var pt:TPoint;sz:TSize;bf:BLENDFUNCTION;
begin
if (uMsg=WM_SHOWWINDOW) and (wParam<>0)//при появлении
   then begin
        pt.X:=0;pt.Y:=0;
        sz.cx:=width;sz.cy:=height;
        bf.BlendOp:=AC_SRC_OVER;
        bf.BlendFlags:=0;
        bf.AlphaFormat:=AC_SRC_ALPHA;
        bf.SourceConstantAlpha:=ConstantAlpha;//а это работает
        UpdateLayeredWindow(wnd,0,@pt,@sz,GetWindowLong(wnd,GWL_LAYEREDDC),@pt,$FF,@bf,ULW_ALPHA);
        end;
result:=DefWindowProc(wnd,uMsg,wParam,lParam);
case uMsg of
  WM_NCCREATE:SetWindowLong(wnd,GWL_LAYEREDDC,InitLayeredDC);
 WM_NCDESTROY:begin
              FreeLayeredDC(SetWindowLong(wnd,GWL_LAYEREDDC,0));
              PostQuitMessage(0);
              end;
 WM_NCHITTEST:if result=HTCLIENT then result:=HTCAPTION;
end;
end;

function CreateAppWnd:HWND;
var clss:WNDCLASS;
begin
clss.style:=0;
clss.lpfnWndProc:=@AppWndProc;
clss.cbClsExtra:=0;
clss.cbWndExtra:=0;
clss.hInstance:=hInstance;
clss.hIcon:=0;
clss.hCursor:=0;
clss.hbrBackground:=0;
clss.lpszMenuName:=nil;
clss.lpszClassName:=sCaption;
RegisterClass(clss);
result:=CreateWindow(clss.lpszClassName,sCaption,WS_POPUP,0,0,0,0,0,0,clss.hInstance,nil);
end;

function CreateWnd(owner:HWND):HWND;
var clss:WNDCLASS;bmp:BITMAP;
begin
clss.style:=CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW or CS_DBLCLKS;
clss.lpfnWndProc:=@MonitorWndProc;
clss.cbClsExtra:=0;
clss.cbWndExtra:=8;
clss.hInstance:=hInstance;
clss.hIcon:=0;
clss.hCursor:=0;
clss.hbrBackground:=CreateSolidBrush(clBack);
clss.lpszMenuName:=nil;
clss.lpszClassName:=PChar('Monitor');
RegisterClass(clss);
result:=CreateWindowEx(WS_EX_TOPMOST or WS_EX_LAYERED,clss.lpszClassName,
                       sCaption,WS_POPUP or WS_VISIBLE,0,0,width,height,
                       owner,0,clss.hInstance,nil);
end;

var msg:TMSG;
begin
if CreateWnd(CreateAppWnd)<>0
   then while GetMessage(msg,0,0,0) do
              begin
              TranslateMessage(msg);
              DispatchMessage(msg);
              end;
end.
Помогите плиз разобраться.
При значения PerPixelAlpha:=$FF и ConstantAlpha:=$50 все выглядит так как я и ожидал (ничем не лучше и не хуже SetLayeredWindowAttributes). А если поменять эти значения, то картинка почему-то меняется, и у меня складывается впечатление, что откуда-то вмешался в картинку прозрачности какой-то слой белого цвета. 

Давайте вместе что-нить придумаем... 

Автор: urix 20.6.2006, 11:51
вот, работающий правильно пример: http://www.codeproject.com/gdi/pxalphablend.asp 

Автор: Girder 20.6.2006, 12:25
Код

procedure TForm1.FormCreate(Sender: TObject);
type
    TAlphaTable=Array[0..255] of Byte;
    TRGBAData=Array[0..3] of Byte;
    PRGBAData=^TRGBAData;
var b1,b2,BA:TBitmap;
    BF:TBlendFunction;
    FBmpSize:TSize;
    FBmpTopLeft:TPoint;
    AlphaTable:TAlphaTable;
    pAlphaTable:Array[0..255] of TAlphaTable;
    Lb1,Lb2,LBA:Integer;
    PRGBA,PRGB:PRGBAData;
    PA:PByte;
    A:Byte;
    ReverseA:Boolean;
    i,j:integer;
begin
 for i:=0 to 255 do
  for j:=0 to 255 do pAlphaTable[i,j]:=(j*i) shr 8;
  
 form1.BorderStyle:=bsNone;
 form1.Width:=500;
 form1.Height:=500;
 form1.Position:=poScreenCenter;
 b1:=TBitmap.Create;
 b2:=TBitmap.Create;
 b1.PixelFormat:=pf32Bit;
 b2.PixelFormat:=pf32Bit;

 b1.Width:=form1.Width;
 b1.Height:=form1.Height;
 b2.Width:=form1.Width;
 b2.Height:=form1.Height;

 b1.Canvas.Brush.Color:=0;
 b1.Canvas.FillRect(Rect(0,0,form1.Width,form1.Height));
 b1.Canvas.Brush.Color:=$fff0ff;
 b1.Canvas.RoundRect(10,10,form1.Width-10,form1.Height-10,50,50);
 //b1.SaveToFile('e:\vvv.bmp');

 b2.Canvas.Brush.Color:=$0;
 b2.Canvas.FillRect(Rect(0,0,form1.Width,form1.Height));
 b2.Canvas.Brush.Color:=$40f0ff;
 b2.Canvas.RoundRect(10,10,form1.Width-10,form1.Height-10,50,50);

 b2.Canvas.Brush.Color:=0;
 b2.Canvas.RoundRect(50,50,form1.Width-50,form1.Height-50,10,10);
 b2.PixelFormat:=pf8Bit;
 //b2.SaveToFile('e:\vvv2.bmp');

 SetWindowLong(form1.Handle, GWL_EXSTYLE, GetWindowLong(form1.Handle, GWL_EXSTYLE) or WS_EX_LAYERED);

 BF.BlendOp:=AC_SRC_OVER;
 BF.BlendFlags:=0;
 BF.SourceConstantAlpha:=255;
 BF.AlphaFormat:=AC_SRC_ALPHA;

 FBmpSize.cx := form1.Width;
 FBmpSize.cy := form1.Height;
 FBmpTopLeft := Point(0, 0);

 BA:=TBitmap.Create;
 BA.PixelFormat:=pf32Bit;
 BA.Width:=form1.Width;
 BA.Height:=form1.Height;

 LBA:=DWord(BA.Scanline[1])-DWord(BA.Scanline[0])-(form1.Width shl 2);
 Lb1:=DWord(b1.Scanline[1])-DWord(b1.Scanline[0])-(form1.Width shl 2);
 Lb2:=DWord(b2.Scanline[1])-DWord(b2.Scanline[0])-form1.Width;

 PRGBA:=BA.Scanline[0];
 PRGB:=b1.Scanline[0];
 PA:=b2.Scanline[0];

 ReverseA:=true; //Или False

 for i:=0 to form1.Height-1 do
  begin
   for j:=0 to form1.Width-1 do
    begin
     A:=PA^;
     if ReverseA then A:=not(A);
     AlphaTable:=pAlphaTable[A];

     PRGBA[0]:=AlphaTable[PRGB[0]];
     PRGBA[1]:=AlphaTable[PRGB[1]];
     PRGBA[2]:=AlphaTable[PRGB[2]];
     PRGBA[3]:=A;

     DWord(PRGBA):=DWord(PRGBA)+4;
     DWord(PRGB):=DWord(PRGB)+4;
     DWord(PA):=DWord(PA)+1;
    end;
    DWord(PRGBA):=DWord(PRGBA)+LBA;
    DWord(PRGB):=DWord(PRGB)+Lb1;
    DWord(PA):=DWord(PA)+Lb2;
  end;

 //BA.SaveToFile('e:\vvv3.bmp');
 UpdateLayeredWindow(form1.Handle, 0, nil, @FBmpSize, BA.Canvas.Handle, @FBmpTopLeft, clNone, @BF, ULW_ALPHA);

 BA.Free;
 b1.Free;
 b2.Free;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 ReleaseCapture();
 SendMessage(form1.Handle,WM_NCLBUTTONDOWN, HTCAPTION, 0);
end;


PS: Или ReverseA:=false; 

Автор: bems 20.6.2006, 15:32
urix, Girder, списибо ребята, я уже разобрался. Нагуглил этот пример с codeproject. Весь фокус был в предумноженном цвете (как перевести premultipled?) Я думал так никто и не откликнется.
Спасибо вам еще раз и "+" 

Автор: Wolf 4.5.2009, 13:59
Хм, а теперь как бы на этом всём контролы какие нибуть рисовать? Что-то они не охотно рисуются )

Автор: vovaok 1.12.2010, 12:07
вот-вот.. я знаю 2 варианта.. рисовать контролы вручную, либо сделать дырку в LayeredWindow а под ней помещать обычную форму с контролами

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)