Fixed unreliable header tooltips (issue #728) - #1396
Open
TetzkatLipHoka wants to merge 1 commit into
Open
Conversation
The header occupies the window's non-client area (WMNCCalcSize reserves it, WMNCHitTest returns HTBORDER), so hovering it produces WM_NCMOUSEMOVE messages. The stock THintWindow.IsHintMsg tells the VCL to cancel a pending hint on every such message. TVirtualTreeHintWindow.IsHintMsg already filters those out, but it only takes effect while Application.FHintWindow is an instance of that class - which is why header hints worked only once a tree hint had been shown and broke again after another control's hint replaced the application's hint window. Install TVirtualTreeHintWindow as the application-wide hint window class so the override is always in effect. For hints that do not belong to a tree it falls back to the stock rendering (the AData / FHintData.Tree = nil branches in CalcHintRect and Paint), leaving other controls' hints unaffected. Only the default THintWindow is replaced, so applications using their own hint window class are left untouched. Tests/VTHeaderHintIssue728Tests.pas pins down both facts (the registration and the foreign-hint fallback); the end-to-end cancel behaviour is verified by a deterministic measurement harness. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #728.
Root cause
The header occupies the window's non-client area (
WMNCCalcSizereserves its height,WMNCHitTestreturnsHTBORDER), so hovering it producesWM_NCMOUSEMOVEmessages. The stockTHintWindow.IsHintMsgreturnsTrueforWM_NCMOUSEMOVEunconditionally, which makesTApplication.IsHintMsgcallCancelHintand drop the pending header hint.TVirtualTreeHintWindow.IsHintMsgalready filters those messages out — but it only takes effect whileApplication.FHintWindowis an instance of that class. That is exactly why the reporters observed the hint working only after a tree hint had been shown (which makesApplication.FHintWindowaTVirtualTreeHintWindow), and breaking again after another control's hint replaced it with a stockTHintWindow. It also matches @gwideman's 2023 observation that activating another control's hint reliably breaks the header hints and scrolling a tree row restores them.Both possible causes named by @joachimmarder in the issue discussion are two faces of this one mechanism.
Fix
Install
TVirtualTreeHintWindowas the application-wide hint window class so itsIsHintMsgoverride is always in effect. For hints that do not belong to a tree, it falls back to the stock rendering (theAData/FHintData.Tree = nilbranches added toCalcHintRectandPaint), so other controls' hints look and behave exactly as before. Only the defaultTHintWindowis replaced, leaving applications that install their own hint window class untouched.The change is confined to
VirtualTrees.AncestorVCLand contains no conditional compilation.Tests
Tests/VTHeaderHintIssue728Tests.paspins down both facts the fix relies on: that the class is registered application-wide, and that the foreign-control fallback returns a non-empty hint rect (it previously returned an empty rect, which is why the app-wide class could not simply be registered before).The end-to-end cancellation behaviour was verified separately with a deterministic measurement harness that drives the real
TApplication.IsHintMsgcancel path and counts visible hint windows before/after a syntheticWM_NCMOUSEMOVE:Application.FHintWindowWM_NCMOUSEMOVETHintWindowTVirtualTreeHintWindow(this fix)Stable across repeated runs on Delphi 7 through 13.1.