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

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

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

Re[5]: MouseWheelイベントで移動量を無視する方法について


(過去ログ 20 を表示中)

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

■8508 / inTopicNo.1)  MouseWheelイベントで移動量を無視する方法について
  
□投稿者/ あら (29回)-(2007/10/01(Mon) 19:11:03)

分類:[C#] 

お世話になっております。

numericUpDownコントロールでマウスの移動量に関係なく+/-1づつ値をnumericUpDown.Valueに入れたいと思っています。

下記のように移動量を取得して、移動量分を増減させようとしたのですが、境界値では移動量分の増減となってしまいまし
た。

そこで、MouseWheelのイベント発生時にマウスの移動量は無視して指定した値を、numericUpDown.Valueに入れたいのです
が、そのようなことはできるのでしょうか?

ご教授、アドバイス宜しくお願いします。
(C# .NET Framwork2.0)
--------------

        private void NumericUpDown1_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            Microsoft.VisualBasic.Devices.Computer myComputer = new Microsoft.VisualBasic.Devices.Computer();
            int i = myComputer.Mouse.WheelScrollLines;

            try
            {
                if (numericUpDown1.Value >= 0)
                {
                    if (e.Delta > 0)
                    {
                        numericUpDown1.Value += 1 - i;

                    }
                    else
                    {
                        numericUpDown1.Value -= 1 - i;
                    }
                }
                else
                {
                    if (e.Delta > 0)
                    {
                        numericUpDown1.Value += 1 - i;

                    }
                    else
                    {
                        numericUpDown1.Value -= 1 - i;
                    }
                }
            }
            catch (ArgumentOutOfRangeException)
            {
                //max:100, min:-100とし場合
                if (numericUpDown1.Value >= 100)
                {
                    numericUpDown1.Value = 100;
                }
                else
                {
                    numericUpDown1.Value = -100;
                }
            }
        }

引用返信 編集キー/
■8514 / inTopicNo.2)  Re[1]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ RUN (3回)-(2007/10/01(Mon) 23:05:42)
No8508 (あら さん) に返信
> お世話になっております。
>
> numericUpDownコントロールでマウスの移動量に関係なく+/-1づつ値をnumericUpDown.Valueに入れたいと思っています。

とりあえずお聞きしたいのですが、
マウスの移動量に関係なく+/-1づつ値をnumericUpDown.Valueに入れたい
と言う事ならば、

>numericUpDown1.Value += 1 - i;

の様に、WheelScrollLinesの値を引く意味って何かあるのでしょうか?
単純にnumericUpDown1.Value += 1; なのでは?

引用返信 編集キー/
■8515 / inTopicNo.3)  Re[1]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ mあ (86回)-(2007/10/01(Mon) 23:44:26)
2007/10/02(Tue) 00:40:49 編集(投稿者)
2007/10/02(Tue) 00:27:14 編集(投稿者)
2007/10/02(Tue) 00:18:11 編集(投稿者)
2007/10/02(Tue) 00:13:21 編集(投稿者)

んー、チカチカする VB ソースでよければ載せるが・・・

ホイールの終了をどうやって判定するか、だね。
ホイールの開始は Event#Wheel で取れますね。
デルタは、MouseEventArgs#Delta で取れます。

NumericUpDown#Increment = 0.01 ってやれば、ホイール3周くらいやらないと
±1加算すら出来ないようになります。上下キー入力とマウスクリックで反応
が鈍くなるのでここらへんがポイントですね。タイマーイベントでホイールが
無かったことにするように修正してみたらどーでしょう?
で、タイマーのタイムアウトがホイールの終了(切れ目)ということになります。
従って、かなりシビアに設定しないと、タイマーが終わる前に再びタイマーを
起動してしまうことになりますが、まぁ、こちらのテストだと、100ms くらいの
設定ならば、ホイールに足乗っけてズリズリ前後に滑らせてもちゃんとホイール
移動量を無視して±1が達成できています。

がんばってください。


微妙な書き換えが見えてしまうのを避けるには、、、、
うーん、 UpDownBase#UpdateEditText() をオーバーライドするのが一番手っ取り早い
のだと思っているだが、中々てこずりますな・・・

我が家のちっこいマウスだと100ms タイマー(ホイールイベント発生毎にstop/start
繰り返す)で、7回ホイールイベントが来ることが分かっています。
ホイールの分解性能が関わってくるので、ホイール1クリックあたりの分解能力に
よっては、イベントがもっと多くくる可能性もあります。イベントが一杯発生する
ことはつまり、処理が重くなるわけですから、1回のイベント処理も最小工数で
まかなうようにしなければなりません。こちらのテストでは足し算引き算が10行く
らいですが。
ホイールを回すとカクカクいうでしょ、あれの「1カク」がイベント1回です。
ちっこいマウスなので、ホイールもちっこいです。でっかいマウスだと、ホイール
もでっかいので、ギヤの歯数が多くなれば、見えてる部分の1コスリ分での「カクカク」
が増えることになります。まぁ、なんぼでかいって言っても・・・
トラックボールだと・・・デッドロックも考えられます。


# 人差し指をホイール先端に乗っけて、手前一杯までなぞったときのイベント発生回数
# です。


引用返信 編集キー/
■8521 / inTopicNo.4)  Re[1]: MouseWheelイベントで移動量を無視する
□投稿者/ @echo (12回)-(2007/10/02(Tue) 01:55:16)
2007/10/02(Tue) 07:06:19 編集(投稿者)

No8508 (あら さん) に返信
> そこで、MouseWheelのイベント発生時にマウスの移動量は無視して指定した値を、numericUpDown.Valueに入れたいのです
> が、そのようなことはできるのでしょうか?

MouseWheel は前処理なので、イベント内での対処は無理だと思います。
(イベント内で操作後に加算される)

NumericUpDown を継承またはサブクラス化して WM_MOUSEWHEEL で
NumericUpDown.Value を操作し、メッセージを base に渡さなければ
希望の動作になるはずです。

サブクラス化の参考 URL:
http://ant0x.udap.jp/tips/tips_NativeWindow.htm

または、手軽に実装するなら MouseWheel イベントから PostMessage で
遅延起動して書き換える手もありますね。

ちなみに WheelScrollLines は、
SystemInformation.MouseWheelScrollLines
でも取得できるはずです。
(上記の方法の場合、使用する必要はありませんが...)

引用返信 編集キー/
■8522 / inTopicNo.5)  Re[2]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ れい (147回)-(2007/10/02(Tue) 04:15:41)
2007/10/02(Tue) 04:29:34 編集(投稿者)
以下のコードがよいと思います。

Public Class SlowWheelNumericUpDown
    Inherits NumericUpDown

    Private wheeldelta As Integer = 0
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = &H20A Then
            If SystemInformation.MouseWheelScrollLines > 0 Then
                Dim delta As Integer
                wheeldelta += (m.WParam.ToInt32 >> 16)
                delta = (wheeldelta \ 120) * 120 \ SystemInformation.MouseWheelScrollLines
                wheeldelta = wheeldelta Mod 120
                m.WParam = New IntPtr((delta << 16) Or (m.WParam.ToInt32 And &HFFFF))
            End If
        End If
        MyBase.WndProc(m)
    End Sub

End Class

マウスのホイールによる移動量は将来の拡張やスムーズな移動を実現するために、
ちょっと癖がある仕様になっています。

デフォルトだと
マウスホイールの1目盛りに対して120単位の移動量に相当するメッセージが送られてきて、
それに対して3行スクロールするよう設定されています。
これはマウスのプロパティから設定を変えることができます。

120単位で何行スクロールすべきかは、
SystemInformation.MouseWheelScrollLines
で取得できます。

Windowsの仕様上は、
120単位の整数倍や整数分の1の移動量が送られてくる場合もありえますし、0の場合もあります。
複数回のホイールメッセージが積算されて送られてくることもありえます。
ホイールメッセージを適当に書き換えてマウスの移動量を制御するようなソフトも存在します。

中途半端な移動量が送られてきた場合の実装は実装者にまかされていますが、
積算して120単位ごとにスクロールするとか、
送られてきた量に合わせて少しだけスクロールするとか、
そういった常識的処理をする必要があります。

TextBoxやRichTextBoxは内部で移動量を積算し、
120単位になって初めてスクロールを行います。
一方、NumericUpDownも同じように内部で移動量を積算しますが、
(120単位/MouseWheelScrollLines)で1行スクロールを行います。

仕様上は、送られてくるメッセージの回数が実際のホイール移動回数に対応していない可能性があります。
例えば、システムが重いときはメッセージがまとめられる場合もありえますし、
ホイールの移動量を調節するソフトが入っている場合は
適当に調節された120の整数倍でない移動量が送られてくる場合があります。

ですので、
「マウスの移動量に関係なく+/-1づつ値をnumericUpDown.Valueに入れたい」というのを
メッセージを見て移動量が正の時には+1、負の時には-1、0の時にはなにもしない、というコードで済ませると、
動かしたノッチの数と、結果として動いた量がずれてしまう可能性があります。

マウスホイールの移動に関して決まっているのは
ホイール1ノッチが120単位であることだけですので、
きちんとやるならば、移動量を積算し、120単位ごとに1ノッチと数えなければいけません。
「マウスの移動量に関係なく+/-1づつ値をnumericUpDown.Valueに入れたい」は
「1ノッチで1lineずつスクロールしたい」と読み替えるべきでしょう。

NumericUpDownは(120単位/MouseWheelScrollLines)で1行スクロールを行ってくれますので、
移動量を積算し、総ノッチ数を数え、
ノッチ数 x 1行分の移動量(120単位/MouseWheelScrollLines)を設定したWM_MOUSEWHEELを送ってやれば
きちんと動作してくれます。

TextBoxやRichTextBoxは120単位でしか動かず、
動く場合はMouseWheelScrollLinesだけ動いてしまうので、
この方法ではだめで、自前でスクロール機構をいれなければいけません。

引用返信 編集キー/
■8591 / inTopicNo.6)  Re[3]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ あら (30回)-(2007/10/03(Wed) 16:19:46)
RUNさん、mあさん、@echoさん、れいさん返信ありがとうございます。

教えて頂いたソースをC#に変更して実行したら
 ・境界値の挙動で2ノッチしないと値が変わらない・・・
 ・VBも計算式もよくわからなかったので、値を減らす場合の処理がいいのか不明・・・
といった問題が残りましたが、大体考えていた挙動になりましたので、
解決済とさせて頂きます。

ありがとうございました。

--------------------------
以下れいさんに教えて頂いたソースのC#に変更したものです。

    public class SlowWheelNumericUpDown : NumericUpDown
    {
        private int wheeldelta = 0;
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x20A)
            {
                if (SystemInformation.MouseWheelScrollLines > 0)
                {
                    int delta;
                    wheeldelta += ((int)m.WParam >> 16);
                    delta = (wheeldelta / 120) + 120 / SystemInformation.MouseWheelScrollLines;
                    if (wheeldelta < 0)
                    {
                        delta = -delta;
                    }
                    wheeldelta = wheeldelta % 120;
                    m.WParam = (IntPtr)((delta << 16) | ((int)m.WParam & 0xffff));
                }
            }

            base.WndProc(ref m);
        }
    }

解決済み
引用返信 編集キー/
■8604 / inTopicNo.7)  Re[4]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ れい (148回)-(2007/10/03(Wed) 20:19:26)
No8591 (あら さん) に返信
> delta = (wheeldelta / 120) + 120 / SystemInformation.MouseWheelScrollLines;
> if (wheeldelta < 0)
> {
> delta = -delta;
> }


これは

>delta = (wheeldelta \ 120) * 120 \ SystemInformation.MouseWheelScrollLines

とはずいぶん違いますよ。

引用返信 編集キー/
■8622 / inTopicNo.8)  Re[5]: MouseWheelイベントで移動量を無視する方法について
□投稿者/ あら (31回)-(2007/10/04(Thu) 11:37:19)
返信ありがとうございます。

> > とはずいぶん違いますよ。
あまり理解せずに写してたので、掛け算と足し算を見間違えました・・・
delta = (wheeldelta / 120) * 120 / SystemInformation.MouseWheelScrollLines;
とすれば、問題なく動作しました。

ありがとうございます。

解決済み
引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -