1

私はswingを使用してゲームキャンバスを作成してJTextFieldおり、パネルへのユーザー名とパスワードの入力にを使用することにしました。

すべてをリアルタイムでパネルに直接描画するのではなく、画像をバッファリングしてから画面にレンダリングしています。

問題が発生しました。背景をペイントし、両方のテキストフィールドを不透明に設定しましたが、これらのテキストフィールドに何かを入力しようとすると、ある場所に黒いボックスが点滅するようJTextFieldです。

これは、ユーザー名とパスワードの両方のフィールドで発生します。これの原因が何であるかについての考えはありますか?

その他の役立つ情報:テキストボックスをクリックすると、最初の文字が表示される場所で両方のコンポーネントが黒く点滅します。

編集-私が持っているログインボタンも、とのときに黒く点滅することに気づきMOUSE_ENTEREDましたMOUSE_EXIT

public class GamePanel extends JPanel implements Runnable {


public GamePanel(int width, int height) {
    this.pWidth = width; 
    this.pHeight = height;

    setController(new LoginGameController(this));

    setPreferredSize( new Dimension(pWidth, pHeight));
    setBackground(Color.BLACK);

    setFocusable(true);
    requestFocus();    // the JPanel now has focus, so receives key events

    // create game components

    addMouseListener(this);
    addKeyListener(this);

    setLayout(null);

    startGame();
}
 private void startGame()
  // initialise and start the thread 
  { if (animator == null) {
      animator = new Thread(this);
      animator.start();
    }
  }

public void run() {
    while(true) {
          gameUpdate(); 
          if(getGraphics() != null){
              gameRender();   // render the game to a buffer
              paintScreen();  // draw the buffer on-screen
          }
          try {
            Thread.sleep(28);
          } catch (InterruptedException e) {}
    }
}

private void paintScreen() {
    Graphics2D g = (Graphics2D) getGraphics();

    if ((g != null) && (img != null))
            g.drawImage(img, 0, 0, null);

    Toolkit.getDefaultToolkit().sync();
    g.dispose();
}

private void gameRender() {
    if(getWidth() > 0 && getHeight() > 0)
        img = createImage(getWidth(), getHeight());

    if(img != null) {
        Graphics2D g = (Graphics2D) img.getGraphics();
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, pWidth, pHeight);

        getController().render(img);

        paintComponents(img.getGraphics());


    }
}

}

テキストフィールドは次のとおりです:(getPanel()を使用してGamePanelを完全に呼び出す別のクラスから...)

//Setup Login fields
    usernameTF = new JTextField();
    usernameTF.setOpaque(false);
    usernameTF.getCaret().setBlinkRate(0);
    usernameTF.setForeground(Color.WHITE);
    usernameTF.setBounds(USERNAME_FIELD);
    usernameTF.setBorder(null);
    getPanel().add(usernameTF);

    passwordTF = new JPasswordField();
    passwordTF.setOpaque(false);
    passwordTF.getCaret().setBlinkRate(0);
    passwordTF.setForeground(Color.WHITE);
    passwordTF.setBounds(PASSWORD_FIELD);
    passwordTF.setBorder(null);
    getPanel().add(passwordTF);

    loginBtn = new JButton();
    loginBtn.setOpaque(false);
    loginBtn.setBackground(null);
    loginBtn.setBorder(null);
    loginBtn.setBounds(LOGIN_BUTTON);
    loginBtn.addMouseListener(getPanel());
    getPanel().add(loginBtn);

ありがとう!

4

2 に答える 2

3

基本的な問題は、Swings の再描画プロセスを回避し、グラフィックを更新するときに EDT を尊重しないことです。

JComponent#getGraphics次の再描画時に再描画される一時/スクラッチ バッファーです。また、グラフィックを作成していない場合は、破棄しないでください。

public void run() {
    while(true) {
          gameUpdate(); 
          if(getGraphics() != null){
              gameRender();   // render the game to a buffer
              try {
                  SwingUtilities.invokeAndWait(new Runnable() {
                      public void run() {
                          paintScreen();  // draw the buffer on-screen
                      }
                  });
              } catch (Exception exp) {
                  exp.printStackTrace(); // please clean this up
              }
          }
          try {
            Thread.sleep(28);
          } catch (InterruptedException e) {}
    }
}

これで治るかどうかはわかりませんが、仕方ありません。(これは FPS に影響を与えるため、ペイントにかかった時間と待機時間を考慮する必要があります)

別の方法として、 を呼び出すのではなく、 をpaintScreen()呼び出しrepaintて (または呼び出しpaintScreenて)、メソッドをオーバーライドしpaintComponentてバッファをペイントすることもできます。

これにより、Swing はペイント プロセスを適切に制御できるようになります。

于 2012-10-17T02:56:22.547 に答える
2

ウィンドウまたはコンポーネントには、少なくとも 3 つの再描画方法があります。

  1. ウィンドウ バッファの一部が失われたときに、オペレーティング システムからの要求に応じて。
  2. 状態が変化したときのライブラリ コンポーネントからのオンデマンド。
  3. 独自のフレーム バッファを手動で操作します。

通常、次の経路がアクティブです。

オペレーティング システムは、特定の四角形の更新を要求する場合があります。これはツールキットによって取得されます。repaintさらに、コンポーネントは、メソッドを介してツールキットにも変更を通知する場合があります。ツールキットは、しばらくの間、着信再描画要求のマージを収集し続け、その後、特定の四角形を再描画するようにウィンドウに要求します。paintComponentウィンドウのデフォルトのアクションは、ソリッドの子と重ならないメソッドを呼び出してウィンドウ自体をペイントし、そのコンポーネントを再帰的にペイントすることです。

独自のレンダリングを行う場合、ツールキットもそれを行います。をオーバーライドしなかったためpaintComponent、このメソッドが実行されると、デフォルトとして機能します。デフォルトのアクションは何もしないことです。次に、ツールキットは空のフレーム バッファーを取得し、その上にボタン (背景は描画されません) を描画します。

ツールキットのレンダリング プロセスを無効にして、すべてのレンダリングを自分で行うことができます (バッファーを取得し、そこにペイントしてから送信します)。setIgnoreRepaint(true)OS による要求を無視するメソッドを呼び出すことができます。

于 2012-10-17T03:17:10.627 に答える