Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repeat Button Tapping

I have a control that allows the user to perform some heavy duty image processing on a specific part of an image and they have arrow buttons to move this area around the image.

as the process is very heavy duty (avg 800ms per run) I have used a repeat button which turns this are into a "Ghost" and only executes the process upon the mouse up event.

This works really well and solves most performance issues relating to this function

HOWEVER

A certain group of users are refusing to learn this method of holding and releasing and persist in tapping the button to move it rather than holding and releasing.

This means that the heavy duty method is being called every time the they tap and as it only moves a small increment each time the method fires, so they end up with a application hang whilst it tries to do > 100 of these 800ms + processes

MY QUESTION

How can I handle this tapping behaviour in the same way as holding and releasing?

I thought about a timer but cant work out how I would detect the difference between a normal tap and the last tap.

like image 941
Steven Wood Avatar asked Jan 31 '17 11:01

Steven Wood


3 Answers

Quick, dirty solution: use a Timer.

Each time the user taps the button, stop the timer, increase the number of taps, start the timer. If the timer elapses before the user taps again, then it should do your big work method.

Is this prone to threading issues? Probably. I'm not a threading expert. I would love if a threading expert can come comment on it.

Is this the best solution? Hardly. But it will get you by for a while (until the threading issues come up).

private int _totalTaps = 0;
private const int _tapSequenceThreshold = 250; // Milliseconds
private Timer _tapTimer = new Timer(_tapSequenceThreshold);

private void InitializeTimer()
{
    _tapTimer.Elapsed += OnTapTimerElapsed;
}

private void OnTapTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
    _tapTimer.Stop();

    // The `DoBigLogic` method should take the number of taps and
    // then do *something* based on that number, calculate how far
    // to move it, for example.
    DoBigLogic(_totalTaps);

    _totalTaps = 0;
}

// Call this each time the user taps the button
private void Tap()
{
    _tapTimer.Stop();
    _totalTaps++;
    _tapTimer.Start();
}

Best solution: this method plus moving this work off the GUI thread. Then you don't have to worry about taps or click-and-hold, you won't block the GUI thread.

If you have to do work that doesn't update the UI (redraw the image, for example) then send the image to the UI, you can make a new thread, then you'll hit an error about 'accessing a UI element from a non-UI thread', just drop the UI code in a Marshal for it.

await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
    Windows.UI.Core.CoreDispatcherPriority.Normal,
    () => { UpdateDisplay(); }
);
like image 118
Der Kommissar Avatar answered Oct 23 '22 14:10

Der Kommissar


Consider monitoring mouse activity and start your heavy duty process after a short period of inactivity.

Consider running the process on a separate thread - this might mean cloning (part of) the image in memory.

Consider preventing the process from being ran multiple times concurrently (if that is possible ie. the process is async).

like image 2
Leo Avatar answered Oct 23 '22 12:10

Leo


Consider one of these options:

Disable the button until the process completes, causing that 800ms delay. Users will soon learn to use the hold down method. This would involve the smallest amount of code and put the onus on humans. It also ensures you are not holding up the app with clicks in the buffer or over-using resources.

Put a timer in your button click event: 'Ghost area' Timer Start ( or reset to zero)

Then the code to call your main work is in the timer elapsed event which will be set to whatever pause you wish. (ie If a user has not clicked again within a second or so) Then stop the timer Execute code

like image 2
Joe C Avatar answered Oct 23 '22 14:10

Joe C