- PR -

描画位置をずらす

投稿者投稿内容
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-06-20 11:21
田村ともうします

スプレッドシート風のアプリを作っています。

(0, 0)の位置を原点として、以下の様に同じ位置に描画する場合は
問題ないのですが、

public void paint(Graphics inGra) {
Rectangle aBounds = inGra.getClipBounds();

// 内容に変更がある場合、変更後、変更箇所のみを再描画する
if (mModel.isModified()) {
Point[] aPos = mModel.lastModified();

for (int i = 0; i < aPos.length; ++i) {
mRenderer.render(aPos[i].x, aPos[i].y,
mModel.getCurStateAt(aPos[i].x, aPos[i].y));
}

aBounds = getClipBounds();
}

// off screen imageを取りだし、転送
inGra.drawImage(
mRenderer.getImage(),
aBounds.x, aBounds.y, aBounds.x + aBounds.width,
aBounds.y + aBounds.height,
aBounds.x, aBounds.y, aBounds.x + aBounds.width,
aBounds.y + aBounds.height,
this
);

mModel.flush();
}

指定した量だけずらして描画しようとすると、別のセルを選択したとき
画像が消えたり、表示位置がずれたりします

java.awt.Insets aInsets = getInsets();

// off screen imageを取りだし、転送
inGra.drawImage(
mRenderer.getImage(),
aBounds.x+aInsets.left, aBounds.y+aInsets.top,
aBounds.x + aBounds.width+aInsets.left,
aBounds.y+aInsets.top + aBounds.height,
aBounds.x, aBounds.y, aBounds.x + aBounds.width,
aBounds.y + aBounds.height,
this
);

Graphicsの原点をずらしたり、offscreen imageの原点をずらしたりも
しましたが、思うような結果が得られません。

指定した量だけ、位置をずらして描画するためには、どの様にすればよ
いでしょうか。

以上、よろしくお願いします。

OS : windows 98se
SDK : J2SDK 1.4.0_1
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2003-06-20 23:19
状況にもよるのですが、グラフィクスコンテキストの原点をずらして描画した場合、その後元にもどしたらうまくいかないでしょうか?
コード:
   g.translate(x, y);
   component.paint(g);
   g.translate(-x, -y);



# あと、スプレッドシートやるなら,javax.swing.JTable 使うっていう選択肢は
# だめでしょうか?
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-06-22 08:23
回答ありがとうございます。

g.translate(x, y);
component.paint(g);
g.translate(-x, -y);

のように原点をずらした場合、全画面の再描画のときは問題ないのですが、
マウスクリック後のクリック位置の再描画のとき、
画像がずれてしまうのです。

java.awt.Canvasから継承していることも描画がずれることに起因しているのでしょうか

# あと、スプレッドシートやるなら,javax.swing.JTable 使うっていう選択肢は
# だめでしょうか?

javax.swing.JTableほどの高機能は必要としていないので....
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-06-23 13:19
unibon です。こんにちわ。

引用:

かずくんさんの書き込み (2003-06-20 11:21) より:

// 内容に変更がある場合、変更後、変更箇所のみを再描画する
if (mModel.isModified()) {

}

mModel.flush();



あまり良くは分からないので以下は推測も混じりますが、疑問に思う点としては、
paint メソッドの内部でモデル(mModel)の状態を flush メソッドにより、
おそらく変えてしまっているように見えますが、それが一因のように思います。
paint メソッドは、ウィンドウシステムの都合でいつなんどき呼ばれるかどうかは分からない、
というスタンスで処理を書くべきです。
ちなみに mModel とはなにか汎用的な型でしょうか。それとも独自のものでしょうか。

あと、ズレるという現象には一般に、
(drawImage における)ソース側がズレるのとデスティネーション側がズレるのとの、
2通りありえますが、どちらでしょうか。
英-Ran
ベテラン
会議室デビュー日: 2002/06/12
投稿数: 55
投稿日時: 2003-06-23 13:45
Graphics#translate()で移動するのは、絵画位置だけでコンポーネント上のマウスのクリック位置は移動しません。
憶測ですが、これが原因ということはありませんか。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-06-24 14:58
unibonさん、英-Ranさん、回答ありがとうございます。

原因が発覚しました。

imageをupdateさせるため、repaint()メソッドを呼ぶとき、最適化としてupdate領域を必要最小限に制限して呼び出していたのですが(repaint(int,int,int,int)バージョン)、
この呼び出しをImageを動かす前、すなわち、(0, 0)を原点として呼び出していました。

debuggerで追っかけていてはじめて知ったのですが、paint()メソッドが呼ばれる前、
指定した領域を消去していました。

その後、paint()メソッドでGraphicsの原点をずらすと、消去された領域と描画される領域に不整合が生じていました。

対策として、単純にupdate領域を正しい領域に変更することで問題なく表示することができました。

具体的には、以下の様にしただけです。

public void paint(Graphics inGra) {
Rectangle aBounds = new Rectangle();
inGra.getClipBounds(aBounds);

java.awt.Insets aInsets = getInsets();
aBounds.translate(-aInsets.left,-aInsets.top);

inGra.translate(aInsets.left, aInsets.top);

// 内容に変更がある場合、変更後、変更箇所のみを再描画する
if (mModel.isModified()) {
Point[] aPos = mModel.lastModified();

for (int i = 0; i < aPos.length; ++i) {
mRenderer.render(aPos[i].x, aPos[i].y, mModel.getCurStateAt(aPos[i].x, aPos[i].y));
}
}

// off screen imageを取りだし、転送
inGra.drawImage(
mRenderer.getImage(),
aBounds.x, aBounds.y, aBounds.x + aBounds.width, aBounds.y + aBounds.height,
aBounds.x, aBounds.y, aBounds.x + aBounds.width, aBounds.y + aBounds.height,
this
);

inGra.translate(-aInsets.left,-aInsets.top);

mModel.flush();
}

かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-06-24 15:55
このスレッドを立てた、田村です

今回の件について、追加で質問したいことがあります。

今回の件を追う段階で、repaint()を発行してからpaint()が呼ばれるまでに、
指定した領域が消去されることが分かりました。

私が作成しているアプリはアニメーションを行っていないため、Imageを消去する必要がないのですが、Imageを消去することなく、paint()メソッドを呼ばせることは可能でしょうか?

単純に考えて、repaint()メソッドで領域0を指定すればよいのではと思い試してみましたが、単純に再描画されないという結果に終わりました。

以上よろしくお願い致します。

OS Windows 98SE
SDK J2SDK 1.4.0_1

Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2003-06-24 22:54
幾つかの取扱い上の違いはありますが、java.awt.Canvasでなく、
java.awt.Componentの直接のサブクラスにしたら駄目でしょうか?

スキルアップ/キャリアアップ(JOB@IT)