如何使用 TStyleManager::UnRegisterStyle() 取消注册样式
How to unregister style using 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)
}
}
它有效。样式似乎未注册,GUI 会自动切换到默认的 Windows 样式。
但是当程序关闭时,我收到此错误:
项目项目.exe引发异常类 $C 0000005 并带有消息 "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()
?
答案已更新!再。
好吧,我不是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
来源,您可以轻松检查我在这里所写内容的合理性。
高技术
我已经为TStyleManager
创建了class-helper
,允许检查样式文件是否已注册并在需要时取消注册。为了用 style-file 中的实际值填充TStyleInfo
记录,我们需要将指定的样式保存到TMemoryStream
然后将 stream 传递给IsValidStyle
函数。我们也可以使用物理路径来样式(例如C:EmbarcaderoDelphiStylesEmerald.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
缩写。还修复了一些内存泄漏。
我不确定是否有另一种方法可以"即时">重新加载样式文件。
- 挂起和取消挂起一个文件DLL
- 无法将结构注册为增强几何体3D点
- 如何取消对nullptr的屏蔽,返回正确的对象
- C++取消引用指针.为什么会发生变化
- 如何使用AngelScript注册SFML Vector2运算符
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 取消引用运算符不能重载
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 在遍历处理程序的向量时注册和注销处理程序
- 如何在Qt中取消捕获字符串
- 有没有任务栏API可以立即应用注册表更改
- 使用QJsEngine在Qt中注册自定义类型
- 检查注册表项是否链接到(或副本)另一个注册表项
- 如何使用 TStyleManager::UnRegisterStyle() 取消注册样式
- GLEW/GLUT:调用init并创建一个窗口后,取消初始化并重新初始化?
- C++ 关于指针取消引用的技术问题
- WINAPI 注册应用程序重新启动时不清除打开的套接字
- 在多个线程上自行取消/注册Observer
- std::函数作为回调,可以取消注册
- 我们是否应该在取消注册时删除观察者