0

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. 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:

Color Wheel PNG

UPDATE: I've got an overlay working, and I'm passing the click event successfully. Seems like I might be going the right way. Just need to figure out how to grab the pixel data next.

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); } } 
5
  • Please be specific. There can be quite a few different questions here, “I cannot click the physical wheel under it”, do you want the wheel shape respond to mouse click event? Commented Jul 10, 2018 at 2:11
  • I apologize. I want the wheel shape to respond to mouse click, but I want the white section (transparent section) to be invisible to mouse clicks. I'm still fiddling with using an invisible overlay using an Ellipse, and I believe I'm on the right track. I am now attempting to use its MouseDown event and just pass it on to the wheel circle as another Event. I will update with any changes. Commented Jul 10, 2018 at 2:31
  • That is more clear. And show the code of the wheel and the overlay, they are written in XAML, right? Commented Jul 10, 2018 at 2:35
  • You need to give up on getting the pixel data. WPF uses retained mode graphics. Among other things this means that you cannot use screen pixels as a kind of scratch buffer to figure out things you should have already known. The way to approach this problem is to calculate the color based on the position of the mouse click relative to the center of the image. Commented Jul 10, 2018 at 18:16
  • @AQuirky I did not realize the OP was trying to grab the RGB value directly from the underlying image. I thought he was trying to first get the position of the mouse click and then map/translate the position to an RGB value, just like your suggestion. Commented Jul 11, 2018 at 2:50

2 Answers 2

1

You can use a Path element to draw the overlay. In this case, I combine two EllipseGeometry to form the Path, first one is the outer circle, then exclude the inner circle.

<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.

enter image description here

And you don't need to pass the event to the image beneath, all is done in the MouseDown event of the overlay.

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); } 
Sign up to request clarification or add additional context in comments.

Comments

0

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. So, it all works. (Sorry, I don't like XAML, so here's what I came up with:

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. :)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.