View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0001832 | JEDI VCL | 00 JVCL Components | public | 2004-06-03 19:09 | 2004-06-10 00:26 |
Reporter | anonymous | Assigned To | user72 | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | |||||
Target Version | Fixed in Version | ||||
Summary | 0001832: TJvPanel - OnMouseLeave and Enter events get fired in strange orders | ||||
Description | Place a TJvPanel (pnl1) on a form, and then place another TJvPanel (pnl2) inside pnl1. i.e pnl1 is on form1, pnl2 is on pnl1 Add a memo to the form, and set the MouseEnter/Leave handlers on the panels to track the events as they fire, e.g: procedure TForm3.pnl1MouseEnter(Sender: TObject); begin JvMemo1.Lines.Add((Sender as TJvPanel).Name + '.Enter'); end; With handlers on pnl2 only: Mouse enters pnl2, get events: pnl2.Leave pnl2.Enter Mouse leaves pnl2 <no events> With handlers on both pnl1 and pnl2: Mouse enters pnl1 pnl1.Leave pnl1.Enter Mouse enters pnl2 pnl1.Leave pnl2.Leave pnl1.Enter pnl2.Enter Mouse leaves pnl2 pnl1.Leave pnl1.Enter Mouse leaves pnl1 <no events> | ||||
Additional Information | unit Unit3; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, JvExStdCtrls, JvMemo, ExtCtrls, JvExExtCtrls, JvComponent, JvPanel; type TForm1 = class(TForm) JvMemo1: TJvMemo; pnl1: TJvPanel; pnl2: TJvPanel; procedure pnl2MouseEnter(Sender: TObject); procedure pnl2MouseLeave(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.pnl2MouseEnter(Sender: TObject); begin JvMemo1.Lines.Add((Sender as TJvPanel).Name + '.Enter'); end; procedure TForm1.pnl2MouseLeave(Sender: TObject); begin JvMemo1.Lines.Add((Sender as TJvPanel).Name + '.Leave'); end; end. | ||||
Tags | No tags attached. | ||||
|
YOu could try modifying MouseEnter/MouseLeave and move the "inherited MouseXXXX" calls outisde the if statement and see if that changes anything but I seem to remember that doing that might cause other problems... |
|
The mysterious behaviour you experience is probably caused by the fact that the MouseDown-property of the derived class TJvExCustomPanel is not properly initialized. Most computers initializes boolean variables to false (that's probably the reason the error wasn't discovered before), but that is not true for all systems. Some behave in a random way. Try to add the following line to the TJvExCustomPanel.Create constructor (in JvExExtCtrls.pas): FMouseOver := False; Regards Hans-Eric Grönlund |
|
I spoke too soon. The solution does not solve the issue described. But, still - the FMouseOver field variable is uninitialized, which is not recommendable. |
|
Ah, finally I found the problem. The messages CM_MOUSEENTER and CM_MOUSELEAVE are invoked for the Control's parent(s), but the help procedures in JvExtControls.pas doesn't take that into concideration. So, to avoid the faulty setting of FMouseOver, do the following: In Control_MouseEnter: Change the following: [...snip...] if (not FMouseOver) and not (csDesigning in Instance.ComponentState) then begin FMouseOver := True; [...snip...] into: [...snip...] // Control is nil iff Instance is the control that the mouse has entered. // Otherwise this is just a notification that one of it's child controls // where entered. if (Control = nil) and (not FMouseOver) and not (csDesigning in Instance.ComponentState) then begin FMouseOver := True; [...snip...] In Control_MouseLeave, change the following: [...snip...] if FMouseOver then begin FMouseOver := False; [...snip...] into: [...snip...] // Control is nil iff Instance is the control that the mouse has left. // Otherwise this is just a notification that one of it's child controls // where left. if (Control = nil) and FMouseOver and not (csDesigning in Instance.ComponentState) then begin FMouseOver := False; [...snip...] (Please note that the condition 'not (csDesigning in Instance.ComponentState)' should also be added to conform with Control_MouseEnter. Hope this helps, at least it works great for me. Best regards Hans-Eric Grönlund edited on: 06-08-04 02:22 |
|
> But, still - the FMouseOver field variable is > uninitialized, which is not recommendable. Have you ever looked into TObject.NewInstance -> TObject.InitInstance ? I seems you have not because then you would have seen the "FillChar(Instance^, InstanceSize, 0);". And So all fields of a class are set to 0/False/nil/''. > Ah, finally I found the problem. The messages CM_MOUSEENTER > and CM_MOUSELEAVE are invoked for the Control's parent(s), > but the help procedures in JvExtControls.pas doesn't take > that into concideration. What must I do to fix this bug in JvExControls (sorry, I have not the time at the moment to find the fix myself). |
|
HEG, I modified your entry slightly (there was a logical) mix up in Control_MouseLeave. Additionally, IMO the "if Assigned(Event)" should be moved inside the "if" (and maybe the InheritMsgEx should as well?), otherwise it will be triggered even if the mouse didn't enter/leave Instance: JvExControls.pas: {$IFDEF VCL} procedure Control_MouseEnter(Instance, Control: TControl; var FMouseOver: Boolean; var FSavedHintColor: TColor; FHintColor: TColor; var Event: TNotifyEvent); {$ENDIF VCL} {$IFDEF VisualCLX} procedure Control_MouseEnter(Instance: TControl; var FMouseOver: Boolean; var FSavedHintColor: TColor; FHintColor: TColor); {$ENDIF VisualCLX} begin // (HEG) Control is nil iff Instance is the control that the mouse has left. // Otherwise this is just a notification that the mouse entered // one of it's child controls if (Control = nil) and not FMouseOver and not (csDesigning in Instance.ComponentState) then begin FMouseOver := True; FSavedHintColor := Application.HintColor; if FHintColor <> clNone then Application.HintColor := FHintColor; {$IFDEF VCL} if Assigned(Event) then Event(Instance); {$ENDIF VCL} end; {$IFDEF VCL} InheritMsgEx(Instance, CM_MOUSEENTER, 0, Integer(Control)); {$ENDIF VCL} end; {$IFDEF VCL} procedure Control_MouseLeave(Instance, Control: TControl; var FMouseOver: Boolean; var FSavedHintColor: TColor; var Event: TNotifyEvent); {$ENDIF VCL} {$IFDEF VisualCLX} procedure Control_MouseLeave(var FMouseOver: Boolean; FSavedHintColor: TColor); {$ENDIF VisualCLX} begin // (HEG) Control is nil iff Instance is the control that the mouse has left. // Otherwise this is just a notification that the mouse left // one of it's child controls if (Control = nil) and FMouseOver and not (csDesigning in Instance.ComponentState) then begin FMouseOver := False; Application.HintColor := FSavedHintColor; {$IFDEF VCL} if Assigned(Event) then Event(Instance); {$ENDIF VCL} end; {$IFDEF VCL} InheritMsgEx(Instance, CM_MOUSELEAVE, 0, Integer(Control)); {$ENDIF VCL} end; Another one: TJvPanel uses a Timer to make sure the CM_MOUSELEAVE message is sent even if there are hickups, and this is causing MouseLeave to be called sometimes even if not really necessary. The overriden MouseEnter/MouseLeave methods in TJvPanel should be modified like so: procedure TJvPanel.MouseEnter(Control: TControl); begin if csDesigning in ComponentState then Exit; if not MouseOver and ((Control = nil) or (Control = Self)) then begin FOldColor := Color; if not Transparent then begin Color := HotColor; MouseTimer.Attach(Self); end; end; inherited MouseEnter(Control); end; procedure TJvPanel.MouseLeave(Control: TControl); begin if csDesigning in ComponentState then Exit; if MouseOver and ((Control = nil) or (Control = Self)) then begin if not Transparent then begin Color := FOldColor; MouseTimer.Detach(Self); end; end; inherited MouseLeave(Control); end; With all these changes, it seems it now has the correct behavior (I tested with TJvPanel's and TJvShape's) but I would like some feedback on this before comitting. edited on: 06-08-04 02:34 |
|
AHUser: >Have you ever looked into TObject.NewInstance -> TObject.InitInstance ? I seems >you have not because then you would have seen the "FillChar(Instance^, >InstanceSize, 0);". And So all fields of a class are set to 0/False/nil/''. You're right of course, but I'm pretty sure this wasn't always the case (I've been around since TP 3.0). Anyways, I stated that I spoke too soon in my next posting. I was wrong about that one. >What must I do to fix this bug in JvExControls (sorry, I have not the time at >the moment to find the fix myself). I thought I did explain that. Please read the whole bugnote (but Peter is already on to it) Regards |
|
Peter: >Additionally, IMO the "if Assigned(Event)" should be moved inside the "if" (and >maybe the InheritMsgEx should as well?), otherwise it will be triggered even if >the mouse didn't enter/leave Instance: I agree with Event, but not with InheritMsgEx. >Another one: TJvPanel uses a Timer to make sure the CM_MOUSELEAVE message is >sent even if there are hickups, and this is causing MouseLeave to be called >sometimes even if not really necessary. The overriden MouseEnter/MouseLeave >methods in TJvPanel should be modified like so: These changes look good, although I don't think the (Control = Self) conditions are neccessary. It's always nil for the same control I believe. |
|
> These changes look good, > although I don't think the (Control = Self) conditions are neccessary I had it as Control = nil at first and it worked fine but then I thought I might have missed something, so I added the Control = Self as well but I can't see any difference in the tests I've performed. So Andreas, supposing this is the way to solve it, will you commit or should I? |
|
You have the changed files. I would have to insert the changes. So you can commit it. > You're right of course, but I'm pretty sure this wasn't always > the case (I've been around since TP 3.0). The instances are initilized to 0 starting with Delphi 1. The TurboVision TObject had done the FillChar, if I remember correctly, but then you were forced to call the inherited constructor as the first command in the new constructor. But that is history. |
|
Fixed in CVS. Also updated template in devtools\JvExVCL |
Date Modified | Username | Field | Change |
---|---|---|---|
2004-06-03 19:09 | anonymous | New Issue | |
2004-06-04 01:07 |
|
Note Added: 0004460 | |
2004-06-07 06:24 | hasse42g | Note Added: 0004488 | |
2004-06-07 06:34 | hasse42g | Note Added: 0004489 | |
2004-06-08 01:11 | hasse42g | Note Added: 0004490 | |
2004-06-08 02:21 |
|
Status | new => assigned |
2004-06-08 02:21 |
|
Assigned To | => user72 |
2004-06-08 02:22 |
|
Note Edited: 0004490 | |
2004-06-08 02:26 | AHUser | Note Added: 0004492 | |
2004-06-08 02:29 |
|
Note Added: 0004493 | |
2004-06-08 02:34 |
|
Note Edited: 0004493 | |
2004-06-08 02:50 | hasse42g | Note Added: 0004495 | |
2004-06-08 03:03 | hasse42g | Note Added: 0004496 | |
2004-06-08 04:14 |
|
Note Added: 0004497 | |
2004-06-09 07:58 | AHUser | Note Added: 0004509 | |
2004-06-10 00:26 |
|
Status | assigned => resolved |
2004-06-10 00:26 |
|
Resolution | open => fixed |
2004-06-10 00:26 |
|
Note Added: 0004518 |