バグかどうかわかりませんが、 "Windows"以外のVCLスタイルを設定すると、ウィンドウの幅が狭くなります。VCLスタイル - クライアントのサイズを小さくしました
-
このため任意の解決策はありますか?
UPDATE は私がQCにこれを提出した:彼らはそれを修正しますhttp://qc.embarcadero.com/wc/qcmain.aspx?d=103697 ホープ...
バグかどうかわかりませんが、 "Windows"以外のVCLスタイルを設定すると、ウィンドウの幅が狭くなります。VCLスタイル - クライアントのサイズを小さくしました
-
このため任意の解決策はありますか?
UPDATE は私がQCにこれを提出した:彼らはそれを修正しますhttp://qc.embarcadero.com/wc/qcmain.aspx?d=103697 ホープ...
確かにVCLのバグのように見えるん。スタイルがプロジェクトオプションでシステムスタイル以外に設定されている場合、ClientWidth
プロパティが.dfmファイルから正しくストリーミングされません。
QualityCentralに報告書を提出することをお勧めします。その間に、フォームが作成された後に.dprファイルのスタイルを設定することで、この問題を回避することができます。
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
TStyleManager.SetStyle('Amakrits');//after CreateForm, rather than before
Application.Run;
しかし、私はそれが非常に遠く、おそらくその場でフォームを作成し、すべての起動時に作成する必要はありませんできるようにしたいので、あなたを得るでしょう想像していません。
ここにXE2はありませんが、これは非常によく知られています。 AutoScroll
を真の(奇妙なことに、this answerの逆)に設定して、境界線サイズではなくクライアントフォームサイズを保存してみてください。
'AutoScroll'はデフォルトで' False'になり、その状態でバグが発生します。実際に 'AutoScroll'を' True'に設定すると、プログラムが期待どおりに動作するようになります! –
@David Hmm、strange。これはXE2(またはそれ以前)で変更されたようです。 D7では、 'AutoScroll'のデフォルトは' True'です。 – NGLN
2010年にFalseにデフォルト設定されていますが、D7とD2010の間にバージョンがありません –
これは、VCLスタイルのバグ、
これは、VCLスタイルがどのように機能するかを、各スタイル(スキン)は時々ネイティブウィンドウの境界線のサイズと一致しない独自の境界線の幅と高さを、持っているではありません。
チェックを次の画像
炭素スタイルは5つの画素
Amakritsスタイルは6つのピクセルの境界線の幅と高さを有するの境界線の幅と高さを有します
あなたはVCL Styles Designer
>高さ。
この問題はまだDelphi XE8にあります。簡単な回避策はいくつかの注意事項(最も重要なのは、AutoScroll
はFalse
に設定する必要があります)で、ちょうどClientWidth
/ClientHeight
設計時に復元し、次のコードを使用することです:
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/
私たちにお知らせいただきありがとうございます。私はXE8のアップデート(XE7と同様)の代金を支払わなかったことをうれしく思っています。私はこの問題についてQCレポートをチェックしましたが、2012年に投稿されましたがまだ修正されていません... – djsoft
OKを - 私はいくつかのより多くの調査を行なったし、このバグの根本的な問題を発見した(最後までスキップ回避策を参照してください)。インターネット上に散在し、このメッセージの前に議論された他の回避策の大半またはすべては、根本的な原因を実際に発見することなく、バグの症状を隠しているように見えますが、これらの回避策には他の望ましくない副作用や制限彼らの著者のいくつかが指摘しているように)。
根本的な問題はwParam
パラメータがFALSE
ときTFormStyleHook.WMNCCalcSize
メッセージがWM_NCCALCSIZE
メッセージのいずれかの処理を提供しないということです。機能は基本的に不完全です。 デフォルトのウィンドウハンドラは - Windows提供のデフォルトハンドラ - もちろんは、ユーザが指定したVCLスタイルではなくWindows-defaultスタイルのクライアント矩形を返します。このバグを修正するにはwParam
がFALSE
の場合、EmbarcaderoはWM_NCCALCSIZE
の処理を追加して、VCLスタイル情報が返されるようにする必要があります。これは非常に簡単な修正であり、私が調査して問題を発見したので、修正がVCLの次のリリースに適用されることを願っています。
これが問題の原因だったことを証明するために、私は(WndProc
をオーバーライドすることによって)フォームに送信されたすべてのメッセージをログに記録され、各メッセージのために、Win32のGetClientRect
によって提供されるクライアントRECTは、VCLスタイルのために正しかったかどうかを指摘しました。私はまた、関数呼び出しのタイプ(wParam
の値)に注意しました。最後に、WM_NCCALCSIZE
ハンドラによって返された新しいクライアント矩形に注目しました。
WM_NCCALCSIZE
メッセージのほとんどすべてがTRUE
(TRUE
)に設定されているため、このバグは表示されないため、表示されません。そのため、Embarcaderoは今までこのバグを解決してきました。しかし、メッセージはwParam
がに設定された状態で送信され、重要な瞬間にメッセージが送信されます./ClientHeight
のプロパティの前には、ファイルの値がTCustomForm.ReadState
に設定されます。 TControl.SetClientSize
関数は、現在のウィンドウ幅から現在のクライアント幅(Windows GetClientRect
で測定)を減算して動作し、新しいクライアント幅を加算します。 つまり、TControl.SetClientSize
は、新しいクライアントrectを計算するために現在のウィンドウクライアントrectを正確にする必要があります。そして、そうではないので、フォームは間違った幅のセットを取得し、残りは履歴です。
なぜ、幅に影響があり、高さではないのだろうか?それは証明するのが容易でした。ClientWidth
が設定された後、ClientHeight
が設定される前に判明しました。別のWM_NCCALCSIZE
が送信されました。今回はwParam
のTRUE
で送信されます。 VCLスタイルで正しく処理され、クライアントのサイズが適切な値に戻されます。したがって、ClientHeight
の計算が正しく行われます。フォームが表示されている間も、Microsoftは、より定期的にFALSE
にwParam
セットでWM_NCCALCSIZE
メッセージを送信することを決定した場合、物事はVCLのために非常にひどく破損します:Windowsの将来のバージョンは、よりひどく壊すかもしれない
注意。
手動でフォームにWM_NCCALCSIZE
を送信することで、バグを簡単に突き止めることができます。再現する手順:
TButton
コントロールをフォームに追加します。は、ボタンのOnClick
イベントに次のコードを追加します
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))));
}
}
は、プロジェクトを実行し、ボタンをクリックしてください。合格テストを受けると、VCLスタイルのNC幅がデフォルトのWindows NC幅と一致することを意味します。フォームの境界線スタイルを変更するか、VCLスタイルを別のものに変更して、もう一度やり直してください。
この問題を回避するには、当然のことながら、wParam
がFALSE
あるWM_NCCALCSIZE
メッセージを傍受し、その後wParam
がTRUE
あるメッセージに変換する方法を見つけることです。これは実際にはグローバルベースで行うことができます:TFormStyleHook
の派生クラスを作成して問題を修正し、フックをグローバルに使用することができます。これにより、VCLで作成したフォーム(Vcl.Dialogsなど)単位)。上に示したサンプルプロジェクトでは、次のようにメインProject1.cpp
を変更します。
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <tchar.h>
#include <string.h>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include <Vcl.Styles.hpp>
#include <Vcl.Themes.hpp>
USEFORM("Unit1.cpp", Form1);
//---------------------------------------------------------------------------
class TFixedFormStyleHook : public TFormStyleHook
{
public:
__fastcall virtual TFixedFormStyleHook(TWinControl* AControl)
: TFormStyleHook(AControl) {}
protected:
virtual void __fastcall WndProc(TMessage &Message)
{
if (Message.Msg == WM_NCCALCSIZE && !Message.WParam) {
// Convert message to format with WPARAM == TRUE due to VCL styles
// failure to handle it when WPARAM == FALSE. Note that currently,
// TFormStyleHook only ever makes use of rgrc[0] and the rest of the
// structure is ignored. (Which is a good thing, because that's all
// the information we have...)
NCCALCSIZE_PARAMS ncParams;
memset(&ncParams, 0, sizeof(ncParams));
ncParams.rgrc[0] = *reinterpret_cast<RECT*>(Message.LParam);
TMessage newMsg;
newMsg.Msg = WM_NCCALCSIZE;
newMsg.WParam = TRUE;
newMsg.LParam = reinterpret_cast<LPARAM>(&ncParams);
newMsg.Result = 0;
this->TFormStyleHook::WndProc(newMsg);
if (this->Handled) {
*reinterpret_cast<RECT*>(Message.LParam) = ncParams.rgrc[0];
Message.Result = 0;
}
} else {
this->TFormStyleHook::WndProc(Message);
}
}
};
//---------------------------------------------------------------------------
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
// Register our style hook. An audit of C++ Builder XE8 VCL source code
// for registration of the existing TFormStyleHook shows that these are
// the only two classes we need to register for.
TCustomStyleEngine::RegisterStyleHook(__classid(TForm),
__classid(TFixedFormStyleHook));
TCustomStyleEngine::RegisterStyleHook(__classid(TCustomForm),
__classid(TFixedFormStyleHook));
Application->Initialize();
Application->MainFormOnTaskBar = true;
TStyleManager::TrySetStyle("Carbon");
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
return 0;
}
//---------------------------------------------------------------------------
今すぐプロジェクトを実行し、ボタンをクリックしてください。 WM_NCCALCSIZEが正しく処理されるようになります。また、DFM
ファイルに明示的にClientWidth
を設定すると、正しく使用されることがわかります。
どのバージョンのDelphiですか? –
これはプレーンなアプリでは再現できません。動作がなくなるまで、フォーム/アプリケーションから削除するようにしてください。次に、あなたは犯人にポインタを持っているかもしれません。 –
@CosminスタイルはXE2で導入されました。 –