比较鼠标移动事件流,鼠标位置不会减少
本文关键字:鼠标 位置 移动 事件 比较 | 更新日期: 2023-09-27 18:30:30
我有一个Windows窗体应用程序,我正在使用Rx查询MouseMove事件流,并根据鼠标的位置(当前和以前)生成结果。我的代码如下所示:(标签 1 显示结果,标签 2 显示包含当前和上一个位置的"日志"。
var observable = Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove");
observable
.PairWithPrevious()
.Select(tuple =>
{
if (tuple.Item2 == null || tuple.Item1 == null) return Tuple.Create(0, 0);
var currPosition = tuple.Item2.EventArgs.Location;
var prevPosition = tuple.Item1.EventArgs.Location;
var x = 0;
if (currPosition.X > prevPosition.X) x = 1;
else if (currPosition.X < prevPosition.X) x = -1;
var y = 0;
if (currPosition.Y > prevPosition.Y) y = 1;
else if (currPosition.Y < prevPosition.Y) y = -1;
label2.Text = string.Format("Curr X: {0} * Y: {1} |||| Prev X: {2} * Prev Y: {3}", currPosition.X, currPosition.Y, prevPosition.X, prevPosition.Y);
return Tuple.Create(x, y);
})
.Subscribe(x =>
{
label1.Text = string.Format("X: {0} ** Y: {1}", x.Item1, x.Item2);
});
PairWithPrevious 函数:
public static IObservable<Tuple<TSource, TSource>> PairWithPrevious<TSource>(this IObservable<TSource> source)
{
return source.Scan(
Tuple.Create(default(TSource), default(TSource)),
(acc, current) => Tuple.Create(acc.Item2, current));
}
问题是:当您向左或向上移动鼠标时,前一个和当前 (x, y) 是相同的值,结果 (label1) 永远不会显示"-1"值。
我尝试使用Zip函数来比较以前的值和当前值,但结果是相同的:
Zip(observable.Skip(1), Tuple.Create)
那么,为什么会出现这种情况?以及如何解决它?
如果您观察 MouseMove 事件触发的频率,您将看到导致问题的原因。我已经更新了您的代码以包含计数。 我还添加了一个包含三列的简单列表视图,并将列表视图的视图设置为详细信息,使其非常明显。
我的一些代码与你的不同。 这主要是一个风格问题。 但是我将PairWithBefore更改为WithPrior并隐藏了元组
//http://www.zerobugbuild.com/?p=213 with a tweak to hide the Tuple
public static IObservable<TResult> WithPrevious<TSource, TResult>(this IObservable<TSource> source, Func<TSource, TSource, TResult> projection)
{
return source.Scan(Tuple.Create(default(TSource), default(TSource)),
(previous, current) => Tuple.Create(previous.Item2, current))
.Select(t => projection(t.Item1, t.Item2));
}
RX Select 运算符的重载为 int,它只是一个计数器。 我将使用它来添加到匿名对象以向下链接。 WithPrevious 现在只是投影到另一个包含我们所需数据的匿名对象。 然后在订阅中,我们将更新两个标签和新的列表视图。
var observable = Observable.FromEventPattern<MouseEventArgs>(this, "MouseMove")
.Select((eventPattern, count) => new {eventPattern.EventArgs, Count = count})
.WithPrevious((previous, current) =>
{
var currentPoint = current == null
? new Point(0, 0)
: current.EventArgs.Location;
var previousPoint = previous == null
? new Point(0, 0)
: previous.EventArgs.Location;
return
new
{
CurrentPoint = currentPoint,
PreviousPoint = previousPoint,
Count = current == null ? 0 : current.Count
};
})
.Subscribe(a =>
{
label2.Text =
String.Format(
"Curr X: {0} * Y: {1} |||| Prev X: {2} * Prev Y: {3} - Count = {4}",
a.CurrentPoint.X, a.CurrentPoint.Y,
a.PreviousPoint.X, a.PreviousPoint.Y,
a.Count);
label1.Text = String.Format("X: {0} ** Y: {1}",
a.CurrentPoint.X.CompareTo(
a.PreviousPoint.X),
a.CurrentPoint.Y.CompareTo(
a.PreviousPoint.Y));
var listItem = new ListViewItem(a.Count.ToString());
listItem.SubItems.Add(a.CurrentPoint.X.ToString());
listItem.SubItems.Add(a.CurrentPoint.Y.ToString());
listView1.Items.Add(listItem);
listView1.EnsureVisible(listView1.Items.Count - 1);
});
您现在可以看到,如果您将鼠标向下或向右移动缓慢,事件只会触发一次,但是,在我的计算机上,如果您向上或向左移动鼠标,我可以获得的最小事件数是三个,最后一个总是与前一个相同。 这就是为什么它总是零,零。
现在,如果我们添加.DistinctUntilChanged(a => a.CurrentPoint) 紧接在 WithPrevious 之后和订阅之前,您可以获得更多您想要的东西。 我说大多数是因为移动鼠标对角线在我的电脑上的事件永远不会有 X 和 Y 不同。 您也许可以使用 Throttle - 类似 .Throttle(TimeSpan.FromMilliseconds(25),CurrentThreadScheduler.Instance)在选择之后和之前与Previous。 这对我的电脑有帮助,但并不完美。