C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

マウスカーソルの動きを縦横に制限する方法

[トピック内 11 記事 (1 - 11 表示)]  << 0 >>

■95517 / inTopicNo.1)  マウスカーソルの動きを縦横に制限する方法
  
□投稿者/ RRZ (1回)-(2020/08/12(Wed) 21:44:51)

分類:[.NET 全般] 

VBあるいはC#に関する質問です。



PictureBox上でシフトキーを押している間だけ
マウスカーソルが、
縦か横方向にか動かせないように制限したいのですが
(つまり、斜め方向には動かせないように制限したい)
どのようにすれば良いですか?

可動範囲を制限するには
https://www.atmarkit.co.jp/fdotnet/dotnettips/388limitcursor/limitcursor.html

この辺りのページに書かれてあるのですが、
方向だけを制限する方法が調べても分かりませんでした。

どなたかお教えください。


引用返信 編集キー/
■95518 / inTopicNo.2)  Re[1]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ くまくま (32回)-(2020/08/13(Thu) 06:56:54)
>>縦か横方向にか動かせないように制限したいのですが
まずマウスカーソルはxy座標の移動の連続で
可動範囲を制限(xy座標の範囲指定)はできても
x座標のみy座標のみの移動制限はできません。

マウスポインタの位置を取得、変更(移動)する
https://dobon.net/vb/dotnet/system/cursorposition.html
マウス ポインターがコントロール上を移動すると発生します。
https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.mousemove?view=netcore-3.1

ただまったく方法が無いわけではありません
マウスポインターがチラつく可能性がありますが
1. PictureBoxでマウスポインター移動のイベントを所得。
2. 前回移動時のxy座標と比較し移動量が大きい方で縦横の移動を判定。
3. イベント処理キャンセルフラグを立てる。
4. マウスポインター位置を変更する。
5. マウスポインター移動のイベントが再度発生するがイベント処理キャンセルフラグで判定し
処理をぜすフラグを取り消す

一応これで可能ですが、マウスポインター本来の動きではないので
その後想定されている処理に影響がない様にして下さい。
引用返信 編集キー/
■95519 / inTopicNo.3)  Re[1]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ 魔界の仮面弁士 (2807回)-(2020/08/13(Thu) 09:19:56)
No95517 (RRZ さん) に返信
> マウスカーソルが、縦か横方向にか動かせないように制限したいのですが

どの位置を起点としての縦横でしょうか。

たとえば右方向に 300px 動かした後、そこから上方向に 300px 動かした場合、
どのような位置に移動することを想定していますか?

(1) それぞれは水平と垂直にしか動かしていないので、最初の位置から見ると右斜め上に移動できる。
(2) 最初に右方向に移動させたので、センター位置に戻してから操作しないと上方向には移動できない。(右位置のまま)
(3) 最後に上方向に移動させたので、右方向への移動はキャンセルされて、上位置に移動した状態になる。
(4) 右方向と上方向の移動量が同一なので、移動方向を決定できず、最初の位置のままになる。


> PictureBox上でシフトキーを押している間だけ
マウスカーソルが PictureBox 上にある時に Shift を押したときに処理を開始するとして、
マウスの移動量が、PictureBox の領域外に出ることを許容しますか?


ドラッグ操作なら、PictureBox の Capture が true 状態になるので、
MouseMove 等で追跡しやすいのですけれどね…。


ところで、その水平垂直移動制限は、何のために必要な処理なのでしょうか?


たとえば Excel のオートシェイプで四角形を描画した後、
シェイプ周辺のハンドルをつかんで、Shift を押しながらドラッグしてみてください。

この場合、図形は水平・垂直(あるいは縦横比維持)のままリサイズされますが、
「マウスの座標」と「ドラッグしているハンドルの座標」は同じものでは無いはずです。


これと同じような動作で良いのなら、「実際のマウス座標」を制限するのではなく、
そこから算出される目標座標を PictureBox で捕らえるようにし、Shift が離された瞬間、
実際のカーソル位置を移動させるようにしてみる…というのはどうでしょう。

対象を PictureBox 内に限定するのであれば、Shift が押された時点で現在のカーソルを非表示にし、
上記算出座標で得られた位置に、カーソル代わりの矢印なり十字画像なりを描画すれば、
要件次第では、それっぽい動作になるんじゃないかと想像してみました。
引用返信 編集キー/
■95526 / inTopicNo.4)  Re[2]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ RRZ (2回)-(2020/08/13(Thu) 18:06:14)
ありがとうございます。

説明不足でしたが、


シフトキーを押した時を起点とした縦横です。


Excel のオートシェイプで四角形を描画した後、
四角形をドラッグ移動させるときにシフトキーを押しながらだと縦横にしか動かせないですが
これと同様の操作を行いたいと考えています。

Excelの場合には、マウスカーソルは縦横に制限されないが、
オートシェイプの位置だけが縦横に制限されるような動きをします。

一方で、できれば、カーソル側も縦横に制限したいと考えています。

この方法があればお教えください、

もし難しいようであれば、Excelと同様に
オートシェイプの位置だけが縦横に制限される仕様にするしかないと思います。

引用返信 編集キー/
■95527 / inTopicNo.5)  Re[3]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ くまくま (33回)-(2020/08/13(Thu) 18:35:46)
2020/08/13(Thu) 18:36:54 編集(投稿者)

> Excel のオートシェイプで四角形を描画した後、
> 四角形をドラッグ移動させるときにシフトキーを押しながらだと縦横にしか動かせないですが
> これと同様の操作を行いたいと考えています。

すみません。1点質問なのですが

魔界の仮面弁士さんの引用をお借りします。
Excelのオートシェイプの場合、選択すると「□」が8カ所表示されます。
この「□」の上下2つは縦方向、左右2つは横方向のサイズ変更、残りは4つは縦横方向のサイズとなります。
これはどこの「□」を選択したかで縦方向、横方向、縦横方向(フリー)が決まる仕組みです。

RRZさんは、Excelのオートシェイプのような「どの場所をマウスダウンしたかでマウスの方向を決定する」仕組みか
例えば「シフトキーの場合は縦方向、コントロールキーの場合横方向に限定する」等をお考えですか?

引用返信 編集キー/
■95529 / inTopicNo.6)  Re[4]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ RRZ (3回)-(2020/08/13(Thu) 19:03:43)
8カ所の「□」をクリックするのは四角のサイズを変更するためですが、
そこではなく、四角の中をクリックした場合の、並進操作の場合の話です

引用返信 編集キー/
■95530 / inTopicNo.7)  Re[3]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ 魔界の仮面弁士 (2808回)-(2020/08/13(Thu) 19:25:42)
No95526 (RRZ さん) に返信
> 四角形をドラッグ移動させるときにシフトキーを押しながらだと縦横にしか動かせないですが
> これと同様の操作を行いたいと考えています。

では、ドラッグ操作が目的、という前提で回答してみます。
(マウスボタンを押しているかどうかで、処理の捉え方が変わってきます)

PictureBox 上でのドラッグ中であれば、MouseMove イベントが継続的に発生するので、
そのイベント内にて、現在のカーソル位置を捕らえられます。
ドラッグの終了も管理しやすいので、基本的にはこれがお奨め。


もしもドラッグ操作ではない場合(MouseDown を伴わないカーソル移動)だと、
カーソル位置が PictureBox の範囲外に出てしまうと、
PictureBox のイベントでは捉えられないため、監視が手間になります。
(タイマー監視あるいは RawInput など、やりようはあるのですが)



> シフトキーを押した時を起点とした縦横です。

ドラッグ開始時に Shift を押していない時は、斜め移動も許可されているのでしょうか。

そうすると、斜め位置にドラッグしたところで Shift を押すと、
Shift を押した所を起点として垂直・水平移動が始まるのであって、
ドラッグ開始位置を起点として垂直・水平移動となるわけではないのですね?

その場合、移動終了を伝えるのは、MouseUp なのか Shift の KeyUp なのか、それとも…。



> 一方で、できれば、カーソル側も縦横に制限したいと考えています。

最初に右に動かして、やっぱり上方向に変更したいような場合、
どういう操作になることを想定しておられますか?


【案1】マウスの移動可能領域を完全に制限して、
    開始位置からの斜め移動を禁止させる

■■■■■■■■■
■■■■□■■■■
■■■■□■■■■  黒マスは移動不可領域
■■■■□■■■■
■□□□始→→☆■  右方向への移動操作を行っていたが
■■■■□■■■■
■■■■□■■■■
■■■■□■■■■
■■■■■■■■■

■■■■■■■■■
■■■■☆■■■■
■■■■↑■■■■  それをキャンセルして
■■■■↑■■■■  (または開始位置までドラッグで戻してから)
■□□□戻←←←■  改めて上方向にドラッグ操作させる
■■■■□■■■■
■■■■□■■■■
■■■■□■■■■
■■■■■■■■■



【案2】カーソル移動範囲は特に制限しない。ただし、本来のカーソルは非表示となり、
    ドラッグ中は移動量に応じた水平・垂直位置に疑似カーソルが描画される

→ 移動完了後には本来のカーソルを再表示して、目標座標にカーソル座標を移動する


□□□□□□□□□
□□□□□□□□□
□□□□□□□☆□  非表示にしたカーソル「☆」が
□□□□□□□□□  X 方向に + 3、Y 方向に -2 のオフセットにあるので
□□□□始→→★□  右方向への移動と判断して、
□□□□□□□□□  X += 3 な「★」の座標に疑似カーソルを描画する
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□

□□□□□□□□□
□□□□★□☆□□
□□□□↑□□□□  非表示にしたカーソル「☆」が
□□□□↑□□□□  X 方向に + 2、Y 方向に -3 のオフセットにあるので
□□□□始□□□□  上方向への移動と判断して、
□□□□□□□□□  Y -= 3 な「★」の座標に疑似カーソルを描画する
□□□□□□□□□
□□□□□□□□□
□□□□□□□□□

※水平・垂直の移動量が同じだった場合は、どの向きに動かす?
 (移動させない? 水平優先? 垂直優先? 最初の移動方向を優先? 最後の移動方向を優先?)
引用返信 編集キー/
■95531 / inTopicNo.8)  Re[5]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ くまくま (34回)-(2020/08/13(Thu) 19:47:57)
No95529 (RRZ さん) に返信
> 8カ所の「□」をクリックするのは四角のサイズを変更するためですが、
> そこではなく、四角の中をクリックした場合の、並進操作の場合の話です
了解しました。

まずExcelのオートシェイプの場合ですが、
通常時はマウスで移動した位置XYに対してオートシェイプを移動します。
シフトキーを押した場合「座標の考え方」が変わり
「マウス移動量が一定以下の場合、前回移動した移動軸に対してのみ移動」
「マウス移動量が一定以上の場合、移動量の大きい軸に対して移動」
となります。
マウスの移動に対してのイベントでXY座標は取得できるので
あとはそのXY座標をどう処理するか?だけで良いです。

これがRRZさんが希望されていた「マウスカーソル移動も制限する」となると話が変わります。
・縦方向のみ
・横方向のみ
ならRRZさんが質問で書かれていた「可動範囲を制限するには」の応用で
縦方向なら幅を、横方向なら高さを狭く設定することで対応できなくもないです。
ただ今回の質問のような
・縦横方向のみ
という場合は、先の回答で書いた方法をとらなくてはならず
マウスカーソルのチラつきやコントロールが複雑となり
RRZさんが希望されていた動きとは違う結果になる可能性が高いと思います。

私も魔界の仮面弁士さんの回答と同様に
マウスカーソル移動も制限するのではなく、Excelのオートシェイプを模倣する形が良いかと思います。
引用返信 編集キー/
■95532 / inTopicNo.9)  Re[4]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ くまくま (35回)-(2020/08/13(Thu) 19:51:55)
RRZ さん
魔界の仮面弁士 さん

すみません、被ってしまいました。
申し訳ございませんが、今後魔界の仮面弁士さんに回答をお任せしたいと思います。
よろしくお願いします。
引用返信 編集キー/
■95533 / inTopicNo.10)  Re[5]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ 魔界の仮面弁士 (2809回)-(2020/08/13(Thu) 20:28:25)
No95532 (くまくま さん) に返信
> 申し訳ございませんが、今後魔界の仮面弁士さんに回答をお任せしたいと思います。

(^_^;)


えぇと、それじゃ No95530 の案2パターンでのサンプル。


PictureBox 上の矩形をドラッグ移動できるようにして、
Shift キー押下中は移動範囲を制限してみました。


ただし、いろいろ手抜きな実装になっています。

たとえば、縦横移動制限時の起点座標は、
No95526 で書いていた「シフトキーを押した時の位置」ではなく、
「ドラッグ開始位置」に変更されています。

また、下記だと MouseDown 時にいきなりドラッグが開始されてしまいますが、
本来は、SystemInformation.DragSize 以上のマウス移動が発生するまでは
ドラッグを開始するべきではないですね。


public partial class Form1 : Form
{
    // ドラッグ中にマウスカーソルを非表示にするかどうか
    private readonly bool InvisibleCursor = true;

    public Form1()
    {
        InitializeComponent();
    }

    private Rectangle box = new Rectangle(200, 200, 64, 64);
    private Point? dragStart = null;  // ドラッグ開始位置

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (dragStart == null)
        {
            e.Graphics.FillRectangle(Brushes.Blue, box);
        }
        else
        {
            bool shiftDown = ModifierKeys.HasFlag(Keys.Shift);
            var pos = pictureBox1.PointToClient(Cursor.Position);
            e.Graphics.DrawRectangle(shiftDown ? Pens.DarkGreen : Pens.DarkRed, box);
            e.Graphics.FillRectangle(shiftDown ? Brushes.Green : Brushes.Red, DraggingPosition());
        }
    }

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {
        if (dragStart != null)
        {
            pictureBox1.Invalidate();
        }
    }

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
    {
        if (box.Contains(e.Location) && e.Button.HasFlag(MouseButtons.Left))
        {
            if (InvisibleCursor) { Cursor.Hide(); }
            dragStart = e.Location;
        }
    }

    private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
    {
        if (dragStart != null)
        {
            if (InvisibleCursor) { Cursor.Show(); }
            box = DraggingPosition();
            dragStart = null;
            pictureBox1.Refresh();
            if (InvisibleCursor)
            {
                var pos = pictureBox1.PointToScreen(box.Location);
                pos.Offset(box.Width / 2, box.Height / 2);
                Cursor.Position = pos;   // ドラッグ終了時に、マウス座標を本当に移動させる
            }
        }
    }

    private Rectangle DraggingPosition()
    {
        var newBox = box;
        var f = dragStart.Value;
        var t = pictureBox1.PointToClient(Cursor.Position);
        bool shiftDown = ModifierKeys.HasFlag(Keys.Shift);

        // 縦横の移動量を計測
        int offsetX = t.X - f.X;
        int offsetY = t.Y - f.Y;

        // 新しい移動先を算出
        // ただし Shift 押下中は、垂直・水平方向に制限する
        int direction = Math.Abs(offsetX).CompareTo(Math.Abs(offsetY));
        if (!shiftDown || direction > 0) { newBox.X += offsetX; }
        if (!shiftDown || direction < 0) { newBox.Y += offsetY; }
        return newBox;
    }
}

引用返信 編集キー/
■95534 / inTopicNo.11)  Re[6]: マウスカーソルの動きを縦横に制限する方法
□投稿者/ 魔界の仮面弁士 (2810回)-(2020/08/13(Thu) 20:36:03)
No95533 (魔界の仮面弁士) に追記
> ただし、いろいろ手抜きな実装になっています。


ドラッグ中に Shift キーを押したり離したりした場合の
再描画処理が漏れていました。コンストラクタを差し替え。


public Form1()
{
  InitializeComponent();
  KeyPreview = true;
  KeyEventHandler forceDraw = delegate { pictureBox1.Invalidate(); };
  KeyDown += forceDraw;
  KeyUp += forceDraw;
}
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ