
Если при загрузке программы, показывается Splash Screen (это небольшое окно с картинкой), то к таким программам пользователи относятся лучше, чем программам, при запуске которых несколько секунд ничего не происходит.
В интернете есть много примеров изготовления Splash Screen-а в Delphi, однако обычно это квадратная форма с натянутой на ней картинкой.
Но у многих программ это не квадратная форма, а красивое окно со сглаженными краями.
Я пытался сделать такое окно с помощью регионов, но края были неровные и смотрелись неказисто.
Выходом стали «Слоистые окна» (LayeredWindow).
Был создан класс TSplash:
Create(Image:TPNGImage) создает экземпляр класса и загружает картинку,
Show показывает Splash, Close скрывает.
Процедура, преобразующая обычное окно в LayeredWindow:
procedure TSplash.ToLayeredWindow; var BitMap: TBitMap; bf: TBlendFunction; BitmapSize: TSize; BitmapPos: TPoint; begin // создание правильной битовой карты(32 бит на пиксель, precalc альфа канал) BitMap := TBitMap.Create; CreatePremultipliedBitmap(Bitmap,FImage); // описание BlendFunction with bf do begin BlendOp := AC_SRC_OVER; BlendFlags := 0; AlphaFormat := AC_SRC_ALPHA; SourceConstantAlpha := 255; end; // получаем размеры BitMap BitmapSize.cx := Bitmap.Width; BitmapSize.cy := Bitmap.Height; // получаем координаты BitMap BitmapPos.X := 0; BitmapPos.Y := 0; // слоистый стиль окна SetWindowLong(SplashForm.Handle, GWL_EXSTYLE, GetWindowLong(SplashForm.Handle, GWL_EXSTYLE) + WS_EX_LAYERED); // превращение окна в слоистое окно UpdateLayeredWindow( SplashForm.Handle, 0, nil,//pos @BitmapSize,//size bitmap.Canvas.Handle,//src @BitmapPos,//pptsrc 0, @bf, ULW_ALPHA ); BitMap.Free; end;
процедура CreatePremultipliedBitmap преобразует TPNGImage в 32-х разрядный TBitMap, нужный функции UpdateLayeredWindow:
procedure CreatePremultipliedBitmap(DstBitMap: TBitmap; SrcPngImage: TPNGImage); type TRGBTripleArray = ARRAY[Word] of TRGBTriple; pRGBTripleArray = ^TRGBTripleArray; TRGBAArray = array[Word] of TRGBQuad; PRGBAArray = ^TRGBAArray; var x, y: Integer; TripleAlpha: Double; pColor: pRGBTripleArray; pAlpha: pbytearray; pBmp: pRGBAArray; begin DstBitMap.Height := SrcPngImage.Height; DstBitMap.Width := SrcPngImage.Width; DstBitMap.PixelFormat := pf32bit; for y := 0 to SrcPngImage.Height - 1 do begin pAlpha := SrcPngImage.AlphaScanline[y]; pColor := SrcPngImage.Scanline[y]; pBmp := DstBitMap.ScanLine[y]; for x := 0 to SrcPngImage.Width - 1 do begin pBmp[x].rgbReserved := pAlpha[x]; // преобразуем в нужный формат TripleAlpha := pBmp[x].rgbReserved / 255; pBmp[x].rgbBlue := byte(trunc(pColor[x].rgbtBlue * TripleAlpha)); pBmp[x].rgbGreen := byte(trunc(pColor[x].rgbtGreen * TripleAlpha)); pBmp[x].rgbRed := byte(trunc(pColor[x].rgbtRed * TripleAlpha)); end; end; end;
В качестве изображения используется экземпляр класса TPNGImage, что позволяет создавать полупрозрачные Splash Screen-ы.
Результат работы:

Полный код модуля:
{*******************************************************} { Splash Screen Library v1.01 } { } { Copyright(c) 2006-2012 ErrorSoft } { } { Данная библиотека предназначена для отображения } { красивых (прозрачных) SplashScreen-ов в ваших } { программах } { } { вопросы, отсчеты об ошибках, предложения сюда: } { Enter256@yandex.ru } { } {*******************************************************} unit SplashScreen; interface uses Windows, PNGImage, Forms, Graphics; type TSplashForm = TForm; TSplash = class private FImage: TPNGImage; SplashForm: TSplashForm; procedure SetImage(value: TPNGImage); procedure ToLayeredWindow; public constructor Create; overload; constructor Create(Image: TPNGImage); overload; destructor Destroy; procedure Show(StayOnTop: Boolean); procedure Close; property Image: TPNGImage read FImage write SetImage; end; implementation procedure CreatePremultipliedBitmap(DstBitMap: TBitmap; SrcPngImage: TPNGImage); type TRGBTripleArray = ARRAY[Word] of TRGBTriple; pRGBTripleArray = ^TRGBTripleArray; TRGBAArray = array[Word] of TRGBQuad; PRGBAArray = ^TRGBAArray; var x, y: Integer; TripleAlpha: Double; pColor: pRGBTripleArray; pAlpha: pbytearray; pBmp: pRGBAArray; begin DstBitMap.Height := SrcPngImage.Height; DstBitMap.Width := SrcPngImage.Width; DstBitMap.PixelFormat := pf32bit; for y := 0 to SrcPngImage.Height - 1 do begin pAlpha := SrcPngImage.AlphaScanline[y]; pColor := SrcPngImage.Scanline[y]; pBmp := DstBitMap.ScanLine[y]; for x := 0 to SrcPngImage.Width - 1 do begin pBmp[x].rgbReserved := pAlpha[x]; // преобразуем в нужный формат TripleAlpha := pBmp[x].rgbReserved / 255; pBmp[x].rgbBlue := byte(trunc(pColor[x].rgbtBlue * TripleAlpha)); pBmp[x].rgbGreen := byte(trunc(pColor[x].rgbtGreen * TripleAlpha)); pBmp[x].rgbRed := byte(trunc(pColor[x].rgbtRed * TripleAlpha)); end; end; end; constructor TSplash.Create; begin SplashForm := TSplashForm.Create(nil); FImage := TPNGImage.Create; end; constructor TSplash.Create(Image: TPNGImage); begin SplashForm := TSplashForm.Create(nil); FImage := TPNGImage.Create; FImage.Assign(Image); end; destructor TSplash.Destroy; begin SplashForm.Free; FImage.Free end; procedure TSplash.SetImage(value: TPNGImage); begin FImage.Assign(value); end; procedure TSplash.ToLayeredWindow; var BitMap: TBitMap; bf: TBlendFunction; BitmapSize: TSize; BitmapPos: TPoint; begin // создание правильной битовой карты(32 бит на пиксель, precalc альфа канал) BitMap := TBitMap.Create; CreatePremultipliedBitmap(Bitmap,FImage); // описание BlendFunction with bf do begin BlendOp := AC_SRC_OVER; BlendFlags := 0; AlphaFormat := AC_SRC_ALPHA; SourceConstantAlpha := 255; end; // получаем размеры BitMap BitmapSize.cx := Bitmap.Width; BitmapSize.cy := Bitmap.Height; // получаем координаты BitMap BitmapPos.X := 0; BitmapPos.Y := 0; // слоистый стиль окна SetWindowLong(SplashForm.Handle, GWL_EXSTYLE, GetWindowLong(SplashForm.Handle, GWL_EXSTYLE) + WS_EX_LAYERED); // превращение окна в слоистое окно UpdateLayeredWindow( SplashForm.Handle, 0, nil,//pos @BitmapSize,//size bitmap.Canvas.Handle,//src @BitmapPos,//pptsrc 0, @bf, ULW_ALPHA ); BitMap.Free; end; procedure TSplash.Show(StayOnTop: Boolean); begin // устанавливаем нужные параметры with SplashForm do begin BorderStyle := bsNone; Width := FImage.Width; Height := FImage.Height; Position := poDesktopCenter; if StayOnTop then formstyle := fsStayOnTop; end; // преобразуем в "слоистое" окно ToLayeredWindow; // показываем SplashForm.Show; end; procedure TSplash.Close; begin SplashForm.Close; end; end.
Модуль предназначен для Delphi XE и выше.
Скачать модуль и пример использования можно здесь:
TSplash.zip
Надеюсь, данный модуль сделает ваши приложения более привлекательными для пользователя.
UPD: Теперь при вызове Show(StayOnTop: Boolean), нужно указать делать SplashScreen поверх всех окон или нет.
