Disable setting for certain controls?

I know that you can use SetWindowTheme found in uxTheme.pas to disable / enable themes on controls, for example, such as:

SetWindowTheme(Button1.Handle, nil, nil); 

This works on quite a few controls, however it will not work on some controls, such as TBitBtn or TSpeedButton. I think it should be because TBitBtn and TSpeedButton are not Windows controls, but normal?

There may be other controls that won't work either, so I was hoping someone could share a solution or an alternative to achieve this?

I want some controls to have no theme at all, for example, they will appear as classic, and the rest of the controls will not be affected.

Thanks.

+8
delphi delphi-xe
source share
2 answers

Your analysis is correct. SetWindowTheme works for window controls, but TSpeedButton and TBitBtn are non-vinyl items.

In XE, from my quick scan, it seems that most controls call Themes.ThemeControl to determine if they should be drawn. Thus, a simple solution is to replace this procedure with logic that you control. Since it does not provide any extension points, you need to connect it. Like this:

 procedure PatchCode(Address: Pointer; const NewCode; Size: Integer); var OldProtect: DWORD; begin if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then begin Move(NewCode, Address^, Size); FlushInstructionCache(GetCurrentProcess, Address, Size); VirtualProtect(Address, Size, OldProtect, @OldProtect); end; end; type PInstruction = ^TInstruction; TInstruction = packed record Opcode: Byte; Offset: Integer; end; procedure RedirectProcedure(OldAddress, NewAddress: Pointer); var NewCode: TInstruction; begin NewCode.Opcode := $E9;//jump relative NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode); PatchCode(OldAddress, NewCode, SizeOf(NewCode)); end; function MyThemeControl(AControl: TControl): Boolean; begin Result := False; if AControl = nil then exit; if AControl is TSpeedButton then exit; if AControl is TBitBtn then exit; Result := (not (csDesigning in AControl.ComponentState) and ThemeServices.ThemesEnabled) or ((csDesigning in AControl.ComponentState) and (AControl.Parent <> nil) and (ThemeServices.ThemesEnabled and not UnthemedDesigner(AControl.Parent))); end; initialization RedirectProcedure(@Themes.ThemeControl, @MyThemeControl); 

Be that as it may, this will not work with runtime packages, but it is easy enough to extend the code to work with packages.

+13
source share

If you look at the source code for TBitBtn (specifically TBitBtn.DrawItem ), you will see that it is displayed manually in the Delphi source code. It uses the Windows Visual Themes API to draw a button ( ThemeServices.Draw* ) in the current theme, if themes are enabled. If not, it uses the old-style Windows API functions to draw controls such as Rectangle and DrawFrameControl . I think you need to change the source code of the control to get around this behavior.

+5
source share

All Articles