2016-05-07 6 views
1

私は現在、学校向けの小さなプロジェクトに取り組んでいます。私はまだ始まっています。私はちょうどJFrameとそのすべてのものに読んで始めたので、私があなたが私に示すすべてのものにそれほど精通していないかもしれないのだろうかと思ってはいけません。Javaは既に追加されたオブジェクトに変更を加えます

ここでの目標は、画像を出力し、その画像のすべての単一ピクセルを手動で変更できるプログラムを作成することです。まあ、コードはこれまでのところ(xDさんをスポッティング厄介なエラーの多くの時間後に)動作しますが、私は何をしたい

public class Pixel extends Component { 
    private BufferedImage img; 
    private int width; 
    private int height; 
    private Graphics graphics; 

    public Pixel(int w, int h) { 
     width = w; 
     height = h; 
    } 

    public void create() { 
     img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 

     //Set any color for now 
     for(int wc = 0; wc < width; wc++) { 
      for(int hc = 0; hc < height; hc++) { 
       img.setRGB(wc, hc, new Color(0xAAFFBB).getRGB()); 
      } 
     } 
    }  

    @Override 
    public void paint(Graphics g) { 
     super.paint(g); 
     graphics = g; 
     create(); 
     update(); 
    } 

    public void update() { 
     graphics.drawImage(img, 0, 0, null); 
    } 

    public void testChange() { 
     for(int i = 50; i < 80; i++) { 
      for(int j = 80; j < 120; j++) { 
       img.setRGB(i, j, new Color(0xFF8876).getRGB()); 
      } 
      for(int j = 460; j < 493; j++) { 
       img.setRGB(i, j, new Color(0xFF8876).getRGB()); 
      } 
     } 
    } 
} 

public class JavaGraphicsTest { 
    private static Pixel pixel; 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
     frame.setVisible(true); 
     pixel = new Pixel(1600, 900); 
     frame.getContentPane().add(pixel); 
     //pixel.testChange(); 
    } 
} 

と:したがって、私は、次のコードを書いています今は動作していないようです:mainメソッド(現在コメントされています)でメソッド "pixel.testChange()"を呼び出したいと思います。しかし、私がJFrameの仕組みを理解している限り、JFrameに追加したオブジェクトは何もできません。しかし、それは誰のために働くべきですか?アクティブなオブジェクトを削除したり再追加したりすることなく、どのように変更できますか?

PS:testChangeメソッドが想定していることを理解できない場合は、画像の2ブロックを別の色に変更する必要があります。基本的に画像を正常に変更したかどうかを確認するテストです。

プロジェクトに関する詳細な情報が必要な場合は、私に聞いてください:)事前に

おかげで、 ジュリアン

+0

こんにちはJulian、そしてstackoverflowへようこそ! :D私はrevalidate()メソッドを調べることをお勧めします。私は自分自身についてはあまりよく分かりませんが、わかっているように、あなたがしたいことをしなければなりません。 :) –

+0

@EthanMooreありがとう^^これを行うための基本だと思われますが、より多くのエラーが見つかると、私は現在戦っている問題が別のものだということを知りました:私はこの行を呼び出すときに 'img.setRGB (80、80、new Color(0xFF8876).getRGB()) 'paint()メソッドでは動作しますが、testChange()メソッドでは常にNullPointerを取得します:(ただし、なぜそれはこのようなものです... –

+0

'new Color(0xFF8876).getRGB()'を既存の値に変更してみてください(ちょっと別の80?を入れてください)、何が起こるか教えてください。@JulianThurner –

答えて

0

をごtestChange方法(または、それを呼び出した後)の終わりには、あなたが上invalidateを呼び出す必要がありますPixelオブジェクトです。これは、コンポーネントが変更されたときに再描画されることをコンポーネントに通知するためのシグナルです。

また、this SO questionも確認してください。

+0

レイアウトが変更されたときに '#invalidate()'を使うべきです。レイアウトが既に最新の場合は、コンポーネントの再描画をスキップすることがあります。再描画が確実に行われるようにするには '#repaint()'を使用してください。 – AJNeufeld

+0

@AJNeufeldあなたはおそらく '#revalidate()'を参照しています。私は、グラフィカルに表現されたデータが変更されているので、これは「ダーティ」オブジェクトの定義であり、古い表現は無効化されているとみなされるので、新しい「有効な」表現が必要です。 – sanastasiadis

4

Graphicsオブジェクトを保管しないでください。これまでグラフィックスオブジェクト

public class Pixel extends Component { 
    private Graphics graphics; // <<-- DO NOT DO THIS 

    @Override 
    public void paint(Graphics g) { 
     // ... 
     graphics = g; // <<-- DO NOT DO THIS 
     // ... 
    } 
} 

#paint(Graphics g)が呼び出されるたびに再作成することができ、場合#paint(Graphics g)終了し、無効に破壊または破損することができます。

の呼び出し中に画像を作成しないでください。これは、Pixelが作成されたときに1回だけ実行する必要があります。

public class Pixel extends Component { 

    @Override 
    public void paint(Graphics g) { 
     // ... 
     create(); // <<-- DO NOT DO THIS, EITHER. 
     // ... 
    } 
} 

しかし、あなたが安全にpaint(Graphics g)から呼び出された他の方法にGraphicsオブジェクトを渡すことができます。

public class Pixel extends Component { 
    // ... 

    public Pixel(int w, int h) { 
     width = w; 
     height = h; 
     create(); 
    } 

    @Override 
    public void paint(Graphics g) { 
     super.paint(g); 
     update(g); 
    } 

    private void update(Graphics g) { 
     graphics.drawImage(img, 0, 0, null); 
    } 
} 

です。手元のお仕事に - #testChange()メソッド。画像を変更した後、#repaint()呼び出しを使用してSwingにコンポーネントを再度描画するように要求するだけです。

public class Pixel extends Component { 

    public void testChange() { 
     int rgb = new Color(0xFF8876).getRGB()); // Cached, for efficiency. 

     for(int i = 50; i < 80; i++) { 
      for(int j = 80; j < 120; j++) { 
       img.setRGB(i, j, rgb); 
      } 
      for(int j = 460; j < 493; j++) { 
       img.setRGB(i, j, rgb); 
      } 
     } 

     repaint(); // <<-- Ask Swing to repaint the component. 
    } 
} 

最後の注意:あなたが本当にユーザーインターフェイススレッド(EDT)以外でのSwingオブジェクトを変更しないでください。例外は通常、最初のウィンドウを作成するときに表示可能になる前に許可されます。

public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
    frame.setVisible(true);    // <<-- Window becomes visible here 
    pixel = new Pixel(1600, 900); 
    frame.getContentPane().add(pixel); // <<-- DANGEROUS!! 
} 

代わりに、あなたはこのようなコード再構築することができます

public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
    pixel = new Pixel(1600, 900); 
    frame.getContentPane().add(pixel); // <<-- Safe - window not visible yet. 
    frame.setVisible(true);    // <<-- Window becomes visible here 
} 

ベター、SwingUtilities.invokeLater(...)を使用して、実際にEDTに切り替えることである。

public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      JFrame frame = new JFrame(); 
      frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
      frame.setVisible(true);    // <<-- Window becomes visible here 
      pixel = new Pixel(1600, 900); 
      frame.getContentPane().add(pixel); // <<-- Safe - running on EDT. 
      pixel.testChange(); // <<-- Also safe - running on EDT 
     } 
    }); 
} 

ああ、Java8と、あなたは多くのRunnableボイラープレートコードを取り除くことができます:

public static void main(String[] args) { 
    SwingUtilities.invokeLater(() -> { 
     JFrame frame = new JFrame(); 
     frame.setExtendedState(JFrame.MAXIMIZED_BOTH); 
     frame.setVisible(true);    // <<-- Window becomes visible here 
     pixel = new Pixel(1600, 900); 
     frame.getContentPane().add(pixel); // <<-- Safe - running on EDT. 
     pixel.testChange(); // <<-- Also safe - running on EDT 
    }); 
} 
+0

これは非常に役に立ちました! ^^グラフィックスオブジェクトを保存していたのは本当に問題だったようですね。別の質問:通常のJFrameの代わりにEDTを使用する利点は何ですか? –

+0

これは別のものです。 'JFrame'は**ウィンドウ**です - メニュー、パネル、ボタン、その他のグラフィックオブジェクトを保持するコンテナです。 Event Dispatching Thread(EDT)は**(_singular!_)スレッドです** Swingはグラフィカルオブジェクトの操作に使用します。あなたのプログラムは、計算やデータベースへのアクセスなどのために多くのスレッドを作成できますが、EDTからグラフィカルオブジェクトを操作する必要があります。 SwingUtilities.invokeLater(...)は、EDTに切り替えるために必要な魔法の呪文です。あなたはまだ "通常の" JFrameを作成しています。あなたは単に「安全な」場所からやっているだけです。 – AJNeufeld

+0

すべてのコードを実行しているわけではありませんが、原則として、フレーム上で 'setVisible'を最後に呼び出す必要があります。そうしないと、' revalidate'と 'repaint';を呼び出す必要があります。 – MadProgrammer

関連する問題