我不知道这是不是一个错误...但是当我设置除“Windows”之外的任何其他VCL样式时,窗口宽度会减小。
-
有没有解决方案?
更新 我已将此提交给QC:http://qc.embarcadero.com/wc/qcmain.aspx?d=103697 希望他们能解决它......
答案 0 :(得分:5)
这不是vcl样式bug,这是vcl样式的工作方式,每个样式(皮肤)都有自己的边框宽度和高度,有时与本机窗口边框不匹配尺寸。
检查下一张图片
碳风格的边框宽度和高度为5像素
Amakrits风格的边框宽度和高度为6像素
您可以使用VCL Styles Designer
因此,根据上述属性,表单的Style钩子重新计算Client区域的边界。
答案 1 :(得分:4)
确实看起来确实是一个VCL错误。当在项目选项中设置样式而不是系统样式时,{。1}}属性未从.dfm文件正确流式传输。
我建议您向QualityCentral提交报告。在此期间,您可以通过在创建表单后在.dpr文件中设置样式来解决此问题。
ClientWidth
但是,我认为这不会让你走得太远,因为你可能希望能够动态创建表单,而不必在启动时创建全部表单。
答案 2 :(得分:4)
好的 - 我做了一些调查,发现了这个bug的根本问题(跳到最后解决方法)。分散在互联网上并在此消息之前讨论的大多数/所有其他解决方法似乎只是掩盖了错误的症状,而没有真正找到根本原因 - 而那些其他解决方法可能会产生其他不良副作用或限制(正如他们的一些作者所指出的那样。)
根本问题是TFormStyleHook.WMNCCalcSize
消息在wParam
参数为FALSE
时未提供WM_NCCALCSIZE
消息的任何处理。功能基本上不完整。所以默认窗口处理程序被称为 - Windows提供的默认处理程序 - 当然返回Windows默认样式的客户端rect,而不是用户指定的VCL样式。要修复此错误,当WM_NCCALCSIZE
为wParam
时,Embarcadero必须添加FALSE
的处理,以便仍然返回VCL样式信息。这对他们来说是一个非常简单的修复方法,现在我已经调查并发现了问题,我希望修复程序可以应用于VCL的下一个版本。
为了证明这是问题的原因,我记录了发送到表单的所有消息(通过覆盖WndProc
),并为每条消息指出Win32 GetClientRect
提供的客户端是否为正确的VCL风格。我还注意到WM_NCCALCSIZE
函数调用的类型(wParam
的值)。最后,我注意到WM_NCCALCSIZE
处理程序返回的新客户端rect。
我发现在应用程序运行时,几乎每一条WM_NCCALCSIZE
消息都将wParam
设置为TRUE
(这样可以正常工作),因此该错误是隐藏的,不会发生。这就是为什么Embarcadero到目前为止已经解决了这个问题。但是,邮件会在wParam
设置为FALSE
的情况下发送,并且会在关键时刻发生:恰好在ClientWidth
/ ClientHeight
属性设置为来自DFM
TCustomForm.ReadState
档案。 TControl.SetClientSize
函数通过从当前总窗口宽度减去当前客户端宽度(由Windows GetClientRect
测量)来运行,然后添加新的客户端宽度。 换句话说,TControl.SetClientSize
要求当前窗口客户端rect准确,因为它使用它来计算新客户端rect。并且由于它不是,因此表单的宽度设置错误,其余的都是历史。
哦,你想知道为什么宽度受到影响而不是高度?这很容易证明 - 在设置ClientWidth
之后但在ClientHeight
设置之前,发送了另一个WM_NCCALCSIZE
- 这次wParam
为{{1} }}。 VCL样式正确处理它并将客户端大小设置回适当的值 - 因此TRUE
的计算结果正确。
请注意,Windows的未来版本可能会破坏得更厉害:如果Microsoft决定更频繁地发送ClientHeight
消息,WM_NCCALCSIZE
设置为wParam
,即使表单可见,事情也会中断VCL非常糟糕。
通过手动将FALSE
发送到表单,可以很容易地证明该错误。重现的步骤:
WM_NCCALCSIZE
控件。将以下代码添加到按钮的TButton
事件:
OnClick
运行项目并单击按钮。如果通过测试,则意味着VCL样式的NC宽度恰好与默认的Windows NC宽度一致。更改表单的边框样式或将VCL样式更改为其他样式,然后重试。
当然,解决方法是找到一种方法来拦截void __fastcall TForm1::Button1Click(TObject *Sender)
{
// Compute the current cumulative width of the form borders:
int CurrentNonClientWidth = Width - ClientWidth;
// Get the current rectangle for the form:
TRect rect;
::GetWindowRect(Handle, &rect);
// Ask the window to calculate client area from the window rect:
SendMessage(Handle, WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
// Calculate the new non-client area given by WM_NCCALCSIZE. It *should*
// match the value of CurrentNonClientWidth.
int NewNonClientWidth = Width - rect.Width();
if (CurrentNonClientWidth == NewNonClientWidth) {
ShowMessage("Test pass: WM_NCCALCSIZE with wParam FALSE gave "
"the right result.");
} else {
ShowMessage(UnicodeString::Format(L"Test fail: WM_NCCALCSIZE with "
"wParam FALSE gave a different result.\r\n\r\nCurrent NC width: %d"
"\r\n\r\nNew NC width: %d", ARRAYOFCONST((
CurrentNonClientWidth, NewNonClientWidth))));
}
}
为WM_NCCALCSIZE
的{{1}}邮件,然后将其转换为wParam
为{{{}}的邮件1}}。这实际上可以在全局基础上完成:我们可以从FALSE
创建一个修复问题的派生类,然后全局使用钩子 - 这将解决所有表单上的问题,包括VCL创建的表单(例如来自Vcl.Dialogs单位)。在上面显示的示例项目中,修改主wParam
,如下所示:
TRUE
现在运行项目并单击按钮;你会看到现在正确处理了WM_NCCALCSIZE。另外,您会看到,如果您在TFormStyleHook
文件中明确设置了Project1.cpp
,则现在可以正确使用它。
答案 3 :(得分:3)
对于那些希望为这种非常奇怪的行为找到真正聪明的解决方案的人,请看一下詹姆斯·约翰斯顿的答案。我已经将其应用到我的项目中,并且可以正常工作。以下是詹姆斯回答中的德尔福翻译。谢谢詹姆斯!
services.AddHangfire(config =>
config.UsePostgreSqlStorage(Configuration.GetConnectionString("Hangfire1ConnectionString"), new PostgreSqlStorageOptions {
InvisibilityTimeout = TimeSpan.FromMinutes(720)
}));
使用此代码,将尊重ClientWidth / ClientHeight尺寸,并且正确显示内部内容。 当然,Window的外部尺寸会更大以适应ClientWidth / ClientHeight尺寸,但这并不算太坏,因为通常窗口内容更为重要。
您可能希望将代码放在单独的单元中,以在任何项目中使用它。这只是直接的原始解决方案。
答案 4 :(得分:1)
该错误在Delphi Rio 10.3.3中仍然存在。我以为我通过使用Carlos Feitoza Filho的代码解决了这个问题。但是,当Windows Scaling处于打开状态(高DPI监视器)时,它不起作用。许多用户对此表示抱怨。
这是我一直有效的解决方案:使用FormResize事件!
procedure TForm1.FormResize(Sender: TObject);
begin
ClientHeight := Button1.Top + Button1.Height + Button1.Top; // whatever you want
ClientWidth := Button1.Left + Button1.Width + Button1.Left; // whatever you want
end;
答案 5 :(得分:0)
这里没有XE2,但这听起来很熟悉。尝试将AutoScroll
设置为True (奇怪的是,与this answer相反)以存储客户端表单大小,而不是边框大小。
答案 6 :(得分:0)
Delphi XE8中仍然存在此问题。一个简单的解决方法是使用以下代码,只需恢复设计时ClientWidth
/ ClientHeight
,但需要注意一些警告(最重要的是,AutoScroll
必须设置为False
}):
type
TFormHelper = class helper for Vcl.Forms.TCustomForm
private
procedure RestoreDesignClientSize;
end;
procedure TfrmTestSize.FormCreate(Sender: TObject);
begin
RestoreDesignClientSize;
end;
{ TFormHelper }
procedure TFormHelper.RestoreDesignClientSize;
begin
if BorderStyle in [bsSingle, bsDialog] then
begin
if Self.FClientWidth > 0 then ClientWidth := Self.FClientWidth;
if Self.FClientHeight > 0 then ClientHeight := Self.FClientHeight;
end;
end;
给出以下设计时间表:
这将从以下位置更正运行时:
要:
我的博客上有更多细节和图片:http://marc.durdin.net/2015/07/fixing-the-incorrect-client-size-for-delphi-vcl-forms-that-use-styles/
答案 7 :(得分:0)
我在我的 C++Builder VCL 应用程序中解决了这个问题,方法是将以下代码添加到表单的 FormResize 函数中,无论所选样式如何,该函数似乎都可以工作并监视该程序正在最大化。我认为这段代码应该继续如果 Embarcadero 终于开始修复错误,那么工作正常:
|name |employee_id|work_place |sex_age |skills_score |depart_title |
+-------+-----------+-------------------+--------------+----------------+---------------------------------------+
|Michael|100 |[Montreal, Toronto]|[Male -> 30] |[DB -> 80] |[Product -> [Product, DeveloperLead]] |
|Will |101 |[Montreal] |[Male -> 35] |[Perl -> 85] |[Product -> [Product, Lead,Test, Lead]]|
|Steven |102 |[New York] |[Female -> 27]|[Python -> 80] |[Test -> [Test, Lead,COE, Architect]] |
|Lucy |103 |[Vancouver] |[Female -> 57]|[Sales -> 89,HR]|[Sales -> [Sales, Lead]] |