追記(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コメント:
コメントを投稿