Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 03/29/22 in all areas

  1. Perhaps "terse" can be understood as rudeness. But for me personally, the words "keep your advice to yourself" mean unambiguously rudeness. I don't know, maybe I was brought up wrong.
  2. @de la Mancha- you asked and got a relevant answer from someone known for doing heavy math with Delphi. No reason to be rude.
  3. Zoë Peterson

    ScrollBox ScrollBar Mouse Tracking

    I just spent an unreasonable amount of time looking into this myself 😄 1) The stock TScrollBox didn't support reacting to the mouse wheel. That changed in Delphi 11, but they did a poor job of it and broke it so it kind of scrolls, but TScrollBox no longer calls the DoMouseWheel/OnMouseWheel events. [RSP-35333] (My comment there is outdated compared to the rest of this post) 2) The WM_MOUSEWHEEL messages used to require focus. In a recent Windows 10 update (and Windows 11), Microsoft introduced a new mouse setting, "Scroll inactive windows when I hover over them" that instead sends the message to the control that the mouse is over. AFAICT it's turned on by default now. If it's turned off it reverts to the old behavior of sending it to the focused control. 3) Delphi used to forward the CM_MOUSEWHEEL messages to the focused control in TCustomForm.MouseWheelHandler, which meant that it could still require focus even if Windows was sending the messages elsewhere. That code was removed sometime between XE7 and 10.4, so the CM_MOUSEWHEEL wheels now go to the control the message is sent to. 4) TControl.IsControlMouseMsg incorrectly treats the X/Y coordinates for WM_MOUSEWHEEL events as if they're in client coordinates like the other WM_MOUSE* events are, rather than in screen space coordinates. This has the effect that if you have a TScrollBox with a big TImage on it, whether the scrollbox scrolls or not depends on where the form is on the screen. Likewise, TControl.IsControlMouseMessage doesn't pay attention to the WM_MOUSEWHEEL return values, so if you fix the first issue, it actually breaks TScrollBox scrolling if it's over the image because the image swallows the WM_MOUSEWHEEL message and TScrollBox's handler never gets called. 5) If you don't have TScrollBox.VertScrollBar.Smooth := true, as you're scrolling there will be a smear as the nested controls don't redraw before the scrollbox scrolls again. It will clear up once the apps been idle a bit, and for simple scrolls this isn't noticeable, but it can look terrible, especially if the scrollbox redraw slowly (e.g., lots of nested controls with VCL styles enabled) and you use a free-spinning mouse. 6) Once you fix all of the above, if you have scrollable controls nested in a TScrollBox, the lack of focus requirement means that if the mouse cursor goes over the top of the nested control as a result of the TScrollBox's scroll, it'll start scrolling the nested one instead. I can provide a workaround for that, but it's a little out of scope of just "Fix the bugs". On to the fixes! 1) Patch VCL.Forms.pas (fixes issue #1). The least invasive fix is to change TScrollBox's WMMouseWheel handler to this, which at least fixes the OnMouseWheel handlders getting called. procedure TScrollBox.WMMouseWheel(var Message: TWMMouseWheel); const LScrollBarValues: array[Boolean] of WPARAM = (SB_LINEDOWN, SB_LINEUP); begin inherited; if (Message.Result <> 0) or not VertScrollBar.IsScrollBarVisible then Exit; Message.Result := 1; var LScrollBarValue := LScrollBarValues[Message.WheelDelta > 0]; for var LLineToScroll := 1 to Mouse.WheelScrollLines do Perform(WM_VSCROLL, LScrollBarValue, 0); end; A better fix is to instead remove TScrollBox.WMMouseWheel entirely (if you're on Delphi 11) and put the code in a newly overridden DefaultHandler: TScrollBox = class(TScrollingWinControl) public ... procedure DefaultHandler(var Message); override; end; procedure TScrollBox.DefaultHandler(var Message); const LScrollBarValues: array[Boolean] of WPARAM = (SB_LINEDOWN, SB_LINEUP); var LScrollBarValue: WPARAM; LLineToScroll: Integer; begin if (WindowHandle <> 0) and (TMessage(Message).Msg = WM_MOUSEWHEEL) and VertScrollBar.IsScrollBarVisible then begin LScrollBarValue := LScrollBarValues[TWMMouseWheel(Message).WheelDelta > 0]; for LLineToScroll := 1 to Mouse.WheelScrollLines do Perform(WM_VSCROLL, LScrollBarValue, 0); TMessage(Message).Result := 1; Exit; end; inherited; end; The advantage of using DefaultHandler instead of a WM_MOUSEWHEEL message handler is that the scrollbox now works just like native Win32 controls do, where the parents all the way up to the form get the OnMouseWheel messages, and the innermost scrollbox scrolls if none of them handle it. 2) Patch VCL.Controls.pas (fixes issue #4): function TWinControl.IsControlMouseMsg(var Message: TWMMouse): Boolean; var Control: TControl; P: TPoint; IsWheelMsg: Boolean; begin IsWheelMsg := (Message.Msg = WM_MOUSEWHEEL) or (Message.Msg = WM_MOUSEHWHEEL); if GetCapture = Handle then begin if (CaptureControl <> nil) and (CaptureControl.Parent = Self) then Control := CaptureControl else Control := nil; end else if IsWheelMsg then Control := ControlAtPos(ScreenToClient(SmallPointToPoint(Message.Pos)), False) else Control := ControlAtPos(SmallPointToPoint(Message.Pos), False); Result := False; if Control <> nil then begin if IsWheelMsg then begin Message.Result := Control.Perform(Message.Msg, Message.Keys, TMessage(Message).LParam); Result := (Message.Result <> 0); end else begin P.X := Message.XPos - Control.Left; P.Y := Message.YPos - Control.Top; Message.Result := Control.Perform(Message.Msg, Message.Keys, PointToLParam(P)); Result := True; end; end; end; 3) To make the mouse wheel consistently affect the control the mouse is over, regardless of which version of Windows you're running or which way the new setting is configured (which matches what official Microsoft apps do), add a TApplicationEvents object with this as the OnMessage handler. (Fixes issues #2 and #3) procedure TMyForm.ApplicationEventsMessage(var Msg: tagMSG; var Handled: Boolean); var Wnd: HWND; begin if (Msg.message = WM_MOUSEWHEEL) or (Msg.message = WM_MOUSEHWHEEL) then begin Wnd := GetCapture; if Wnd = 0 then Wnd := WindowFromPoint(SmallPointToPoint(TSmallPoint(Msg.lParam))); if Wnd <> 0 then msg.hwnd := Wnd; end; end; 4) To fix the smeared appearance, you can A) Turn on VertScrollBar.Smooth, which triggers an Update call between each scroll B) Call Update yourself, either in the OnMouseWheel handler or in the TScrollBox WMMouseWheel/DefaultHandler method in between Perform calls. C) Change TScrollBox WMMouseWheel/DefaultHandler's Perform loop to the below, to update the scrollbar position once instead of with repeated WM_VSCROLL messages. if VertScrollBar.Smooth then begin LScrollBarValue := LScrollBarValues[TWMMouseWheel(Message).WheelDelta > 0]; for LLineToScroll := 1 to Mouse.WheelScrollLines do Perform(WM_VSCROLL, LScrollBarValue, 0); end else { Move the scrollbar directly to only update the position once. TControlScrollBar.Increment uses different defaults for smooth vs chunky scrolling (TControlScrollBar.Update), so this may produce smaller scrolls than if you set Smooth:=true } VertScrollBar.Position := VertScrollBar.Position + VertScrollBar.Increment * Mouse.WheelScrollLines * -TWMMouseWheel(Message).WheelDelta div WHEEL_DELTA; And yes, none of the above should be necessary because the VCL should handle all of this. The IsControlMouseMsg bugs have existed forever though and appear to have been reported as QC-135258 at least as far back as 2015.
  4. Uwe Raabe

    Windows Dayligthsaving problem

    You are working too much...
  5. To be fair: David also tends to be - lets say "terse" - in his answers. That can also be interpreted as rude, in particular by people for whom English is a foreign language.
  6. What else could be said for post of "I have a problem pls solve it completely for me" kind? If the one who needs solution does zero for the problem, why someone else should do more?
  7. Here's what to do. First of all you need to understand the R code. You need to know what it's purpose is, and how it achieves it. You will need a clear understanding of what data types are expected to be passed to, and returned from the function. You may need to talk to the author of the code, or learn enough R to work it out yourself. Once you have a clear understanding then you will be in a good place to write an equivalent function in Delphi. Good luck.
  8. SwiftExpat

    Deputy IDE Expert

    I created a plugin to terminate orphaned processes left behind by the IDE during development. You can see the demo here: Source and a release build are available here: https://github.com/SwiftExpat/Deputy Install it manually using these instructions: https://swiftexpat.com/docs/doku.php?id=rttk:deputy:install There is a gentle nag for you to download my compiled demo, which you can decline. The expert is built using TOTAL as a framework: https://github.com/DelphiWorlds/TOTAL If you want to build your own, a step by step to setup your project is here: https://github.com/SwiftExpat/Deputy/wiki/Step-by-Step---Create-Total-plugin-project Enjoy, SwiftExpat
  9. Lajos Juhász

    Several F2084 Internal Error on Delphi 10.4.2

    The only way to find out is to open a QC with this screen shot.
  10. Let's hope it wasn't "soon" from a geological perspective...
  11. qubits

    Delphi 11.1 is available

    if i include FMX.TextLayout.GPU in my uses and add this line to the form.close TGPUObjectsPool.Instance.Free; the leak is gone.. should add, also fixes the console sample that was in the qc's. wrap it up like this maybe, using that cool little if you posted.. {$IF RTLVersion111} TGPUObjectsPool.Instance.Free; {$ENDIF}
×