Windowsフォームで、ユーザーがアイドルまたは非アクティブのときにタイマーを設定することについて質問があります。マウスイベントでもタイマーを設定する必要があります。ユーザーが任意の瞬間を作る場合は、タイマーをリセットする必要があります。したがって、これは要件です。これがコードです。
using System;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;
namespace FormsTimerSetup.Globals
{
public class SetApplicationTimeOut : Form
{
#region
/// <summary>
/// Private Timer Property
/// </summary>
private static Timer _timer;
/// <summary>
/// Timer Property
/// </summary>
public static Timer Timer
{
get
{
return _timer;
}
set
{
if (_timer != null)
{
_timer.Tick -= Timer_Tick;
}
_timer = value;
if (_timer != null)
{
_timer.Tick += Timer_Tick;
}
}
}
#endregion
#region Events
public event EventHandler UserActivity;
#endregion
#region Constructor
/// <summary>
/// Default/Parameterless SetApplicationTimeOut Constructor
/// </summary>
public SetApplicationTimeOut()
{
KeyPreview = true;
FormClosed += ObservedForm_FormClosed;
MouseMove += ObservedForm_MouseMove;
KeyDown += ObservedForm_KeyDown;
}
#endregion
#region Inherited Methods
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected virtual void OnUserActivity(EventArgs e)
{
// Invoking the UserActivity delegate
UserActivity?.Invoke(this, e);
}
/// <summary>
///
/// </summary>
public void SetTimeOut()
{
// postpone auto-logout by 30 minutes
_timer = new Timer
{
Interval = (30 * 60 * 1000) // Timer set for 30 minutes
};
Application.Idle += Application_Idle;
_timer.Tick += new EventHandler(Timer_Tick);
}
#endregion
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_MouseMove(object sender, MouseEventArgs e)
{
OnUserActivity(e);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_KeyDown(object sender, KeyEventArgs e)
{
OnUserActivity(e);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_FormClosed(object sender, FormClosedEventArgs e)
{
FormClosed -= ObservedForm_FormClosed;
MouseMove -= ObservedForm_MouseMove;
KeyDown -= ObservedForm_KeyDown;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Application_Idle(object sender, EventArgs e)
{
_timer.Stop();
_timer.Start();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
Application.Idle -= Application_Idle;
MessageBox.Show("Application Terminating");
Application.Exit();
}
#endregion
}
}
コードを実装しましたが、それが正しい方法であるかどうかは不明です。
どんなリードもいただければ幸いです。投稿とSTAY SAFEをご利用いただきありがとうございます。
Q:「マウスイベントにタイマーを設定する必要があります...ユーザーが何か動きをした場合、タイマーをリセットする必要があります...どんなリードでもありがたいです。」
A:役立つと思われるいくつかのリードを提供するように努めます。 MouseMoveイベントでタイマーをリセットしたいが、問題がある:子コントロールにフォーカスがあるときは常に、マウスイベントを受け取るのは子であり、メインフォームはそうしません。 これは修正可能です。
短い答え:「メインウィンドウクラスにIMessageFilterインターフェイスを実装して、マウスの動きが検出されたときにタイマーがリセットされるようにします。」 MessageFilterを追加すると、フォーカスされたコントロールに送信される前にマウスメッセージをインターセプトできます。
だから、私はあなたにすべての詳細を与えなければならないので、ここで長い答えがあります:それはこのようにメインのForm1にIMessageFilterインターフェースを追加することから始まります:
public partial class Form1 : Form, IMessageFilter
IMessageFilterには、クラスに1つのメソッドのみを実装する必要があります。
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_MOUSEMOVE:
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Commit f9367d7c added at OP's request
case WM_KEYDOWN:
// This makes WakeUp persist if user is typing in the textbox.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TimeOutState = TimeOutState.WakeUp;
break;
}
return false; // Do not suppress downstream message
}
const int // WinOS Messages
WM_KEYDOWN = 0x0100,
WM_MOUSEMOVE = 0x0200;
マウスを動かすと、アプリのTimeOutStateが「WakeUp」に戻ることがわかります。
enum TimeOutState{ WakeUp, Sleeping, Warning, Exit }
必要なタイマーは1つだけで、タイマーのティック間隔(ここでは5秒に設定)ごとに状態を1つ減らします。マウスが動かない場合は、マウスを下に下げて、最後に終了します。
60秒 video アプリを60秒間実行する例を示します。 5秒ごとに、またはマウスを動かすと、変化が発生することがわかります。サンプルを実行したい場合は、GitHubリポジトリから clone 最新のコミットを実行できます。
残りの詳細は次のとおりです。
MessageFilterを接続する必要があります。フォームにはウィンドウハンドルが必要なので、ここでこれを実行してタイマーを開始します。
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// When our main window is ready for messages, add the MessageFilter
Application.AddMessageFilter(this);
// ...and start the timer for the first time.
TimeOutState = TimeOutState.WakeUp;
}
タイマーをインスタンス化する必要がありますが、CTorで一度だけです。
public Form1()
{
InitializeComponent();
_wdt = new Timer();
_wdt.Interval = 5000; // Use a very short time-out for this demo
_wdt.Tick += _wdt_Tick;
}
Timer _wdt; // Watch-Dog Timer
Timer.Tickを処理する必要があります。
private void _wdt_Tick(object sender, System.EventArgs e)
{
// A tick reduces the TimeOutState by 1
TimeOutState = (TimeOutState)(TimeOutState - 1);
}
最後に、TimeOutStateの状態変化を処理し、メッセージを表示します。
TimeOutState TimeOutState
{
get => _timeOutState;
set
{
switch (value)
{
case TimeOutState.WakeUp:
_wdt.Stop();
_wdt.Start();
break;
case TimeOutState.Exit:
_wdt.Stop();
Application.Exit();
return;
}
if (value != _timeOutState) // If state changes, write message
{
Debug.WriteLine(value.ToString(), _timeOutState.ToString());
// In a timer callback that changes the UI, it's
// best to post the action in the message queue.
BeginInvoke((MethodInvoker)delegate
{
textBox1.AppendText(_timeOutState.ToString());
if (TimeOutState == TimeOutState.Warning)
{
textBox1.AppendText(
": Closing in " + (_wdt.Interval / 1000).ToString() + " seconds.");
}
textBox1.AppendText(Environment.NewLine);
textBox1.Select(textBox1.TextLength, 0);
});
}
_timeOutState = value;
}
}
TimeOutState _timeOutState = (TimeOutState)(-1); // Initialize to invalid state
私は自分のアプリでIMessageFilterを非常に確実に使用しており、あなたの投稿に答えるための1つの代替手段としてそれを提案すると確信しています。
私はあなたのコードを深く掘り下げることはしませんが、問題に直接アプローチしたいと思います。この場合、「回り道」がうまくいくと思います。
たとえばマウスが動くたびに確認し、初期位置と比較できます。
これを上記のInitialize Component();に追加します。
GlobalMouseHandler gmh = new GlobalMouseHandler();
gmh.TheMouseMoved += new MouseMovedEvent(gmh_TheMouseMoved);
Application.AddMessageFilter(gmh);
次にこれを追加します:
void gmh_TheMouseMoved()
{
if(XY==false)
{
MouseX = Convert.ToInt32(Cursor.Position.X);
MouseY = Convert.ToInt32(Cursor.Position.Y);
}
else
{
MouseX1 = Convert.ToInt32(Cursor.Position.X);
MouseY1 = Convert.ToInt32(Cursor.Position.Y);
XY = true;
if(MouseX1==MouseX && MouseY1==MouseY)
{
if(yourTimerNameHere.Enabled==false)
{
yourTimerNameHere.Start();
}
}
else
{
yourTimerNameHere.Stop();
yourTimerNameHere.Start();
}
}
}
これをフォームのクラスの外に追加します。
public delegate void MouseMovedEvent();
public class GlobalMouseHandler : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x0200;
public event MouseMovedEvent TheMouseMoved;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
{
if (TheMouseMoved != null)
{
TheMouseMoved();
}
}
return false;
}
}
次に、MouseX = 0、MouseY = 0、MouseX1 = 0、MouseY1 = 0、bool XY = falseという名前の4つのintを作成します。
したがって、実際には、カーソルが移動するたびに、位置が記録され、次の位置と比較されます。したがって、マウスがアイドル状態かどうかを確認できます!
Plsはこのコードをテストしていないので、エラーが発生した場合は元に戻してください。