Используйте прозрачность изображения для фильтрации событий мыши

Я весь день копался в примерах, учебных пособиях и форумах, и мне кажется, что я не могу понять, что такое простая концепция.

По сути, я создаю инструмент выбора цвета цветового круга. Инструмент имеет форму кольца, поэтому я не хочу, чтобы мышь выполняла функции, если она не находится над самой формой инструмента.

Цветовое колесо - это простое изображение. Я пытался найти способы использовать отображение непрозрачности, рисуя эллипсы для обнаружения мыши (что работает, но тогда я не могу щелкнуть физическое колесо под ним).

Я просто здесь сталкиваюсь с пробелами.

То, чего я хочу достичь (неизбежно), это: мышь перемещается в область цветового круга, меняет курсор на пипетку. Когда пользователь нажимает на пиксель в xPos/yPos, мы хотим получить значение RGB пикселя в этом месте. Выглядит легко на бумаге, верно?

Кто-нибудь хочет помочь? Может быть, какой-то плевок? Большое спасибо за любую помощь, и спасибо, что нашли время, чтобы хотя бы взглянуть на мой вопрос!

Вот изображение, которое сейчас используется для цветового круга:

Колесо цвета PNG

ОБНОВЛЕНИЕ: у меня работает оверлей, и я успешно передаю событие click. Похоже, я иду правильным путем. Просто нужно выяснить, как получить данные пикселей дальше.

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);
     }
 } 

2 ответа

Решение

Итак, мне пришлось как-то обойтись. Я управлял щелчком прозрачного эллипса и собирал данные пикселей из элемента управления изображениями в координатах мыши. Итак, все работает. (Извините, мне не нравится 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);

Я действительно надеюсь, что это поможет любому на том же пути.:)

Вы можете использовать элемент 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);
}
Другие вопросы по тегам