5

縁なしフォームのサイズを変更しようとしていますが、右側/下部を使用してサイズを大きくすると、マウスを動かす速度に応じて、境界と古いクライアント領域の間に隙間ができます。

左の境界線または左下隅からサイズを変更すると、効果がより顕著になります。どこでもひどいものです (他の商用アプリで試してみましたが、同様に発生します)。この効果は、大きな境界線に変更したときにも発生しますが、フォームの境界線を削除するときほどひどいものではありません

フォーム レイアウトは、タイトル バー機能を実行するトップ パネル (いくつかの tImage とボタンを含む) と、その他の情報 (メモ、その他のコントロールなど) を表示するその他のパネルで構成されます。

マウスボタンをキャプチャしてウィンドウにメッセージを送信するコードの一部がありますが、同様の結果で手動で実行しようとしました

トップ パネルのダブル バッファをアクティブにすると、ちらつきが回避されますが、パネルのサイズ変更はフォームのサイズ変更と同期されないため、ギャップが表示されたり、パネルの一部が消えたりします。

 procedure TOutputForm.ApplicationEvents1Message( var Msg: tagMSG;
  var Handled: Boolean );
const
  BorderBuffer = 5;
var
  X, Y: Integer;
  ClientPoint: TPoint;
  direction: integer;
begin
  Handled := false;
  case Msg.message of
    WM_LBUTTONDOWN:
      begin
        if fResizable then
        begin
          if fSides = [sTop] then
            direction := 3
          else if fSides = [sLeft] then
            direction := 1
          else if fSides = [sBottom] then
            direction := 6
          else if fSides = [sRight] then
            direction := 2
          else if fSides = [sRight, sTop] then
            direction := 5
          else if fSides = [sLeft, sTop] then
            direction := 4
          else if fSides = [sLeft, sBottom] then
            direction := 7
          else if fSides = [sRight, sBottom] then
            direction := 8;
          ReleaseCapture;
          SendMessage( Handle, WM_SYSCOMMAND, ( 61440 + direction ), 0 );
          Handled := true;
        end;
      end;
    WM_MOUSEMOVE:
      begin
        // Checks the borders and sets fResizable to true if it's in a "border" 
        // ...
      end; // mousemove
  end; // case
end;

その領域を回避したり、ウィンドウを強制的に再描画するにはどうすればよいですか? 私はDelphiを使用していますが、一般的な解決策(または他の言語で)または前進する方向性でさえも問題ありません

前もって感謝します

4

4 に答える 4

6

前回、WM_SYSCOMMAND とマウス ドラッグでサイズ変更するトップ レベル ウィンドウを手動で作成しようとしましたが、ネストされたパネルが含まれているかどうかに関係なく、問題はちらつきだけに限定されないことがわかりました。

サイズ変更可能な境界線のない裸の TForm を使用しても、独自のサイズ変更可能な境界線を追加し、マウス ダウンとマウスの移動とマウス アップのメッセージを直接処理すると、問題が大きすぎることが判明しました。ここで示しているコードアプローチをあきらめましたが、代わりに2つの実行可能なアプローチを見つけました。

  1. 非クライアント領域のペイントを引き継ぐアプローチを使用します。これは、Google Chrome や他の多くの完全にカスタム化されたウィンドウが行うことです。まだ非クライアント領域があり、それをペイントして、非クライアントと境界のペイントを処理するのはあなた次第です。つまり、真のボーダレスではありませんが、必要に応じてすべてを単色にすることもできます。開始するには、 WM_NCPAINT メッセージに関するこのヘルプをお読みください。

  2. 境界のないサイズ変更可能なウィンドウを使用します(サイズ変更可能なウィンドウとしての非クライアント領域がなくても)。ポストイット ノート アプレットを考えてみてください。ボーダレスでサイズ変更可能なウィンドウを持つ滑らかなちらつきのない方法を提供する実用的なデモ. 答えの基礎となる技術は David H. によって提供されました.

于 2011-07-13T16:45:23.703 に答える
2

さて、ウォーレン P はすでにかなり説得力を持って別の方向性を示していますが、私はあなたの質問に答えようとします. またはそうではありません。

あなたの編集により、質問が非常に明確になりました。

左の境界線または左下隅からサイズを変更すると、効果がより顕著になります。どこでもひどいものです (他の商用アプリで試してみましたが、同様に発生します)。この効果は、かなり大きな境界線に変更した場合にも発生しますが、境界線を削除した場合ほどひどいものではありません.

他の商用アプリケーションだけでなく、すべての OS ウィンドウがこの効果を発揮します。エクスプローラ ウィンドウの上部を拡大すると、ステータス バーまたは下部パネルも「非表示」および「展開」されます。絶対に負けられないと確信しています。

ボーダーレスなフォルムは悪く見えるかもしれませんが、それは単なる視覚的な欺瞞だと思います。

この効果を推測して説明する必要がある場合、サイズ変更操作中に、上と左の更新が幅と高さの更新よりも優先されるため、両方が同じ回数更新されないという結果になります。グラフィックカード関連かも。または多分、...地獄私は何について話しているのですか?これは私の手の届かないところにあります。

ただし、フォームの右および/または下のサイズを変更するためにまだ再現できません。コントロールの量、またはそれらの align プロパティと anchor プロパティ (の組み合わせ) が問題である場合は、align をすべて一緒に一時的に無効にすることを検討できますが、それも望ましくないことはほぼ確実です。以下は私のテストコードで、質問からコピーされ、わずかに変更され、もちろん Sertac の定数が追加されています。

function TForm1.ResizableAt(X, Y: Integer): Boolean;
const
  BorderBuffer = 5;
var
  R: TRect;
  C: TCursor;
begin
  SetRect(R, 0, 0, Width, Height);
  InflateRect(R, -BorderBuffer, -BorderBuffer);
  Result := not PtInRect(R, Point(X, Y));
  if Result then
  begin
    FSides := [];
    if X < R.Left then
      Include(FSides, sLeft)
    else if X > R.Right then
      Include(FSides, sRight);
    if Y < R.Top then
      Include(FSides, sTop)
    else if Y > R.Bottom then
      Include(FSides, sBottom);
  end;
end;

function TForm1.SidesToCursor: TCursor;
begin
  if (FSides = [sleft, sTop]) or (FSides = [sRight, sBottom]) then
    Result := crSizeNWSE
  else if (FSides = [sRight, sTop]) or (FSides = [sLeft, sBottom]) then
    Result := crSizeNESW
  else if (sLeft in FSides) or (sRight in FSides) then
    Result := crSizeWE
  else if (sTop in FSides) or (sBottom in FSides) then
    Result := crSizeNS
  else
    Result := crNone;
end;

procedure TForm1.ApplicationEventsMessage(var Msg: tagMSG;
  var Handled: Boolean);
var
  CommandType: WPARAM;
begin
  case Msg.message of
    WM_LBUTTONDOWN:
      if FResizable then
      begin
        CommandType := SC_SIZE;
        if sLeft in FSides then
          Inc(CommandType, WMSZ_LEFT)
        else if sRight in FSides then
          Inc(CommandType, WMSZ_RIGHT);
        if sTop in FSides then
          Inc(CommandType, WMSZ_TOP)
        else if sBottom in FSides then
          Inc(CommandType, WMSZ_BOTTOM);
        ReleaseCapture;
        DisableAlign;
        PostMessage(Handle, WM_SYSCOMMAND, CommandType, 0);
        Handled := True;
      end;
    WM_MOUSEMOVE:
      with ScreenToClient(Msg.pt) do
      begin
        FResizable := ResizableAt(X, Y);
        if FResizable then
          Screen.Cursor := SidesToCursor
        else
          Screen.Cursor := Cursor;
        if AlignDisabled then
          EnableAlign;
      end;
  end;
end;

上部に配置されたパネルについて: と を設定Align = alCustomしてみてくださいAnchors = [akLeft, akTop, akRight]。ただし、強化は、フォームの色とは異なるパネルの色に依存するか、光学的にだまされている可能性があります。;)

于 2011-07-14T21:30:12.447 に答える
0

フォームを に設定してみましたDoubleBuffered := Trueか?

于 2011-07-11T16:26:35.150 に答える
-1

このスレッドがかなり古いことは知っていますが、人々がまだ苦労しているスレッドです。

答えは簡単です。問題は、サイズ変更をしようとすると、サイズ変更しているフォームを参照として使用したくなることです。そうしないでください。

別のフォームを使用してください。

ここに役立つ TForm の完全なソースがあります。このフォームにBorderStyle = bsNoneがあることを確認してください。おそらく、それが表示されていないことも確認する必要があります。

unit UResize;
{
  Copyright 2014 Michael Thomas Greer
  Distributed under the Boost Software License, Version 1.0
  (See accompanying file LICENSE.txt or copy
   at http://www.boost.org/LICENSE_1_0.txt )
}

//////////////////////////////////////////////////////////////////////////////
interface
//////////////////////////////////////////////////////////////////////////////

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
  ResizeMaskLeft   = $1;
  ResizeMaskTop    = $2;
  ResizeMaskWidth  = $4;
  ResizeMaskHeight = $8;

type
  TResizeForm = class( TForm )
    procedure FormMouseMove( Sender: TObject;      Shift: TShiftState; X, Y: Integer );
    procedure FormMouseUp(   Sender: TObject;
                             Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
  private
    anchor_g: TRect;
    anchor_c: TPoint;
    form_ref: TForm;
    resize_m: cardinal;

  public
    procedure SetMouseDown( AForm: TForm; ResizeMask: cardinal );
  end;

var
  ResizeForm: TResizeForm;


//////////////////////////////////////////////////////////////////////////////
implementation
//////////////////////////////////////////////////////////////////////////////

{$R *.DFM}

//----------------------------------------------------------------------------
procedure TResizeForm.SetMouseDown( AForm: TForm; ResizeMask: cardinal );
  begin
  anchor_g.Left   := AForm.Left;
  anchor_g.Top    := AForm.Top;
  anchor_g.Right  := AForm.Width;
  anchor_g.Bottom := AForm.Height;
  anchor_c        := Mouse.CursorPos;
  form_ref        := AForm;
  resize_m        := ResizeMask;
  SetCapture( Handle )
  end;

//----------------------------------------------------------------------------
procedure TResizeForm.FormMouseMove(
  Sender: TObject;
  Shift:  TShiftState;
  X, Y:   Integer
  );
  var
    p: TPoint;
    r: TRect;
  begin
  if Assigned( form_ref ) and (ssLeft in Shift)
    then begin
         p := Mouse.CursorPos;
         Dec( p.x, anchor_c.x );
         Dec( p.y, anchor_c.y );

         r.Left   := form_ref.Left;
         r.Top    := form_ref.Top;
         r.Right  := form_ref.Width;
         r.Bottom := form_ref.Height;

         if (resize_m and ResizeMaskLeft)   <> 0 then begin r.Left   := anchor_g.Left   + p.x;  p.x := -p.x end;
         if (resize_m and ResizeMaskTop)    <> 0 then begin r.Top    := anchor_g.Top    + p.y;  p.y := -p.y end;
         if (resize_m and ResizeMaskWidth)  <> 0 then       r.Right  := anchor_g.Right  + p.x;
         if (resize_m and ResizeMaskHeight) <> 0 then       r.Bottom := anchor_g.Bottom + p.y;

         with r do form_ref.SetBounds( Left, Top, Right, Bottom )
         end
  end;

//----------------------------------------------------------------------------
procedure TResizeForm.FormMouseUp(
  Sender: TObject;
  Button: TMouseButton;
  Shift:  TShiftState;
  X, Y:   Integer
  );
  begin
  ReleaseCapture;
  form_ref := nil
  end;

end.

ResizeForm に単純な

ResizeForm.SetMouseDown( self, (sender as TComponent).Tag );

これを配置するのに適した場所は、ボーダレス フォームのエッジを追跡するために使用しているコンポーネントの MouseDown イベントです。(Tag プロパティを使用して、フォームのどの端をドラッグ/サイズ変更するかを示すことに注意してください)。

ああ、フォームをDoubleBuffered = trueに設定して、残りのちらつきを取り除きます。

これは私があなたに与えることができる小さな幸せです.

于 2014-03-06T09:56:51.710 に答える