主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

WPF: ブックリーダーα版

                


13111202.png


発端:http://elicon.blog57.fc2.com/blog-entry-317.html
KindleアプリがいつまでもWindowsOSに対応しないことに触発されて、青空文庫にあるテキスト形式のファイル(XHTMLではないファイル)を縦書き表示できるものを作った。テキストファイルを真ん中のコントロールにドロップでファイルを開くようになっている。
自動しおり機能搭載。アプリケーション終了時のページを保持。再び同じファイルを開いたときに保持したページから再開。ただし直近20冊まで。
テスト済み環境:.NET Framework 4.0, Windows 7(64bit)

https://skydrive.live.com/redir?resid=14D4B360C466B0C5!230&authkey=!AF10e61RyOZL2rI
スポンサーサイト



WPF: ブックリーダーアプリちょくちょく開発中

                
 文章をきちんとしたレイアウトにするためには禁則処理をほどこさなければならない。行頭に点や丸などの句点がきてはいけないという規則だ。詳しくは禁則処理はWikipediaで。
http://ja.wikipedia.org/wiki/禁則処理

開発中のブックリーダに行頭の禁則処理を実装してみた。文章は青空文庫の『変身(カフカ)』から抜粋。
13111201.png

WPF: デスクトップブックリーダー事始め

                
 Kindleストアに読みたいマンガや新書が多数そろってきた。しかしいまだにKindleのアプリがWindowsに対応してこない。その理由として、縦書き対応が難しいからということがうわさされている。そんなに難しいのか? いやどうにかできるだろと思ったので、テキストを縦書き表示できるものを作ってみることにする。

 文章組みとフォントは手元にある文庫本を参考にして、17列36行程度で明朝にしようと考えた。だが読みづらさを感じたので行間や文字幅から考え直し、フォントもメイリオにした。まずはこの条件で文章をレンダリングしてみる。文章は青空文庫から、カフカの『変身』を持ってきた。
 縦書きは、一行をStackPanel要素一つとし、ここに一文字ずつテキストの入ったLabelを順次、子要素として追加していくことで実現した。
13111002.jpg
文字はわりといい感じに描画されたが、記号系がめちゃくちゃである。ハイフンやカッコ、句点など。

 ハイフンやカッコは反時計方向に90度回転させなければならないようだ。WPFにおける要素の回転は、要素の中心点でなく、要素の左上隅の点が中心となって回転が実行される。だから回転後には要素の表示位置がずれるため、表示位置の調整も必要になる。以下の例を参考にした。
http://social.msdn.microsoft.com/Forums/vstudio/en-US/a0d473fe-3235-4725-aa24-1ea9307752d3/how-to-rendertransform-in-code-behind-c?forum=wpf
 メイリオフォントでは文字幅が非固定なため、ハイフンのような小さい記号は回転させることによって、その小ささから一方向に寄せられてしまう。そして単純な方法ではこれをセンタリングすることができない。
13111002.png
こういったケースに該当する記号だけ固定幅のフォントを適用することで、センタリングの問題を回避した。

 ハイフンやカッコなどの記号に加え、丸や点の句点も違和感がある。これは要素を180°回転させればいい位置におさまりそうである。これもハイフン系と同様に回転と移動で調整をする。

 以上を踏まえてレンダリングを再度試みる。

13111001.png

あともう一歩。『っ』の描画位置が気持ち悪い。『っぁぃぅぇぉゃゅょ』あたりもまとめて描画位置の調整が必要そうだ。少しだけ右上へずらす。

13111003.png

難なく読める縦書きリーダーができ上がった。とりあえずWindowsでもやればできるようだ。このまま青空文庫リーダーでも作ってみるか。

BooとC#のちょっとした違い(おまけでJavaScriptも)

                
Booは静的型付け言語ながら、変数宣言がPythonと同様に”x = 0”とシンプルな式で行える。
C#では型を教えてやる必要がある。varを使ってもいいが。"int x = 0;"

クロージャを使う場合を考える。下記のように書くと、スコープの関係から匿名関数内から上位スコープにあるxが参照できるので、innerFuncの実行がxの値を書き換えてしまう。実行すると10が表示される。クロージャの中と外で変数名の重複があるとまずいということ。
import System

def Main():
x = 0

innerFunc = def():
x = 10

innerFunc()

print x

print "Press any key to continue . . . "
Console.ReadKey(true)


というわけで一句はさんで匿名関数の中の変数xを宣言する。こうすることで関数Mainのスコープにある変数xの値は0が保たれる。
import System

def Main():
x = 0

innerFunc = def():
x as int = 10

innerFunc()

print x

print "Press any key to continue . . . "
Console.ReadKey(true)


C#で上記にあるようなことをしようとすると、コンパイラが親切にエラーを出してくれる。「スコープ内に同じ名前の変数が使われてるから、その名前の変数は使わないで」
public static void Main(string[] args)
{
var x = 0;

Action innerFunc = delegate()
{
var x = 10;
};

innerFunc();

Console.WriteLine(x);

Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}


ちなみにJavaScriptでは実行可能。
function func()
{
var x = 0;

var innerFunc = function(){x = 10};

innerFunc();

alert(x);
}

func();

Boo: オブジェクトのシリアライズ

                
Pythonではpickleというモジュールが用意されていて、オブジェクトをバイナリデータとしてファイルに保存してまた読み込むことでオブジェクトの復元ができる。Booで同様のことをするにはどうしたらいいだろう。

.NET FrameworkでこれをやるにはBinaryFormatterがある。これをファイルストリームと組み合わせて使う。
import System
import System.IO
import System.Runtime.Serialization.Formatters.Binary


// Serialize
obj = {"FRA": "Camus", "GER": "Hesse", "US": "Golding"}
formatter = BinaryFormatter()
stream = FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None)
formatter.Serialize(stream, obj)
stream.Close()


// Deserialize
stream = FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read)
obj = formatter.Deserialize(stream) as Hash
stream.Close()

Console.WriteLine("FRA: {0}", obj["FRA"])
Console.WriteLine("GER: {0}", obj["GER"])
Console.WriteLine("US: {0}", obj["US"])

print "Press any key to continue . . . "
Console.ReadKey(true)


http://msdn.microsoft.com/ja-jp/library/ms973893.aspx#feedback
プロフィール

h

Author:h

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon