Форум: "Основная";
Текущий архив: 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