使用图像透明度过滤鼠标事件
Use image transparency to filter mouse events
我整天都在研究示例、教程和论坛,但我似乎无法理解这个看似简单的概念。
本质上,我正在创建一个色轮颜色选择工具。该工具是一个环形,所以我不希望鼠标在悬停在工具形状本身上时执行功能。
色轮是一个简单的图像。我已经尝试寻找利用不透明度映射的方法,绘制椭圆来检测鼠标(这有效,但我无法点击它下面的物理滚轮)。
我只是 运行 这里一片空白。
我想(不可避免地)实现的是:鼠标移动到色轮的域中,将光标更改为滴管。当用户点击 xPos/yPos 处的像素时,我们想要获取该位置像素的 RGB 值。在纸面上看起来很简单,对吧?
有人想帮忙吗?也许有些口水球?非常感谢您的帮助,也感谢您抽出时间至少看看我的问题!
这是目前用于色轮的图像:
更新:我有一个叠加层在工作,并且我正在成功传递点击事件。看来我可能走对了路。只需要弄清楚接下来如何抓取像素数据即可。
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#:
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);
}
}
您可以使用 Path 元素来绘制叠加层。在这种情况下,我将两个 EllipseGeometry
组合成路径,第一个是外圈,然后排除内圈。
<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>
我使用紫色来突出显示此 Path
元素,我对事件处理程序使用相同的名称只是为了向您展示我只是将 Ellipse
替换为 Path
- 自己重命名它们。
而且您不需要将事件传递给下方的图像,所有这些都在叠加层的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);
}
所以,我不得不试一试。我控制了对透明椭圆的点击,并从鼠标坐标处的图像控件收集了像素数据。所以,这一切都有效。 (抱歉,我不喜欢 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);
我真的希望这能帮助到同一条道路上的任何人。 :)
我整天都在研究示例、教程和论坛,但我似乎无法理解这个看似简单的概念。
本质上,我正在创建一个色轮颜色选择工具。该工具是一个环形,所以我不希望鼠标在悬停在工具形状本身上时执行功能。
色轮是一个简单的图像。我已经尝试寻找利用不透明度映射的方法,绘制椭圆来检测鼠标(这有效,但我无法点击它下面的物理滚轮)。
我只是 运行 这里一片空白。
我想(不可避免地)实现的是:鼠标移动到色轮的域中,将光标更改为滴管。当用户点击 xPos/yPos 处的像素时,我们想要获取该位置像素的 RGB 值。在纸面上看起来很简单,对吧?
有人想帮忙吗?也许有些口水球?非常感谢您的帮助,也感谢您抽出时间至少看看我的问题!
这是目前用于色轮的图像:
更新:我有一个叠加层在工作,并且我正在成功传递点击事件。看来我可能走对了路。只需要弄清楚接下来如何抓取像素数据即可。
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#:
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);
}
}
您可以使用 Path 元素来绘制叠加层。在这种情况下,我将两个 EllipseGeometry
组合成路径,第一个是外圈,然后排除内圈。
<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>
我使用紫色来突出显示此 Path
元素,我对事件处理程序使用相同的名称只是为了向您展示我只是将 Ellipse
替换为 Path
- 自己重命名它们。
而且您不需要将事件传递给下方的图像,所有这些都在叠加层的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);
}
所以,我不得不试一试。我控制了对透明椭圆的点击,并从鼠标坐标处的图像控件收集了像素数据。所以,这一切都有效。 (抱歉,我不喜欢 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);
我真的希望这能帮助到同一条道路上的任何人。 :)