Words of the Day - Thursday March 19, 2009
1. I can assure you that I will make the new application. 2. Let go of my redundant emotions.
1. I can assure you that I will make the new application. 2. Let go of my redundant emotions.
よくGUIやWebアプリの簡単なサンプルソースなどは、UIとアプリケーションのロジックが同じクラスまたはメソッドに書かれている場合が多い。それはそのサンプルがある特定の機能や関数の紹介の為に簡潔に書いているのだが、仮にいざそのソースを元にアプリを作りこんで機能の追加を行っていくとUIとアプリのロジックは分離したほうが保守・拡張と共に行い易い。 下記のプログラムは1秒毎に数値をカウントし、それを2進数と10進数でGUI上のラベルに出力する機能をモデルとビューに分けている。すなわち、数値のカウントをするモデルと数値をUIに表示するビューに。(いくつかの言語ではGUIの部品としてタイマーがあるようだが。。)
以前デザインパターンの理解の確認がてら簡単なコードを書いた。リファクタリングの前後を省いているので初見ではパターンのメリットと適応基準が見えにくく、またサンプルのテーマ設定が良くなかったので少々説明し難い。今回のようなToyコードみたいなのはたまに書く。
文字列の分割プログラム。 入力: クラス名+<区切り文字>+メソッド名の文字列 出力: その文字列の分割結果が格納されたインスタンス(Namerクラス)。 文字列の形式が"<クラス名>#<メソッド名>"か"<クラス名>.<メソッド名>"によって、すなわち区切り文字によって分割処理のメソッドの内容が変わるので、その違いを派生クラスでオーバーライドして定義したメソッドで吸収しようというもの。 これによる利点はMain側が分割対象の文字列の形式を意識しなくてよいこと。単にNameFactory#getNamer()に渡すだけ。文字列の形式が2つの内のどちらで、どのクラスに処理を任せるかの処理はgetNamer()が行う。これによって、仮に文字列の形式を増やす場合に修正するのはgetNamer()のifブロック、追加するのは新しい派生クラス。
日時を扱うクラスはDateとGregorianCalendarがありますが、Sunは後者を推奨しているようです。実際GregorianCalendarのほうが扱いやすいです。下のサンプルは、現在時刻が指定した期間内か否かを判定するものです。
<%@page contentType="text/html" pageEncoding="UTF-8"%> <%@page import="java.util.*" %> <%! final int MONTH_OFFSET = 1; String showTime(Calendar cal) { String str; str = cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH) + MONTH_OFFSET) + "/" + cal.get(Calendar.DATE) + " " + cal.get(Calendar.HOUR) + ":" + cal.get(Calendar.MINUTE); return str; } boolean isPeriod(Calendar start, Calendar end) { Calendar cur = Calendar.getInstance(); return cur.after(start) && cur.before(end); } %> JSP Date Comparison
# JSP Date Comparison
<% // (year, month, date, hour, minute) monthの範囲は0-11で1月は0 Calendar startTime = new GregorianCalendar(2009, 2 - MONTH_OFFSET, 23, 21, 0); Calendar endTime = new GregorianCalendar(2009, 2 - MONTH_OFFSET, 23, 21, 10); out.println("開始時刻: " + showTime(startTime) + "
"); out.println("終了時刻: " + showTime(endTime) + "
"); if (isPeriod(startTime, endTime)) { out.println("現時刻は指定期間「内」"); } else { out.println("現時刻は指定期間「外」"); } %>
日時の比較はGregorianCalendar#after、beforeメソッド以外にint compareTo(Calendar cal)等もあります。 実際に使う際、期間を指定するGregorianCalendarのコンストラクタの引数データは他の入力から受け取るようにします。
本日の21:05に計ると…
JSP Date Comparison
開始時刻: 2009/2/23 9:0
終了時刻: 2009/2/23 9:10
現時刻は指定期間「内」
d_kamiさんに改良していただきました。ありがとうございます(^-^)
String showTime(Calendar cal) { Date date = cal.getTime(); SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm"); return format.format(date); } と書けばすっきりするよ、import java.text.SimpleDateFormatを忘れずに - SimpleDateFormat - マイペースなプログラミング日記
showTimeを修正して計りなおした実行結果は、
開始時刻: 2009/02/23 21:00
終了時刻: 2009/02/24 21:10
現時刻は指定期間「内」
確かに出力はyyyy/MM/dd HH:mmの形式になっていて見栄えも良いです。
JComponentはほとんど全てのSwing コンポーネントの基底クラスで、Graphicsオブジェクトも持っています。下記のソースは、そのGraphicsを用いて画面に直線を描画するものです。
package linecomp;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class LineComp extends JComponent {
public static void main(String[] args) {
Runnable myGUI = new Runnable() {
@Override
public void run() {
JFrame win = new JFrame("Line Component");
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insets ins = win.getInsets();
win.setSize(300 + ins.left + ins.right, 300 + ins.top + ins.bottom);
win.add(new LineComp());
win.setVisible(true);
}
};
SwingUtilities.invokeLater(myGUI); // 保留中のすべての AWT イベントが処理されたあとに発生
}
@Override
public void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawLine(0, 0, getWidth(), getHeight());
}
}
GUI部品の(再)描画レンダリングが発生した際、オーバーライドしたpaintComponent()内の手続きをEventQueueに登録しEDT(Event Dispatch Thread)が処理をします。標準のGUI部品をカスタマイズしたい場合などに使えます。その場合は予めsuper.paintComponent(g);でデフォルトのレンダリングを基底クラスに任せ、その後にカスタムの描画処理を書きます。
InsetとJFrame#setSizeを使わずにJComponent#setPreferredSizeとJFrame#packを使うようにした - 他のやり方 - マイペースなプログラミング日記
comp.setPreferredSize(new Dimension(300, 300));
win.add(comp);
win.pack();
確かにsetPreferredSizeでコンポーネントのサイズを直接指定したほうが今プログラムの文脈に沿っています。私のほうはコンポーネントでなくJFrameのサイズの指定ですから。また、オーバーライドしたpaintComponent()でgetWidth()やgetHeight()を二度使うのであれば、一度ローカル変数に格納することでオーバヘッドを下げるのも大切ですね。日頃からの習慣にしないと。 とても勉強になりました。ありがとうございます。
Windows版NetBeans6.5でソースをインポートまたはコミットする際に以下のようなエラーが発生する場合がある。
'.' is not a working copy Can't open file '.svn/entries': No such file or directory
これはNetBeansが使用するsvnクライアントがcygwinのものだった場合に生じるエラーのようだ。 未だcygwin環境のsvn以外のsvnをインストールしていない場合は下のアドレスからダウンロードする。 subversion: Subversion Packages その後、メニューバーの「ツール」→「オプション」から設定画面を開いて、「その他」タブ→「バージョン管理」画面のSubversion画面を開く。左にあるリストメニューからSubversionを選択し、最初の設定項目である_「SVN実行可能ファイルパス」_を設定すれば正常にインポート、コミットできるようになる。 ちなみに、cygwinのでなければ↑のsvnパッケージでなくともOK。
Twitterにその日の学習ログを残してみようかな。そして、その学習ログをWordPress のプラグインでこのブログに週に一回落とし込んで確認してみようかな。 学習ログの形式は例えば以下のようにします。 [word] <単語> : <日本語の意味> 例文は, [e.g.] <例文> : <日本語訳> 音読とかした場合は、 [<テキスト名(の略でもOK)>] <章番号1>, <章番号2>... : 音読-X回, オーバーラップ-Y回, シャドウイング-Z回 みたいに。 とりあえず1週間試してみます。その内飽きるだろうけれど。 https://twitter.com/yukun_ あと、遅くなりましたが、 あけましておめでとうございます。 本ブログ記事が貴方にとって有益な情報であれば幸いです。今年もよろしくお願いします。 昨年からぽつぽつとCSネタを書いてきましたが、今年は英語学習に力を入れるため昨年より頻度が落ちるかと思います。
今日、体育会系(卓球部)の人と朝食の話していたら「今日はTKGで済ませたよ」と。TKG? これは「(T)卵(K)かけ(G)ご飯」の略だそうです。いやーその定番メニューを頭3文字直す発想がおもしろい。なるほど「たまごかけごはん」より「TKG」の方が確かに言いやすいかも。となると「なっとうかけごはん」は「NKG」か。
設置環境はFedoraを想定。 注:ソースからインストールした場合や他の環境だと一部ファイルのパスが違うところがある。 機会があれば今後も少しずつ書き足し・修正していく。
起動
# /etc/rc.d/init.d/httpd start または、 # service httpd start
終了
# /etc/rc.d/init.d/httpd stop または、 # service httpd stop
再起動
# /etc/rc.d/init.d/httpd restart または、 # service httpd restart
自動起動に設定
# chkconfig httpd on
自動起動の確認(Run level 3:on)
# chkconfig --list httpd
設定の反映
# /etc/rc.d/init.d/httpd reload
ディレクトリの所有者の変更
# chown <ユーザ名>. /var/www/html/
ディレクトリをApache実行ユーザに変更
# chown -R apache:apache /var/www/html/cgi-bin/
設定ファイルhttpd.confのパス
/etc/httpd/conf/httpd.conf
外部設定ファイル*.confを置くパス
/etc/httpd/conf.d/*.conf ・起動時に読み込まれる ・AliasとDirectoryを合わせて用いる場合が多い
DocumentRoot
ルートディレクトリの設定 e.g. DocumentRoot "/var/www/html" で www.example.com/へのアクセスは/var/www/htmlのインデックスページとなる。
Alias
Alias <ドメイン以下のURLパス> <サーバ内のディレクトリパス> e.g. Alias /blog /var/www/blog の場合は、http://www.example.com/blog/にアクセスした際、サーバの/var/www/blog/内の既定のインデックスファイルが読み込まれる。
Directoryタグ
e.g.
<directory "/var/www/html">〜<directory>
属性にディレクトリパスを指定している。
.htaccessを許可する場合
AllowOverride All
IPアドレスによるアクセス制限
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
Allow from 192.168.1.0/24
↑はlocalhost、イントラネット以外からのアクセスを拒否
SSLRequireSSL # SSL経由のアクセス
AuthUserFile <認証するユーザリストのパス>
AuthGroupFile <パス>
AuthName "<ページ名>"
AuthType Basic # 認証タイプ
require valid-user
初回は # htpasswd -b -c <保存先> <ユーザ名> <パスワード> 二件目以降は既にファイルが作成されているので-cを抜く # htpasswd -b <保存先> <ユーザ名> <パスワード> ここで作成したファイルのパスを上のAuthUserFile項目に書く。
任意のアドレスのWebサイト[サービス]のネットワーク状況を検知するURLMonitorと、任意のサーバ+ポートに接続可能か否かを検知するSocketMonitorクラスの動作サンプルを下記に示します。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
applicationComplete="startup()">
<mx:Script>
<![CDATA[
import air.net.SocketMonitor
import air.net.URLMonitor;
import flash.net.URLRequest;
import flash.events.StatusEvent;
private var SERVER_URL:String = "http://www.yukun.info/";
private var SOCK_ADRR:String = "yukun.info";
private var PORT:int = 6667;
private var INTERVAL_TIME:int = 3000; // ms
private var serviceMonitor:URLMonitor = null;
private var socketMonitor:SocketMonitor = null;
private function startup():void {
var endpoint:URLRequest = new URLRequest(SERVER_URL);
serviceMonitor = new URLMonitor(endpoint);
serviceMonitor.addEventListener(StatusEvent.STATUS, onStatusEvent);
serviceMonitor.pollInterval = INTERVAL_TIME;
serviceMonitor.start();
socketMonitor = new SocketMonitor(SOCK_ADRR, PORT);
socketMonitor.addEventListener(StatusEvent.STATUS, onSocketStatusChange);
socketMonitor.pollInterval = INTERVAL_TIME;
socketMonitor.start();
}
// ネットワークサービスの状態の検知
private function onStatusEvent(e:StatusEvent):void {
var date:Date = new Date();
trace(date.toLocaleTimeString());
trace(SERVER_URL + "に" + (serviceMonitor.available ? "接続可" : "切断中"));
}
private function onSocketStatusChange(e:StatusEvent):void {
trace(SOCK_ADRR + "のポート" + PORT + "は" +
(socketMonitor.available ? "接続可" : "切断中"));
}
]]]]><![CDATA[>
</mx:Script>
</mx:WindowedApplication>
http://www.yukun.info/に接続可
yukun.infoのポート6667は切断中
URLMonitorはネットワーク状況を検知する為にサーバへGETリクエストを送出して、レスポンスのステイタスコードを確認して判断しているようです↓。