How to handle MouseOff actions for a custom Menu Panel lazarus / 39-Graphics ---------------------------------------------------------------------- funk247 · 2014-06-04 09:37 I've been trying to create a menu of links as a component based on a TCustomPanel, I have the menu reading from a TString list and generating an array of TRects that serve as the links and am now trying to create a Mouse hover event so that the links highlight on Mouse over. I have managed to do this, but am unable to account for the Mouse Out event that switches off the highlight when the user moves the pointer out of the panel. Does anyone know of, or can someone supply me with some example code that would point me in the right direction as I've been flailing aimlessly for a couple of days now without any success whatsoever! Basically what happens at the moment is the links respond as expected, highlighting on mouseover, however when I remove the mouse from the component space the last highlighted link remains turned on - until I hover over another link. I can't work out how to 'turn off' the hover state. Before I go any further, I'm an amateur programmer and unused to working in Pascal so if I've missed something blatantly obvious please forgive my lack of knowledge! Am keeping fingers crossed some kind soul will help me out! I'm trying to do most of my work in my MouseMove: Code: [Select]// User actions procedure T_MenuPanel.MouseMove(Shift:TShiftState; X,Y:Integer); var   i : integer; begin      // Get cursor position within the control      pt := Mouse.CursorPos;      pt := ScreenToClient(pt);      // loop through Array of Rectangles      for i := 0 to High(MenuRects) do        begin          if PtInRect(MenuRects[i], Point(X, Y)) then             begin                chosenRect := i;                Refresh;             end          else             begin                chosenRect := -1;             end;        end;    inherited; end; And the loop that deals with the actual drawing, contained in the Canvases paint event. Code: [Select]// Canvas painting procedure T_MenuPanel.Paint; var   // TextStyle: TTextStyle;   R, itemR: TRect;   count : Integer;   x1,y1,x2,y2 : Integer; begin    // Set length of array    SetLength(MenuRects, fLinesText.Count);    // Set TRect to Canvas size    R := Rect(5, 5, Width-5, Height-5);    x1 := 10;    y1 := 10;    x2 := Width-10;    inherited Paint;    with Canvas do begin      // Set fonts      Font.Height := MenuFontHeight;      Font.Color := clWhite;      // Draw outerbox      GradientFill(R, clLtGray, clWhite, gdVertical);      // Draw inner boxes      if fLinesText.Count = 0 then exit         else      for count := 0 to fLinesText.Count - 1 do        begin          // Define y2          y2 := TextHeight(fLinesText.strings[count])*2;          itemR := Rect(x1, y1, x2, y2*(count+1));          Pen.color := clGray;          // Test against mouse.cursorPos value          if (chosenRect = count) and (PtInRect(MenuRects[count], pt)) then             Brush.color := stateColor[bttn_on]          else             Brush.color := stateColor[bttn_off];          Rectangle(itemR);          // Push rectangle info to array          MenuRects[count] := itemR;          // Draw the text          TextRect(itemR, x1+5,  y1+5, fLinesText.strings[count]);          // inc y1 for positioning the next box          y1 := y1+y2;        end;    end; end; ---------------------------------------------------------------------- Blaazen · 2014-06-04 09:56 You need override method MouseLeave. ---------------------------------------------------------------------- funk247 · 2014-06-04 10:00 Really? That simple? I'll be banging my head on the desk if it is! ---------------------------------------------------------------------- howardpc · 2014-06-04 10:53 or change your MoseMove loop to something like this: Code: [Select]... // loop through Array of Rectangles      for i := 0 to High(MenuRects) do        begin          if PtInRect(MenuRects[i], Point(X, Y)) then             begin                chosenRect := i;                Break;             end          else            chosenRect := -1;        end;      Refresh; ... ---------------------------------------------------------------------- Blaazen · 2014-06-04 12:02 @ howardpc I have experience that this does not work well in real life. There are two cases when item will remain highlighted: 1 - when border around items is 0 2 - when mouse hovering is very fast. Mouse cursor is over item and then out of component. MouseMove over border is not caught. ---------------------------------------------------------------------- funk247 · 2014-06-04 12:48 HowardPC's solution works perfectly in this instance. I'll continue looking into the MouseLeave event but my concern with that is that it will only fire when the mouse cursor leaves the canvas and not the link Rects, I'd prefer to do everything in MouseMove if at all possible. ---------------------------------------------------------------------- Blaazen · 2014-06-04 13:05 Try fast hovering across the component. I recommend you to use both MouseMove and MouseLeave. It is very reliable way. It is how it works in my ECControls, TECSwitch for example. ---------------------------------------------------------------------- funk247 · 2014-06-04 15:36 Ah yes I see what you mean, the lights are stay on - so to speak. I'll have a look at your control to see how you do it. Thanks for the tip. ---------------------------------------------------------------------- Blaazen · 2014-06-04 15:48 The simpliest is to call MouseMove from MouseLeave (you said you have all the code there) and for X, Y parameters choose some point out of all menu items. ---------------------------------------------------------------------- howardpc · 2014-06-04 16:40 @ Blaazen I mainly work on Windows, where I cannot reproduce either of the potential problems you mention. But I was recently given a very fast machine. Perhaps MouseMove messages can get lost if the cpu is running relatively slowly? It's good to know that combining MouseMove with MouseLeave can give belt-and-braces security in this situation.