如何select使用半透明select或屏幕上任意位置的颜色?

How to select a color anywhere on the screen using a semi transparent selector?

小免责声明:这是我第一次在表格中弄乱图形,因此我对这里的概念不太熟悉

好的,所以我一直在尝试制作一个应用程序来跟踪光标在整个屏幕中的位置并在其周围绘制一个椭圆。我借用的代码来自 问题(我更改了椭圆的 X 和 Y 位置,以便在光标周围自动调整自身,而不管其大小)到目前为止一切正常。这是到目前为止的代码:

        public static float width;
        public static float height;

        public Main(float w, float h)
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            width = w;
            height = h;
            BackColor = Color.White;
            FormBorderStyle = FormBorderStyle.None;
            Bounds = Screen.PrimaryScreen.Bounds;
            TopMost = true;
            TransparencyKey = BackColor;
            this.ShowInTaskbar = false;
            timer1.Tick += timer1_Tick;
        }

        Timer timer1 = new Timer() { Interval = 1, Enabled = true };

        protected override void OnPaint(PaintEventArgs e)
        {
            DrawTest(e.Graphics);
            base.OnPaint(e);
        }

        private void DrawTest(Graphics g)
        {
            var p = PointToClient(Cursor.Position);
            g.DrawEllipse(Pens.DeepSkyBlue, p.X - (width / 2), p.Y - (height / 2), width, height);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Invalidate();
        }

所以现在我希望应用程序检查椭圆区域内是否存在预先分配的颜色,如果存在,则获取距光标最近的具有该颜色的像素的位置。我到处搜索,但没有找到任何方法。

我知道它背后的逻辑是获取椭圆内的所有像素,检查颜色是否存在并找到离光标最近的具有该颜色的像素,但我无法实现它.

如有任何帮助,我们将不胜感激。

这是一个简化的方法(不需要PInvoking、鼠标tracking/hooking或其他低级操作)。
如果您不需要太多控制 Window 背后发生的事情,它可以很好地工作,您不想记录动画图像,只需执行问题描述中的内容即可:捕获外部 [=73] 的颜色=] / 当前鼠标指针下的桌面元素。

这里使用了一个技巧:表单的 BackColor 和它的 TransparencyKey 被设置为偏蓝的颜色 (Color.Navy)。这允许有一个透明但 solid 形式。
实际上,MouseMove 事件会引发,即使表单是完全透明的并且可以 clicked-though.

另一个准技巧,是使用标准 DoubleBuffer 属性 双缓冲表单,而不是可以调用 SetStyle() 启用的 OptimizedDoubleBuffer方法。

ResizeRedraw 属性 设置为 true,因此 Form 会自行重绘 if/when 调整大小。

使用此设置,要获得光标位置下的颜色,您只需使用大小为 (1, 1) 的位图拍摄当前屏幕的单像素快照(我们只需要一个像素) 并使用(不是很快但很实用)GetPixel() 方法从位图中读取颜色。

单击鼠标右键时,光标下的颜色保存在 List<Color> 中(可使用 public/read-only SavedColors 属性 访问)和然后在用作此 Palette.

的 canvas 的 PictureBox 中绘制

要构建此示例:

  • 创建新表单
  • 添加一个 PictureBox(此处命名为 picColor)并将其固定在右上角。此控件用于在鼠标指针移动时显示光标下的当前颜色。
  • 在前一个 PictureBox 下添加第二个 PictureBox(此处命名为 picPalette)并将其固定在 Top-Right-Bottom 上。这用于绘制当前已保存颜色的调色板。
    在设计器中,使用事件面板订阅 Paint 事件,使用您可以在此代码中找到的处理程序方法(即不要添加其他方法)。

using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

public partial class frmColorPicker : Form
{
    Color m_CurrentColor = Color.Empty;
    List<Color> m_SavedColors = new List<Color>();

    public frmColorPicker()
    {
        InitializeComponent();
        ResizeRedraw = true;
        DoubleBuffered = true;

        TopMost = true;
        BackColor = Color.Navy;
        TransparencyKey = Color.Navy;
    }

    public Color CursorEllipseColor { get; set; } = Color.Orange;

    public List<Color> SavedColors => m_SavedColors;

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        GetColorUnderCursor();
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        var rect = GetCursorEllipse();
        using (var pen = new Pen(CursorEllipseColor, 2)) {
            e.Graphics.DrawEllipse(pen, rect);
        }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        if (e.Button == MouseButtons.Right) {
            m_SavedColors.Add(m_CurrentColor);
            picPalette.Invalidate();
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        Invalidate();
    }

    private Rectangle GetCursorEllipse()
    {
        var cursorEllipse = new Rectangle(PointToClient(Cursor.Position), Cursor.Size);
        cursorEllipse.Offset(-cursorEllipse.Width / 2, -cursorEllipse.Height / 2);
        return cursorEllipse;
    }

    private void GetColorUnderCursor()
    {
        using (var bmp = new Bitmap(1, 1))
        using (var g = Graphics.FromImage(bmp)) {
            g.CopyFromScreen(Cursor.Position, Point.Empty, new Size(1, 1));
            m_CurrentColor = bmp.GetPixel(0, 0);
            picColor.BackColor = m_CurrentColor;
        }
    }

    private void picPalette_Paint(object sender, PaintEventArgs e)
    {
        int rectsCount = 0;
        int rectsLines = 0;
        int rectsPerLine = picPalette.Width / 20;

        foreach (var color in m_SavedColors) {
            using (var brush = new SolidBrush(color)) {
                var rect = new Rectangle(new Point(rectsCount * 20, rectsLines * 20), new Size(20, 20));
                e.Graphics.FillRectangle(brush, rect);
                e.Graphics.DrawRectangle(Pens.DarkGray, rect);
                rectsCount += 1;
                if (rectsCount == rectsPerLine) {
                    rectsCount = 0;
                    rectsLines += 1;
                }
            }
        }
    }
}

这是它的工作原理: