Я хочу отменить регистрацию определенного стиля с помощью этого кода:
void __fastcall TfrmMain::btnUnregStyleClick(TObject *Sender)
{
TCustomStyleServices *MyStyle;
// Get wanted style
MyStyle = TStyleManager::Style["Emerald"]; // this will return a TCustomStyleServices obj
if (MyStyle != NULL)
{
// Remove it
TStyleManager::UnRegisterStyle(MyStyle); // This will set default Windows style (no style)
}
}
Оно работает. Кажется, что стиль не зарегистрирован, и графический интерфейс пользователя автоматически переключается на стиль Windows по умолчанию.
Но когда программа закрывается, я получаю эту ошибку:
Project Project.exe поднял класс исключения $ C0000005 с сообщением
‘нарушение прав доступа по адресу 0x5005fd50: чтение адреса 0xffffffd0’.
Вот стек вызовов:
: 5005fd50 rtl250. @ System @ TObject @ InheritsFrom $ qqrp17System @ TMetaClass + 0x8 : 50d12a8d vcl250. @ Vcl @ Styles @ TStyleEngine @ Уведомление $ qqr54Vcl @ Темы @ TCustomStyleEngine @ TStyleEngineNotificationpv + 0x1d : 00e5a612 vclwinx250. @ Vcl @ Winxctrls @ TSearchBox @ $ bcdtr $ qqrv + 0x1e : 0041fa0f __cleanup + 0x1F : 0041fb92; __wstartup[Обновление: эта ошибка исправлена, если я удаляю TeeChart из своей формы. Но
UnRegisterStyle()
все еще не будет работать]
Если после UnRegisterStyle()
Я звоню:
TStyleManager::LoadFromFile(usStylePath);
TStyleManager::SetStyle("Emerald");
это скажет мне, что «изумрудный стиль уже зарегистрирован».
Итак, очевидно UnRegisterStyle()
выходит из строя.
Получение списка «стилей» через TStyleManager::StyleNames()
показывает, что список остается неизменным после UnRegisterStyle()
,
Embarcadero не может помочь с этой функцией. Должен ли я позвонить что-то еще, кроме UnRegisterStyle()
?
Ответ был обновлен! Снова.
Ну, я не очень опытный пользователь VCL
Это стили, но я постараюсь объяснить, что нужно делать, чтобы избежать вашей проблемы. Прежде чем читать дальше, я должен сказать вам: нет никакого способа отменить регистрацию любого стиля.
Во-первых, вы должны знать, что VCL
стили использует внутренние FRegisteredStyles
словарь для хранения все зарегистрированные стили. Стиль стал зарегистрированным после TStyleManager.LoadFromFile(YourStyleName)
был вызван. К сожалению, стиль никогда не удаляется из словаря.
Не использовать UnregisterStyle
процедура. Это не отменяет стиль вообще. Просто удаляет указанный стиль из списка имеется в наличии стили. Таким образом, после звонка UnregisterStyle(YourStyle)
вы просто уничтожаете YourStyle
из внутреннего списка, а не из словаря, упомянутого ранее, и не может установить этот стиль.
После успешного звонка UnregisterStyle()
ты можешь позвонить LoadFromFile()
Метод и удивление, почему заявка сказала:
Стиль «Изумруд» уже зарегистрирован.
Это происходит потому, что LoadFromFile()
Метод загружает указанный стиль и проверяет его наличие во внутреннем словаре зарегистрированных стилей. Эта проверка всегда возвращает true
как UnregisterStyle()
процедура не удаляет указанный стиль из словаря.
То же самое относится и к собственности StyleNames
, Это свойство возвращает имя стиля использует внутренний FRegisteredStyles
словарь для получения имени стиля с указанным индексом.
Если вы хотите узнать мое мнение, такое поведение стиля странно. метод UnregisterStyle()
Также следует удалить указанный стиль из словаря. Может быть, я ошибаюсь, но это настоящая ошибка. С другой стороны, ошибки нет — вы пытаетесь использовать недокументированный метод. Истина где-то рядом.
В заключение я бы порекомендовал вам использовать прямой доступ к стилям, чтобы решить, использовать выбранный стиль или нет. Посмотрите код ниже (при условии, что у вас включен стиль приложения):
procedure TForm1.Button1Click(Sender: TObject);
begin
if Assigned(TStyleManager.Style['Emerald']) and TStyleManager.Style['Emerald'].Available then
// Do your code
else
ShowMessage('Specified style is not available!');
end;
Если у вас есть источники VCL.Themes
Вы можете легко проверить достоверность того, что я написал здесь.
Я создал class-helper
за TStyleManager
это позволяет проверить, зарегистрирован ли файл стиля, и при необходимости отменить его регистрацию. Для того, чтобы заполнить TStyleInfo
запись с реальными значениями из файла стиля, нам нужно сохранить указанный стиль в TMemoryStream
а затем передать поток IsValidStyle
функция. Также мы могли бы использовать физический путь стиль (например, C:\Embarcadero\Delphi\Styles\Emerald.vsf
) вместо варианта с потоком, но последний выглядит более элегантно.
К сожалению, согласно Комментарий Реми (Я не знаю, как сделать ссылку на него), C++ Builder
(который используется OP) не поддерживает class-helper
особенность. Единственное решение — создать простой модуль, содержащий весь код, необходимый для class-helper
, Для работы достаточно добавить такой блок в uses
и вызывать соответствующие публичные процедуры \ функции.
Этот блок имеет следующую структуру:
unit StyleManager_CH;
interface
uses
VCL.Themes;function IsStyleRegistered_CH(var AStyle: TCustomStyleServices): Boolean;
procedure UnregisterStyleEx_CH(var AStyle: TCustomStyleServices);implementation
uses
System.SysUtils, System.Classes, System.Generics.Collections;type
TStyleManagerHelper = class helper for TStyleManager
public
class function IsStyleRegistered(var AStyle: TCustomStyleServices): Boolean;
class procedure UnregisterStyleEx(var AStyle: TCustomStyleServices);
end;class function TStyleManagerHelper.IsStyleRegistered(var
AStyle: TCustomStyleServices): Boolean;
begin
Result := Assigned(AStyle) and
TStyleManager.FRegisteredStyles.ContainsKey(AStyle.Name);
end;
class procedure TStyleManagerHelper.UnregisterStyleEx(var
AStyle: TCustomStyleServices);
var
MS: TMemoryStream;
StyleInfo: TStyleInfo;
SourceInfo: VCL.Themes.TStyleManager.TSourceInfo;
begin
if Assigned(AStyle) then
begin
MS := TMemoryStream.Create;
try
AStyle.SaveToStream(MS);
MS.Position := 0;
if AStyle.IsValidStyle(MS, StyleInfo) then
begin
if TStyleManager.FRegisteredStyles.ContainsKey(StyleInfo.Name) then
begin
SourceInfo := TStyleManager.FRegisteredStyles.Items[StyleInfo.Name];
if Assigned(SourceInfo.Data) then
FreeAndNil(SourceInfo.Data);
TStyleManager.FStyles.Remove(AStyle);
TStyleManager.FRegisteredStyles.Remove(StyleInfo.Name);
FreeAndNil(AStyle);
end;
end;
finally
MS.Free;
end;
end;
end;
function IsStyleRegistered_CH(var AStyle: TCustomStyleServices): Boolean;
begin
Result := TStyleManager.IsStyleRegistered(AStyle);
end;
procedure UnregisterStyleEx_CH(var AStyle: TCustomStyleServices);
begin
TStyleManager.UnregisterStyleEx(AStyle);
end;end.
добавление _CH
обозначает class-helper
сокращение. Также были исправлены некоторые утечки памяти.
Я не уверен, есть ли другой способ перезагружать файл стиля «на лету».
Других решений пока нет …