追記(2008.9.6) : ダイエット表を作成するには → http://4diet.appspot.com/
「Google App Engine でダイエット表の作成 (3)」の続き。前回は、実際にダイエット表を作成するクラスである DietTable を作成した。今回は、これをテンプレートから呼出し、ダイエット表を生成する部分、そして最初の設定画面、画面遷移を扱うコントローラ ( webapp.RequestHandler のサブクラス ) を作成して完成。実際には、この部分から作りはじめているのだけれど ^^;
ダイエット表を生成するテンプレート
まずは、DietTable クラスをテンプレートで呼出している部分。シンプルに、
{{dietTable.toHtml}}
としているだけ。そして、このテンプレートにおいて、 DietTable クラスで設定した CSS のクラス指定に対して、CSS を設定している。 CSS における背景の色をプリンタで印刷する場合、デフォルトでは印刷されないのでブラウザの設定が必要。 (cf. Firefox, IE で背景色も印刷する )
diet_table.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional/EN"> <html> <head> <title>ダイエット表</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!-- Diet.py の Diet.DietTable#_addCssToHtmlTable() で設定したものに対応 --> <style type="text/css"> <!-- table { border-collapse: collapse; width: 175mm; height: 240mm; border-color: #000; } table, td { border: solid 1px; text-align: center; } td { height: 4mm; font-size: x-small; } .sunday{ background-color: #FFEEFD; } .saturday{ background-color: #EEF2FF; } .x_axis{ border-top: solid 3px; width:2em;} .y_axis{ border-right: solid 3px; } .x_axis_05 { border-top: dotted 2px; width:2em;} .x_axis_1 { border-top: solid 2px; width:2em;} .y_axis_10 { border-right: solid 2px; } .y_axis_05 { border-right: dotted 2px; } .target , .weightNow { background-color: #ffc; } h1 { color: #000; text-align: center; } .forPrint { text-align: center; } @media print { .forPrint { display: none; } } --> </style> </head> <body> <p class="forPrint">表の中の色を印刷するには <a href="http://jutememo.blogspot.com/2008/08/firefox_23.html#ie"> こちら</a>の説明を参考にしてください。 (Firefox の場合は <a href="http://jutememo.blogspot.com/2008/08/firefox_23.html#firefox"> こちら</a>。) </p> <h1>{{dietTable.year}} / {{dietTable.month}}</h1> {{dietTable.toHtml}} </body> </html>
最初に表示される設定画面
上記のダイエット表を出力するページや設定画面は、当然ながら最初にデザインを無視して作っている。ここでやっと設定画面をデザインすることにした。デザインするのに使ったのは Inkscape 。絵心はないので適当にシンプルなものを作った。 ^^; 以前に少しだけ使ったときのことを参考に。
とりあえず、何かスリムな感じがするようなイメージを… (@_@;)
絵が描けたら、今度はフォームを送信する部分を、表示内容に応じて長さが変化するように設定しなければならない。入力に不備があった場合、エラーメッセージを表示するためだ。作成ボタンを含んでいる影のある四角の部分を切取り、 Gimp で縁を拡大して、CSS で指定して伸縮できるように画像を抜き出した。 (cf. CSS と JavaScript で伸縮する領域を作成 )
HTML のファイルは、フォームの部分だけ抽出して別ファイルとした。
ソースコード
setting_page.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional/EN"> <html> <head> <title>表の設定ページ | 計るだけダイエット</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript"> <!-- /* このページが読み込まれたときに呼出される関数 */ function setup(){ resizeContent(); } /* ウィンドウをリサイズしたときに呼出される関数 * id が topLeft の要素の幅を広げる */ function resizeContent(){ var topRightDiv = document.getElementById("topRightCorner"); contentDiv = document.getElementById("topLeft"); contentDiv.style.width = topRightDiv.offsetWidth + 11 + "px"; } /* 入力された「現在の体重」に応じて「目標体重」を設定する */ function setTargetValue(){ var weight = parseFloat(document.forms["createTable"].weight.value) if (!isNaN(weight)){ document.forms["createTable"].target.value = weight - getTargetValue(); } } /* 設定できる目標体重の上限の 3/4 の値を返す */ function getTargetValue(){ return parseFloat( document.getElementById( "intervalLimit").firstChild.nodeValue) * 3 / 4 } //--> </script> <style type="text/css"> <!-- body{ background: #ffffff url("/img/title.png") top center no-repeat; } h1{ display: none; } .error{ color: red; margin-bottom: 10px; } #content { margin: 300px auto 0px; text-align: center; } #input { margin: 0px auto; width: 450px; } #input table{ text-align: left; margin: 0px auto; } .small { font-size: small } #createBtn{ background: url('/img/createBtn.png'); width: 338px; height: 114px; border: none; cursor: pointer; } #createBtn:hover{ background: url('/img/createBtnActivated.png'); border: none; } /*--------------------------------------------------------------- * 影 */ /* 右側の縦の影のライン */ #rightLine{ position: relative; background: transparent url("/img/rightLine.png") right repeat-y; } /* 右上の角の影 */ #topRightCorner{ position: relative; background: transparent url("/img/topRightCorner.png") top right no-repeat; } /* 右下の角の影 */ #bottomRightCorner{ position: relative; top: 6px; background: transparent url("/img/bottomRightCorner.png") bottom right no-repeat; } /* 下の横の影のライン */ #bottomLine{ position: relative; left: -11px; background: transparent url("/img/bottomLine.png") bottom repeat-x; } /* 左下の角の影 */ #bottomLeftCorner{ position: relative; left: -11px; background: transparent url("/img/bottomLeftCorner.png") bottom left no-repeat; } /* 背景となる色を指定する領域。 * リサイズにより、JavaScript でこの領域の幅を変更する。 */ #topLeft{ position: relative; background-color: #fff; top: -6px; } /* 文字を表示する領域 */ #content2{ position: relative; padding: 10px 0px; } /* --------------------------- */ #bottom_ad{ text-align: center; margin: 30px auto 0px; } --> </style> </head> <body onresize="resizeContent()" onload="setup()"> <h1>計るだけダイエットのための表を作成</h1> <div id="content"> <p>以下の項目を半角数字で入力してください。</p> <!-- ダイエットの情報を設定したときのエラー表示 --> <div id="input"> <div id="rightLine"> <div id="topRightCorner"> <div id="bottomRightCorner"> <div id="bottomLine"> <div id="bottomLeftCorner"> <div id="topLeft"> <div id="content2"> {%include "setting_form.htm" %} </div><!-- end content --> </div> </div> </div> </div> </div> </div> </div><!-- end input --> </div><!-- end content --> </body> </html>
現在の体重を入力すると、設定できる上限の 3/4 の値が「目標体重」に自動的に入力されるように JavaScript で設定した。 (cf. JavaScript でキー入力に応じて HTML の要素の値とスタイルを変化させる )
setting_form.html
<div class="error"> {% if errors %} {% for error in errors %} {{error}}<br /> {% endfor %} {% endif %} </div><!-- end error --> <form name="createTable" action="/createTable" method="post"> <table> <tr> <td>年 / 月</td> <td> <input type="text" name="year" value="{{diet.year}}" maxlength="4" /> / <input type="text" name="month" value="{{diet.month}}" maxlength="2" /> </td> </tr> <tr> <td>現在の体重</td> <td><input type="text" name="weight" value="{{diet.weight}}" onkeyup="setTargetValue()" /></td> </tr> <tr> <td>目標体重</td> <td> <input type="text" name="target" value="{{diet.target}}" /> {% if targetLimit %} <span class="error"> {{targetLimit}} より小さい値は設定できません。 </span> {% endif %} </td> </tr> </table> <p><input id="createBtn" type="submit" value=""></p> </form> <p class="small"> ※「目標体重」は「現在の体重」より -<span id="intervalLimit">{{ dt.intervalLimit }}</span> kg 以内に設定してください。 </p>
設定ファイル
背景となる画像を Google App Engine で参照できるように設定が必要となる。 (cf. Google App Engine で画像を扱うには )
app.yaml
application: 4diet version: 1 runtime: python api_version: 1 handlers: - url: /img static_dir: img - url: /.* script: dietsetting.py
コントローラ
最後になってしまったけれど、コントローラの部分。webapp.RequestHandler のサブクラス。
dietsetting.py
import os import wsgiref.handlers from google.appengine.ext.webapp import template from google.appengine.ext import webapp import Diet import logging class SettingPage(webapp.RequestHandler): """ 設定画面を表示する """ def get(self): moveTo(self.response, 'setting_page.html', { "dt" : Diet.DietTable(), "diet" : Diet.Diet().setDefaultSetting() }) class TablePage(webapp.RequestHandler): """ ダイエット表を作成する """ def post(self): diet = Diet.Diet(self.request.get("weight"), self.request.get("target"), self.request.get("year"), self.request.get("month")) dt = Diet.DietTable() dt.setDiet(diet) try: # 入力された値を検証する diet.validate() # ダイエット表を作成する dt.createHtml() moveTo(self.response, 'diet_table.html', {'dietTable' : dt}) except Diet.DietValErr, e: template_values = { 'errors' : e.errorMessages, # エラーメッセージ 'targetLimit' : e.targetLowerLimit, # 目標体重の下限 'diet' : diet, # ダイエット情報 'dt' : dt } # ダイエット表 moveTo(self.response, 'setting_page.html', template_values) def moveTo(response, tmpl, templateValues={}): u""" 画面遷移 """ path = os.path.join(os.path.dirname(__file__), tmpl) response.out.write(template.render(path, templateValues)) def main(): # ログの設定 logging.getLogger().setLevel(logging.DEBUG) # URL と対応するクラス application = webapp.WSGIApplication( [('/', SettingPage), # 設定 ('/createTable', TablePage)], # ダイエット表 debug=True) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main()
うーん、エラー処理が何か今一 … (+_+)
アップロード
アプリケーションを登録後、作成したファイルをアップロードした。diet フォルダの中に作成していたので、コマンドラインより、
appcfg.py update diet/
0コメント:
コメントを投稿