在运行时创建自定义标题栏和边框,TMainMenu起作用 [英] Creating a custom caption bar and border at runtime, TMainMenu acting up

查看:90
本文介绍了在运行时创建自定义标题栏和边框,TMainMenu起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从事一个使用自定义表单的相当大的项目,并且希望自己绘制这些表单的非客户区域。我无法使用vcl样式,因为许多表格需要在运行时选择带有颜色的标题栏和边框,据我所知,样式在设计上很广泛。

I'm working on a rather large project that uses custom forms and would like to draw the non-client area of these forms myself. I can't use vcl-styles because many of the forms need to have a caption bar and border in a color picked at run time and as far as I know, styles are application wide by design.

到目前为止,我已经完成的工作是绘制标题栏和边框,绘制标题,禁用最小化,最大化和关闭按钮,并用我自己的按钮替换。我通过截获WM_NCPaint和WM_NCACTIVATE消息并在处理WM_NCACTIVATE并在不处理WM_NCPAINT消息的情况下发送WM_ACTIVATE消息的情况下在继承的关键字之后调用我自己的过程来实现此目的:

What I have accomplished so far is drawing the caption bar and border, drawing on the caption, disabling the minimize, maximize and close buttons and replacing them with my own. I achieved this by intercepting the WM_NCPaint and WM_NCACTIVATE messages and calling my own procedure after the inherited keyword when handling WM_NCACTIVATE and sending a WM_ACTIVATE message without handling the WM_NCPAINT message as such:

SendMessage(Handle, WM_NCACTIVATE, ORD(active), -1);

之所以这样做,是因为在步进之后,我无法让TMainMenu始终画出自己的颜色通过代码,似乎正确处理了WM_NCACTIVATE消息可以绘制主菜单。
我尝试过的另一种方法是在主菜单上调用UpdateItems,但这没有产生任何结果。

The reason I did this is because I couldn't get the TMainMenu to paint itself consistently, after stepping through the code it seemed that the WM_NCACTIVATE message being handled correctly paints the main menu. Another approach I tried there was calling UpdateItems on the main menu, but this didn't give any result.

我通过处理WM_NCHITTEST消息如下:

I deactivated the top right buttons by handling the WM_NCHITTEST message as such:

procedure TBasicForm.WMNCHITTEST(var message : TMessage);
begin
  inherited;
  case message.Result of
    HTMINBUTTONE, HTMAXBUTTON, HTCLOSE: message.Result := HTCAPTION;
  end;
end;

通过处理WM_NCLBUTTONDOWN,我得到了自己的按钮(在处理WM_NCACTIVATE时在调用的过程中绘制) ,这不是一个完美的解决方案,但是可以轻松进行改进。 (我相信我不需要对此进行详细说明。

I got my own buttons (which I draw in the procedure I call when Handling WM_NCACTIVATE) by handling WM_NCLBUTTONDOWN, this is not a perfect solution but, can easily be improved on. (I trust I do not need to elaborate on this.

但是,到目前为止,听起来还不错。

So far this sounds pretty good, however.


  • 以某些方式在窗体之间切换焦点时,会出现很多闪烁。

  • 有时会显示原始的右上按钮,尽管它们没有反应

  • 关闭表单时,标题栏(并且只有标题栏)恢复为原来的外观。

直接的问题是,我该如何解决这三个问题呢?可能是因为我使用的是完全错误的方式,在这种情况下,问题是是,我如何才能实现自定义绘制的标题栏和边框,最好不要过多地干扰边框和标题栏的功能并正确绘制主菜单?

The direct question is, how do I solve these three issues? It might be that I'm going about this entirely the wrong way though, in which case the question is, how can I achieve a custom drawn caption bar and border, preferably without meddling with the functionality of the borders and caption bar too much and having the a main menu be drawn properly?

正如我所说,这是一个包含许多表单的相当大的项目,因此在表单设计器中进行更改是我认为要做的最后一件事g。

As I said, it's a rather large project with many forms, so changing things around in the form designer is one of the last things I'd consider doing.

要重现我遇到的问题,请创建一个新表格并处理WM_NCHITTEST,WM_NCACTIVATE和WM_NCPAINT,如我之前所述。 / p>

To Reproduce the problems I'm experiencing, create a new form and handle WM_NCHITTEST, WM_NCACTIVATE and WM_NCPAINT as I described earlier.

...
procedure WMNCHITTEST(var message : TMessage); message WM_NCHITTEST;
procedure WMNCACTIVATE(var message : TMessage); message WM_NCACTIVATE;
procedure WMNCPAINT(var message : TMessage); message WM_NCPAINT;
...
implementation
...
procedure TBasicForm.WMNCHITTEST(var message : TMessage);
begin
  inherited;
  case message.Result of
    HTMINBUTTONE, HTMAXBUTTON, HTCLOSE: message.Result := HTCAPTION;
  end;
end;

procedure TBasicForm.WMNCACTIVATE(var message : TMessage);
begin
  inherited;
  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clRed;

  Canvas.Rectangle(0, 0, Width, GetSystemMetric(SM_CYCAPTION) + GetSystemMetric(SM_CYBORDER));
  Canvas.Rectangle(0, 0, GetSystemMetric(SM_CXBORDER), Height);
  Canvas.Rectangle(Width - GetSystemMetric(SM_CXBORDER), 0, Width, Height);
  Canvas.Rectangle(Width - GetSystemMetric(SM_CXBORDER), Heigth - GetSystemMetric(SM_CYBORDER), Width, Height);
end;

procedure TBasicForm.WMNCPAINT(var message : TMessage);
begin
  SendMessage(Handle, WM_NCACTIVATE, ORD(active), -1);
end;
...

现在,向项目添加第二个表单,确保两个表单创建并在两个窗体之间反复切换焦点(也可以尝试单击第二个窗体,然后单击第一个窗体的自定义绘制标题栏),这将导致闪烁,并显示关闭,最小和最大按钮。关闭表单(按alt + f4键)应简要显示原始标题栏。

Now, add a second form to the project, make sure both forms are created and switch focus between the two forms repeatedly (also try clicking the second form, then click the custom drawn caption bar of first form), this should result in some flickering and the close, min and max button showing up. closing the form (by pressing alt + f4) should briefly show the original caption bar.

推荐答案

写一个适当的类来绘制表单的非客户区域需要大量工作,您已经在处理一些涉及到的基本Windows消息,但还有很多。根据我的经验,这些是我的建议。

Write a proper class to paint the non client area of a form require a lot of work, you are already handling some of the basic windows messages involved but there a lot more. Based on my experience these are my recommendations.

A 。在某些形式之间切换焦点时,会有很多闪烁。

A. There is quite a lot of flickering when switching focus between forms certain ways.

Q 。这个问题可能有很多原因,但主要是在画布上使用了对draw方法的多次调用,您可以使用位图缓冲区( TBitmap )将所有标题栏绘制到画布上,以解决此问题。通过位图一次,最后调用Canvas.Draw。

Q. This issue can have many causes, but the main is use several calls to the draw method on the canvas, you can overcome this using a bitmap buffer (TBitmap) to draw all the title bar to the canvas of the bitmap and finally call the Canvas.Draw just once passing the bitmap.

A 。有时会显示原始的右上按钮,尽管它们不再对鼠标做出反应。

A. Sometimes the original top right buttons show up, though they don't react to the mouse anymore.

请参阅下一个问题的答案。

See the answer to the next question.

A 。关闭表单时,标题栏(仅标题栏)恢复为旧外观。

A. When closing a form, The caption bar (and only the caption) bar reverts to its old appearance.

Q 这是因为您需要还原或调整表单大小时,使该表单的NC区域无效,因此您必须添加对某些其他消息的支持,例如WM_WINDOWPOSCHANGING,WM_SIZE,WM_MOVE,WM_NCMOUSEMOVE,WM_NCLBUTTONDOWN,WM_NCRBUTTONDOWN等,

Q This is because you need to invalidate the NC Area of the form when the form is restored or resized , so you must add support for some additional messages like WM_WINDOWPOSCHANGING, WM_SIZE, WM_MOVE, WM_NCMOUSEMOVE, WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN and so on

为避免所有这些工作,您可以使用VCL样式,为此,您必须覆盖 TFormStyleHook 类,并实现一组自定义样式钩子,并以您要自定义样式的形式应用像这样使用 RegisterStyleHook 方法的标题栏

To avoid all this work you can use the VCL Styles, for this you must override the TFormStyleHook class and implement a set of custom style hooks and apply in the forms which you want to custom the title bar using the RegisterStyleHook method like so

TStyleManager.Engine.RegisterStyleHook(TMyForm1, TMyCustomformStyleHook1);
TStyleManager.Engine.RegisterStyleHook(TMyForm2, TMyCustomformStyleHook2);

这篇关于在运行时创建自定义标题栏和边框,TMainMenu起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆