Здравствуйте!
Создаю LayeredWindow по PNG картинке (картинки загружаю с помощью модуля pngimage: http://pngdelphi.sourceforge.net). Код ниже.
Только почему-то никакие контролы на ней не отображаются.
Копался в MSDN, пробовал методом тыка - не получилось :(
Кто знает, в чем загвоздка?
uses
..., pngimage;
type
pRGBQuadArray = ^TRGBQuadArray;
TRGBQuadArray = array [WORD] of TRGBQuad;
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
20-03-2007 05:38
Кстати оффсет у вас получается, потому что не берете в расчет стиль окна - а он с Caption. Либо делайте стиль окна без WS_CAPTION (ну или borderstyle = bsNone), либо учитывайте высоту Caption (см.GetSystemMetrics)
2RentGen:
>>>Что-то не въехал, что "это"...
под "этим" я подразумевал что собрал твой код в одну кучу,
немного подшаманил чтоб заработало и добавил пример с двумя картинками
Извини не сразу понял вопрос=)
2 qnxoid:
Что-то не въехал, что "это"...
Может я image'и не так расположил или еще что-то?
Вижу ту же Layered форму, но с двумя черными квадратами (image'ми) на ней.
Можете пояснить?
я там в тех имиджах две картинки кнопки засунул. если интересуют исходники пиши в личку - вышлю.
2 qnxoid:
>сейчас за 3 минуты заделал это
Что-то не въехал, что "это"...
Может я image'и не так расположил или еще что-то?
Вижу ту же Layered форму, но с двумя черными квадратами (image'ми) на ней.
Можете пояснить?
>вот на этих двух сайтах чёто есть
Как раз по этому примеру на VC++ с CodeProject'а собственно и создавал такую форму в Delphi.
К сожалению, там ничего нет по отрисовке дочерних форм на LayeredWindow.
Интересно, что на форумах sources.ru зарегистрироваться удалось почему-то только после указания в поле "пол" значения "я не знаю :)" ))) До этого страница не грузилась :)
Да и плюс ко всему надо ещё проверять рабочую платформу на Windows 9х.
А то юзер так и не воспользуется ФУНКЦИОНАЛЬНОСТЬЮ проги
И под Win9x выдавать пользователю более простую форму.
procedure TForm1.FormMouseEnter(Sender: TObject);
begin
UpdateWindow;
end;
procedure TForm1.Image1MouseLeave(Sender: TObject);
begin
Image2.Visible:=true;
Image1.Visible:=false;
UpdateWindow;
end;
procedure TForm1.Image2MouseEnter(Sender: TObject);
begin
Image1.Visible:=true;
Image2.Visible:=false;
UpdateWindow;
end;
procedure TForm1.UpdateWindow;
var
DC: HDC;
begin
if Assigned(FWorkBMP) then
begin
DC := GetDC(0);
TopLeft.X := Left;
TopLeft.Y := Top;
Button1.PaintTo(FWorkBMP.Canvas, Button1.Left, Button1.Top);
PremultiplyBitmapRect(FWorkBMP, ShiftRect(Button1.ClientRect, Point(Button1.Left, Button1.Top)));
if Image1.Visible then
Begin
// у Image не было PaintTo =)
FWorkBMP.Canvas.Draw(Image1.Left,Image1.Top,Image1.Picture.Bitmap);
PremultiplyBitmapRect(FWorkBMP, ShiftRect(Image1.ClientRect, Point(Image1.Left, Image1.Top)));
end;
if Image2.Visible then
Begin
FWorkBMP.Canvas.Draw(Image2.Left,Image2.Top,Image2.Picture.Bitmap);
PremultiplyBitmapRect(FWorkBMP, ShiftRect(Image2.ClientRect, Point(Image2.Left, Image2.Top)));
end;
// правда картинки сдвинуты вверх, на какую-то дельту
// поэтому надо ещё позырить
UpdateLayeredWindow(Self.Handle, DC, @TopLeft, @BmpSize,
FWorkBMP.Canvas.Handle, @BmpTopLeft, clNone, @Blend, ULW_ALPHA);
ReleaseDC(0, DC);
end;
end;
procedure TForm1.PremultiplyBitmapRect(BMP: TBitmap; const Rect: TRect);
var
i, j: integer;
Row: pRGBQuadArray;
begin
for i := Rect.Top to Rect.Bottom - 1 do
begin
Row := BMP.Scanline[i];
for j := Rect.Left to Rect.Right - 1 do
begin
Row[j].rgbReserved := MaxByte;
Row[j].rgbBlue := Round(Row[j].rgbBlue * Row[j].rgbReserved / MaxByte);
Row[j].rgbGreen := Round(Row[j].rgbGreen * Row[j].rgbReserved / MaxByte);
Row[j].rgbRed := Round(Row[j].rgbRed * Row[j].rgbReserved / MaxByte);
end;
end;
end;
Я над этим думал, но ничего подходящего в голову не пришло.
Есть, конечно, вариант - реализовать у нужных компонентов метод PaintTo,
но это не решит второй проблемы, когда компонент сам обновляет свое содержимое.
Решил сделать перерыв - глядишь потом и придет умная мысль :)
procedure TForm1.UpdateWindow;
var
DC: HDC;
begin
if Assigned(FWorkBMP) then
begin
DC := GetDC(0);
TopLeft.X := Left;
TopLeft.Y := Top;
Button1.PaintTo(FWorkBMP.Canvas, Button1.Left, Button1.Top);
PremultiplyBitmapRect(FWorkBMP, ShiftRect(Button1.ClientRect, Point(Button1.Left, Button1.Top)));
Т.е. просто рисуем все визуальные компоненты (в данном примере только одну кнопку)
на битмэп, который потом передаем в UpdateLayeredWindow.
UpdateWindow вызываем каждый раз, когда нужно обновить содержимое формы.
Конечно все это нужно еще довести до ума, определив все события при которых будет вызываться UpdateWindow. Для начала попробовал на WM_MOVE и событиях мыши - работает отлично :)
Дело в том, что вызовы SetLayeredWindowAttributes и UpdateLayeredWindow заставляет систему вести себя принципиально по разному по отношению к окну.
С помощью SetLayeredWindowAttributes можно добавить окну полупрозрачность, но при этом оно будет по прежему получать сообщения WM_PAINT и корректно прорисовывать все свои контролы. При этом все вызовы UpdateLayeredWindow будут терпеть неудачу до тех пор, пока стиль WS_EX_LAYERED не будет сброшен и установлен вручную заново.
Вызов же UpdateLayeredWindow заставит систему обновить содержимое окна (в него войдет только то, что вы передадите в параметрах функции), и за всю дальнейшую перерисовку будет отвечать Windows.
Спасибо!
Статьи почитал, примеры посмотрел... Весьма познавательно.
И все же не совсем понятно как использовать SetLayeredWindowAttributes для
того, чтобы рисовать контролы на layered window, о чем упоминается здесь:
The second way to use layered windows is to continue using the Win32 painting paradigm, but allowing the system to redirect all the drawing for the layered window and its children into an off-screen bitmap. This can be done by calling SetLayeredWindowAttributes with the desired constant alpha value and/or the color-key. Once the API has been called, the system will start redirecting all drawing by the window and automatically apply the specified effects.
Не подскажете где ее (SetLayeredWindowAttributes) нужно использовать приведенном выше коде?
Только почему-то никакие контролы на ней не отображаются.
А они и не должны отображаться. Это такая особенность Layered-окон. Контролы придется отрисовывать самому. Почему так происходит, немного описано здесь. если вкратце, то Layered-окно перестает получать сообщение WM_PAINT и компонент никогда не получит команду на отрисовку самого себя.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.