18. Why did they move over for elderly person in the train.
19. This program takes up so much memory resource.
サイト内検索
2012年2月 月 火 水 木 金 土 日 « 1月 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 -
最近の投稿
Sponsored Link
18. Why did they move over for elderly person in the train.
19. This program takes up so much memory resource.
12. That blog article combines prose with poetry.
13. The up-to-date patch of secrity came out last week.
14. Do you know the well-known fairy tale as a fable.
15. He feels the generation gap toward a contemporary.
16. I use next to nothing about this function.
17. At times I encounter the fabulose sculpture in the museum.
3. We are fair in terms of drawing a card at random in a sense.
4. He stood on leaning against the wall.
5. A girl passed by me giving off a subtle scent of powder smoke.
6. It reminded me of the awful case.
7. I was so beside myself that I’m soaked of sweat.
8. Ichiro is the mental pillar of Japan.
9. The candy that I receive tastes terrific.
10. Regardless of wearing a mask, this room stinks.
11. Do you know such perfume that includes the potential harmful effect that can scarcely tell fact from fiction.
ポツポツ使う場面が増えてきたので、備忘録代わりにまとめていこうかな(気が向いたときに)。
メニューバーからツール→マクロ→Visual Basic Editor(Alt+F11)をクリックするとエディタが起動します。最初は何もファイルが開かれていないと思うので、まず、メニューバーから挿入→標準モジュールをクリックして新規作成し、試しに以下のコードを打ち込んで実行してみます。
Sub helloWorld()
MsgBox "Hello, VBA"
End Sub
入力し終わったらメニューの実行→Sub/ユーザー フォームの実行(F5)をクリックするとスクリプトが実行されます。結果は下図のようになります。

ダイアログボックス内に文字列が表示されていますね。仮に下記のようにした場合は、
Sub helloWorld()
MsgBox "Hello, VBA"
MsgBox "Hello, Excel"
End Sub
一つ目の”Hello, VBA”のダイアログのOKを押した後、”Hello, Excel”のダイアログが表示されます。どうやらMsgBox関数はブロック関数みたい。
Sub varTest()
Dim num1 As Integer
Dim str1 As String
Dim num2 As Integer, str2 As String
num1 = 10
str1 = "文字列1"
MsgBox num1 & " " & str1
MsgBox num2 & " " & str2, vbInformation, "デバッグプリント"
End Sub
変数宣言の一般式は
Dim <変数名> As <型>
のようにDim~Asステートメントを用います。
また、MsgBox関数のvbinformationを指定することで情報メッセージアイコンを表示します。ちなみに、出力する複数の文字列の連結は「&」を用います。
Const <定数名> As <型> = <値>
変数宣言と似てますね。異なるところは、DimがConstに変わり、宣言と値の初期化を同時に行うことですかね。変数も値の初期化は可能ですが、それは任意です。
オブジェクトの参照を代入する際にはSetステートメントを使用します。以下のコードは1つ目のワークシート名を表示しています。
Sub objectTest()
Dim tmpSheet As Worksheet
Set tmpSheet = Worksheets(1)
MsgBox tmpSheet.Name, vbInformation
End Sub
Set <オブジェクト型変数> = <オブジェクト>
大抵ミスタイプです。Worksheets(1)と打つところをWorksheet(1)としてしまうとか。変数宣言のミスでもデフォルトでは「SubまたはFunctionが~」と出力されるので注意。
Dim <配列名>(<要素数>) As <型>
Sub objectTest()
Dim arr(3) As Integer
arr(0) = 99
MsgBox arr(0)
End Sub
ダイアログには99が表示されます。配列の添え字は0から数えますが、下記の文をモジュールの宣言セクションに書くことで1から数えられます。
Option Base 1
Option Base 1
Sub objectTest()
Dim arr(3) As Integer
arr(1) = 99
MsgBox arr(1)
End Sub
実行結果は同じく99です。
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の部品としてタイマーがあるようですが。。)
インスタンスの生成はコンストラクタで行うのがいいのですが、はしょっています。さて、これまでに何らかのフレームワークを使っていた方には上クラス図はMVCの説明図として見慣れているかもしれません。今回ModelとViewを繋ぐControllerの役割はCountListenerが担っています(下記コードではCountChangeEvent経由でModelインスタンスを渡すのみですが)。
ビュー側で自身のインスタンスをモデルに登録し(モデル.addCountListener(ビュー))、モデルのデータが更新された場合、モデル→ビューへイベントを送出。イベント内部にモデルのデータがあり、そのデータでビューがUIを更新します。イベントの発生順序等は下図のシーケンス図のようになります。
ビューを更新するイベントリスナーのメソッド(ここではcountChanged())で再度モデルのプロパティ変更メソッド(ここではsetCount())を用いると、再度イベント通知処理(notifyToListeners())が発生することで、無限ループになるので注意が必要です。
ビューを追加する際の手順は、ビューのインスタンスをモデルのリスナーに登録し(addCountListener())、ビュー自身がリスナーのメソッドを実装することで(countChanged())、モデルからのイベントを受け取ることが出来ます。
そういえば最近はIDEの方でバインド設定したり、ObservableList等があるのであまり意識することがなくなってきたなぁ。
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
class CountView extends JFrame implements CountListener{
private final JLabel binaryLabel = new JLabel("0");
private final JLabel decimalLabel = new JLabel("0");
private CountModel cModel = new CountModel(0);
public static void main(String[] args) {
new CountView();
}
public CountView() {
super("Counter");
Container c = getContentPane();
c.setLayout(new GridLayout(2, 2));
c.add(new JLabel(" 2進数:"));
c.add(binaryLabel);
c.add(new JLabel("10進数:"));
c.add(decimalLabel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cModel.addCountListener(this); // ModelにViewを登録
pack();
setVisible(true);
}
public void countChanged(CountChangeEvent e) {
if (e.getSource() == cModel) {
binaryLabel.setText(Integer.toString(cModel.getCount(), 2));
decimalLabel.setText(Integer.toString(cModel.getCount(), 10));
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* カウントするModel
*/
public class CountModel {
private int count;
private final List<CountListener> listeners = new ArrayList<CountListener>();
private Timer t = new Timer("Count Timer", false);
CountModel(int i) {
count = i;
t.scheduleAtFixedRate(new CountTime(), 0, 1000);
}
// Viewを登録
public void addCountListener(CountListener listener) {
listeners.add(listener);
}
public int getCount() {
return count;
}
public void setCount(int i) {
count = i;
notifyToListeners();
}
// Viewへの通知
private void notifyToListeners() {
for (CountListener listener : listeners) {
listener.countChanged(new CountChangeEvent(this));
}
}
class CountTime extends TimerTask {
@Override
public void run() {
setCount(getCount() + 1);
}
}
}
/**
* View側で実装する(Model側から呼び出し)
*/
public interface CountListener {
public void countChanged(CountChangeEvent e);
}
/**
* 通知内容を表すイベント(Modelが生成しViewが受け取る)
*/
public class CountChangeEvent {
private final CountModel source;
public CountChangeEvent(CountModel count) {
this.source = count;
}
public CountModel getSource() {
return source;
}
}
以前デザインパターンの理解の確認がてら簡単なコードを書いていたので投稿してみます。リファクタリングの前後を省いているので初見ではパターンのメリットと適応基準が見えにくく、またサンプルのテーマ設定が良くなかったのでイマイチ説明し難い(反省)。今回のようなToyコードみたいなのはたまに書くのですが、Blog記事としてまとめるのが手間で大抵HDDの片隅に眠ってしまうのですが、今後はとりあえず上げていこうかと思います。説明などは隙をみて書き足していく感じでまず投稿、みたいな。ただ、そればっかりだと後で自分が読んだときに分からなくなるので、ほどほどにしよう。
文字列の分割プログラム。
入力: クラス名+<区切り文字>+メソッド名の文字列
出力: その文字列の分割結果が格納されたインスタンス(Namerクラス)。
文字列の形式が”<クラス名>#<メソッド名>”か”<クラス名>.<メソッド名>”によって、すなわち区切り文字によって分割処理のメソッドの内容が変わるので、その違いを派生クラスでオーバーライドして定義したメソッドで吸収しようというもの。
これによる利点はMain側が分割対象の文字列の形式を意識しなくてよいこと。単にNameFactory#getNamer()に渡すだけ。文字列の形式が2つの内のどちらで、どのクラスに処理を任せるかの処理はgetNamer()が行う。これによって、仮に文字列の形式を増やす場合に修正するのはgetNamer()のifブロック、追加するのは新しい派生クラス。
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
NameFactory nameFactory = new NameFactory();
Namer namer;
namer = nameFactory.getNamer("String#indexOf()");
printName(namer);
namer = nameFactory.getNamer("ArrayList.get()");
printName(namer);
namer = nameFactory.getNamer("Thread#run()");
printName(namer);
}
private void printName(Namer namer) {
System.out.println("Class Name: " + namer.className);
System.out.println("Method Name: " + namer.methodName);
}
}
public class NameFactory {
// 区切り文字の種類によって、処理する派生クラスを決める
public Namer getNamer(String input) {
if (input.indexOf(".") > 0)
return new PeriodNamer(input);
else if (input.indexOf("#") > 0)
return new SharpNamer(input);
return null;
}
}
public class Namer {
protected String className;
protected String methodName;
public String getClassName() {
return className;
}
public String getMethodName() {
return methodName;
}
}
public class SharpNamer extends Namer {
// 「#」で名前を区切る
public SharpNamer(String str) {
int i = str.lastIndexOf("#");
if (i > 0) {
className = str.substring(0, i); // (beginIndex, endIndex)
methodName = str.substring(i + 1); // (beginIndex)
} else {
className = "";
methodName = str;
}
}
}
public class PeriodNamer extends Namer {
// 「.」で名前を区切る
public PeriodNamer(String str) {
int i = str.lastIndexOf(".");
if (i > 0) {
className = str.substring(0, i); // (beginIndex, endIndex)
methodName = str.substring(i + 1); // (beginIndex)
} else {
className = "";
methodName = str;
}
}
}
Class Name: String Method Name: indexOf() Class Name: ArrayList Method Name: get() Class Name: Thread Method Name: run()
書いた後ふと考えたのですが、これ100形式だと100派生クラスで、if-elseブロックもえらいことになるなぁ。こういう時、現時点では思考停止してしまうので、今月の課題。
今後はなるべく制作中のアプリの中での問題かそれに関わるもの、絡められるものを取り上げていきたい。
日時を扱うクラスはDateとGregorianCalendarがありますが、Sunは後者を推奨しているようです。実際GregorianCalendarのほうが扱いやすいです。下のサンプルは、現在時刻が指定した期間内か否かを判定するものです。
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@page import="java.util.*" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<%!
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);
}
%>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Date Comparison</title>
</head>
<body>
<h1>JSP Date Comparison</h1>
<%
// (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) + "<br />");
out.println("終了時刻: " + showTime(endTime) + "<br />");
if (isPeriod(startTime, endTime)) {
out.println("現時刻は指定期間「内」");
} else {
out.println("現時刻は指定期間「外」");
}
%>
</body>
</html>
日時の比較は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()を二度使うのであれば、一度ローカル変数に格納することでオーバヘッドを下げるのも大切ですね。日頃からの習慣にしないと。
とても勉強になりました。ありがとうございます。