Прозрачность глифов Delphi TSpeedButton

В настоящее время я работаю с компонентом под названием TdsTaskBar, который должен работать как панель задач в окнах, что означает, что все открытые окна (но теперь внутри моего приложения) перечислены в виде кнопок в нижней части моего окна приложения. Это кнопки TSpeedButtons. Теперь я изменил значки своих собственных окон, эти значки всегда отображаются через глиф SpeedButtons. Проблема в том, что прозрачность не работает.

Я знаю о цвете прозрачности, определяемом пикселем в левом нижнем углу, но это не моя проблема. Проблема в том, что прозрачные области глифов показывают "случайные" артефакты изображения вместо фона кнопки при смене активного окна и последующем наведении курсора на кнопки. Это меняет фон на значок теперь активного окна, но с некоторым искажением.

Открыто первое окно Открыто второе окно, навел курсор на кнопку

Я понятия не имею, как эти артефакты попадают туда, но я уверен, что они не исходят от TdsTaskBar-/TdsTaskButton-Component, потому что я изучил все процедуры, связанные с отрисовкой.

Кто-нибудь знает, как решить эту проблему? Я уже думал о том, чтобы нарисовать фон самостоятельно, но поэтому мне нужно знать фактический цвет кнопки за этим глифом, и это еще одна вещь, в которой я не уверен, как это понять.


Здесь фрагмент кода для назначения глифа, рисунок обрабатывается стандартным кодом Vcl SpeedButton:

procedure TTaskBarButton.AssignGlyphIcon;
var
  GlyphIcon: TIcon;
  b: TBitmap;
begin
  if TForm(owner).Icon.Empty then
    GlyphIcon := Application.Icon
  else
    GlyphIcon := TForm(owner).Icon;

  b := TBitmap.create;
  try
    b.Width := GlyphIcon.Width;
    b.Height := GlyphIcon.Height;
    b.Canvas.Brush.Color := b.TransparentColor;    // This two lines were added by me
    b.Canvas.FillRect(b.ClipRect);         // so that the background of my "helper" bitmap is transparent, too
    b.Canvas.Draw(0,0, GlyphIcon);
    Glyph.Width := 16;
    Glyph.Height := 16;
    Glyph.Canvas.StretchDraw(Rect(0, 0, 16, 16), b);
  finally
    b.free;
  end;
end;

person Florian Koch    schedule 07.04.2014    source источник
comment
Мне кажется, что это дефект компонента, спросите у дизайнера?   -  person whosrdaddy    schedule 07.04.2014
comment
У меня есть полные исходники компонента, и это не так много кода, всего один короткий модуль. Рисунок глифа прост и понятен, я действительно уверен, что ошибка не в нем. Я отредактирую вопрос и добавлю код рисунка Glyph.   -  person Florian Koch    schedule 07.04.2014
comment
Я не вижу, где вы очищаете фон Glyph. Я тоже не очень понимаю, зачем вам b. Наконец, похоже, вы используете изображения с альфа-прозрачностью. Если да, то зачем использовать TransparentColor?   -  person David Heffernan    schedule 07.04.2014
comment
@DavidHeffernan Я также могу сделать то же самое, что и в своем растровом изображении в глифе, но это не меняет результат ... Растровое изображение используется в случае, если значок приложения не имеет размер 16x16 пикселей, поэтому я могу использовать растягивание . Я не изобретал этот код, но и не менял его, потому что он казался мне законным.   -  person Florian Koch    schedule 07.04.2014
comment
@SirRufo Это лучшее решение, вы правы, но это ничего не меняет в отношении прозрачности.   -  person Florian Koch    schedule 07.04.2014
comment
Я ошибся, основная проблема в том, как сказал Дэвид, фон Glyph не стирается и из-за прозрачности вы получите эти артефакты   -  person Sir Rufo    schedule 07.04.2014
comment
Но тогда как правильно стереть фон Glyph? Я сделал то же самое с Fillrect(ClipRect), но это ничего не изменило в том, что я вижу...   -  person Florian Koch    schedule 07.04.2014
comment
@DavidHeffernan только что заметил, что я полностью проигнорировал вторую часть вашего комментария. Что вы имеете в виду под «Зачем использовать прозрачный цвет»? Я думал, что рисунок BitMap не поддерживает нормальную прозрачность, скажем, png, через альфа-канал?   -  person Florian Koch    schedule 07.04.2014
comment
Растровые изображения Windows поддерживают альфа-канал. Это собственный формат растровых изображений платформы, поэтому было бы удивительно, если бы они этого не сделали. Типичный файл .bmp не поддерживает альфа-канал, но это другое. Наверняка у вашего изображения есть альфа?   -  person David Heffernan    schedule 07.04.2014
comment
Это файл .ico, разработанный кем-то из моей компании, но я бы сказал «да», потому что обычно они прозрачны, когда я открываю их в программах для просмотра изображений. Итак, вы имеете в виду, что мне не нужно использовать Bitmap.Transparent, хорошо. Но когда я отключу это явно или просто проигнорирую его и возьму стандартную реализацию TdsTaskBar, фон всегда будет белым... Должен ли я включать некоторые параметры для использования рисования с поддержкой альфа-канала? Редактировать: я также могу просто назначить свой GlyphIcon глифу, но это то же самое: хотя значок прозрачен в углу моего окна, он имеет белый фон   -  person Florian Koch    schedule 07.04.2014
comment
Я не уверен в этих вопросах. Я бы помог, но нет SSCCE. Мне пришлось бы возиться, пытаясь сделать репродукцию с небольшой уверенностью, что я сделал это правильно.   -  person David Heffernan    schedule 07.04.2014
comment
Я не уверен, смогу ли я предоставить SSCCE, потому что мне нужен хотя бы проект, который может отображать собственные MDI-Windows для использования компонента TaskBar, поэтому даже пример проекта не очень короткий   -  person Florian Koch    schedule 07.04.2014
comment
Вы думаете, что это взаимодействие со всем этим? Мне кажется маловероятным. Я не понимаю, почему люди так не хотят делать SSCCE.   -  person David Heffernan    schedule 07.04.2014


Ответы (2)


Вы должны стереть фон Glyph.

Вот пример кода, который должен выполнять эту работу

procedure TTaskBarButton.AssignGlyphIcon;
var
  b: TBitmap;
  r: TRect;
begin
  b := TBitmap.create;
  try
    if TForm( Owner ).Icon.Empty then
      b.Assign( Application.Icon )
    else
      b.Assign( TForm(Owner).Icon );

    r := TRect.Create( 0, 0, 16, 16 );
    Glyph.Width := r.Width;
    Glyph.Height := r.Height;
    // clear the background
    Glyph.Canvas.Brush.Color := Glyph.TransparentColor;
    Glyph.Canvas.FillRect( r );
    // draw the icon
    Glyph.Canvas.StretchDraw( r, b );
  finally
    b.free;
  end;
end;
person Sir Rufo    schedule 07.04.2014
comment
извините, но проблема не решена .. все те же эффекты, что и описанные в вопросе - person Florian Koch; 07.04.2014
comment
хотя ваша реализация, очевидно, намного лучше оригинальной: D - person Florian Koch; 07.04.2014
comment
Я не устанавливал компонент, но с помощью обычного SpeedButton я могу нарисовать иконку на Glyph без побочных эффектов. - person Sir Rufo; 07.04.2014
comment
хорошо... Тогда я должен копаться в подпрограммах, если я что-то контролировал в отношении рисования. - person Florian Koch; 07.04.2014

Нашел решение: TdsTaskBar (это TCustomPanel) имеет значение DoubleBuffered по умолчанию, равное false. Кнопки наследуют этот параметр. Изменение этого параметра на true решает проблему.

Таким образом, кажется, что двойная буферизация влияет на функциональность прозрачности кнопок.

person Florian Koch    schedule 08.04.2014
comment
Это прекрасная демонстрация того, почему вы должны были сделать SSCCE! - person David Heffernan; 08.04.2014
comment
да, думаю, ты прав... я подумаю об этом в следующий раз, когда что-нибудь сделаю и сделаю SSCCE - person Florian Koch; 08.04.2014
comment
В 90% случаев вы выполняете SSCCE, и это приводит вас к источнику проблемы. Это беспроигрышный вариант! - person David Heffernan; 08.04.2014