简体   繁体   English

使用图像透明度过滤鼠标事件

[英]Use image transparency to filter mouse events

I've been digging through examples, tutorials, and forums all day and I cannot seem to wrap my head around what seems like a simple concept. 我整天都在浏览示例,教程和论坛,似乎无法将自己笼罩在一个简单的概念上。

Essentially, I am creating a color wheel color selection tool. 本质上,我正在创建一个色轮颜色选择工具。 The tool is a ring in shape, so I do not want the mouse to perform functions unless it is hovering over the tool shape itself. 该工具是环形的,因此除非鼠标悬停在工具形状本身上,否则我不希望鼠标执行功能。

The color wheel is a simple image. 色轮是一个简单的图像。 I've tried finding ways to utilize the opacity mapping, drawing ellipses to detect the mouse (which works, but then I can't click the physical wheel under it). 我试图找到利用不透明度贴图的方法,画出椭圆形来检测鼠标(它可以工作,但是我不能单击它下面的物理轮)。

I'm just running into blanks here. 我只是在这里空白。

What I want to achieve (inevitably) is this: Mouse moves into color wheel's domain, changes cursor to dropper. 我要实现的目标(不可避免)是:鼠标移至色轮的域,将光标更改为滴管。 When user clicks on a pixel at xPos/yPos we want to grab the RGB value of the pixel at that location. 当用户单击xPos / yPos处的像素时,我们要获取该位置的像素的RGB值。 Looks easy on paper, right? 在纸上看起来很容易,对吧?

Anyone wanna try to assist? 有人想协助吗? Maybe some spit-balling? 也许有些吐痰? Thank you so much for any help already, and thank you for taking the time to at least look at my question! 非常感谢您提供的任何帮助,也感谢您抽出宝贵的时间至少看看我的问题!

Here is the image being used for the color wheel for now: 这是目前用于色轮的图像:

色轮PNG

UPDATE: I've got an overlay working, and I'm passing the click event successfully. 更新:我有一个覆盖工作,并且我成功传递了click事件。 Seems like I might be going the right way. 好像我可能走对了路。 Just need to figure out how to grab the pixel data next. 接下来只需要弄清楚如何获取像素数据即可。

XAML: XAML:

<Window x:Name="frmMain" x:Class="MouseImageTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MouseImageTest"
    mc:Ignorable="d"
    Title="Color Picker Example" Height="423.41" Width="572.61">
<Window.Resources>
    <Style x:Key="EllipseStyle1" TargetType="{x:Type Ellipse}"/>
</Window.Resources>
<Grid>
    <Label x:Name="lblOpacity" Content="Update:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="59" HorizontalContentAlignment="Right"/>
    <Label x:Name="lblNumbers" Content="" HorizontalAlignment="Left" Margin="64,0,0,0" VerticalAlignment="Top" Width="149"/>
    <Grid x:Name="grdBleh">
        <Image x:Name="image" HorizontalAlignment="Left" Height="331" Margin="118,29,0,0" VerticalAlignment="Top" Width="323" Source="physicswheel.png" StretchDirection="DownOnly" MouseDown="image_MouseDown">
            <Image.OpacityMask>
                <ImageBrush ImageSource="physicswheel.png" Stretch="Uniform" Opacity="0.99"/>
            </Image.OpacityMask>
        </Image>
        <Ellipse x:Name="swatchOuterBounds" HorizontalAlignment="Left" Height="291" Margin="127,38,0,0" VerticalAlignment="Top" Width="290" Stroke="#FDFF0000" StrokeThickness="50" Style="{DynamicResource EllipseStyle1}" Opacity="0" MouseEnter="ellipse_MouseEnter" MouseLeave="ellipse_MouseLeave" PreviewMouseDown="ellipse_MouseDown"/>
        <Border x:Name="brdrRed1" BorderBrush="Black" BorderThickness="2,2,1,2" Width="29" Height="25" Margin="446,106,89,256" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="4,0,0,4" Background="#FF959595">
            <Label x:Name="lblRed" Content="R:" Margin="0,0,5,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
        <Border x:Name="brdrRed2" BorderBrush="Black" BorderThickness="1,2,2,2" Width="29" Height="25" Margin="475,106,61,256" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="0,4,4,0" Background="#FF959595">
            <Label x:Name="lblRed2" Content="" Margin="5,0,0,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
        <Border x:Name="brdrGreen1" BorderBrush="Black" BorderThickness="2,2,1,2" Width="29" Height="25" Margin="446,135,89,229" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="4,0,0,4" Background="#FF959595">
            <Label x:Name="lblGreen" Content="G:" Margin="0,0,5,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
        <Border x:Name="brdrGreen2" BorderBrush="Black" BorderThickness="1,2,2,2" Width="29" Height="25" Margin="475,135,61,229" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="0,4,4,0" Background="#FF959595">
            <Label x:Name="lblGreen2" Content="" Margin="5,0,0,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
        <Border x:Name="brdrBlue1" BorderBrush="Black" BorderThickness="2,2,1,2" Width="29" Height="25" Margin="446,162,89,200" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="4,0,0,4" Background="#FF959595">
            <Label x:Name="lblBlue" Content="B:" Margin="0,0,5,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
        <Border x:Name="brdrBlue2" BorderBrush="Black" BorderThickness="1,2,2,2" Width="29" Height="25" Margin="475,162,61,200" VerticalAlignment="Center" HorizontalAlignment="Center" CornerRadius="0,4,4,0" Background="#FF959595">
            <Label x:Name="lblBlue2" Content="" Margin="5,0,0,0" Background="{x:Null}" Foreground="Black" BorderThickness="0" Padding="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Right"/>
        </Border>
    </Grid>

</Grid>

C#: C#:

public partial class MainWindow : Window
{
     public MainWindow()
     {
         InitializeComponent();
     }

     private void ellipse_MouseEnter(object sender, MouseEventArgs e)
     {
         Cursor = Cursors.Hand;
     }

     private void ellipse_MouseLeave(object sender, MouseEventArgs e)
     {
         Cursor = Cursors.Arrow;
     }

     private void image_MouseDown(object sender, MouseButtonEventArgs e)
     {
         if (swatchOuterBounds.IsMouseOver)
         {
             lblNumbers.Content = "Clicked the color wheel!";

             // Insert mouseclick evaluation here and grab Pixel Data. 
             // Write to R/G/B labels.
         }
     }

     private void ellipse_MouseDown(object sender, MouseButtonEventArgs e)
     {
         image_MouseDown(sender, e);
     }
 } 

You can use a Path element to draw the overlay. 您可以使用Path元素绘制叠加层。 In this case, I combine two EllipseGeometry to form the Path, first one is the outer circle, then exclude the inner circle. 在这种情况下,我将两个EllipseGeometry组合在一起以形成Path,第一个是外圆,然后排除内圆。

<Path Fill="#CCCCFF" Margin="127,38,0,0" 
    MouseEnter="ellipse_MouseEnter" 
    MouseLeave="ellipse_MouseLeave" 
    PreviewMouseDown="ellipse_MouseDown">
    <Path.Data>                    
        <CombinedGeometry GeometryCombineMode="Exclude">
            <CombinedGeometry.Geometry1>
                <EllipseGeometry RadiusX="150" RadiusY="150" Center="150,150" />
            </CombinedGeometry.Geometry1>
            <CombinedGeometry.Geometry2>
                <EllipseGeometry RadiusX="100" RadiusY="100" Center="150,150" />
            </CombinedGeometry.Geometry2>
        </CombinedGeometry>
    </Path.Data>
</Path>

I use a purple color to highlight this Path element, and I use the same name for the event handlers just to show you I am just replacing the Ellipse with a Path - rename them yourself. 我用紫色来突出这个Path元素,我用的是同一名称的事件处理程序只是为了告诉你,我只是更换EllipsePath -自己重新命名。

在此处输入图片说明

And you don't need to pass the event to the image beneath, all is done in the MouseDown event of the overlay. 而且您无需将事件传递到下面的图像,所有操作都在叠加层的MouseDown事件中完成。

private void ellipse_MouseDown(object sender, MouseButtonEventArgs e)
{
    //Get the x,y position as relative to the upper-left corner of the overlay
    var point = e.GetPosition(sender as IInputElement); 

    //Or, relative to the wheel
    var point2 = e.GetPosition(image);
}

So, I had to kind of wing it. 所以,我不得不给它加翅膀。 I controlled the click on the transparent ellipse and gathered the pixel data from the image control at Mouse coords. 我控制了透明椭圆上的单击,并从Mouse坐标处的图像控件中收集了像素数据。 So, it all works. 因此,一切正常。 (Sorry, I don't like XAML, so here's what I came up with: (对不起,我不喜欢XAML,所以这是我想到的:

Image swatcher = new Image();
        swatcher.Source = new BitmapImage(new Uri("/Icons/physicswheel.png", UriKind.Relative));
        swatcher.Stretch = Stretch.Uniform;
        swatcher.Height = 100;
        swatcher.Width = 100;
        swatcher.Margin = new Thickness(5, 5, 5, 5);
        swatcher.SetValue(Grid.RowProperty, 0);
        swatcher.SetValue(Grid.ColumnProperty, 0);
        swatcher.HorizontalAlignment = HorizontalAlignment.Center;
        columns.Children.Add(swatcher);

        Ellipse bumper = new Ellipse();
        bumper.Height = 95;
        bumper.Width = 95;
        bumper.SetValue(Grid.RowProperty, 0);
        bumper.SetValue(Grid.ColumnProperty, 0);
        bumper.Stroke = new SolidColorBrush(Color.FromArgb(0, 12, 12, 255));
        bumper.StrokeThickness = 17;
        bumper.MouseEnter += delegate (object source, MouseEventArgs e)
        {
                //Change Mouse Cursor to custom dropper.
                Uri curDropper = new Uri("/Cursors/eyedropper.cur", UriKind.Relative);
            bumper.Cursor = new Cursor(App.GetResourceStream(curDropper).Stream);
        };
        bumper.MouseDown += delegate (object source, MouseButtonEventArgs e)
        {
                //Get Mouse position and then grab pixel data.
                int xPos = Convert.ToInt32(e.GetPosition(swatcher).X);
            int yPos = Convert.ToInt32(e.GetPosition(swatcher).Y);

            CroppedBitmap dropper = new CroppedBitmap(swatcher.Source as BitmapSource, new Int32Rect(xPos, yPos, 1, 1));

            byte[] pixel = new byte[4];
            dropper.CopyPixels(pixel, 4, 0);

                //Change Swatch Preview and RGB fields.

                redUpDown.Text = pixel[2].ToString();
            greenUpDown.Text = pixel[1].ToString();
            blueUpDown.Text = pixel[0].ToString();

        };
        columns.Children.Add(bumper);

I really hope this helps anyone on the same path. 我真的希望这对任何走同一条道路的人都有帮助。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM