前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >WPF坐标转换

WPF坐标转换

作者头像
码客说
发布于 2022-10-05 10:24:12
发布于 2022-10-05 10:24:12
52000
代码可运行
举报
文章被收录于专栏:码客码客
运行总次数:0
代码可运行

前言

假如屏幕是1920*1080,缩放是125%;

那么WPF窗口最大设置为1536*864就会占满屏幕。

获取鼠标位置

获取的是屏幕实际像素对应的位置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System.Runtime.InteropServices;

namespace ColorPicker.Utils
{
    internal class ZPoint
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetCursorPos(out POINT pt);

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }
        }
    }
}

调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZPoint.POINT point;
ZPoint.GetCursorPos(out point);

这样获取的坐标是屏幕的实际尺寸算的,即1920*1080。

如果我们根据这个值设置WPF的窗口就会发生偏移。

像素坐标转换为WPF坐标

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZPoint.POINT point;
ZPoint.GetCursorPos(out point);
Matrix transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
Point wpfPoint = transform.Transform(new System.Windows.Point(point.X, point.Y));

获取窗口的缩放率

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Windows;
using System.Windows.Forms;

namespace ColorPicker.Utils
{
    internal class ScreenHelper
    {

        private const string User32 = "user32.dll";

        [DllImport(User32, CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MONITORINFOEX info);

        [DllImport(User32, ExactSpelling = true)]
        [ResourceExposure(ResourceScope.None)]
        public static extern bool EnumDisplayMonitors(HandleRef hdc, COMRECT rcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);

        public delegate bool MonitorEnumProc(IntPtr monitor, IntPtr hdc, IntPtr lprcMonitor, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
        public class MONITORINFOEX
        {
            internal int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
            internal RECT rcMonitor = new RECT();
            internal RECT rcWork = new RECT();
            internal int dwFlags = 0;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            internal char[] szDevice = new char[32];
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;

            public RECT(Rect r)
            {
                left = (int)r.Left;
                top = (int)r.Top;
                right = (int)r.Right;
                bottom = (int)r.Bottom;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public class COMRECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        public static readonly HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);


        /// <summary>
        /// 获取缩放比例
        /// </summary>
        /// <returns></returns>
        public static double GetScalingRatio()
        {
            var logicalHeight = GetLogicalHeight();
            var actualHeight = GetActualHeight();

            if (logicalHeight > 0 && actualHeight > 0)
            {
                return logicalHeight / actualHeight;
            }

            return 1;
        }

        private static double GetActualHeight()
        {
            return SystemParameters.PrimaryScreenHeight;
        }

        private static double GetLogicalHeight()
        {
            var logicalHeight = 0.0;

           MonitorEnumProc proc = (m, h, lm, lp) =>
            {
                MONITORINFOEX info = new MONITORINFOEX();
                GetMonitorInfo(new HandleRef(null, m), info);

                //是否为主屏
                if ((info.dwFlags & 0x00000001) != 0)
                {
                    logicalHeight = info.rcMonitor.bottom - info.rcMonitor.top;
                }

                return true;
            };
            EnumDisplayMonitors(NullHandleRef, null, proc, IntPtr.Zero);

            return logicalHeight;
        }
    }
}

调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ZPoint.POINT point;
ZPoint.GetCursorPos(out point);                   
var ScalingRatio = ScreenHelper.GetScalingRatio();
Console.WriteLine($"当前缩放比例为{ScalingRatio}%");
colorWin.Top = point.Y / ScalingRatio+4;
colorWin.Left = point.X / ScalingRatio+4;

这种作用和下面是一样的。

设置窗口在鼠标右下角

colorWin中添加如下方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void MoveBottomRightEdgeOfWindowToMousePosition()
{
    var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
    var mouse = transform.Transform(GetMousePosition());
    Left = mouse.X + 2;
    Top = mouse.Y - ActualHeight - 2;
}

public System.Windows.Point GetMousePosition()
{
    System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
    return new System.Windows.Point(point.X, point.Y);
}

更新位置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Thread(o => {
    while (true) {
        Dispatcher.Invoke(
            () => 
            {
                if (Visibility == Visibility.Visible)
                {
                    MoveBottomRightEdgeOfWindowToMousePosition();
                }
            }
        );
        Thread.Sleep(10);
    }
})
{
    IsBackground = true
}.Start();
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-10-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 获取鼠标位置
  • 像素坐标转换为WPF坐标
  • 获取窗口的缩放率
  • 设置窗口在鼠标右下角
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档