2013年4月29日月曜日

WPF 円形プログレスバー(未完成)


今日は、WPFで円形プログレスバーを作ってみました。


だいぶ日にちがたってしまいました。
原因はMHFとか↓と格闘してたからなのですが、とりあえず備忘録として残そうと思います。


今回作ったのは↓の「円形プログレスバー」です。


(プログレスバー以外のところはテスト用に適当に作ったものだから気にしないでください。)


最初はもっと簡単に作れるもんだと思ってたけど、これがなかなかめんどくさかった。。。

まず、予備知識として、WPFで円をあらわすのはPathですとEllipseGeometryとかがありますが、これは”円(楕円)”を描画するためのものなので、今回のような”円弧”書くには使えません。

そこで今回は、Pathの「ArcSegment」を使ってみようと思います。
(細かいことはこちらがわかりやすいので、そちらを参照。私も良くわからん。)

ただ、このArcSegment、わかり辛い・・・なんで”中心点”と”角度”を与えて書けるようにしてくれなかったのか。。。
(まあ、Path自体プログラムで絵を描くツールだと思ってるので、今回みたいな使い方事態がイレギュラーなのかな?)


入力は下記のような感じです。
・開始点(StartPoint):
・終了点(Point):
・サイズ(Size):
・角度フラグ(IsLargeArc):
・方向(SweepDirection):
・回転角度(RotationAngle):


これらを一つ一つ与えてもできるのですが、下記のように一気に与えることもできます(今回は使いませんが)。

<path Data="M 0,0 A 36,36 0 1 0 10,10"
Stroke="Black"
StrokeThickness="3">


さ、では今回は下のようなPathを使います。

<path x:Name="pathArc"
Width="200" Height="200"
Stroke="#aaAA54FF" StrokeThickness="10">
<Path.Data>
<pathgeometry x:Name="pathGeometryArc">
<pathfigure x:Name="pathFigureArc" StartPoint="105,5">
<arcsegment Point="195, 105"
Size="95, 95"
IsLargeArc="False"
SweepDirection="Clockwise"
RotationAngle="0"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>





上を先ほどの入力的に書くならば、
・開始点(StartPoint):[105,5]
・終了点(Point):[195,105]
・サイズ(Size):[95,95]
・角度フラグ(IsLargeArc):False
・方向(SweepDirection):Clockwise
・回転角度(RotationAngle):0

となり、↑は「開始点[105,5]から終了点[195,105]まで、半径[95,95](←X半径、Y半径)の円弧を時計回り(Clockwise)で書いて」という意味になります。

↓の紫の部分です。



あとは、終了点を三角関数を使って計算してやるだけです。
(ぶっちゃけ、”だけ”って言っておきながらこれにずっと悩んでました。いちいち計算するなんて思わなんだ・・・)

適当に「Value」という名前のプロパティを作ってその中に・・・

// 線の太さ
double thick = ( this.StrokeThickness / 2 );

// 入力値切捨て
double inputValue = Math.Floor(value);

// 角度の計算
double angle = ( inputValue * 3.6 );

// 0-360を許容
if ( 0 < angle && angle <= 360 ) {            // 角度によってフラグを変える      bool isLargeArcFlg = false;      if ( angle >= 180 ) {

// 180°を超える(180を含む)場合はフラグをtrue
isLargeArcFlg = true;
}

// 角度と半径から座標を計算
double radius = (this.pathArc.Width / 2) - thick;
double jitsuAngle = angle - 90;

double radian = Math.PI * jitsuAngle / 180.0;
double x = radius * Math.Cos(radian);
double y = radius * Math.Sin(radian);

// 終点計算
double endPointX = radius + x;
double endPointY = radius + y;

// 図形生成
PathFigure pfArc = new PathFigure();
pfArc.StartPoint = new Point(100, 0); // 開始点

// セグメント生成
ArcSegment arc = new ArcSegment();
arc.Point = new Point(endPointX, endPointY); // 終点(計算値)
arc.Size = new Size(radius, radius); // 半径
arc.IsLargeArc = isLargeArcFlg;
arc.SweepDirection = SweepDirection.Clockwise;
arc.RotationAngle = 0;

// 図形入れ替え
pfArc.Segments.Clear();
pfArc.Segments.Add(arc);

this.pathGeometryArc.Figures.Clear();
this.pathGeometryArc.Figures.Add(pfArc);


}


これでとりあえず、動的に最終点を変更させることができます。
ちなみに、角度フラグも動的に変えてやらないと180度越えたあたりで円弧がおかしなことになります。

めんどくさいです。まったく。
(あ、上のコードそのまま使うこともできますが、線の太さ(StrokeThickness)が5以上かつvalueが0付近でおかしくなります。→これが題名に”未完成”と付いている理由です。)

色々ソースコード・計算値とうにゃうにゃ相談してみましたが、解決してません。


念のため、図の白い部分(プログレスバーの残りの部分)は上のの部分にパスとソース追加でできます。

【XAML追加分】

<Path x:Name="pathCircleBackground"
Width="200" Height="200"
Stroke="#aaffffff" StrokeThickness="10">
<Path.Data>
<PathGeometry x:Name="pathGeometryCircle">
<PathFigure x:Name="pathFigureCircle" StartPoint="105,5">
<ArcSegment Point="195, 105"
Size="95, 95"
IsLargeArc="True"
SweepDirection="Counterclockwise"
RotationAngle="0"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>



【ソース追加分】

// 図形生成(背景)
PathFigure pfCircle = new PathFigure();
pfCircle.StartPoint = new Point(100, 0); // 開始点

// セグメント生成
ArcSegment circle = new ArcSegment();
circle.Point = new Point(endPointX, endPointY); // 終点(計算値)
circle.Size = new Size(radius, radius); // 半径
circle.IsLargeArc = !isLargeArcFlg;
circle.SweepDirection = SweepDirection.Counterclockwise;
circle.RotationAngle = 0;

// 図形入れ替え
pfCircle.Segments.Clear();
pfCircle.Segments.Add(circle);

this.pathGeometryCircle.Figures.Clear();
this.pathGeometryCircle.Figures.Add(pfCircle);

ここがミソです。



以上です。

お疲れ様。

あ、ソースの欠陥理由がわかったら教えてください。





0 件のコメント:

コメントを投稿

誤字脱字の指摘から、何気ない一言まで気軽な感じでコメントいただけると幸いです。