Как отменить регистрацию стиля с помощью TStyleManager :: UnRegisterStyle ()

Я хочу отменить регистрацию определенного стиля с помощью этого кода:

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()?

-1

Решение

Ответ был обновлен! Снова.

Ну, я не очень опытный пользователь 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 сокращение. Также были исправлены некоторые утечки памяти.

Я не уверен, есть ли другой способ перезагружать файл стиля «на лету».

2

Другие решения

Других решений пока нет …