1

私はwinformウィンドウを持っています。画面のサイズを変更すると、画面がすぐに拡大または縮小します。

ウィンドウのサイズ変更動作がSplit Containerのようになることを希望します。マウスをドラッグする限り、ウィンドウ サイズを示す線のみが表示され、サイズ変更操作を終了するときにのみ実行されます。

ウィンドウのフレームを非表示にしてから、ウィンドウ自体をクリックしてフレームをペイントすることで、それを示す例をいくつか見ました。

ウィンドウではなく、ウィンドウのフレームをクリックして(フレームを非表示にしたくない)、それが必要です

これを行う方法はありますか?(何らかの方法でサイズ変更の動作をオーバーライドする場合があります)。

4

1 に答える 1

5

インターネット上で解決策を見つけることができないと確信しています。ただし、これについてデモを試してみましたが、かなりうまく機能します。

winformsおよび他の多くの UI テクノロジでは、ウィンドウ自体の外に何かをレンダリングすることはできません。必要な効果を得るには、ユーザーがウィンドウのサイズを変更する方法に応じて、ウィンドウの外側または内側に何らかの指示的な境界線をレンダリングする必要があります。行き詰まっているように見えますか?

しかし、それを行うための一種のテクニックがあります(私はそれをレイヤーテクニックと呼んでいます)。指標となる境界線をレンダリングするには、透明でフォーカスされていないレイヤーが必要です。このレイヤーは、メイン ウィンドウのand (わずかなオフセット)SizeLocation同期されます。レイヤーもデフォルトで表示され、ユーザーがサイズ変更したときにのみ表示され、サイズ変更が終了すると非表示になります。SizeLocationinvisible

それは私が言及したテクニックでかなりOKです。ただし、ユーザーがウィンドウのサイズを変更するときにデフォルトのサイズ変更を防止/破棄するにはどうすればよいですか? 幸いなことWin32に、これを簡単に行うために 2 つのメッセージがサポートされています。

  • WM_RESIZING : ユーザーが開始してサイズ変更を続けると、ウィンドウに送信されます。サイズ変更時に現在のウィンドウの構造を保持LParamします。RECTこの情報を読み取って、指示境界線を正しくレンダリングします。次に、これRECTを現在Boundsのウィンドウに変更して、デフォルトのサイズ変更効果を破棄する必要があります (サイズと位置はすぐに変更されます)。
  • WM_EXITSIZEMOVE : サイズ変更または移動が終了したときにウィンドウに送信されます。このメッセージをキャッチして、透明レイヤーの and に基づいてウィンドウの and を割り当て、もちろんレイヤーを非表示にする必要がありSizeます。LocationSizeLocation

今、問題は完全に解決可能です。これが私が作ったデモコードです。ここには非常に厄介で解決不可能で理解できないバグがあることに注意してください。Top-Leftコーナーのサイズを変更すると発生し、Sizeはマウスを放した後に正しく更新されますが、Locationはオフセットで設定されます。デバッグしましたが、うまくいきません。ある時点で、Topが明確な理由もなくLeft予期しない値にジャンプします。ただし、全辺(左、上、右、下)、その他の角のリサイズはOKです。実際、ユーザーがサイズ変更を行うことはほとんどないため、この解決策は受け入れられると思います。Top-Left corner

//Must add using System.Runtime.InteropServices;
public partial class Form1 : Form
{        
    public Form1()
    {
        InitializeComponent();
        //Sizing border initialization
        SizingBorderWidth = 3;
        SizingBorderStyle = DashStyle.Custom;
        SizingBorderColor = Color.Orange;
        //layer initialization
        layer.Owner = this;//especially this one.
        layer.Width = Width + SizingBorderWidth * 2;
        layer.Height = Height + SizingBorderWidth * 2;                         
        //Paint the border when sizing
        layer.Paint += (s, e) => {
            using (Pen p = new Pen(SizingBorderColor) { Width = SizingBorderWidth }) {
                if (Use3DSizingBorder) {
                    ControlPaint.DrawBorder3D(e.Graphics, sizingRect.Left, sizingRect.Top, sizingRect.Width, sizingRect.Height, Border3DStyle.Bump, Border3DSide.All);
                }
                else {
                    p.DashStyle = SizingBorderStyle;
                    p.LineJoin = LineJoin.Round;
                    if(p.DashStyle == DashStyle.Custom)
                       p.DashPattern = new float[] { 8f, 1f, 1f, 1f };//length of each dash from right to left
                    e.Graphics.DrawRectangle(p, sizingRect);
                }
            }
        };
        //Bind the Location of the main form and the layer form together
        LocationChanged += (s, e) => {
            Point p = Location;
            p.Offset(-SizingBorderWidth, -SizingBorderWidth);
            layer.Location = p;
        };
        //Set the intial Location of layer
        Load += (s, e) =>{                
            Point p = Location;
            p.Offset(-SizingBorderWidth, -SizingBorderWidth);
            layer.Location = p;
        };            
    }
    //Set this to true to use 3D indicative/preview border
    public bool Use3DSizingBorder { get; set; }
    //Change the indicative/preview border thickness
    public int SizingBorderWidth { get; set; }
    //Change the indicative/preview border style
    public DashStyle SizingBorderStyle { get; set; }
    //Change the indicative/preview border color
    public Color SizingBorderColor { get; set; }
    //hold the current sizing Rectangle
    Rectangle sizingRect;
    bool startSizing;
    bool suppressSizing;
    //This is a Win32 RECT struct (don't use Rectangle)
    public struct RECT
    {
        public int left, top, right, bottom;
    }
    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x214&&!suppressSizing)//WM_SIZING = 0x214
        {                
            RECT rect = (RECT) m.GetLParam(typeof(RECT));
            int w = rect.right - rect.left;
            int h = rect.bottom - rect.top;
            sizingRect = new Rectangle() {X = SizingBorderWidth/2, Y = SizingBorderWidth/2, 
                                          Width = w, Height = h};
            layer.Left = rect.left-SizingBorderWidth;
            layer.Top = rect.top-SizingBorderWidth;
            layer.Width = w+2*SizingBorderWidth;
            layer.Height = h+2*SizingBorderWidth;
            if (!startSizing)
            {
                layer.Show();
                startSizing = true;
            }
            layer.Invalidate();
            //Keep the current position and size fixed
            rect.right = Right;
            rect.bottom = Bottom;
            rect.top = Top;
            rect.left = Left;
            //---------------------------
            Marshal.StructureToPtr(rect, m.LParam, true);
        }
        if (m.Msg == 0x232)//WM_EXITSIZEMOVE = 0x232
        {
            layer.Visible = false;
            BeginInvoke((Action)(() => {
                suppressSizing = true;
                Left = layer.Left + SizingBorderWidth;
                Top = layer.Top + SizingBorderWidth;
                Width = layer.Width - 2 * SizingBorderWidth;
                Height = layer.Height - SizingBorderWidth * 2;
                suppressSizing = false;
            }));
            startSizing = false;
        }
        base.WndProc(ref m);            
    }
    //Here is the layer I mentioned before.
    NoActivationForm layer = new NoActivationForm();
}    
public class NoActivationForm : Form {
    public NoActivationForm() {
        //The following initialization is very important
        TransparencyKey = BackColor;
        FormBorderStyle = FormBorderStyle.None;
        ShowInTaskbar = false;
        StartPosition = FormStartPosition.Manual;            
        //----------------------------------------------                          
    }
    protected override bool ShowWithoutActivation {
        get { return true; }
    }
}

いくつかのスクリーン ショット:

ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力 ここに画像の説明を入力

編集:(この編集はHodaya Shalom、OP(奇妙な:)によって提案されました

左隅の問題の解決策を見つけました:

BeginInvoke の前に変数を保存し、呼び出しでローカル変数を配置します。

int _top = layer.Top + SizingBorderWidth;
int _left = layer.Left + SizingBorderWidth;
int _width = layer.Width - 2 * SizingBorderWidth;
int _height = layer.Height - SizingBorderWidth * 2;
BeginInvoke((Action)(() => {
    suppressSizing = true;
    Left = _left;
    Top = _top;
    Width =_width;
    Height =_height;
    suppressSizing = false;
}));
于 2013-10-06T10:55:38.123 に答える