我正在编写一个自定义控件,它只是一个非客户区域的容器.在该非客户区域内,有一个小区域是按钮,其余部分是透明的.图纸不是精确的矩形.
到目前为止,我已经中途工作了.问题是它不会预先计算非客户区域,除非我做一个小的调整,例如重新调整它.
我已经按照许多资源描述了如何实现这一目标.我的处理实现WM_NCCALCSIZE与我发现的"工作"示例大致相同.但是,当首次创建控件时,它根本不会计算.当我在mine(WMNCCalcSize)的消息处理程序中放置断点时,根据我发现的示例,我应该首先检查Msg.CalcValidRects,并且只进行我的计算True.但是在调试运行时,它是False,因此计算没有完成.
在设计时,如果我重新调整控件的大小,那么它决定正确计算.它仍然不完美(此代码仍然在工作中),但它似乎没有设置非客户区域,直到我调整它.此外,在运行时,如果我调整代码中的大小,它仍然不会计算.
顶部的图像是最初创建/显示表单的时间.第二个是在我重新调整它的大小之后.注意对齐的测试按钮alLeft.所以最初,它消耗了应该是非客户端的区域.
如果我注释掉支票if Msg.CalcValidRects then begin,那么它会正确计算.但我看到每个例子都在做这个检查,我很确定它是必要的.
我做错了什么以及如何让它始终计算非客户区域?
unit FloatBar;
interface
uses
System.Classes, System.SysUtils, System.Types,
Vcl.Controls, Vcl.Graphics, Vcl.Forms,
Winapi.Windows, Winapi.Messages;
type
TFloatBar = class(TCustomControl)
private
FCollapsed: Boolean;
FBtnHeight: Integer;
FBtnWidth: Integer;
procedure RepaintBorder;
procedure PaintBorder;
procedure SetCollapsed(const Value: Boolean);
function BtnRect: TRect;
procedure SetBtnHeight(const Value: Integer);
procedure SetBtnWidth(const Value: Integer);
function TransRect: TRect;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message …Run Code Online (Sandbox Code Playgroud) 我正在尝试绘制自定义绘制的非客户区域,而不是默认主题边框(Windows 10)。
我将WM_NCCALCSIZE非客户区域的大小调整为每侧 4 个像素,然后WM_NCPAINT绘制红色边框。
当应用程序首次显示时,我的自定义绘制成功,但在调整应用程序大小或最小化和恢复时无法重绘,尽管在调整大小或恢复窗口期间调用了 和WM_NCCALCSIZE。WM_NCPAINT
#pragma comment(lib, "UxTheme")
#include <windows.h>
#include <uxtheme.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HICON) LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = CreateSolidBrush(RGB(0,128,0));
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "window";
wcex.hIconSm = NULL; …Run Code Online (Sandbox Code Playgroud) 我是在一个相当大的应用程序中自定义绘制我的标题栏,有许多表单,并且决定尝试通过自己处理一些消息并在我处理WM_NCPAINT时填写绘图的老式方法.
这幅画本身很顺利,基本上是有效的.有一件事是行不通的是绘制TMainMenu.要么我有默认的WM_NCACTIVATE处理程序绘制整个非客户区域(我必须在我的WM_NCPAINT处理程序中执行WM_NCACTIVATE消息),然后再绘制它,这会导致看似无法帮助的闪烁.或者我可以尝试让WM_NCPAINT的默认处理程序仅绘制包含TMainMenu的Rect,这会产生平滑的结果,但不会重新绘制菜单.
我的问题是:
我已经给了它一些去,我想我是在正确的方式,但我撞到了一堵墙; 我对我正在做的事情知之甚少,似乎无法找到关于它的明确文档.我的代码中最重要的部分是:
RedrawWindow(Handle, nil, MenuRegion, RDW_INVALIDATE or RDW_FRAME or RDW_NOERASE or RDW_ALLCHILDREN or RDW_UPDATENOW);
Run Code Online (Sandbox Code Playgroud)
而且我认为这正是出了什么问题.(或者更确切地说,我计算'MenuRegion'的代码.我只是不知道是否出错,因为我使用了错误的坐标系,或者是因为我这样做完全是错误的.
这是我的代码的简化版本,它将在delphi(xe3)中"按原样"编译和运行:
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus;
type
TForm3 = class(TForm)
private
FDrawMenu: Boolean;
function CalcFrameRegion: HRGN;
function CalcMenuRegion: HRGN;
procedure DrawMenu;
procedure FormFrame(minimal: Boolean = false);
procedure WMNCActivate(var message: TWMNCActivate); message WM_NCACTIVATE;
procedure WMNCPaint(var message: TMessage); message WM_NCPAINT;
procedure WMSIZE(var message : TWMSIZE); message WM_SIZE;
constructor Create(AOwner: TComponent); override;
public
{ Public …Run Code Online (Sandbox Code Playgroud) 我想制作一个具有可选边框大小的自定义控件.请参阅下面的代码.边框绘制在非客户区域中,其宽度可以是0,1或2像素.我已成功完成了边框图WM_NCPAINT.问题是,在我更改控制边框大小的属性后,我不知道如何告诉系统重新计算客户端和非客户端区域的新维度.我注意到当我调整窗口大小(使用鼠标)时会应用更改,但在更改边框大小后,我不知道如何立即执行此操作.

SuperList.pas
unit SuperList;
interface
uses Windows, Controls, Graphics, Classes, Messages, SysUtils, StdCtrls, UxTheme;
type
TBorderType = (btNone, btSingle, btDouble);
TSuperList = class(TCustomControl)
private
HHig,HMidH,HMidL,HLow:TColor;
BCanvas: TCanvas;
FBorderSize: TBorderType;
procedure SetBorderSize(const Value:TBorderType);
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
protected
procedure Paint; override;
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner:TComponent); override;
published
property BorderType:TBorderType read FBorderSize write SetBorderSize default btDouble; …Run Code Online (Sandbox Code Playgroud) 我已经在GitHub 上的RRUZ Vcl Style Utils库上发布了这个问题.但是,我想我也可以在这里得到一些帮助.
我正在使用VCL样式创建Windows 10用户界面,特别是使用"Windows 10 Dark"样式.我也在使用VCL Style Utils来添加按钮到标题栏中的非客户区域.我试图完全忽略表单图标及其默认功能,支持后退按钮,就像大多数新的Windows 10应用程序一样.
我正在尝试使用中的TNCControls组件在表单的最左上角放置一个按钮Vcl.Styles.NC.但是,当我在表单的图标上放置一个按钮时,无法在图标区域中单击该按钮.虽然我能够重叠图标,但点击标题栏的特定区域总是打开表单的系统菜单,而不是单击我放在那里的按钮.
点击那里我不希望弹出这个菜单:
我目前是如何创建此按钮的:
procedure TfrmTestMain.SetupTitleBar;
var
B: TNCButton;
begin
FNCControls:= TNCControls.Create(Self);
B:= FNCControls.ButtonsList.Add;
B.Style := TNCButton.TNCButtonStyle.nsTranparent;
B.BoundsRect := Rect(0, 0, 45, 32);
B.UseFontAwesome:= True;
B.Caption := '';
B.ImageAlignment:= TImageAlignment.iaCenter;
B.ImageStyle:= TNCButton.TNCImageStyle.isNormal;
B.ImageIndex:= fa_chevron_left;
end;
Run Code Online (Sandbox Code Playgroud)
到目前为止我尝试过的:
用完全空的.ico文件替换了表单的Icon.
将表单样式更改为bsSizeToolWin,但标题栏变得太小,我失去了最小化/最大化按钮.
将表单样式更改为bsDialog,但我得到与上面#2相同的效果,以及无法调整表单大小.
确保按钮样式为nsPushButton,虽然它覆盖了表单图标,但单击该区域仍然会单击该图标,该图标将显示默认的系统菜单.
遵循此主题中的所有内容,但结论是Windows强制您拥有此图标.
删除biSystemMenu从窗体的BorderIcons属性,但是这也将删除表格的右上角的默认的按钮,迫使我把我自己的系统按钮那里.
如何完全取消窗体图标及其默认功能,以支持我的Windows 10样式后退按钮?
我想知道是否可以设置无边界表单的客户区。举例来说,我定义了如下形式:
码
public class MyForm : Form
{
public MyForm()
{
this.FormBorderStyle = FormBorderStyle.None;
}
}
Run Code Online (Sandbox Code Playgroud)
结果

我想做的是指定客户区,以便表单具有框架(如标准的Windows框架,但自定义绘制)。
结果

本质上,蓝色区域将成为非客户区域,而灰色区域将保留为客户区域。
我试图设置客户区域,但是这似乎只是在调整整个表单的大小,因此,它不会留下“非客户”区域
这可能吗?
delphi ×4
winapi ×2
c# ×1
c++ ×1
delphi-xe3 ×1
forms ×1
ownerdrawn ×1
resize ×1
titlebar ×1
vcl ×1
vcl-styles ×1
winforms ×1