How to avoid field glitch with mouse focus

108 Views Asked by At

When I drag the mouse pointer outside the processing window, my program reacts in unexpected ways. How to reproduce:

  1. Hover the mouse pointer over the "MIN" field and try to change the value of the numbers in the field, while holding the left mouse button.
  2. Drag the mouse pointer at an average speed or sharply to the left and then to the right, beyond the area of ​​the application window without releasing the left button mouse.
  3. Now the following conditions are not met:
  • MIN < MAX
  • Always MIN - 500 units from MAX.
  • MAX > MIN
  • MAX + 500 units from MIN.

Attention, this effect is observed only when the mouse pointer moves out of the area of ​​the application window. Are there any options to eliminate this effect or how to avoid it?

If you do not move the mouse pointer over the window size area, then everything works without problems!

enter image description here

Сode:

import controlP5.*;

ControlP5 cp5;

// range constants
final float RANGE_MIN = 7.4;
final float RANGE_MAX = 16.8;
// the smallest allowed difference between min/max values
final float RANGE_MIN_DIFFERENCE = 1;
final float RANGE_MID = RANGE_MIN + ((RANGE_MAX - RANGE_MIN) / 2);

float minValue;
float maxValue;

Numberbox inputMin;
Numberbox inputMax;

void setup() {
  size(700, 400);

  PFont font = createFont("arial", 18);

  cp5 = new ControlP5(this);

  inputMin = cp5.addNumberbox("minValue")
    .setPosition(360, 240)
    .setSize(80, 30)
    .setColorValue(0xffffff00)
    .setFont(font)
    .setScrollSensitivity(1.1)
    // set initial acceptable range
    .setMin(RANGE_MIN)
    .setMax(RANGE_MAX)
    // set default value
    .setMultiplier(0.01)
    .setDirection(Controller.HORIZONTAL)
    .setValue(7.4);
  Label labelinputMin = inputMin.getCaptionLabel();
  labelinputMin.setFont(font);
  labelinputMin.setColor(color(#00ffff));
  labelinputMin.toUpperCase(false);
  labelinputMin.setText("MIN");
  labelinputMin.align(ControlP5.LEFT_OUTSIDE, CENTER);
  labelinputMin.getStyle().setPaddingLeft(-100);


  inputMax = cp5.addNumberbox("maxValue")
    .setPosition(360, 300)
    .setSize(80, 30)
    .setColorValue(0xffffff00)
    .setFont(font)
    .setScrollSensitivity(1.1)
    // set initial acceptable range
    .setMin(RANGE_MIN)
    .setMax(RANGE_MAX)
    // set default value
    .setMultiplier(0.01)
    .setDirection(Controller.HORIZONTAL)
    .setValue(RANGE_MID + 1);
  Label labelinputMax= inputMax.getCaptionLabel();
  labelinputMax.setFont(font);
  labelinputMax.setColor(color(#00ffff));
  labelinputMax.toUpperCase(false);
  labelinputMax.setText("МAX");
  labelinputMax.align(ControlP5.LEFT_OUTSIDE, CENTER);
  labelinputMax.getStyle().setPaddingLeft(-93);


  textFont(font);
}

void draw() {
  constrainRangeInputs();
  background(0);
  fill(255);
  text("minValue: " + minValue + "\n" +
    "maxValue: " + maxValue, 10, 15);
}
void controlEvent(ControlEvent event) {
  println(event.getController().getName(), "changed value to", event.getValue(), "RANGE_MIN = ", minValue, "RANGE_MAX = ", maxValue);
}
void constrainRangeInputs() {
  float rangeMinInt = (float)inputMin.getValue();
  float rangeMaxInt = (float)inputMax.getValue();
  //
  if (abs(rangeMaxInt - rangeMinInt) < RANGE_MIN_DIFFERENCE) {
    if (rangeMaxInt > RANGE_MID) {
      inputMin.setValue(rangeMaxInt - RANGE_MIN_DIFFERENCE);
    } else {
      inputMax.setValue(rangeMinInt + RANGE_MIN_DIFFERENCE);
    }
  }
}
1

There are 1 best solutions below

1
On BEST ANSWER

This problem arises from a mix of something you wrote and the way Processing's draw() loop is limited by it's FPS, probably 60 in your case as you haven't set it.

The constrainRangeInputs method is called by the draw() loop, but not the Numberbox.updateInternalEvents method. If your FPS were veeery low, the numberbox could update several time between two loops of the draw() method, even if we wouldn't see it as it's not visually updated.

Then, when it's time for the draw() loop to do it's thing, it calls your constrainRangeInputs() method.

The problem is here:

if (abs(rangeMaxInt - rangeMinInt) < RANGE_MIN_DIFFERENCE) {

The absolute number makes it possible that a rangeMinInt be higher than a rangeMaxInt if it's high enough. Here's an example of when it would happens:

Assuming these values:
rangeMinInt = 15
rangeMaxInt = 10
RANGE_MIN_DIFFERENCE = 1

// Reading these numbers, you already know that this is supposed to be corrected by the constrainRangeInputs() method, but...
// Doing the math reveals that:

rangeMaxInt - rangeMinInt = -5
// yet:
abs(rangeMaxInt - rangeMinInt) = 5

// So:
abs(rangeMaxInt - rangeMinInt) < RANGE_MIN_DIFFERENCE // false
// The program sees this as absolutely normal!

This has nothing to do with going out of the window (if you change the window's size to make it very wide you'll be able to reproduce the problem, I did it experimentally). The problem is that, when the constrainRangeInputs() did it's job, the current number was already high enough to be conform to your conditions.

That's because the mouse moved fast enough to cover more than the RANGE_MIN_DIFFERENCE in the time between two iterations of the draw() loop.

You can fix this easily by getting rid of the abs(). I have no idea why it would be relevant in the first place, but as you adapted this from existing code it's probably an artifact from the original code.

So: change this line

if (abs(rangeMaxInt - rangeMinInt) < RANGE_MIN_DIFFERENCE) {

for this instead:

if (rangeMaxInt - rangeMinInt < RANGE_MIN_DIFFERENCE) {

Hope it helps, that was trickier than it seems. Have fun!