[C.C++] 基于WPF实现拟物音量控件

1550 0
Honkers 2023-5-12 10:00:29 | 显示全部楼层 |阅读模式
WPF 实现拟物音量控件
控件名:Wheel
作者:WPFDevelopersOrg - 俞宏伟
原文链接:https://github.com/WPFDevelopersOrg/SimulationControl
    框架使用.NET6;Visual Studio 2022;绘制使用了Canvas作为容器控件,DrawingContext上绘制水平线。当鼠标滚动滚轮时或按下鼠标向上向下拖动时计算角度偏移并更新图层。


实现代码
1)创建 Wheel.xaml 代码如下:
<UserControlx:Class="TopControl.Wheel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TopControl"
mc:Ignorable="d"
Width="30"Height="180">
<Grid>
<!--进度-->
<GridWidth="2"Background="#0a0a0a"Height="180"HorizontalAlignment="Left"VerticalAlignment="Bottom"/>
<GridWidth="2"x:Name="Grid_Value"Height="0"HorizontalAlignment="Left"VerticalAlignment="Bottom">
<GridHeight="180"VerticalAlignment="Bottom">
<Grid.Background>
<LinearGradientBrushStartPoint="0,0"EndPoint="0,1">
<GradientStopOffset="0"Color="#f0d967"/>
<GradientStopOffset="1"Color="#33b08d"/>
</LinearGradientBrush>
</Grid.Background>
</Grid>
</Grid>
<GridBackground="#0a0a0a"Width="26"HorizontalAlignment="Right"Height="180"Margin="2,0,0,0"/>
<!--滚轮-->
<Gridx:Name="WheelArea"Height="176"Width="22"HorizontalAlignment="Right"Margin="0,0,2,0"
MouseDown="WheelArea_MouseDown"MouseMove="WheelArea_MouseMove"MouseUp="WheelArea_MouseUp"MouseWheel="WheelArea_MouseWheel">
<Grid.Background>
<LinearGradientBrushStartPoint="0,0"EndPoint="0,1">
<GradientStopColor="#141414"Offset="0"/>
<GradientStopColor="#3c3c3c"Offset="0.5"/>
<GradientStopColor="#141414"Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<Gridx:Name="LayerBox"IsHitTestVisible="False"/>
</Grid>
</Grid>
</UserControl>2)创建 Wheel.xaml.cs 代码如下:
usingSystem.Windows;
usingSystem.Windows.Controls;
usingSystem.Windows.Input;

namespaceTopControl
{
publicpartialclassWheel:UserControl
{
publicWheel()
{
InitializeComponent();
Loaded+=Wheel_Loaded;
}

#region属性

publicintMinValue{get;set;}=-720;

publicintMaxValue{get;set;}=720;

publicintValue{get;set;}=-720;

#endregion

#region控件事件

privatevoidWheel_Loaded(objectsender,RoutedEventArgse)
{
InitLayer();
}

privatevoidWheelArea_MouseDown(objectsender,MouseButtonEventArgse)
{
if(e.ChangedButton==MouseButton.Left)
{
BeginDrag();
}
}

privatevoidWheelArea_MouseMove(objectsender,MouseEventArgse)
{
if(_dragMode)
{
Drag();
}
}

privatevoidWheelArea_MouseUp(objectsender,MouseButtonEventArgse)
{
if(e.ChangedButton==MouseButton.Left&&_dragMode)
{
EndDrag();
}
}

privatevoidWheelArea_MouseWheel(objectsender,MouseWheelEventArgse)
{
if(_dragMode)return;

intoffset=e.Delta/120;
if(offset<0&&Value>MinValue)
{
Value+=offset;
UpdateProgress();
_wheelLayer.AngleOffset-=offset*_wheelSpeed;
_wheelLayer.UpdateLayer();
}
elseif(offset>0&&Value<MaxValue)
{
Value+=offset;
UpdateProgress();
_wheelLayer.AngleOffset-=offset*_wheelSpeed;
_wheelLayer.UpdateLayer();
}
}

#endregion

#region鼠标操作

privatevoidBeginDrag()
{
_dragMode=true;
WheelArea.CaptureMouse();

_dragStart=Mouse.GetPosition(WheelArea);
_angleStart=_wheelLayer.AngleOffset;

_valueStart=Value;
_offsetDown=Value-MinValue;
_offsetUp=Value-MaxValue;
}

privatevoidDrag()
{
doubleoffset_y=Mouse.GetPosition(WheelArea).Y-_dragStart.Y;
if(offset_y<_offsetUp)offset_y=_offsetUp;
elseif(offset_y>_offsetDown)offset_y=_offsetDown;

doubleoffset_angle=offset_y*_wheelSpeed;
Value=_valueStart-(int)offset_y;
_wheelLayer.AngleOffset=_angleStart+offset_angle;
UpdateProgress();
_wheelLayer.UpdateLayer();
}

privatevoidEndDrag()
{
_dragMode=false;
WheelArea.ReleaseMouseCapture();
}

#endregion

#region私有方法

///<summary>
///初始化图层
///</summary>
privatevoidInitLayer()
{
_wheelLayer.Width=LayerBox.ActualWidth;
_wheelLayer.Height=LayerBox.ActualHeight;
LayerBox.Children.Add(_wheelLayer);
_wheelLayer.Init();
_wheelLayer.UpdateLayer();
}

///<summary>
///更新进度
///</summary>
privatevoidUpdateProgress()
{
Grid_Value.Height=(double)(Value-MinValue)/(MaxValue-MinValue)*180;
}

#endregion

#region字段

privatereadonlyWheelLayer_wheelLayer=newWheelLayer();

privatePoint_dragStart=newPoint();
privatedouble_angleStart=0;
privateint_valueStart=0;
privatebool_dragMode=false;

///<summary>滚轮速度</summary>
privatereadonlydouble_wheelSpeed=0.7;

///<summary>最大向上偏移</summary>
privatedouble_offsetUp;
///<summary>最大向下偏移</summary>
privatedouble_offsetDown;

#endregion
}
}
3)创建 WheelLayer.cs 代码如下:
usingMathUtil;
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Runtime.CompilerServices;
usingSystem.Windows;
usingSystem.Windows.Media;
usingWpfUtil;

namespaceTopControl
{
publicclassWheelLayer:SingleLayer
{
#region属性

///<summary>槽高度:180px -上下边框(4px)</summary>
publicintGrooveHeight{get;set;}=176;

///<summary>角度:圆弧切线与槽边的夹角</summary>
publicintAngle{get;set;}=90;

///<summary>刻度线数量</summary>
publicintLineCount{get;set;}=90;

///<summary>角度偏移</summary>
publicdoubleAngleOffset{get;set;}=0;

#endregion

#region公开方法

publicoverridevoidInit()
{
//起点、终点、中点
Point2DstartPoint=newPoint2D(0,0);
Point2DendPoint=newPoint2D(GrooveHeight,0);
Point2DcenterPoint=startPoint.CenterWith(endPoint);
//向量:中点->起点
Vector2centerToStart=newVector2(centerPoint,startPoint);
centerToStart.Rotate(-90);
//向量:终点->中点
Vector2endToCenter=newVector2(endPoint,centerPoint);
endToCenter.Rotate(-90+Angle);
//圆心
_circleCenter=centerToStart.IntersectionWith(endToCenter);
//向量:圆心->起点
Vector2vector=newVector2(_circleCenter,startPoint);
_radius=vector.Distance;
_anglePerLine=360.0/LineCount;
}

protectedoverridevoidOnUpdate()
{
//最高点
Point2Dtop=newPoint2D(_circleCenter.X,_circleCenter.Y-_radius);
//向量:圆心->最高点
Vector2vector=newVector2(_circleCenter,top);
doublemax=Math.Abs(vector.Target.Y);
//偏移角度
vector.Rotate(AngleOffset);
//开始旋转计算刻度位置
List<Point2D>pointLis=newList<Point2D>();
for(intcounter=0;counter<LineCount;counter++)
{
if(vector.Target.Y<0)pointList.Add(vector.Target);
vector.Rotate(-_anglePerLine);
}

//绘制刻度线
foreach(variteminpointList)
DrawHorizontalLine(item.X,Math.Abs(item.Y)/max);
}

#endregion

#region私有方法

///<summary>
///绘制水平线
///</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatevoidDrawHorizontalLine(doubley,doubleopacity)
{
Penpen=newPen(newSolidColorBrush(Color.FromArgb((byte)(opacity*255),32,32,32)),1);
Penpen2=newPen(newSolidColorBrush(Color.FromArgb((byte)(opacity*255),64,64,64)),1);
_dc.DrawLine(pen,newPoint(2,y-0.5),newPoint(Width-2,y-0.5));
_dc.DrawLine(pen2,newPoint(2,y+0.5),newPoint(Width-2,y+0.5));
}

#endregion

#region字段

///<summary>圆心</summary>
privatePoint2D_circleCenter=newPoint2D(0,0);
///<summary>半径</summary>
privatedouble_radius=0;
///<summary>刻度线之间的夹角</summary>
privatedouble_anglePerLine=0;

#endregion
}
}
4)创建 WheelExample.xaml 代码如下:
<wd:Windowx:Class="TopControl.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:TopControl"
xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
mc:Ignorable="d"Background="#1e1e1e"
Title="https://github.com/WPFDevelopersOrg/SimulationControl-俞宏伟"Height="450"Width="800">
<Grid>
<local:WheelHorizontalAlignment="Left"VerticalAlignment="Top"Margin="50"/>
</Grid>
</wd:Window>效果图


以上就是基于WPF实现拟物音量控件的详细内容,更多关于WPF拟物音量控件的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4004
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行