2011年11月28日月曜日

バスナビ

先月から作っているバスナビアプリをβテスト登録してみました
http://www.sakasama.com/wp7beta/index.php

今のところ東急バスにしか対応していません。一応他のバス会社にも対応できるようにと考えていますが、バス情報はバス会社がそれぞれ独自に公開しているので、まとまったデータを取得する事ができなそうです。
バス会社毎にアプリで対応させていくのは大変なので、今後対応バス会社が増やせるかどうか???です。誰か手伝ってくれるといいなと思って、外部データを登録できるようにしています





















最終的には東急バスのバス運行情報ページを表示するのですが、モバイル向けに最適化されたページでは無いのを何とかしたいなと思ってますが、今のところ解決できていません。



ヘッダのメタタグでmeta name="viewport" content="width=device-width"を設定するとこんな感じになるのですが、よそ様のページにタグを突っ込むなんてどうやればいいのやら...
上の画像はiframeで東急バスのページを埋め込んでます、これだとスクロール動作がぎこちなくなって操作性が悪くなってしまう




2011年11月20日日曜日

アラームとカメラを使うアプリ

「2011年11月11日11時11分11秒を見逃すな」というアプリを公開しました。

http://windowsphone.com/s?appid=d8719221-93e1-4cc0-be2f-efcf5b85c727

指定した時間にアラームが鳴る機能と日付の焼きこんだ写真が撮れる機能を合わせたアプリです。

参考にしたページ

高橋 忍のブログ : アプリケーション自身のスクリーンキャプチャ機能の実装ブリリアントなWP7 : カメラで撮影した画像を保存する 画像ファイルを端末内に保存する
CH3COOH(酢酸)の実験室 : 静止画撮影を行う
です。特に高橋忍さんのページはコードをほぼコピーしている箇所があって、シャッターを押した後のメッセージ内容がまったく同じままにしてしまっていました。ごめんなさい。見る人が見れば、コピペしただけだろーと突っ込まれるかもしれないので、ここで白状しておきます

時計の表示を更新する部分も誰かの記述を参考にしましたが、どこだったか思い出せません




起動画面、アラームの設定と、カメラの撮影ページへの移行ができます

撮影した写真。画像サイズや撮影モードを切り替えたりとかはできません!ただシャッターボタンを押すだけです

時計部分のコードとXAMLをのっけておきます。
時計はタイマーで更新してます。文字の縁取りをするために数ピクセルずらした黒文字を4方向分の4回レンダリングしてます。(こんなんでいいのか?)
カメラの撮影は参考にしたコードをほぼそのままで、普通に撮影します。
撮影完了したら、写真の画像をlayoytrootの背景に描き出して、スクリーンキャプチャします

ほんとにこんなんで良いのか?って気もしますが、以上です。ここまでは数時間でできました。

一番時間がかかったのは、日時設定画面を作る事とアイコン作る事です。アイコンはちょっと画像がデカすぎたようです...


public partial class ClockPage : PhoneApplicationPage
    {
        bool nowCapturering = false;
        PhotoCamera camera = null;
        public ClockPage()
        {
            InitializeComponent();


            CameraButtons.ShutterKeyPressed += new EventHandler(CameraButtons_ShutterKeyPressed);
            DispatcherTimer tmr = new DispatcherTimer();
            tmr.Interval = TimeSpan.FromSeconds(1);
            tmr.Tick += new EventHandler(tmr_Tick);
            tmr.Start();
        }

        void camera_CaptureThumbnailAvailable(object sender, ContentReadyEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("camera_CaptureThumbnailAvailable");
        }

        void camera_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("camera_CaptureImageAvailable");
            this.Dispatcher.BeginInvoke(delegate()
            {
                BitmapImage bmp = new BitmapImage();
                bmp.SetSource(e.ImageStream);
                CaptureBrush.ImageSource = bmp;
                TakeCapture();
                nowCapturering = false;
            });
        }

        void camera_CaptureCompleted(object sender, CameraOperationCompletedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("camera_CaptureCompleted");
        }

        void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
        {
            nowCapturering = true;
            camera.CaptureImage();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            camera = new PhotoCamera(CameraType.Primary);
            //camera.CaptureThumbnailAvailable += new EventHandler<contentreadyeventargs&rt;(camera_CaptureThumbnailAvailable);
            camera.CaptureImageAvailable += new EventHandler<contentreadyeventargs&rt;(camera_CaptureImageAvailable);
            camera.CaptureCompleted += new EventHandler<cameraoperationcompletedeventargs&rt;(camera_CaptureCompleted);
            nowCapturering = false;
            PreviewBrush.SetSource(camera);
            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
        {
            if (camera != null)
            {
                camera.Dispose();
                camera.CaptureImageAvailable -= camera_CaptureImageAvailable;
                camera.CaptureCompleted -= camera_CaptureCompleted;
                camera = null;
            }
            base.OnNavigatingFrom(e);
        }

        void tmr_Tick(object sender, EventArgs e)
        {
            if (!nowCapturering)
            {
                textBlock1.Text = DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss");
            }
        }

        private void TakeCapture()
        {
            WriteableBitmap bitmap = new WriteableBitmap(this.LayoutRoot, null);
            MemoryStream stream = new MemoryStream();

            bitmap.SaveJpeg(stream, bitmap.PixelWidth, bitmap.PixelHeight, 0, 80);

            using (MediaLibrary medialib = new MediaLibrary())
            {
                Picture pic = medialib.SavePictureToCameraRoll(DateTime.Now.ToString("yyMMddHHmmss"), stream.ToArray());
            }
            
            MessageBox.Show("Saved");
        }


xaml
<phone:PhoneApplicationPage 
    x:Class="Serial11.ClockPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Landscape" Orientation="Landscape"
    mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="728"
    Language="ja-JP"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
    <Grid x:Name="LayoutRoot">
        <Grid.Background>
            <ImageBrush x:Name="CaptureBrush"/>
        </Grid.Background>
        <Grid x:Name="ContentPanel">
            <Rectangle x:Name="PreviewRectangle">
                <Rectangle.Fill>
                    <VideoBrush x:Name="PreviewBrush"/>
                </Rectangle.Fill>
            </Rectangle>
            <StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
                <Grid Margin="0,0,10,0">
                    <TextBlock x:Name="textBlock3" Text="{Binding Text, ElementName=textBlock1}" VerticalAlignment="Top" FontFamily="Segoe WP Black" FontSize="48" Margin="0" HorizontalAlignment="Right" RenderTransformOrigin="0.5,0.5" Foreground="Black">
                        <TextBlock.RenderTransform>
                            <CompositeTransform TranslateX="3" TranslateY="3"/>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                    <TextBlock x:Name="textBlock4" Text="{Binding Text, ElementName=textBlock1}" VerticalAlignment="Top" FontFamily="Segoe WP Black" FontSize="48" Margin="0" Foreground="Black" HorizontalAlignment="Right" RenderTransformOrigin="0.5,0.5" >
                        <TextBlock.RenderTransform>
                            <CompositeTransform TranslateX="-3" TranslateY="3"/>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                    <TextBlock x:Name="textBlock5" Text="{Binding Text, ElementName=textBlock1}" VerticalAlignment="Top" FontFamily="Segoe WP Black" FontSize="48" Margin="0" Foreground="Black" HorizontalAlignment="Right" RenderTransformOrigin="0.5,0.5" >
                        <TextBlock.RenderTransform>
                            <CompositeTransform TranslateX="-3" TranslateY="-3"/>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                    <TextBlock x:Name="textBlock6" Text="{Binding Text, ElementName=textBlock1}" VerticalAlignment="Top" FontFamily="Segoe WP Black" FontSize="48" Margin="0" Foreground="Black" HorizontalAlignment="Right" RenderTransformOrigin="0.5,0.5" >
                        <TextBlock.RenderTransform>
                            <CompositeTransform TranslateX="3" TranslateY="-3"/>
                        </TextBlock.RenderTransform>
                    </TextBlock>
                    <TextBlock x:Name="textBlock1" Text="----/--/-- --:--:--" VerticalAlignment="Top" FontFamily="Segoe WP Black" FontSize="48" Margin="0" Foreground="Yellow" HorizontalAlignment="Right" />
                </Grid>
            </StackPanel>
        </Grid>
    </Grid>
 
    <!--ApplicationBar の使用法を示すサンプル コード-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

2011年11月11日金曜日

2011年11月11日11時11分11秒を見逃すな

serial11.xap

windows phon7 用に"2011年11月11日11時11分11秒を見逃すな"というアプリを思いつきで作りました。

思いついたのが11月10日の朝だったので、マーケットへの審査に提出は全然間に合わないので、xapファイルだけアップしてみます。

これを書いてる時間も既に11月11日を回っているので、ちょーーと遅すぎですが.....


ベータ版なので不具合があったらごめんなさい、といってもダウンロードする人がいるか?という気もします



アプリを起動して、2011年11月11日11時11分11秒の5分前にアラームを登録することができて、日付と時間入りの決定的瞬間の写真を撮ることが出来るアプリです。

IS12Tでしか試してないです

当然11時11分の5分前を過ぎるとアラーム登録できないです。たぶん例外吐いて落ちると思います。



2011年11月8日火曜日

コマンドラインで配置配線のススメ

XILINXのFPGA合成ツールの話です。

ここではise12を使う事を前提に記事を書いてます。
すでにise13.3がリリースされている今なぜise12なの?と思うかもしれませんが、諸事情でise12を使い続けているから仕方がないのです。

これから書く内容はise13ではPlanAhedが使えるツールに進化していて、もう必要ないよって事かもしれませんが、僕の個人的な予想ではise13でもまだコマンドラインを使い続ける必要があるかなと思ってます

2011年11月7日月曜日

バスナビアプリ

iphoneやandroidにはバス接近情報表示するアプリがあるのですが、WindowsPhone7には今のところ無くて、これから先に誰かが作ってくれる可能性は低そうです。
(ローカル路線毎にはできるかもしれませんが、東急バスをサポートするアプリとなるとまず自分で作らないとだめかな)
なので、東急バスのバスナビページをwp7で見るアプリを作ってます

折角なので、東急バス以外のバス会社のページも表示できるような作りにしようと目論んで、バス会社選択ページがあります。
が、バス情報のページは各社ばらばらで、まとまった情報を得る手段はなさそうなので他社に対応できるかどうか怪しいです。

というか東急バスのページだけでもう気力がなくなりました。あぁぁ


アプリではwebページを取得して内容を解析してリストボックスに表示するような事をします。
htmlを解析する必要があるのですが、デバイスで解析させないでyqlを使ってみました。
リストを取得するのにいちいちyql経由でアクセスするのでちょっと動作が遅いですし、yql使ってアプリにしちゃって良いものかどうか?いまいちわかりません

yql使う利点は他の人が勝手にyqlのコードを書いて別会社のサービスを追加したりとか出来そうなところです。そのためにはバス会社情報のデータもweb上に置く必要があって、ホストを用意しなきゃいけないのですが

できたらβ版配布を試してみたいなと思ってますが、ローカルすぎて需要は0かも



ノッテちゃんのアイコン画像はまずいかな...

サービスの選択

路線一覧から選択する

これが最終的にたどり着くバス接近情報ページです。ここをスクレイピングしてGUI化する気力は残ってませんでした。でももう少しデバイスにフィットした表示したいんだけど、どうすれば良いのやら?

駅から路線を選択する

駅から路線選択で渋谷駅を選択したときの画面。ここもwebページそのまま。うまくスクレイピングできなかった。

バス停名称を入力してバス停を選択する画面

バス停を選択したときの画面

画面デザインをなんとかしないといけないですねー

2011年11月2日水曜日

QRコードメーカ


WindowsPhone7の標準で組み込まれているQRコードリーダは良くできてるなー、自分のアプリから使用するにはどうすればいいんだろう...とうい疑問から始まりましたが、ひとまず自分のアプリからQRコードを表示する方法を試してみました。

QRコード表示して何に使うか!は夢が広がりますが、やっぱりリーダも使えないと中途半端かな。
まぁいずれ解決されるでしょう。それはさておき


QRコードを表示するアプリを作る
他力本願なアプローチでなるべく簡単にします。
まずプロジェクトを作って、MainPageに

  1. TextBox
  2. Button
  3. Image

を配置します。 Image のSourceに以下のURLを指定します

http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=Shift_JIS&chl=http://nextgate.blogspot.com/
XAMLは下記のようになりました
<!--ContentPanel - 追加コンテンツをここに入力します-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Grid.RowSpan="2">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="0.817*"/>
    </Grid.RowDefinitions>
    <StackPanel>
        <TextBox x:Name="textBox1" Text="" AcceptsReturn="True" InputScope="Url" TextWrapping="Wrap" />
        <Button Content="作成" Click="Button_Click" />
    </StackPanel>
    <Image Margin="0" x:Name="image1" Stretch="Fill" d:LayoutOverrides="GridBox" Grid.Row="1" HorizontalAlignment="Center" Width="300" Height="300" Source="http://chart.apis.google.com/chart?chs=300x300&amp;cht=qr&amp;choe=Shift_JIS&amp;chl=http%3A%2F%2Fnextgate.blogspot.com%2F" />
</Grid>
という感じでUrlを指定します。


こんな感じになります。
なんかもうQRコードが表示されてて、完成したみたいです。

これだけだと使い道がないので、ユーザーが指定した文字列のQRコードを表示するようにしてみます。

”作成”ボタンを押したときのコードを記述します。ボタンをダブルクリックして以下のようにコードを追加します

private void Button_Click(object sender, RoutedEventArgs e)
{
    string url_base = "http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=Shift_JIS&chl={0}";

    string url = string.Format(url_base, Uri.EscapeDataString(textBox1.Text));

    image1.Source = new BitmapImage(new Uri(string.Format(url_base, textBox1.Text), UriKind.Absolute));

}

GoogleChart APIにテキストボックスの文字列を追加したURLを作成して、Imageのソースとして設定するコードです

これで完成





プロジェクトファイル QRMaker.zip


2011年9月25日日曜日

GuGuReader デモ動画を作った

紹介用にデモ動画を作ったので載せておきます。
エミュレータで実行したときの動作をビデオにしました。
だいたいの感じが判るかな?


 


マーケットプレースでの評価に画面の固定の仕方が判らないと指摘があったけど、答える方法がわからないのでココに書いておきます。

記事を開いているときに、画面を固定したいときはページのどこかを長押しします。
画面右下にピンマークがでたら固定状態です。(動画の1:20秒あたり)
ピンマークをクリックすると固定を解除します

2011年9月21日水曜日

GuGuReader Ver1.1公開しました

WindowsPhone7用のGoogleReaderアプリのGuGuReaderがMarketPlaceにてダウンロードできるようになりました。
ほんとうはWindowsMobile用に作ったアプリと同じ名前にするつもりだったのですが、UltimateGuitarReaderrとやらに先を越されてしまいこの名前になりました。

http://windowsphone.com/s?appid=178a6e59-0f4d-46a2-bf2e-af05b8abecb1

使用するにはGoogleReaderのアカウントが必要です。GuGuReaderでサイトの購読追加は出来ないので
PCの補助的な感じで、通勤途中とかに記事を流し読みするような使い方を想定しています。

 気になる記事はスターを付けて後で読むか、共有ボタンでtwitter,facebookに投稿することができます

今のところオフライン動作には対応していません。
未読の記事のみ表示します

簡単ですが画面の紹介



フォルダ画面
記事はフォルダごとにまとめて読みます



オプション画面
GoogleReaderのアカウントログイン、記事の更新等

記事一覧
縦に記事をスクロール、横にスクロールでメニューを表示します。
フォルダタイトルをクリックしてサイトの絞り込みができます


記事画面
タイトルリンクをクリックすると元記事、mobile+リンクをクリックするとモバイル向けに変換した元記事を開くことができます。左右に画面をフリックして次の記事に進めることができます。画面を長押しすると記事を固定できます。


サイト選択
フォルダ内でサイト別に記事を絞り込んで表示できます。
このメニューは記事一覧中に左から右にフリックすると表示できます。
逆にフリックするか戻るボタンでメニューを閉じることができます

メニュー
今のところ全部既読にする、記事の更新があります
このメニューは記事一覧中に右から左にフリックすると表示できます
逆にフリックするか戻るボタンでメニューを閉じることができます

2011年9月6日火曜日

ShareLinkTaskを試してみる

WindowsPhone7ではプログラムから簡単にFacebookやtwitterにメッセージを投稿するしくみが用意されています。
具体的には ShareStatusTask や ShareLinkTask を使用するようです。詳しくはWP7アプリ開発者ならお馴染みのCH3COOHさんのページShareStatusTaskを使ってステータスを共有するShareLinkTaskを使ってリンクを共有するに紹介されています。

さっそく試してみることにします。

という テストの為のエントリー

2011年9月4日日曜日

WindowsPhone7多言語対応アプリ申請までのメモ

今日やっとこさWindowsPhone7アプリを申請しました。
もともとMango以前から開発していたのでアプリの言語設定は英語でしたが、日本で発表するからにはマーケットには日本語で説明を書きたい。ついでだから世界中にもアプリを公開したい、アプリの説明は英語にしたい。といったところで一寸つまずいたのでメモしておきます。

まず、申請してみたわかったのですが、言語設定を英語で作成したアプリにはマーケット上で英語の紹介文しかかけない。日本語で作った場合は日本語しかかけない。言語の設定はアップロードしたアプリファイルから自動的に決定される。つまり両言語同時に申請するにはアプリを多言語対応で作る必要がある?っぽい。

アプリケーション自体は元々英語表記で作っているし、メッセージなどを特に日本語化する必要も感じられなかったのですが、とにかく多言語対応という体裁を作ることにします。

まずはお試しでテストアプリを作りました
多言語対応の仕方はここに書いてあるので、その通りにやってみます
http://msdn.microsoft.com/en-us/library/ff637520(v=vs.92).aspx


まずアプリのプロジェクトを作成


MultLangPhoneApp としました。


プラットフォームは当然 OS 7.1 です
プロジェクトを作成したら、ソリューションエクスプローラから追加→新しい項目して新規リソースファイル追加します





アセンブリリソースファイルを選択してAppResource.resxとします。これがデフォルト言語のリソースファイルになります


今度は日本語用のリソースファイルを同じ手順で作成します。リソースファイル名は AppResource.ja-JP.resx とします。



それぞれ作成したリソースファイルにメッセージ文字列を追加します。
ここではアプリケーションのひな形で作成されたアプリ画面をマルチ言語対応化することにします



AppResouce.resx にデフォルト言語(英語)の文字列を追加します
TitleNameとPageName文字列を追加しました



AppResouce.ja-JP.resx に日本語の文字列を追加します
英語の時と同じ文字列名で日本語文字列を追加しました



次にニュートラル言語設定を日本語から英語に変えます




アプリケーションの設定でアセンブリ情報→ニュートラル言語を英語(米国)にしておきます。ニュートラル言語を英語にしておくと、例えばフランス語設定の端末にインストールしたときに仏語のリソースを作っていない場合に英語リソースが使われるので、不用意に日本語文字列を表示して文字化けしまうことが防げると思います




HowToページの解説にあったので、よくわからないけどとりあえず .csproj ファイルにja-JP;en-USを追記しておきました。これ必要なのかな....





HowToページ通りにApp.xaml.csに LocalizedStringクラスを作りました。このクラスを経由してApplicationPageのxamlから直接リソースをbindするのだと思います。



App.xamlに Application.Resoucesを追加します。これでアプリケーションページ作成画面からローカルリソースとしてリソースファイルをbind出来るようになります。
HowToページではxmlns:local ="clr-namespace:GlobalizationSample" 記述がいっしょくたに書いてあったけど、コンパイルしたらエラーが出たので の中に移動しました。
このあたりの決まり事がいまいち理解できていない



MainPage.xamlを編集してGUI画面を多言語対応します


編集前の状態ではこんな感じです。マイアプリケーションとページ名をリソースファイルから指定した文字列に置き換えするようにします



ApplicationTitleのTextにbindを指定します。StaticResourceにこれまで頑張って追加したLocalizedStringsクラスが見えています。ソースに指定して、続けてパスを指定します



パスはTitleNameです
同様にPageTitleもバインドします

パスはPageNameです

XAMLはこんな感じで Binding になっています


以上で多言語対応のアプリが完成です!!
こんな感じで画面の表示文字列をリソースから指定する事で、マルチランゲージ対応ができます。ちょっと手順が多くてめんどくさいです


ビルドして表示が端末の言語設定で変わることを確認します。エミュレータで実行しました




エミュレータは日本語なので日本語メッセージが表示されています
エミュレータの言語設定を英語に変更します



変更後、エミュレータのOSがリブートして英語環境になりました


アプリはばっちり英語表示になっています。




テストサンプルアプリが完成したので、申請画面で英語と日本語の説明が入力できることを確認してみます。





パソコンでAppHUBを開いて新しいアプリを申請します




作ったアプリをアップロードします。とりあえずプライベートベータテストです。





詳細に英語と日本語の記入が出来るようになっています。説明文から画像ファイルまで英語用と日本語用を別々にしてすることができます