基于WPF開發(fā)簡單的顏色選擇器
WPF 簡單實現(xiàn)顏色選擇器
- 框架使用
.NET4; Visual Studio 2022;

實現(xiàn)代碼
1)新增 xaml 代碼如下:
- 定義一個
WriteableBitmap用于記錄顏色緩沖值。 - 在
XAML中定義Canvas設(shè)置背景為一張圖像。 - 在
Canvas中添加Thumb是一個可拖動的控件,用于實現(xiàn)交互中的拖動后獲取顏色。
<Canvas?x:Name="canvas"?MouseLeftButtonDown="canvas_MouseLeftButtonDown">
????????????????<Canvas.Background>
????????????????????<ImageBrush?ImageSource="{Binding?Bitmap}"?/>
????????????????</Canvas.Background>
????????????????<Thumb
????????????????????x:Name="thumb"
????????????????????Canvas.Left="0"
????????????????????Canvas.Top="0"
????????????????????Width="20"
????????????????????Height="20"
????????????????????Background="Transparent"
????????????????????BorderBrush="Black"
????????????????????BorderThickness="2"
????????????????????DragDelta="Thumb_DragDelta">
????????????????????<Thumb.Template>
????????????????????????<ControlTemplate?TargetType="Thumb">
????????????????????????????<Border
????????????????????????????????Background="{TemplateBinding?Background}"
????????????????????????????????BorderBrush="{TemplateBinding?BorderBrush}"
????????????????????????????????BorderThickness="{TemplateBinding?BorderThickness}"
????????????????????????????????CornerRadius="10"
????????????????????????????????SnapsToDevicePixels="True"?/>
????????????????????????</ControlTemplate>
????????????????????</Thumb.Template>
????????????????</Thumb>
????????????</Canvas>2)新增 Loaded邏輯 處理代碼如下:
- 首先嵌套循環(huán),用于在圖像的每個像素位置上進行操作色值。
height和width是圖像的高度和寬度。- 在外層循環(huán)中,變量
y從 0 開始遞增,直到小于height。 - 在內(nèi)層循環(huán)中,變量
x從 0 開始遞增,直到小于width。 - 在每個像素位置上,通過計算
normalizedX和normalizedY,將x和y的值歸一化到 [0, 1] 范圍內(nèi)。 - 使用
HSVToRGB函數(shù)將歸一化后的normalizedX、normalizedY和 1(表示最大亮度)轉(zhuǎn)換為 RGB 值,并將結(jié)果存儲在r、g和b變量中。 - 計算像素在圖像數(shù)據(jù)緩沖區(qū)中的偏移量
pixelOffset,其中stride是每行像素占用的字節(jié)數(shù)。 - 使用
Marshal.WriteByte方法將 RGB 值寫入圖像數(shù)據(jù)緩沖區(qū)中的相應(yīng)位置,同時設(shè)置 Alpha 通道為 0xFF(完全不透明)。
????????????IntPtr?backBuffer?=?Bitmap.BackBuffer;
????????????int?stride?=?Bitmap.BackBufferStride;
????????????for?(int?y?=?0;?y?<?height;?y++)
????????????{
????????????????for?(int?x?=?0;?x?<?width;?x++)
????????????????{
????????????????????byte?r,?g,?b;
????????????????????double?normalizedX?=?(double)x?/?(width?-?1);
????????????????????double?normalizedY?=?(double)y?/?(height?-?1);
????????????????????HSVToRGB(normalizedX,?normalizedY,?1,?out?r,?out?g,?out?b);
????????????????????int?pixelOffset?=?y?*?stride?+?x?*?4;
????????????????????Marshal.WriteByte(backBuffer,?pixelOffset?+?0,?b);
????????????????????Marshal.WriteByte(backBuffer,?pixelOffset?+?1,?g);
????????????????????Marshal.WriteByte(backBuffer,?pixelOffset?+?2,?r);
????????????????????Marshal.WriteByte(backBuffer,?pixelOffset?+?3,?0xFF);
????????????????}
????????????}3)新增 HSVToRGB 方法代碼如下:
- HSVToRGB 方法返回 r 、g、b
h是色相值,取值范圍為 [0, 1]。s是飽和度值,取值范圍為 [0, 1]。v是亮度值,取值范圍為 [0, 1]。r、g和b是輸出參數(shù),用于存儲轉(zhuǎn)換后的 RGB 值。- 在函數(shù)內(nèi)部,根據(jù) HSV 轉(zhuǎn)換公式進行計算。如果飽和度
s為 0,則表示灰度色調(diào),此時將 RGB 的三個分量都設(shè)置為亮度v的值,并乘以 255 轉(zhuǎn)換為字節(jié)表示。 - 如果飽和度
s不為 0,則根據(jù)色相h的值確定所處的色相區(qū)間,并根據(jù)公式計算出對應(yīng)的 RGB 值。具體步驟如下: - 將色相
h乘以 6,得到一個擴展的色相值hue。 - 取
hue的整數(shù)部分作為索引i,表示所處的色相區(qū)間。 - 計算
hue的小數(shù)部分f。 - 根據(jù)公式計算出對應(yīng)的 RGB 值,其中
p是亮度v與飽和度s的乘積,q是亮度v與飽和度s以及f的乘積,t是亮度v與飽和度s以及(1.0 - f)的乘積。 - 根據(jù)索引
i的值,將計算得到的 RGB 值賦給輸出參數(shù)r、g和b。
private?static?void?HSVToRGB(double?h,?double?s,?double?v,?out?byte?r,?out?byte?g,?out?byte?b)
????????{
????????????if?(s?==?0)
????????????{
????????????????r?=?g?=?b?=?(byte)(v?*?255);
????????????}
????????????else
????????????{
????????????????double?hue?=?h?*?6.0;
????????????????int?i?=?(int)Math.Floor(hue);
????????????????double?f?=?hue?-?i;
????????????????double?p?=?v?*?(1.0?-?s);
????????????????double?q?=?v?*?(1.0?-?(s?*?f));
????????????????double?t?=?v?*?(1.0?-?(s?*?(1.0?-?f)));
????????????????switch?(i)
????????????????{
????????????????????case?0:
????????????????????????r?=?(byte)(v?*?255);
????????????????????????g?=?(byte)(t?*?255);
????????????????????????b?=?(byte)(p?*?255);
????????????????????????break;
????????????????????case?1:
????????????????????????r?=?(byte)(q?*?255);
????????????????????????g?=?(byte)(v?*?255);
????????????????????????b?=?(byte)(p?*?255);
????????????????????????break;
????????????????????case?2:
????????????????????????r?=?(byte)(p?*?255);
????????????????????????g?=?(byte)(v?*?255);
????????????????????????b?=?(byte)(t?*?255);
????????????????????????break;
????????????????????case?3:
????????????????????????r?=?(byte)(p?*?255);
????????????????????????g?=?(byte)(q?*?255);
????????????????????????b?=?(byte)(v?*?255);
????????????????????????break;
????????????????????case?4:
????????????????????????r?=?(byte)(t?*?255);
????????????????????????g?=?(byte)(p?*?255);
????????????????????????b?=?(byte)(v?*?255);
????????????????????????break;
????????????????????default:
????????????????????????r?=?(byte)(v?*?255);
????????????????????????g?=?(byte)(p?*?255);
????????????????????????b?=?(byte)(q?*?255);
????????????????????????break;
????????????????}
????????????}
????????}4)新增 Thumb_DragDelta 代碼如下:
- 在事件處理程序中,首先獲取拖動的
Thumb控件,并計算出新的左側(cè)和頂部位置。通過Canvas.GetLeft(thumb)和Canvas.GetTop(thumb)方法獲取當前Thumb控件在Canvas中的左側(cè)和頂部位置,然后將其與拖動的變化量e.HorizontalChange和e.VerticalChange相加,得到新的位置。 - 計算
Canvas的右側(cè)和底部邊界。通過canvas.ActualWidth - thumb.ActualWidth和canvas.ActualHeight - thumb.ActualHeight計算出Canvas的右側(cè)和底部邊界位置。 - 對新的左側(cè)和頂部位置進行邊界檢查。如果新的左側(cè)位置小于 0,則將其設(shè)置為 0,以保證
Thumb控件不會超出Canvas的左側(cè)邊界。如果新的左側(cè)位置大于Canvas的右側(cè)邊界位置canvasRight,則將其設(shè)置為canvasRight,以確保Thumb控件不會超出Canvas的右側(cè)邊界。類似地,對新的頂部位置進行邊界檢查。 - 通過
Canvas.SetLeft(thumb, newLeft)和Canvas.SetTop(thumb, newTop)將Thumb控件的位置更新為新的左側(cè)和頂部位置。 - 調(diào)用
GetAreaColor()方法來獲取更新后的區(qū)域顏色。
?private?void?Thumb_DragDelta(object?sender,?DragDeltaEventArgs?e)
????????{
????????????var?thumb?=?(Thumb)sender;
????????????double?newLeft?=?Canvas.GetLeft(thumb)?+?e.HorizontalChange;
????????????double?newTop?=?Canvas.GetTop(thumb)?+?e.VerticalChange;
????????????double?canvasRight?=?canvas.ActualWidth?-?thumb.ActualWidth;
????????????double?canvasBottom?=?canvas.ActualHeight?-?thumb.ActualHeight;
????????????if?(newLeft?<?0)
????????????????newLeft?=?0;
????????????else?if?(newLeft?>?canvasRight)
????????????????newLeft?=?canvasRight;
????????????if?(newTop?<?0)
????????????????newTop?=?0;
????????????else?if?(newTop?>?canvasBottom)
????????????????newTop?=?canvasBottom;
????????????Canvas.SetLeft(thumb,?newLeft);
????????????Canvas.SetTop(thumb,?newTop);
????????????GetAreaColor();
????????}5)新增 canvas_MouseLeftButtonDown 代碼如下:
實現(xiàn)鼠標左鍵按下時,將 Thumb 控件移動到鼠標點擊位置,并進行邊界限制。同時,還獲取了鼠標點擊位置的顏色信息
?private?void?canvas_MouseLeftButtonDown(object?sender,?MouseButtonEventArgs?e)
????????{
????????????var?canvasPosition?=?e.GetPosition(canvas);
????????????double?newLeft?=?canvasPosition.X?-?thumb.ActualWidth?/?2;
????????????double?newTop?=?canvasPosition.Y?-?thumb.ActualHeight?/?2;
????????????double?canvasRight?=?canvas.ActualWidth?-?thumb.ActualWidth;
????????????double?canvasBottom?=?canvas.ActualHeight?-?thumb.ActualHeight;
????????????if?(newLeft?<?0)
????????????????newLeft?=?0;
????????????else?if?(newLeft?>?canvasRight)
????????????????newLeft?=?canvasRight;
????????????if?(newTop?<?0)
????????????????newTop?=?0;
????????????else?if?(newTop?>?canvasBottom)
????????????????newTop?=?canvasBottom;
????????????Canvas.SetLeft(thumb,?newLeft);
????????????Canvas.SetTop(thumb,?newTop);
????????????var?thumbPosition?=?e.GetPosition(canvas);
????????????GetAreaColor(thumbPosition);
????????}6)新增 GetAreaColor 代碼如下:
Thumb 控件的中心點坐標轉(zhuǎn)換為相對于 Canvas 的坐標。
計算每行像素數(shù)據(jù)所占的字節(jié)數(shù)。
創(chuàng)建一個字節(jié)數(shù)組,用于存儲位圖的像素數(shù)據(jù)。
將位圖的像素數(shù)據(jù)復(fù)制到字節(jié)數(shù)組中。
計算要訪問的像素在字節(jié)數(shù)組中的索引位置。
Color.FromArgb取其 Alpha、紅色、綠色和藍色通道的值。在這段代碼中,它被用于構(gòu)造一個 Color 對象,表示位圖中特定像素的顏色。
pixels[pixelIndex + 3]表示字節(jié)數(shù)組中的第pixelIndex + 3個元素,即 Alpha 通道的值。pixels[pixelIndex + 2]表示字節(jié)數(shù)組中的第pixelIndex + 2個元素,即紅色通道的值。pixels[pixelIndex + 1]表示字節(jié)數(shù)組中的第pixelIndex + 1個元素,即綠色通道的值。pixels[pixelIndex]表示字節(jié)數(shù)組中的第pixelIndex個元素,即藍色通道的值。
?void?GetAreaColor(Point??thumbPosition?=?null)
????????{
????????????thumbPosition?=?thumbPosition?==?null???thumbPosition?=?thumb.TranslatePoint(new?Point(thumb.ActualWidth?/?2,?thumb.ActualHeight?/?2),?canvas)?:?thumbPosition;
????????????int?xCoordinate?=?(int)thumbPosition?.X;
????????????int?yCoordinate?=?(int)thumbPosition?.Y;
????????????if?(xCoordinate?>=?0?&&?xCoordinate?<?Bitmap.PixelWidth?&&?yCoordinate?>=?0?&&?yCoordinate?<?Bitmap.PixelHeight)
????????????{
????????????????int?stride?=?Bitmap.PixelWidth?*?(Bitmap.Format.BitsPerPixel?/?8);
????????????????byte[]?pixels?=?new?byte[Bitmap.PixelHeight?*?stride];
????????????????Bitmap.CopyPixels(new?Int32Rect(0,?0,?Bitmap.PixelWidth,?Bitmap.PixelHeight),?pixels,?stride,?0);
????????????????int?pixelIndex?=?(yCoordinate?*?stride)?+?(xCoordinate?*?(Bitmap.Format.BitsPerPixel?/?8));
????????????????Color?color?=?Color.FromArgb(pixels[pixelIndex?+?3],?pixels[pixelIndex?+?2],?pixels[pixelIndex?+?1],?pixels[pixelIndex]);
????????????????MyBtn.Background?=?new?SolidColorBrush(color);
????????????}
????????}效果圖

到此這篇關(guān)于基于WPF開發(fā)簡單的顏色選擇器的文章就介紹到這了,更多相關(guān)WPF顏色選擇器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# HttpClient Post參數(shù)同時上傳文件的實現(xiàn)
這篇文章主要介紹了C# HttpClient Post參數(shù)同時上傳文件的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06

