【问题标题】:Exclude VCL Styles from styling Dialog / ShowMessage borders从样式对话框/ ShowMessage 边框中排除 VCL 样式
【发布时间】:2015-03-14 07:14:02
【问题描述】:

有什么方法可以从系统对话框的边框样式中排除 VCL 样式。

特别是通过调用 MessageDlg 或 ShowMessage 显示的对话框。

我阅读了一些关于“The Road To Delphi”的文章(顺便说一句,这是一个很棒的网站),但找不到答案。

这是我想要实现的目标:

现在(带有样式边框的碳风格):

目标(带有标准窗口边框的碳风格):

我仍然想要有样式的控件,但没有样式的边框。

从父表单 StyleElements 中删除 seBorder 并不能解决问题。

谢谢!

【问题讨论】:

  • 我认为您应该重新表述您已经尝试设置 parent 表单样式的声明。它的写法已经误导了两个人。此外,您对哪些对话框感兴趣,因为大量对话框甚至不支持没有 3rd 方单元的样式。
  • 我改写了第一句话
  • 感谢您的编辑,但也请编辑您尝试过的内容。当您从 StyleElements 中删除 'seBorder' 时,'Setting' 是错误的词并且具有误导性。我建议:来自 parent 表单 StyleElementsRemoving seBorder` 并不能解决问题。`
  • 听到答案会很有趣,但目标截图对我来说看起来有点奇怪和丑陋。将自定义样式与随机系统样式(谁知道用户安装了什么)混合起来对我来说听起来不是一个好计划。事实上,由于皮肤,我收到了很多用户投诉,以至于我现在倾向于回避它们。默认的 windows 样式可能很无聊,但它们经过了很好的测试。

标签: delphi vcl delphi-xe7 vcl-styles


【解决方案1】:

MessageDlg()ShowMessage() 是 Delphi VCL 函数。他们动态创建一个 Delphi TForm 并显示它,因此您没有机会自定义它。但是,您可以使用CreateMessageDialog() 代替创建相同的TForm,然后根据需要修改其样式元素,然后将其显示出来。例如:

function DoMessageDlgPosHelp(MessageDialog: TForm; X, Y: Integer): Integer;
begin
  with MessageDialog do
    try
      if X >= 0 then Left := X;
      if Y >= 0 then Top := Y;
      if (Y < 0) and (X < 0) then Position := poScreenCenter;
      Result := ShowModal;
    finally
      Free;
    end;
end;

procedure ShowStyledMessage(const Msg: string; const StyleElements: TStyleElements);
var
  Form: TForm;
begin
  Form := CreateMessageDialog(Msg, mtCustom, [mbOK]);
  Form.StyleElements := StyleElements;
  DoMessageDlgPosHelp(Form, -1, -1);
end;

这样称呼它:

ShowStyledMessage('Some text', [seFont, seClient]);

对话框如下所示:

【讨论】:

  • 上述解决方案不适用于由 3rd 方代码调用的消息对话框。任何 ShowMessage 都会产生完全样式化的表单。
  • @Dalija 没错。还有任何系统对话框,即调用 MessageBox 或 TaskDialogIndirect。
【解决方案2】:

要设置无边框样式的表单,您必须从表单的 StyleElements 属性中删除 seBorder

  StyleElements := [seFont, seClient];

但是您必须为每个表单设置该属性。如果我理解正确,您希望显示带有 Windows 边框的消息对话框。在这种情况下,为调用ShowMessage 的表单设置StyleElements 属性将不会影响对话框,因为这是全新的表单。

您需要做的是以某种方式为 Delphi 创建的对话框表单设置 StyleElements 属性,而您无法访问。为此,您必须创建自己的表单 StyleHook 并替换为所有表单注册的 TFormStyleHook

只需在您的项目中添加以下单元,所有表单都会有 Windows 边框,无需为每个表单显式设置。

unit WinBorder;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  Vcl.Themes,
  Vcl.Controls,
  Vcl.Forms;

type
  TWinBorderFormStyleHook = class(TFormStyleHook)
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AControl: TWinControl); override;
  end;

implementation

constructor TWinBorderFormStyleHook.Create(AControl: TWinControl);
begin
  inherited;
  OverridePaintNC := false;
end;

procedure TWinBorderFormStyleHook.WndProc(var Message: TMessage);
begin
  inherited;
  if Message.Msg = CM_VISIBLECHANGED then
    begin
      if (Control is TCustomForm) and (seBorder in TCustomForm(Control).StyleElements) then
        TCustomForm(Control).StyleElements := [seFont, seClient];
    end;
end;

initialization

  TCustomStyleEngine.UnRegisterStyleHook(TCustomForm, TFormStyleHook);
  TCustomStyleEngine.UnRegisterStyleHook(TForm, TFormStyleHook);
  TCustomStyleEngine.RegisterStyleHook(TCustomForm, TWinBorderFormStyleHook);
  TCustomStyleEngine.RegisterStyleHook(TForm, TWinBorderFormStyleHook);

finalization

  TCustomStyleEngine.UnRegisterStyleHook(TCustomForm, TWinBorderFormStyleHook);
  TCustomStyleEngine.UnRegisterStyleHook(TForm, TWinBorderFormStyleHook);
  TCustomStyleEngine.RegisterStyleHook(TCustomForm, TFormStyleHook);
  TCustomStyleEngine.RegisterStyleHook(TForm, TFormStyleHook);

end.

【讨论】:

  • Plus 1 符合风格精神的好解决方案。我现在删除了不相关的 cmets。
  • 需要注意的重要一点是,该单位必须在Vcl.Forms 单位之后使用。 (+1)。如果由我决定,我会将其作为公认的答案。
  • @JerryDodge 因为这个单元本身使用 Vcl.Forms,所以你把它放在 uses 子句中的什么地方都没有关系。
猜你喜欢
  • 1970-01-01
  • 2012-06-14
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多