-1

我想使用以下代码取消注册特定样式:

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)
    }
}

有用。该样式似乎未注册,GUI 会自动切换到默认的 Windows 样式。

但是当程序关闭时,我收到此错误:

Project Project.exe 引发异常类 $C0000005,并带有消息“0x5005fd50 的访问冲突:读取地址 0xffffffd0”。

这是调用堆栈:

:5005fd50 rtl250.@System@TObject@InheritsFrom$qqrp17System@TMetaClass + 0x8
:50d12a8d vcl250.@Vcl@Styles@TStyleEngine@Notification$qqr54Vcl@Themes@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()吗?

4

1 回答 1

3

答案已更新!再次。

好吧,我不是很有经验VCL的样式用户,但我会尝试解释如何避免你的问题。在您进一步阅读之前,我应该告诉您:没有办法取消注册任何样式

风格与否 风格

首先,您必须知道VCL's 样式使用内部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-helperTStyleManager允许检查样式文件是否已注册并在需要时取消注册。为了TStyleInfo用样式文件中的真实值填充记录,我们需要将指定的样式保存到TMemoryStream然后将流传递给IsValidStyle函数。我们也可以使用物理路径来样式化 (fe C:\Embarcadero\Delphi\Styles\Emerald.vsf) 而不是带有流的变体,但后者看起来更优雅。

不幸的是,根据Remy 的评论(我不知道如何创建链接),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缩写。还修复了一些内存泄漏。

我不确定是否有另一种方法可以“即时”重新加载样式文件。

于 2018-10-24T12:22:16.053 回答