HeaderPane
Main
Hide

SftTree/OCX 8.0 - ActiveX Tree Control

Share Link
Print

Per-Monitor DPI and Scaling

SftTree/OCX 8.0 is fully Per-Monitor v2 DPI-aware. A tree control hosted on a Per-Monitor v2 aware top-level window re-renders automatically when its window moves to a monitor of a different DPI or when the system DPI changes. The control owns the metrics it controls; the caller owns the images and fonts it provides. Two opt-in properties let the caller hand those over to the control as well.

Host setup

The host application must declare Per-Monitor v2 DPI awareness. This is the single most common reason high-DPI applications do not re-render correctly when moved between monitors of different DPI. Without a Per-Monitor v2 declaration, Windows keeps the process in System-aware mode: the DPI is fixed for the process lifetime, the control does not observe DPI changes, the DPIChanged event is never fired, and high-DPI monitors render at System-DPI sizes stretched by Windows.

Declare Per-Monitor v2 awareness in the host application's manifest, for example:

<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>

In a .NET project, this corresponds to selecting Per Monitor V2 for the application's DPI awareness. The DPI property returns the control's current monitor DPI (96 at 100%, 120 at 125%, 144 at 150%, 192 at 200%). If the returned value never changes as the window is dragged between monitors with different scale factors, the host is not in Per-Monitor v2 mode.

What scales automatically

When the host is Per-Monitor v2 aware, the control scales these metrics itself on every DPI change without any caller involvement: row height and item height, grid-line thickness, scroll bar and scroll arrow metrics, the drag threshold, 3D frame widths, the column drop-down / filter button width, the resize handle between panes of a split tree, the built-in expand / collapse glyphs, and the splitter bar width.

What the caller controls

Two independent opt-in properties let the caller choose whether caller-supplied images and pixel metrics also scale with DPI. Both default to back-compatible behavior (no automatic scaling), so existing applications keep working unchanged. Each uses SftTreeScalingConstants: scalingSftTreeAsIs (default) or scalingSftTreeStretch.

PropertyCoversscalingSftTreeAsIs (default)scalingSftTreeStretch
ImageScalingEvery image the control draws: cell, label, item, row-header, column-header and column-footer pictures; plus / minus bitmaps; user-supplied tree button bitmaps; and control-owned glyphs.Images are drawn at their native pixel size. Bitmaps supplied at 96 DPI look physically smaller on a high-DPI monitor.Images are scaled by current DPI / 96 using high-quality interpolation.
PixelScalingCaller-supplied pixel dimensions: column widths, indentation, row header width, horizontal extent and offset, item heights and the splitter offset.Values are used verbatim in physical screen pixels. A column width of 100 is 100 pixels on any monitor.Values are interpreted as 96-DPI reference pixels (100 pixels at 100%, 150 at 150%, 200 at 200%). Stored values and getters always return caller-reference units, so serialized configurations stay portable across monitors of different DPI.

On DPI change

When the control's monitor DPI changes, the DPIChanged event is fired. The application should re-send a font sized for the new DPI (the control does not own the application's font). If ImageScaling is scalingSftTreeStretch and PixelScaling is scalingSftTreeStretch, no further action is needed - the control scales existing images and stored pixel values automatically.


Last Updated 05/24/2026 - (email)
© 2026 Softel vdm, Inc.