Prevent Controls Firing When Clicking on an Inactive Window

Is there an elegant way to stop controls firing when clicking to bring a window to the front? For example, I click on an inactive window and my canvas based button records a mousedown event and starts doing something that may not have been expected.

I can only think of starting a timer on window.activate and ignoring events shortly after.

Just thinking out loud…

What if you subclass your controls and windows.
Add the following to the subclassed window:

  • Boolean property: Active
  • Eventhandler: Activate
  • Eventhandler: Deactivate

Set the Active property in those event handlers

Subclass the controls you need. Add something like

If not me.window.active then return 

Write that code in the KeyDown, Action, etc events.

Again I am thinking out loud. Not tested it yet. But I think it might do the trick

[quote=233293:@Stephen Dodd]Is there an elegant way to stop controls firing when clicking to bring a window to the front? For example, I click on an inactive window and my canvas based button records a mousedown event and starts doing something that may not have been expected.

I can only think of starting a timer on window.activate and ignoring events shortly after.[/quote]

I believe setting enable = False for all controls by looping through Window.Control() would do the trick.

But then, why not simply close that window ?

On Mac it’s standard behavior that clicking down on a button on a window that’s behind does start the button press, as well as bring the window forward. Not sure what Windows and Linux do.

Maybe the problem is you’re firing the Action from MouseDown. If so you should do it from MouseUp and it’ll act like standard buttons (at least on Mac). Something like this for a Canvas subclass…

[code]Private Property isDown As boolean

Event Action()

Function MouseDown(X As Integer, Y As Integer) As Boolean
isDown = true
Invalidate
return true
End Function

Sub MouseDrag(X As Integer, Y As Integer)
if isDown <> inside(X, Y) then
isDown = not isDown
Invalidate
end
End Sub

Sub MouseUp(X As Integer, Y As Integer)
isDown = false
Invalidate
if inside(X, Y) then RaiseEvent Action
End Sub

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
if isDown then g.ForeColor = &c00FF00 else g.ForeColor = &c808080
g.FillRect 0, 0, g.Width, g.Height
End Sub

Private Function inside(x As integer, y As integer) As boolean
return x>0 and x0 and y<height
End Function[/code]

[quote]
What if you subclass your controls and windows.
Add the following to the subclassed window:

Boolean property: Active
Eventhandler: Activate
Eventhandler: Deactivate[/quote]

The question is, does the activate event fire consistently on Mac and PC before the mousedown event?

Yes, true. And I probably should allow the click. It’s just that I have controls that appear only on mouseover near the area and the mouseover doesn’t function when the window is inactive so… you click on a blank area and the control suddenly appears out of nowhere and gets clicked - surprise!

[quote=233710:@Stephen Dodd]
Yes, true. And I probably should allow the click. It’s just that I have controls that appear only on mouseover near the area and the mouseover doesn’t function when the window is inactive so… you click on a blank area and the control suddenly appears out of nowhere and gets clicked - surprise![/quote]

The ultimate solution : Place your controls inside a PagePanel or on top of a Canvas or inside a ContainerControl so you can make them all invisible.

In the Deactivate event, DrawInto the window in the window Backdrop.

Make the controls invisible (change Page, make the containing control invisible).

Upon Activate, or in a small period timer, nil the window backdrop and reinstate the controls visible.

So when the window is in the back, all it shows is a picture.

Ha, I read this and looked over to my movie playing app with buttons like this and they work the way you want. Opening the project the button class is pretty much what I posted above except there’s MouseEnter and MouseExit events which control an isShowing property for the hover.

[code]Sub MouseEnter()
if not System.MouseDown then
isShowing = true
Invalidate
end
End Sub

Sub MouseExit()
if not System.MouseDown then
isShowing = false
Invalidate
end
End Sub[/code]

Basically there’s a property that says when to show the widget, but it’s only flipped in MouseEnter/Exit when the mouse is up (if it’s down then the MouseDown/Drag/Up sequence handles it).

The thing is, when the window is behind and the button clicked, MouseDown comes first, then MouseEnter. This means isShowing will be false in MouseDown, so discriminate on that…

Function MouseDown(X As Integer, Y As Integer) As Boolean if isShowing then isDown = true Invalidate return true end End Function

You should check that MouseEnter comes after MouseDown on Windows OS.