質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

15194閲覧

描いた絵をリセットしたい。(Graphicsをうまく扱いたい)

toutou

総合スコア2050

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/05/10 09:25

現在画面をすべて消すリセットボタンを作ろうとしています。
それにつきましてまだ、Graphicsの理解が浅く扱いがうまくいかずできないです。

import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class Test1 { public static void main(String[] args) { main a = new main(); a.setVisible(true); } } class main extends JFrame implements ActionListener{ main(){ super("描写テスト");//タイトル this.setSize(400,400);//大きさ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//終了 JPanel kabe = new JPanel();//パネル作成 JButton osu =new JButton("押す");//ボタン作成 remove(osu); osu.addActionListener(this);//ボタンにイベントをプラス kabe.setLayout(new BorderLayout());//壁をセット kabe.add(osu,BorderLayout.EAST);//壁にボタンを配置 getContentPane().add(kabe,BorderLayout.EAST);//本体にパネルを設置 this.add(new event(), BorderLayout.CENTER);//真ん中にイベントを設置 } public void actionPerformed(ActionEvent e){//ボタンイベント // System.out.println("aaa");//確認用 event gura = new event(); gura.kanri(); gura.repaint(); } } class event extends JPanel implements MouseListener, MouseMotionListener{ int lastMouseX = -100;//移動距離 int lastMouseY = -100; int start_x = -100;//スタート地点座標 int start_y = -100; static boolean flag = false;//全体の管理 BasicStroke BStroke = new BasicStroke(5.0f);//筆の大きさを設定 BufferedImage seve_field = new BufferedImage(600,600, BufferedImage.TYPE_4BYTE_ABGR);//メモリの確保 Graphics seve = seve_field.createGraphics();//メモリへの窓口 event() { addMouseListener(this);//中央にマウスイベントを配置 addMouseMotionListener(this);//同上 } @Override public void paintComponent(Graphics g) { if(flag) { System.out.println("ifルート");//確認用 flag = false;//戻し seve_field = null;//メモリの中を破棄 seve = null;//seveを破棄 g.dispose() ;//gの中身を破棄 repaint(); }else{ seve = seve_field.createGraphics();//メモリへの窓口 // System.out.println("描写");//確認用 Graphics2D g2= (Graphics2D)g;//2Dに変更 g2.setStroke(BStroke);//線の設定 g2.setColor(Color.RED);//線の色 Graphics2D seve2= (Graphics2D)seve;//メモリ加工 seve2.setStroke(BStroke);//線の設定 seve2.setColor(Color.RED);//線の色 if(start_x==-100||start_y== -100||lastMouseX==-100||lastMouseY==-100) { lastMouseX = lastMouseY = start_x = start_y = -100; } g.drawImage(seve_field,200,300,this);//g2の中身をメモリの大きさだけゲット seve2.drawImage(seve_field,0,0,this);//メモリの絵を投下 seve2.drawLine(start_x, start_y, lastMouseX, lastMouseY);//線を引く g2.drawLine(start_x, start_y, lastMouseX, lastMouseY);//メモリに線を引く start_x = lastMouseX;//スタート地点の変更 start_y = lastMouseY;}//同上 } public boolean kanri() { lastMouseX = lastMouseY = start_x = start_y = -100; flag = true;//フラグ設定 return flag; } @Override public void mousePressed(MouseEvent e) { /*初期位置の保存*/ start_x = lastMouseX = e.getX(); start_y = lastMouseY = e.getY(); flag = false; } @Override public void mouseReleased(MouseEvent e) { lastMouseX = lastMouseY = start_x = start_y = -100; } @Override public void mouseDragged(MouseEvent e) { lastMouseX = e.getX(); lastMouseY = e.getY(); repaint(); } @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } }

自分の頭の中では、

1、ボタンを押すとfalseを返す。
2、gとseveの中身を消している。
3、repaint()でgが空っぽなのでまっさらな画面になっている。
4その後trueになってdrawImageをしてもgおよびメモリの中身がないのでまっさらになってる。

の想定です。
しかしなっていません。
どこら辺の考えが間違っているのでしょうか。
理解を深めたいのでアドバイスをお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

mainクラスの初期化においてeventのインスタンス(※)をCENTERへ配置していますが、そのインスタンスとボタンを押したときにnewしているインスタンスは別物でありどちらか一方へ描画した内容がもう一方へ影響を及ぼすといった関係はありません。

ボタンを押したときにeventインスタンスをnewし、それに対してrepainしていますが、このインスタンスはGUI階層中に存在しない(JFrameを最上位とするコンポーネント階層中に現れない)ので画面への表示には何の効果も及ぼさないと思います。

※のインスタンスの表示内容を消す(背景色で塗りつぶす)ならこのインスタンスのpaintメソッド中でそれをする必要があります。paintメソッド以外から表示内容を更新することはできないと思ってください。

自分の頭の中では、...

質問者さんは「2でgやseveの中身を消している」と表現されているのでGraphicsの中身に描画結果があると想定されているように見えます。しかし、Graphicsクラスは描画対象のコンポーネントへ何かを描画するための「ペンとしての属性」という意味合いのものであり描画結果を保持するようなものではありません。


蛇足:

  • paintComponentの中でrepaintを呼び出すこと

やったことがないので何が起こるかはわかりませんが多分よした方がいいでしょう。

投稿2017/05/10 11:10

KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

toutou

2017/05/11 00:33

ありがとうございます。あいかわらず言ってることはなんとなくわかるんですが、それを実現できる力がないようです。とりあえずGraphicsクラスの中身は特に関係なく、またまったく意味のないNEWをしてたことがわかったのが大きな収穫です。ここから修正を入れていきます.
KSwordOfHaste

2017/05/11 01:57

回答がわかりにくそうだなぁとは感じてたのですが、回答すること自体も自分にはなかなか難しく… おそらくは自分が実装するイメージと質問者さんのコードの違いを、自分がうまく消化しきれてないせいだと思います。Q&Aって難しいです。orz
toutou

2017/05/11 14:43

こっちのイメージとそちらのイメージが合わないのは、こちらが悪いせいですから気になさらずに。なぜならそっちはちゃんと出来てるイメージでありみんながやってることなので、ちゃんとした思考です。それに比べてこっちは合わないということは妄想と一緒です。勝手に間違ったイメージを作ってます。
toutou

2017/05/11 14:57

すいません。あと今唐突に発見したのですが前回の線が途切れる現象は、setBounds(600,600,500,500)を使ってるせいか最大化してその中の範囲から外に描くように描くと、途切れる模様です。原因をさぐってくれとかじゃなく報告だけしておきます。
KSwordOfHaste

2017/05/11 21:20

setBoundsなど直接サイズを指定するコードとLayoutManger(BorderLayoutなど)を併用すると今一つレイアウトが自然に行えないので自分は全てコンテナのレイアウト機能に任せるように心がけてます。JFrameのコンストラクターの最終行は常にpack()にし、setSize/setBoundsは決して使わないと決めている感じです。(w;
guest

0

ベストアンサー

既に問題を解決できる回答をKSwordOfHasteさんが提示していらっしゃいますが

描画コンポーネントをクリアしたいという要件だけでしたら。
※オフスクリーンの扱いについては余談欄に記入しました。

class main

Java

1class main extends JFrame implements ActionListener { 2 3 private final event gura; 4 5 main() { 6 super("描写テスト");//タイトル 7 this.setSize(400, 400);//大きさ 8 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//終了 9 JPanel kabe = new JPanel();//パネル作成 10 JButton osu = new JButton("押す");//ボタン作成 11 remove(osu); 12 osu.addActionListener(this);//ボタンにイベントをプラス 13 kabe.setLayout(new BorderLayout());//壁をセット 14 kabe.add(osu, BorderLayout.EAST);//壁にボタンを配置 15 getContentPane().add(kabe, BorderLayout.EAST);//本体にパネルを設置 16 gura = new event(); 17 this.add(gura, BorderLayout.CENTER);//真ん中にイベントを設置 18 } 19 20 @Override 21 public void actionPerformed(ActionEvent e) {//ボタンイベント 22 // System.out.println("aaa");//確認用 23 gura.kanri(); 24 gura.repaint(); 25 } 26 27}

event#paintComponent

Java

1 @Override 2 public void paintComponent(Graphics g) { 3 if (flag) { 4 System.out.println("ifルート");//確認用 5 flag = false;//戻し 6 super.paintComponent(g); 7 // BufferedImageを再度作成。 8 seve_field = new BufferedImage(600, 600, BufferedImage.TYPE_4BYTE_ABGR); 9 // インスタンス変数 seveへの代入は下記行で行っているので、省略 10 return; 11 } 12 13 seve = seve_field.createGraphics();//メモリへの窓口 14 // System.out.println("描写");//確認用 15 Graphics2D g2 = (Graphics2D) g;//2Dに変更 16 g2.setStroke(BStroke);//線の設定 17 g2.setColor(Color.RED);//線の色 18 Graphics2D seve2 = (Graphics2D) seve;//メモリ加工 19 seve2.setStroke(BStroke);//線の設定 20 seve2.setColor(Color.RED);//線の色 21 if (start_x == -100 || start_y == -100 || lastMouseX == -100 || lastMouseY == -100) { 22 lastMouseX = lastMouseY = start_x = start_y = -100; 23 } 24 g.drawImage(seve_field, 200, 300, this);//g2の中身をメモリの大きさだけゲット 25 seve2.drawImage(seve_field, 0, 0, this);//メモリの絵を投下 26 seve2.drawLine(start_x, start_y, lastMouseX, lastMouseY);//線を引く 27 g2.drawLine(start_x, start_y, lastMouseX, lastMouseY);//メモリに線を引く 28 start_x = lastMouseX;//スタート地点の変更 29 start_y = lastMouseY; 30 }

余談という確認事項

1点目、event#paintComponentメソッド内でsuper.paintComponent(g);を行っていないため、描画内容はクリアされません。
オフスクリーンメモリ(seve_field)はどういう意図を持って使用されたのでしょうか?

描画内容を保持したいという点だけでしたら、オフスクリーンは不要です。g.drawImage、seve2.drawImage、seve2.drawLine、g2.drawLineは以下の一行だけで要件は満たせます。

Java

1g.drawLine(start_x, start_y, lastMouseX, lastMouseY);//線を引く

2点目、オフスクリーンメモリの扱いと描画順序について
event#paintComponentメソッド内でseve2.drawLine、g2.drawLineとJPanelとメモリの2箇所に対してdrawLineを行っていますが
0. オフスクリーン(seve_field)にdrawLine
0. オフスクリーンをevent#paintComponent関数で渡されたGraphicsに対してg.drawImage
オフスクリーンを使う目的から勝手に想像すると、こーなると思うのですが。

3点目、インスタンス変数start_xとstart_yと2つのint変数で宣言していますが、
座標を扱う時はjava.awt.Pointjava.awt.Rectangleを使うと管理しやすくなります。

4点目、あるコンポーネントのペイント領域を知りたい時はSwingUtilities#calculateInnerAreaが使用できます。
自分でオフスクーンを管理する時はJFrame(mainクラス)のウィンドウのサイズ変更イベントを契機にしてオフスクーンのサイズをコンポーネントのペイント領域と一致させる必要があります。面倒ならmainクラスのコンストラクタでthis.setResizable(false);を設定し、ウィンドウサイズを変更不可にしてください。

5点目、インスタンス変数seve について。
インスタンス変数に代入箇所が2箇所あります、
0. Graphics seve = seve_field.createGraphics();
0. event#paintComponentメソッド内

Graphics にはdisposeメソッドがあるため
使い終わったらseve.dispose();を呼び出してください。

投稿2017/05/10 19:53

編集2017/05/10 20:24
umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2017/05/10 22:11

umyuさんの指摘は色々勉強になると思います。>質問者さん ただ、前の質問からの流れで考えると質問者さんはseve_fieldをオフスクリーンバッファという意味ではなく「お絵かきの結果としての画像ドキュメント」と想定されていると思います。つまり必ずしも画面の大きさに追従するべきとは言えないかもしれません。 むしろ、表示内容を変更する際の線の描画などは全てpaintComponent以外の場所でseve_fieldへ直接描画し、event#paintComponentの中ではdrawImage(seve_field, 0, 0, this);しかやらないというのが素直な実装と思います。ただ、そこを指摘し始めるとかなり根本的な部分からの指摘になってくるので自分の回答ではGraphicsの扱いという点にだけ絞って回答しました。そのためかなり中途半端なコメントになってしまいましたが…
toutou

2017/05/11 00:56

ありがとうございます。 seve_fieldは自分のイメージではスクリーンショットのようなものが入っている記録装置だと思い、それをdrawImageで投下してる感じです。いつの間にかミスって消えてしまったようですが、 Graphics seve = seve_field.createGraphics();//メモリへの窓口 seve2に変換前に入ってました。結果意味ないので影響がなかったという感じです。ここらへんの間違いを少し考えます。 また、線を引くg.drawLineについてなんですが、その記述だけだと一本線が引かれるだけで他がすべて消えてしまう、そう考えたので他もいろいろ足してます。 java.awt.Point、java.awt.Rectangleは自分には未知の世界なので、これから習得って感じになります。 SwingUtilities#calculateInnerAreaも同様です。 disposeメソッドは破棄のところで使っていますが使い方がおかしいです。これもがんばります。
toutou

2017/05/11 14:47

おかげで実装できました。ほぼ書いてもらったのであまり考えてませんが。余談の部分はまだぜんぜん理解してませんが、これらの部分は自分で解析をして学ぶところです。ですので本題の部分はおおむね解決したということでこの質問は閉めさせてもらいます。またわからなくなったら質問するのでそのときによろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問