【问题标题】:How to select a color anywhere on the screen using a semi transparent selector?如何获取椭圆内指定颜色的坐标?
【发布时间】:2020-06-17 12:19:43
【问题描述】:

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

好的,所以我一直在尝试制作一个应用程序来跟踪光标在整个屏幕中的位置并在其周围绘制一个椭圆。我借用的代码来自this 问题(我更改了椭圆的 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();
        }

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

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

任何帮助将不胜感激。

【问题讨论】:

    标签: c# winforms graphics drawing gdi+


    【解决方案1】:

    这是一种简化的方法(它不需要 PInvoking、鼠标跟踪/挂钩或其他低级操作)。
    如果您不需要过多控制 Window 后面发生的事情,您不想录制动画图像,它可以很好地工作,只需执行问题描述中的操作:捕获当前位于鼠标指针。

    这里使用了一个技巧:表单的BackColor 及其TransparencyKey 被设置为蓝色(Color.Navy)。这允许有一个透明但实心的形式。
    在实践中,即使表单完全透明并且可以点击,也会引发MouseMove 事件。

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

    ResizeRedraw 属性设置为 true,因此窗体在调整大小时会自行重绘。

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

    单击鼠标右键时,光标下的颜色将保存在List<Color>(可使用公共/只读SavedColors 属性访问)中,然后在用作画布的PictureBox 中绘制调色板

    构建这个例子:

    • 新建表单
    • 添加一个 PictureBox(此处命名为 picColor)并将其锚定在右上角。此控件用于在鼠标指针移动时显示光标下的当前颜色。
    • 在前一个图片框下方添加第二个图片框(此处命名为 picPalette)并将其锚定在右上角。这用于绘制保存颜色的当前调色板。
      在设计器中,使用您可以在此代码中找到的处理程序方法使用事件面板订阅 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();
            this.ResizeRedraw = true;
            this.DoubleBuffered = true;
    
            this.TopMost = true;
            this.BackColor = Color.Navy;
            this.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);
            this.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;
                    }
                }
            }
        }
    }
    

    它是这样工作的:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-08
      • 2021-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多