[Delphi] Как намутить прозрачный заголовок окна?

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by RedFern.89, 4 Jan 2011.

  1. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    575
    Likes Received:
    48
    Reputations:
    0
    доброго времени суток)) и всех с наступившим Новым Годом)
    как заголовок окна сделать прозрачным?) в принципе я знаю, как перерисовать сам заголовок, средствами winapi. а как же сделать его прозрачным? блин понять до сих пор не могу(((

    ОС: Windows XP SP3
     
  2. CodeSender:)

    CodeSender:) Elder - Старейшина

    Joined:
    29 Jul 2010
    Messages:
    245
    Likes Received:
    115
    Reputations:
    23
    Никак, только в vista+ ведь aero...
     
  3. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    575
    Likes Received:
    48
    Reputations:
    0
    есть AeroEffects для WinXP и ниче же) работает через GDI32.dll
     
  4. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    получать текст под окном, потом сумировать сцета по спец алгоритму чтобы добиться прозрачности и рисовать где надо
     
  5. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    575
    Likes Received:
    48
    Reputations:
    0
    мне никто не помог, а я селал) но сделал лажу, которая проц жрет страшно

    Code:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Buttons, ExtCtrls;
    
    type
      TForm1 = class(TForm)
        img1: TImage;
        btn1: TBitBtn;
        tmr1: TTimer;
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
        procedure WMEnterSizeMove(var Msg:TMessage);message WM_EnterSizeMove;
        procedure WMExitSizeMove(var Msg:TMessage);message WM_ExitSizeMove;
        procedure WMPaint(var Msg: TWMPaint); message WM_Paint;
        procedure WMMove(var Msg:TMessage);message WM_Move;
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
      BM1, BM2 : TBitmap;
      Transparency:Integer = 60;
      TranspColor: TColor = clBlue;
      Moving : Boolean;
    
    type PRGBArray=^TRGBArray;
         TRGBArray=array[0..1000000] of TRGBTriple;
    
    
    implementation
    
    {$R *.dfm}
    
    procedure Delay(DelayTime:Integer);
    var
      TicksNow:Integer;
    begin
      TicksNow:=GetTickCount;
      repeat
       Application.ProcessMessages
      until GetTickCount - TicksNow >= DelayTime
    end;
    
    // Получение контекста заголовка окна
    procedure GetWindowTitleDC(Wnd: THandle; ADC: HDC);
    var
      Dc   : HDC;   // Контекст устройсва
      Rect : TRect; // Прямоугольник окна
    begin
     // Получем контекст окна
      Dc := GetWindowDC(Wnd);
     // Получаем прямоугольник окна
      GetWindowRect(Wnd, Rect);
     // Записываем полученное изображение и отдаем его
      BitBlt(ADC, 0, 1, Rect.Right, 25, Dc, 0, 1, SRCCOPY);
     // Контекст нам больше ненужен, о чем мы и сообщаем
      ReleaseDC(Wnd, Dc);
    end;
    
    // Задаем картинку заголовку
    procedure SetWindowTitleImage(Wnd: THandle; szImage: TBitmap);
    var
      DC   : HDC;
      CA   : TCanvas;
      Rect : TRect;
      PWi  : tagWINDOWINFO;
    begin
      DC := GetWindowDC(Wnd); // Получаем контекст окна
      CA := TCanvas.Create;
      CA.Handle := DC;
      GetWindowRect(Wnd, Rect);
      GetWindowInfo(Wnd, PWi);
    
     // Срезаем изображение
      Rect.Bottom := 25;
      Rect.Top := 0;
      Rect.Left := 0;
      Rect.Right := PWi.rcWindow.Right - PWi.rcWindow.Left;
    
     // Отрисовываем изображение
      CA.Draw(0, 0, szImage);
    
      ReleaseDC(Wnd, DC); // Сообщаем винде, что данный контекст более не требуеся
      CA.Free; // Убиваем канву
    end;
    
    procedure TForm1.WMPaint;
    var
      DC     : HDC;           // Контекст устройства
      Rect   : TRect;         // Прямоугольник окна
      PWi    : tagWINDOWINFO; // Информация об окне
      X, Y   : Integer;       // Позиции по ширине и высоте
      CW, CH : Integer;       // Ширина и высота
      SL     : PRGBArray;     // Указатель на строку писелей
      CA     : TCanvas;
    begin
     // Считываем координаты окна
      GetWindowRect(Handle, Rect);
      GetWindowInfo(Handle, PWi);
    
      BM2.Width  := Rect.Right;
      BM2.Height := 25;
      BM2.PixelFormat := pf24bit;
    
      BitBlt(bm2.Canvas.Handle, 0, 0, BM1.Width, BM1.Height,
             BM1.Canvas.Handle, Rect.Left, Rect.Top, SRCCOPY);
    
      DC := GetWindowDC(Handle); // Получаем контекст окна
      CA := TCanvas.Create;
      CA.Handle := DC;
    
    
      for Y :=0 to bm2.height -1 do
        begin
         SL:=BM2.ScanLine[Y];
         for X:=0 to BM2.Width -1 do
          begin
           SL[X].rgbtRed:=(Transparency*SL[X].rgbtRed+(100-Transparency)*GetRValue(TranspColor)) div 100;
           SL[X].rgbtGreen:=(Transparency*SL[X].rgbtGreen+(100-Transparency)*GetGValue(TranspColor)) div 100;
           SL[X].rgbtBlue:=(Transparency*SL[X].rgbtBlue+(100-Transparency)*GetBValue(TranspColor)) div 100
          end
        end;
    
    
     // Отрисовываем изображение
      CA.Draw(0, 0, BM2);
    
      Msg.DC := dc;
      inherited;
    
      ReleaseDC(Handle, DC); // Сообщаем винде, что данный контекст более не требуеся
      CA.Free; // Убиваем канву
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      dc: hdc;
    begin
      BM1 := TBitmap.Create; { Тут будет храниться изображение экрана }
      BM2 := TBitmap.Create;
      Moving := False;
     // Задаем размеры изображения по размеру экрана
      BM1.Width  := GetSystemMetrics(SM_CXSCREEN);
      BM1.Height := GetSystemMetrics(SM_CYSCREEN);
      BM1.PixelFormat := pf24bit;
    
        DC := GetDC(0); // Получаем контекст дисплея
       // Закидываем контекст в изображение
        BitBlt(BM1.Canvas.Handle, 0, 0, BM1.Width, BM1.Height,
               DC, 0, 0, SRCCOPY);
       // Контекст больше не требуется, сообщаем винде,
       // что он свободен и передаем его дальше
        ReleaseDC(Handle, DC);
    
    end;
    
    procedure TForm1.WMMove;
    begin
     Invalidate;   //  Всё, пора перерисовываться
     inherited
    end;
    
    procedure TForm1.WMEnterSizeMove;
    begin
     Moving:=True;
     inherited
    end;
    
    procedure TForm1.WMExitSizeMove;
    begin
     inherited;
     Moving:=False
    end;
    
    
    end.
    
    если кто сможет улучшить производительность, скиньте норм вариант )) плиииз) всех с нг))
     
  6. RedFern.89

    RedFern.89 Member

    Joined:
    20 Jan 2010
    Messages:
    575
    Likes Received:
    48
    Reputations:
    0
    fd00ch, пример в студию))
     
  7. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    Яжжж, тебе писал уже.
    Code:
    #include <windows.h>
    #include <tchar.h>
    #include <GdiPlus.h>
    #pragma comment(lib, "GdiPlus.lib")
    using namespace Gdiplus;
    
    // тут ловчей структуру сделать
    #define RAMKA_H 300
    #define RAMKA_W 500
    HWND hRamka;
    HWND hMainWindow;
    
    //--------------------------------------------------------------------------------
    
    LRESULT CALLBACK RamkaProc(HWND hWnd,UINT Message, UINT wParam, LONG lParam)
    {
    	switch(Message)
    	{
    
    
    	case WM_ACTIVATE: // если у нас активизировалось окошко, то активизируем главное окно
    		if((LOWORD(wParam)==WA_CLICKACTIVE || LOWORD(wParam)==WA_ACTIVE) && (HWND)lParam==hMainWindow) { 
    			SetActiveWindow(hMainWindow);
    			return 0; }
    		break;
    	case WM_PAINT:{
    		PAINTSTRUCT ps;
    		HDC hDC = BeginPaint(hWnd, &ps);
    
    		// наведем красоту в виде округленных уголков
    		// рисуем сначала прозрачные прямоугольники, а потом врисовываем черные элипсы :)
    		Graphics g(hDC);
    
    		RectF top_left(0.0f, 0.0f, 5.0f, 5.0f);
    		RectF bottom_left(0.0f,(ps.rcPaint.bottom-ps.rcPaint.top)-5.0f, 5.0f, 5.0f);
    		RectF top_right((ps.rcPaint.right-ps.rcPaint.left)-5,0.0f, 5.0f, 5.0f);
    		RectF bottom_right((ps.rcPaint.right-ps.rcPaint.left)-5,(ps.rcPaint.bottom-ps.rcPaint.top)-5, 5.0f, 5.0f);
    		RectF rects[4] = {top_left, bottom_left,top_right,bottom_right};
    
    		SolidBrush sBrush(Color(255,255,255));
    		SolidBrush sBrush2(Color(0,0,0));
    		Pen pen(&sBrush, 1);
    		g.FillRectangles(&sBrush,rects,4);
    
    		for(int i=0;i<4;i++) { 
    			rects[i].Width=rects[i].Height=10; 
    			if(i>1) { rects[i].X-=6; } 
    			if(((i+1)%2)==0) { rects[i].Y-=6; }
    			g.FillEllipse(&sBrush2,rects[i]);
    		}
    
    
    
    		EndPaint(hWnd, &ps);
    
    		return 0;
    				  }
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hWnd,Message,wParam,lParam);
    }
    
    LRESULT CALLBACK MainWinProc(HWND hWnd,UINT Message, UINT wParam, LONG lParam)
    {
    	switch(Message)
    	{
    	case WM_ACTIVATE:
    		if(LOWORD(wParam)==WA_ACTIVE && (HWND)lParam!=hRamka) { SetForegroundWindow(hRamka); } // передаем управление рамке
    		break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    	return DefWindowProc(hWnd,Message,wParam,lParam);
    }
    
    int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,
    	LPSTR lpCmdLine,int nShowCmd)
    {
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
    
    	GdiplusStartupInput gdiplusStartupInput; 
    	ULONG_PTR gdiplusToken; 
    	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
    	WNDCLASS WndClass;
    	TCHAR szClassName[]=_TEXT("lol");
    	TCHAR szClassName2[]=_TEXT("lol2");
    	WndClass.style=CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    	WndClass.lpfnWndProc=RamkaProc;
    	WndClass.cbClsExtra=0;
    	WndClass.cbWndExtra=0;
    	WndClass.hInstance=hInstance;
    	WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    	WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    	WndClass.hbrBackground=CreateSolidBrush(0x000000);
    	WndClass.lpszMenuName=NULL;
    	WndClass.lpszClassName=szClassName;
    
    	if(!RegisterClass(&WndClass))
    	{
    		MessageBox(NULL,_TEXT("Невозможно создать класс"),NULL,MB_OK|MB_ICONERROR);
    		return 0;
    	}
    
    	// вычисление координат центра экрана
    	RECT screen_rect;
    	GetWindowRect(GetDesktopWindow(),&screen_rect); // разрешение экрана
    	int x = screen_rect.right / 2 - RAMKA_W / 2;
    	int y = screen_rect.bottom / 2 - RAMKA_H / 2;
    
    	hRamka=CreateWindowEx(WS_EX_LAYERED|WS_EX_TOOLWINDOW,szClassName,NULL,WS_POPUP,
    		x,y,
    		RAMKA_W,RAMKA_H,
    		NULL,NULL,
    		hInstance,NULL);
    
    	if(!hRamka)
    	{
    		MessageBox(NULL,_TEXT("Невозможно создать окно"),NULL,MB_OK|MB_ICONERROR);
    		return 0;
    	}
    
    	// создаем прозрачное окно и делаем белый цвет практически прозрачным
    	SetLayeredWindowAttributes(hRamka, 0xFFFFFF, 50, LWA_ALPHA|LWA_COLORKEY);
    
    	WndClass.lpszClassName=szClassName2;
    	WndClass.hbrBackground=CreateSolidBrush(0xFFFFFF);
    	WndClass.lpfnWndProc=MainWinProc;
    	RegisterClass(&WndClass);
    	hMainWindow=CreateWindow(szClassName2,NULL,WS_POPUP|WS_VISIBLE,x+10,y+10,RAMKA_W-20,RAMKA_H-20,NULL,NULL,hInstance,NULL);
    
    
    	ShowWindow(hRamka, nShowCmd);
    	SetActiveWindow(hMainWindow);
    	MSG Msg;
    	while(GetMessage(&Msg,NULL,0,0))
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    	GdiplusShutdown(gdiplusToken);
    	return (int)Msg.wParam;
    }
    
    результат на лицо
    [​IMG]
     
    _________________________
    1 person likes this.
  8. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    Вот заморочился и написал свой первый в жизни класс на С++, который упрощает код опубликованный выше. [БРАТЬ ЗДЕСЬ]

    Юзать просто:
    Code:
    #include "theme.hpp"
    
    int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPrevInstance,
    	LPSTR lpCmdLine,int nShowCmd)
    {
    	UNREFERENCED_PARAMETER(hPrevInstance);
    	UNREFERENCED_PARAMETER(lpCmdLine);
    
    // ширина, высота, размер рамки, цвет рамки, прозрачность от 0 до 255
    	Theme window(500,300,10,0x000000,50);
    	window.Create();
    
    
    	MSG Msg;
    	while(GetMessage(&Msg,NULL,0,0))
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    
    
    	return (int)Msg.wParam;
    }
    
    Пока правда одно окно можно делать, но сейчас может попробую модифицировать на диалоги :)
     
    _________________________
    #8 Gar|k, 6 Jan 2011
    Last edited: 6 Jan 2011