Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.08.28;
Скачать: [xml.tar.bz2];

Вниз

Прозрачность SpeedButton при включенных стилях XP.   Найти похожие ветки 

 
Tab   (2005-08-07 23:09) [0]

Вообщем ситуация такая:
На Image лежит SpeedButton (Flat=true, transparent=true) Glyph прозрачный, в местах прозрачности виден фон Image1.
Если же включить стиль XP синий, или серебристый.
То при том же расположении SpeedButton, в местах прозрачности закрашивается цветом BtnFace т.е. цветом формы на которой лежит Image.
Естественно SpeedButton очень не красиво выделяется на фоне image.
Вопрос в следующем: Можно ли как то указать для SpeedButton что он должен отображат фон Image а не Form"ы?


 
y-soft ©   (2005-08-08 08:51) [1]

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

Автоматически правильно рисуются только стандартные контролы Windows

TBitBtn тоже, кстати, неправильно рисуется


 
Tab   (2005-08-08 22:02) [2]

Или отрисовать не зависимо от темы?
А можно посмотреть на код определяющий используется тема или нет?


 
Наиль ©   (2005-08-08 22:07) [3]

Странно, а у меня всё нормально.


 
Tab   (2005-08-08 22:10) [4]

Нарисуй что нибудь на image (закрась однородным цветом) и включи серебристую тему, и положи на него Flat, transparent SpeedButton/


 
Mx ©   (2005-08-08 22:13) [5]


> Tab   (08.08.05 22:02) [2]
> А можно посмотреть на код определяющий используется тема
> или нет?

Если используется что-то вроде ThemeServices.ThemesEnabled, то однозначно используется Themes API... или по-крайней мере об этом задумываются :)


 
Наиль ©   (2005-08-08 22:28) [6]

Так и сделал, всё ОК.


 
Ученик   (2005-08-09 00:17) [7]

>Наиль ©   (08.08.05 22:28) [6]
Проблема действительно есть, наверно не подключили манифест


 
Наиль ©   (2005-08-09 01:23) [8]

Манифест подключил. Проблема возникла. Посмотрел исходники. Цвет панели оказался не при чём. При рисовании плоской кнопки Делфя запрашивает у Винды как должен выглядеть ToolButton. И рисует, вернее просит нарисовать, соответсвующий прямоугольник. После этого рисуется значок (прозрачный) поверх прямоугольника. При этом Transparent игнорируется. Сделано это, по видимому, для того чтобы острые углы от InflateRect не портили общую картину.
Выход один, создавать собственую компаненту на основе Image.


 
Наиль ©   (2005-08-09 02:37) [9]

Попытался найти более дешёвое решение. Вот результат:
Uses Themes, Buttons и т.д.;
 TThem=Class(TThemeServices)
 private
  function GetThemesEnabled: Boolean;
  procedure SetThemesEnabled(const Value: Boolean);
 published
  property ThemesEnabled:Boolean read GetThemesEnabled write SetThemesEnabled;
 End;

 TSpeed=Class(TSpeedButton)
 protected
   procedure Paint; override;
 End;

implementation
{ TSpeed }

procedure TSpeed.Paint;
Var
x:TThemeServices;
b:boolean;
begin
x:=ThemeServices;
b:=x.ThemesEnabled;
if x is TThem then TThem(x).ThemesEnabled:=false;
inherited;
if x is TThem then TThem(x).ThemesEnabled:=b;
end;

{ TThem }

function TThem.GetThemesEnabled: Boolean;
begin
result:=inherited ThemesEnabled;
end;

procedure TThem.SetThemesEnabled(const Value: Boolean);
Var
p:^Boolean;
begin
p:=@inherited ThemesAvailable;
p^:=Value;
end;

initialization
ThemeServicesClass:=TThem;
end.

TSpeed не подчиняется манифесту.
Про этот способ можно сказать: "дешево не значит качественно".
Если в модуле Themes будут изменения (в будущем) связаные с ThemesEnabled или ThemesAvailable, то код перестанет работать.
Так что, первый вариант надёжный, а этот быстрый.


 
y-soft ©   (2005-08-09 08:00) [10]

Буквально вчера столкнулся с необходимостью надежно определять, использует ли приложение темы.

В ThemeAPI есть функция IsAppThemed, которая согласно MSDN и должна давать искомый результат. Но, как выяснилось, работает она неправильно - всегда возвращает True, если Windows использует тему :(

Работаю я в Delphi 5, поэтому использовать подходы, аналогичные ранее предложенным не получается

Решил использовать тот факт, что темы могут использоваться приложением только в том случае, если загружена ComCtl32.dll версии 6 или старше, а специально для того, чтобы определить версию загруженной ComCtl32.dll, Microsoft заботливо предусмотрела экспортируемую этой библиотекой функцию DllGetVersion. Если темы не используются, то всегда грузится ComCtl32.dll версии 5 или ниже...

В результате написал вот такую функцию (благодаря использованию чистого WinAPI работает быстро):


uses
 Windows;
const
 COMCTL32_DLL = "comctl32.dll";
 DLLGETVERSION_NAME = "DllGetVersion";
 MINCOMCTL32_MAJORVERSION = 6;

type
 TDllVersionInfo = record
   cbSize : DWORD;
   dwMajorVersion : DWORD;
   dwMinorVersion : DWORD;
   dwBuildNumber : DWORD;
   dwPlatformID : DWORD;
 end;
 TDllGetVersion = function(var dvi : TDllVersionInfo) : HResult; stdcall;

function IsThemedAPI : boolean;
var
 hMod : HMODULE;
 dvi : TDllVersionInfo;
 DllGetVersion : TDllGetVersion;
begin
 Result := False;
 //Если темы используются, то в любом случае
 //уже загружена ComCtl32.dll
 hMod := GetModuleHandle(COMCTL32_DLL);
 if hMod <> 0 then
 begin
   //ComCtl32.dll должна экспортировать функцию DllGetVersion
   DllGetVersion := GetProcAddress(hMod, DLLGETVERSION_NAME);
   if assigned(DllGetVersion) then
   begin
     //Обязательно инициируем запись dvi!!!
     dvi.cbSize := SizeOf(dvi);
     //Получаем информации о версии загруженной ComCtl32.dll
     if SUCCEEDED(DllGetVersion(dvi)) then
     begin
       //Если используются темы, то версия ComCtl32.dll не менее 6.x.x.x
       if (dvi.dwMajorVersion >= MINCOMCTL32_MAJORVERSION) then
         Result := True;
     end;
   end;
 end;
end;


P.S. Можно усилить функцию дополнительной проверкой, загружена ли uxtheme.dll и вызовом, экспортируемых ей IsAppThemed и IsThemeActive


 
y-soft ©   (2005-08-09 08:43) [11]

Подумал и решил дополнить

Строго говоря, возможны 3 случая, когда надо определять, используются ли темы:

1. При инициализации приложения - поддерживаются ли темы ОС вообще
2. При изменении глобальных настроек ОС
3. При изменении настроек приложения

Отсюда алгоритм использования функции (совсем необязательно вызывать при каждой отрисовке):

1. При инициализации приложения
2. При получении сообщения WM_THEMECHANGED
3. При изменении настроек, определяющих использование тем приложением...


 
Mx ©   (2005-08-09 11:05) [12]


> y-soft ©   (09.08.05 08:43) [11]

Чем не устраивает стандартный ThemesEnabled? Я с ним проблем не имел. У меня TSpeedButton нормально все определяет.


 
y-soft ©   (2005-08-09 12:01) [13]

>Mx ©   (09.08.05 11:05) [12]
y-soft ©   (09.08.05 08:00) [10]
 Работаю я в Delphi 5, поэтому использовать подходы, аналогичные ранее предложенным не получается


В D7 естественно мудрить незачем


 
Mx ©   (2005-08-09 12:37) [14]


> y-soft ©   (09.08.05 12:01) [13]

Упс, извиняй, про D5 не заметил. Кстати, может тебе поможет код функции ThemesEnabled из Delphi 7?

Судя по нему должны выполняться следующие условия:

1) Наличие uxtheme.dll
2) GetComCtlVersion >= ComCtlVersionIE6, где ComCtlVersionIE6 = $00060000
3) Функции IsThemeActive и IsAppThemed библиотеки uxtheme.dll возвращают True

Ну и, естественно, реакция на WM_THEMECHANGED. Динамически необходимо работать только с 3-м пунктом.


 
y-soft ©   (2005-08-09 13:44) [15]

>Mx ©   (09.08.05 12:37) [14]

Хм... Вообще-то я сам в [10] привожу решение :)
Насчет IsThemeActive и глюка IsAppThemed там же


 
Tab   (2005-08-09 22:38) [16]

Насчет определения темы понятно.
А вот насчет отключения тем именно  для SpeedButton что-то не понял. Если можно поподробнее.


 
Наиль ©   (2005-08-09 23:59) [17]

Попробую прокоментировать свой код [9].
Для взаимодействия с темами используется функция ThemeServices которая возвращает объект InternalServices
Для проверки активности темы используется метод ThemesEnabled (TE). Если создать потомка от спидбутона, в паинте которого отключать и востанавливать активность темы, то можно получить не активный к темам компонент. К сожалению, TE - ReadOnly-свойство. Если бы InternalService был бы другого типа, то TE можно было бы менять. Т.к. IS создаётся при первом обращении к нему из глобальной переменной-класса
ThemeServicesClass:=TThemeServices (TSC и TTS), то мы заменяем её на свой класс-потомок  с изменяемым TE. Хуже всего, то что в классе TThemeServices нет  virtul-методов protected-public-полей. В результате повлиять любыми  чесными способами на поведение TE, нет возможности. Но TE зависит от private поля FAvailable. Изменяя его изменяем TE  (procedure SetThemesEnabled).
Что получилось:
1) Подменяем тип объекта ThemeServices на класс с изменяемым TE (Initialization)
2) При рисовании любого контрола создаётся объект IS, возвращаемый функцией ThemeServices, с нашим типом.
3) При изменении TE в нашем классе, методом грубой силы изменим private-поле предка (т.е. в TTS) FAvailable. В результате чего TE тоже меняется. (SetThemesEnabled)
4) Перед рисованием потомка от Спидбуттона делаем TE:=false, а после востанавливаем (procedure TSpeed.Paint)
PS. Смешно, но сутки назад я даже не знал, что такое темы в Delphi.
PPS Востановлено из дневка PuntoSwitcher, поэтому в тексте могут быть корявости.


 
Наиль ©   (2005-08-10 00:05) [18]

Чтобы вникнуть в выше написанный текст, придётся не раз его перечитать. Для удобства анализа повторю свой код.
Uses Themes, Buttons и т.д.;
TThem=Class(TThemeServices)
private
 function GetThemesEnabled: Boolean;
 procedure SetThemesEnabled(const Value: Boolean);
published
 property ThemesEnabled:Boolean read GetThemesEnabled write SetThemesEnabled;
End;

TSpeed=Class(TSpeedButton)
protected
  procedure Paint; override;
End;

implementation
{ TSpeed }

procedure TSpeed.Paint;
Var
x:TThemeServices;
b:boolean;
begin
x:=ThemeServices;
b:=x.ThemesEnabled;
if x is TThem then TThem(x).ThemesEnabled:=false;
inherited;
if x is TThem then TThem(x).ThemesEnabled:=b;
end;

{ TThem }

function TThem.GetThemesEnabled: Boolean;
begin
result:=inherited ThemesEnabled;
end;

procedure TThem.SetThemesEnabled(const Value: Boolean);
Var
p:^Boolean;
begin
p:=@inherited ThemesAvailable;
p^:=Value;
end;

initialization
ThemeServicesClass:=TThem;
end.

Добавь сюда Register для TSpeed. Помести модуль в пакет и получишь компонент который ведёт себя как класический спидбутон, но независящий от темы.
Кстати, если управлять ThemesEnabled когда Transparent, то будет удобней.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.08.28;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.041 c
10-1100616891
MegaLexx
2004-11-16 17:54
2005.08.28
Нетривиальный (то бишь неправильный) импорт ActiveX компонента


14-1123061077
StarCarfter
2005-08-03 13:24
2005.08.28
Как из DLL и EXE-файлов вытащить исходный код?


9-1115234771
Qwertyk
2005-05-04 23:26
2005.08.28
3D Модель танка (любого)


3-1121348982
Uran
2005-07-14 17:49
2005.08.28
Номер недели в ADO


14-1123410322
Juice
2005-08-07 14:25
2005.08.28
Компонент-сетка с выпадающим списком





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский