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);

ここがミソです。



以上です。

お疲れ様。

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





2013年4月16日火曜日

MHF最後の日(ダダンダンダダン)

本日はMHF(モンスターハンターフロンティア)の記事です。




といっても明日(4/17)にはアップデートで「MHF-G」になるためこれで最後なんですよねMHF。


で、そんな大晦日とでもいう雰囲気なのですが運営がやってくれました。

公式サイトにこんな告知が↓



クエの説明文には↓と書いてあります。




で、実際にそのクエストに行ってみました。
グロ画像注意!)




ででん!




別アングル!!




さらに別アングル!!!


(しっぽにはキノコとか岩じゃなくて、パッケを持っています。あ、部位破壊で落としてもパッケもらえません。)



何じゃこれ?って人もいるかと思われますが、この方MHFのプロデューサーです。
ちゃんとおなかに”Producter”って書いてあります。

名前あだ名はギウラス。
ちゃんと記事になってるほどに有名→ギウラス
(ずっと、”ギウラス”じゃなくて”ギラウス”だと思ってたよ・・・ママン)




さて、こいつの落し物や剥ぎ取り素材で”G級企画書○”(←○は数字です)といったものが手に入ります。

(事前に得た情報では「有用な情報」という触れ込みだったので期待したのですが・・・)



「困ったときはおすすめマークの付いたワールドへ入ろう。(清算アイテム)」

はい。解散。

ちなみに、清算価格は・・・

一個1zでしたorz
(いらねぇ・・・)


あ、そうそう。
こいつが(攻撃モーションとして)花火上げるんですが、花火を置いた跡地に「ギルドへの推薦状」が落ちています。


たくさんほしい人は花火ツアーしたら良いんじゃないかな?




とまあ、最終日はこんな感じでgdgd過ぎていきました。
すでにやること終わってたしね♪


最後にギウのアップで。





でわです~♪



あ、題名の「ダダンダンダダン」はターミネーターです。

2013年4月11日木曜日

C#は名前空間とクラス名を区別していない。

何とか二日目です。
(ね、寝るまでが1日だからセーフだよね汗)


本日は「プログラミング」について書きます。


事の発端は3年前・・・んなわけない。
つい先日、ニコニコ動画で↓を見かけたのです。

【自作】SAOようなランチャーを開発しました - SAO Utils

んで、らび爺はというと・・・

「すげぇぇええええ!!」
「C++でこんなことできるんだ~」
「ちょっと入れてみよう!!」

(ゴソゴソ←DL中・・・)

「よっし!(配置完了)」
「Ret's Go !!(exeをぽちっとな)」

「・・・」
「・・・」
「・・・」

なんかエラー出たんですけど・・・orz
まあ、エラーの内容を見るに画像のパスが見つからないだどうのこうの・・・解凍したZIPの中をあさったところ探してる画像自体はあるみたい・・・

きっと画像ファイルを探すときのパスが相対パスと絶対パスで間違ってるんだろう。。。
(開発者の方はC直下とかで開発して、テストとかあんまりしなかったのかな~)

んで、エラーは出るけど何とか動いているようなので、動画に習って動かしてみました。


「SAOの雰囲気が出てていいかも!!」
「画像デスクトップ上に貼れるし」

ところがここで問題が発生。

画像をデスクトップ上に張ったは良いが、消す方法がわからない!!
(なんでもいいやと、エ○画像なんて張るんじゃなかったorz)

ということがあり、使うことを断念(画像はプロセス殺して消したよ!よ!)。



・・・長いな、前置き。巻いていきましょう。



結局何が言いたかったかというと、「上の動画を見たおかげでUI系プログラムを作りたくなったよ。」という話。

ちょうど会社でC#を使ってることもあり、いろいろ調べているうちにWindows Presentation Foundation (WPF)というものがあることを知る。
(英語がtionのあとにtionがあってすごく違和感・・・頭痛が痛い的な・・・)

→VisualStudio2012で開発できるらしく、早速DL(ユーザー登録したので無制限につかえるよ。)し、
ある程度できてきた(今度紹介するかも・・・)ので、そろそろ効率化を図ろうと試しにユーザーコントロール(UserControl)を作成してみることに。

そこで下記のようなソースを作成しました。
(適当に「ソリューション」作って、「プロジェクト」作って、「UserControl」フォルダ作ってその下に↓)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplicationTest.src.UserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}


勘の良い方ならお気づきかと思いますが、これ、自動生成したはずなのにコンパイルエラーになります。

エラー内容は下記:
「WpfApplicationTest.src.UserControl' は '名前空間' ですが、'型' のように使用されています。」

1晩悩みました。
(あっちこっち探したけど、こんなこと起きてる人がそんなにいなかった。)

もともとjavaプログラマーだったらび爺はC#(WPFはC#で書けるから同じ問題を内包してるよ)のイケてない仕様にはまることに。

結論から言うと「C#は名前空間とクラス名を区別していない。」ってのが問題。
だから上みたいなソースだと
名前空間:WpfApplicationTest.src.UserControl
継承元(親)クラス:UserControl

がクラスなのか名前空間なのかわからなくなって、こんなエラーを吐くことに。。。

ちなみに、名前空間(フォルダ名)を下記のように変え、画像のOriginalUserControlの右下に出てるマークの▼を押すと
「名前を'UserControl'から'OriginalUserControl'に変更します。」といっているのでクリック。







こうなります。
ここからコンパイルするとまた「WpfApplicationTest.src.OriginalUserControl' は '名前空間' ですが、'型' のように使用されています。」が出ることに・・・。

この問題、↑の結論がわかっていたら何てことないんだけど、C#初めて間もない自分にはなかなか難題でした。
(片方だけ変更してよとか思ってませんよ。うん。)


難題になった背景には、「javaだとこんなことは起こらない。」から疑いもしなかったこと。
(ちなみにjavaだと、パッケージ名(上で言うUserControlというフォルダ名)は小文字始まりが推奨されているため、そもそもこんなことはしない。)
(さらに、推奨をぶっちぎってパッケージ名と同盟のクラスを継承してもコンパイルエラーにはならない。)


この問題の回避方法は簡単に思いつくところで以下の2つ。

回避策①:名前空間にクラス名で使われているような名前をつけない。
回避策②:親クラスのクラス名をフルパスでかく。

回避策①のソース

namespace WpfApplicationTest.src.OriginalUserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}



回避策②のソース

namespace WpfApplicationTest.src.UserControl {

///
/// ExtendsLabel.xaml の相互作用ロジック
///

public partial class ExtendsLabel : System.Windows.Controls.UserControl {
public ExtendsLabel () {
InitializeComponent();
}
}
}



大体、フレームワークだと②の方法が使われている。
これは、「DLL等で配布したクラスが継承される際にどんな名前空間に置かれるか保障できないため」かと思われる(憶測)。


だいぶ長くなりましたが、まとめると

「○○は'名前空間' ですが、'型' のように使用されています。」的なエラーメッセージが出たら、
「名前空間(フォルダ名)が継承しようとしている親クラスと同じになっていないか」を確認すること。
もしなっているなら、
回避策①:名前空間にクラス名で使われているような名前をつけない。
回避策②:親クラスのクラス名をフルパスでかく。
を行うこと。

原因は「C#は名前空間とクラス名を区別していない。」から。





以上!がんばった。




2013年4月9日火曜日

ブログはじめました!(3日坊主にならないことを祈る)

このブログは、管理人「らび爺」が28歳になった日に「そろそろブログでも始めるか。。。」と思いつきではじめたブログです。

内容は「趣味」・・・「ゲーム」「プログラミング」「映画」「備忘録」等の内容を書いていこうと思います。
(らび爺は好奇心旺盛な飽き性&気分屋なので、内容は随時変わります。)

駄文長文がザラザラ存在する予定です。



・・・とお堅い文章を初めに書いてみて、早速次の更新するかなやんでるけど、、、このブログの運命やいかに!?うふ♪(* ̄ー ̄)v