基于WPF開發(fā)簡(jiǎn)單的顏色選擇器
WPF 簡(jiǎn)單實(shí)現(xiàn)顏色選擇器
- 框架使用
.NET4
; Visual Studio 2022
;
實(shí)現(xiàn)代碼
1)新增 xaml
代碼如下:
- 定義一個(gè)
WriteableBitmap
用于記錄顏色緩沖值。 - 在
XAML
中定義Canvas
設(shè)置背景為一張圖像。 - 在
Canvas
中添加Thumb
是一個(gè)可拖動(dòng)的控件,用于實(shí)現(xiàn)交互中的拖動(dòng)后獲取顏色。
<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),用于在圖像的每個(gè)像素位置上進(jìn)行操作色值。
height
和width
是圖像的高度和寬度。- 在外層循環(huán)中,變量
y
從 0 開始遞增,直到小于height
。 - 在內(nèi)層循環(huán)中,變量
x
從 0 開始遞增,直到小于width
。 - 在每個(gè)像素位置上,通過(guò)計(jì)算
normalizedX
和normalizedY
,將x
和y
的值歸一化到 [0, 1] 范圍內(nèi)。 - 使用
HSVToRGB
函數(shù)將歸一化后的normalizedX
、normalizedY
和 1(表示最大亮度)轉(zhuǎn)換為 RGB 值,并將結(jié)果存儲(chǔ)在r
、g
和b
變量中。 - 計(jì)算像素在圖像數(shù)據(jù)緩沖區(qū)中的偏移量
pixelOffset
,其中stride
是每行像素占用的字節(jié)數(shù)。 - 使用
Marshal.WriteByte
方法將 RGB 值寫入圖像數(shù)據(jù)緩沖區(qū)中的相應(yīng)位置,同時(shí)設(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ù),用于存儲(chǔ)轉(zhuǎn)換后的 RGB 值。- 在函數(shù)內(nèi)部,根據(jù) HSV 轉(zhuǎn)換公式進(jìn)行計(jì)算。如果飽和度
s
為 0,則表示灰度色調(diào),此時(shí)將 RGB 的三個(gè)分量都設(shè)置為亮度v
的值,并乘以 255 轉(zhuǎn)換為字節(jié)表示。 - 如果飽和度
s
不為 0,則根據(jù)色相h
的值確定所處的色相區(qū)間,并根據(jù)公式計(jì)算出對(duì)應(yīng)的 RGB 值。具體步驟如下: - 將色相
h
乘以 6,得到一個(gè)擴(kuò)展的色相值hue
。 - 取
hue
的整數(shù)部分作為索引i
,表示所處的色相區(qū)間。 - 計(jì)算
hue
的小數(shù)部分f
。 - 根據(jù)公式計(jì)算出對(duì)應(yīng)的 RGB 值,其中
p
是亮度v
與飽和度s
的乘積,q
是亮度v
與飽和度s
以及f
的乘積,t
是亮度v
與飽和度s
以及(1.0 - f)
的乘積。 - 根據(jù)索引
i
的值,將計(jì)算得到的 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
代碼如下:
- 在事件處理程序中,首先獲取拖動(dòng)的
Thumb
控件,并計(jì)算出新的左側(cè)和頂部位置。通過(guò)Canvas.GetLeft(thumb)
和Canvas.GetTop(thumb)
方法獲取當(dāng)前Thumb
控件在Canvas
中的左側(cè)和頂部位置,然后將其與拖動(dòng)的變化量e.HorizontalChange
和e.VerticalChange
相加,得到新的位置。 - 計(jì)算
Canvas
的右側(cè)和底部邊界。通過(guò)canvas.ActualWidth - thumb.ActualWidth
和canvas.ActualHeight - thumb.ActualHeight
計(jì)算出Canvas
的右側(cè)和底部邊界位置。 - 對(duì)新的左側(cè)和頂部位置進(jìn)行邊界檢查。如果新的左側(cè)位置小于 0,則將其設(shè)置為 0,以保證
Thumb
控件不會(huì)超出Canvas
的左側(cè)邊界。如果新的左側(cè)位置大于Canvas
的右側(cè)邊界位置canvasRight
,則將其設(shè)置為canvasRight
,以確保Thumb
控件不會(huì)超出Canvas
的右側(cè)邊界。類似地,對(duì)新的頂部位置進(jìn)行邊界檢查。 - 通過(guò)
Canvas.SetLeft(thumb, newLeft)
和Canvas.SetTop(thumb, newTop)
將Thumb
控件的位置更新為新的左側(cè)和頂部位置。 - 調(diào)用
GetAreaColor()
方法來(lái)獲取更新后的區(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
代碼如下:
實(shí)現(xiàn)鼠標(biāo)左鍵按下時(shí),將 Thumb 控件移動(dòng)到鼠標(biāo)點(diǎn)擊位置,并進(jìn)行邊界限制。同時(shí),還獲取了鼠標(biāo)點(diǎn)擊位置的顏色信息
?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
控件的中心點(diǎn)坐標(biāo)轉(zhuǎn)換為相對(duì)于 Canvas
的坐標(biāo)。
計(jì)算每行像素?cái)?shù)據(jù)所占的字節(jié)數(shù)。
創(chuàng)建一個(gè)字節(jié)數(shù)組,用于存儲(chǔ)位圖的像素?cái)?shù)據(jù)。
將位圖的像素?cái)?shù)據(jù)復(fù)制到字節(jié)數(shù)組中。
計(jì)算要訪問(wèn)的像素在字節(jié)數(shù)組中的索引位置。
Color.FromArgb
取其 Alpha
、紅色、綠色和藍(lán)色通道的值。在這段代碼中,它被用于構(gòu)造一個(gè) Color
對(duì)象,表示位圖中特定像素的顏色。
pixels[pixelIndex + 3]
表示字節(jié)數(shù)組中的第pixelIndex + 3
個(gè)元素,即 Alpha 通道的值。pixels[pixelIndex + 2]
表示字節(jié)數(shù)組中的第pixelIndex + 2
個(gè)元素,即紅色通道的值。pixels[pixelIndex + 1]
表示字節(jié)數(shù)組中的第pixelIndex + 1
個(gè)元素,即綠色通道的值。pixels[pixelIndex]
表示字節(jié)數(shù)組中的第pixelIndex
個(gè)元素,即藍(lán)色通道的值。
?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ā)簡(jiǎn)單的顏色選擇器的文章就介紹到這了,更多相關(guān)WPF顏色選擇器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#使用SQLDMO操作數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了C#使用SQLDMO操作數(shù)據(jù)庫(kù)的方法,實(shí)例分析了基于SQLDMO.dll動(dòng)態(tài)鏈接庫(kù)操作數(shù)據(jù)庫(kù)的相關(guān)技巧,需要的朋友可以參考下2015-06-06Unity實(shí)現(xiàn)老虎機(jī)滾動(dòng)抽獎(jiǎng)效果的示例代碼
這篇文章主要介紹了Unity實(shí)現(xiàn)老虎機(jī)滾動(dòng)抽獎(jiǎng)效果的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04C# Base 64 編碼/解碼實(shí)現(xiàn)代碼
這篇文章主要介紹了C# Base 64 編碼/解碼實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-02-02C# HttpClient Post參數(shù)同時(shí)上傳文件的實(shí)現(xiàn)
這篇文章主要介紹了C# HttpClient Post參數(shù)同時(shí)上傳文件的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06