Java的最后添加按钮允许agent.move,不要休息 [英] Java last added button allows agent.move, rest dont

查看:260
本文介绍了Java的最后添加按钮允许agent.move,不要休息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的Java,并一直在努力建立一个code来获得汽车的小图片使用键移动。我的问题是,当我增加超过1按钮面板。在code口张贴按钮的功能是什么,只是打印按钮[I]点击消息。目的是为他们从该文件中的数据读出的文件并更新汽车的位置。这应该是对我的强化学习项目的一块。我认为这将是学习java,因为这个图形包是没有必要的项目的好机会,只是一个好加法。在code是在这里:

I'm new to java, and have been working on creating a code to get a small picture of a car to move using the keys. My problem is when I add more than 1 buttons to the panel. The function of the button in the code I post is nothing, just prints "button [i] clicked" message. The purpose is for them to read a file and update the locations of the car from the data in the file. This is supposed to be a piece on my Reinforcement Learning project. I thought it would be a good opportunity to learn java since this "graphics package" is not necessary for the project, just a "nice" addition. The code is here:

package graphics;

public class Board extends JPanel implements ActionListener {

private Timer timer;
private Agent agent;

private String button = "button.png";
private Image image;


protected JButton b1;
protected JButton b2;
protected JButton b3;

public Board() {

    //Keylistener added for the agent to respond to arrow keys

 addKeyListener(new TAdapter());
     agent = new Agent();
    timer = new Timer(10, this); //10ms timer calls action performed
    timer.start();     

            //This part for the button.
    ImageIcon i = new ImageIcon(this.getClass().getResource(button));
    image = i.getImage();

    b1 = new JButton("1", i);
    b1.setVerticalTextPosition(AbstractButton.CENTER);
    b1.setHorizontalTextPosition(AbstractButton.LEADING); 
    b1.setActionCommand("Active1");



    b2 = new JButton("2", i);
    b2.setVerticalTextPosition(AbstractButton.CENTER);
    b2.setHorizontalTextPosition(AbstractButton.LEADING); 
    b2.setActionCommand("Active2");



    b3 = new JButton("3", i);
    b3.setVerticalTextPosition(AbstractButton.CENTER);
    b3.setHorizontalTextPosition(AbstractButton.LEADING);
    b3.setActionCommand("Active3");



    b1.addActionListener(this); 
    b2.addActionListener(this);
    b3.addActionListener(this);

     add(b1);          add(b2);  add(b3);          

    setFocusable(true);
    setBackground(Color.BLACK);
    setDoubleBuffered(true);


  }


public void paint(Graphics g) {
    super.paint(g);

    Graphics2D g2d = (Graphics2D)g;

    //Transformations for the agent to be painted based upon its position and orientation

    AffineTransform trans = new AffineTransform();

    trans.rotate(Math.toRadians(agent.getTh()), agent.getX()+64, agent.getY()+64);  
    trans.translate(agent.getX(), agent.getY());

    g2d.drawImage(agent.getImage(), trans, this); // Draws agent with said transformations

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


public void actionPerformed(ActionEvent ae) {

    b1.setEnabled(true);
    b2.setEnabled(true);
    b3.setEnabled(true);

    if (ae.getActionCommand()=="Active1") {
        b1.setEnabled(false);
        b2.setEnabled(true);
        b3.setEnabled(true);
       System.out.println("Clicked 1");
       agent.reset();
    } 



    if(ae.getActionCommand()=="Active2") {
        b1.setEnabled(true);
        b2.setEnabled(false);
        b3.setEnabled(true);
        System.out.println("Clicked 2");
        agent.reset();
    }

    if (ae.getActionCommand()=="Active3") {
        b1.setEnabled(true);
        b2.setEnabled(true);
        b3.setEnabled(false);
        System.out.println("Clicked 3");
        agent.reset();


    }

    agent.move();
    repaint();

}

private class TAdapter extends KeyAdapter {

    public void keyReleased(KeyEvent e) {
        agent.keyReleased(e);
    }

    public void keyPressed(KeyEvent e) {
        agent.keyPressed(e);
    }
}

}

现在,问题是这样的。如果我点击按钮1或2键,其他按键被禁用,它说点击了1(或2),这是好的。但agent.move()和重绘()不被调用。当我preSS的钥匙车子不动。如果我再单击按钮3,其他两个按钮都被禁止,车用钥匙移动。

Now, the problem is this. If I click button 1, or button 2, the other buttons are disabled and it says "Clicked 1 (or 2)" which is fine. But the agent.move() and repaint() aren't invoked. The car doesn't move when I press the keys. If I then click button 3, the other two buttons are disabled and the car moves with the keys.

如果我添加按钮以不同的顺序添加(B3);加(B2);加(B1);那么同样的情况,但这次它的键1的正常工作。

If I add buttons in a different order add(b3); add(b2); add(b1); then the same happens but this time its button 1 that works fine.

推荐答案

问题:


  • 您的主要问题是焦点之一 - 当一个JButton获得焦点,并在JPanel失去焦点,JPanel的KeyListener的将无法工作,因为的KeyListener的需要的是,听了组件具有焦点,也不例外。

  • 一个不好解决很给力的JPanel在任何时候都保留焦点。这将是坏的,如果你的窗口有Jbutton将,将是灾难,如果你需要显示JTextField的,JTextAreas或其他文本组件。

  • 一个更好的解决办法是不使用的KeyListener,因为它有许多与Swing应用程序的问题,特别是它具有如上所述关注的问题。使用按键绑定来代替。谷歌的教程在这血淋淋的细节。

  • 请不要使用 == 来比较字符串,用等于(...) equalsIgnoreCase(...)来代替。问题是,对于对象相等的 == 检查,是字符串A​​中的同一个对象的为String B,你不关心这个。你想知道如果两个字符串中这也正是这两种方法都以相同的顺序持有相同的字符。

  • 请不要的Dispose()由JVM给你,因为这可能搞砸组件的边框,儿童绘画Graphics对象,并且有连对方影响。

  • 请不要在JPanel的漆(...)方法来绘制,而是在其的paintComponent(...)方法,就像教程告诉你这样做。在绘制漆(...)可以对组件的边框和儿童的副作用,如果你不小心,也没有默认双缓冲的利益而是流畅的动画很重要。 的paintComponent(...)解决所有这些问题。

  • 说到这,你应该谷歌阅读摇摆图文教程和。你不能让东西了,希望它会成功,并且图形编程将要求你用什么一个完全不同的方法。

  • 忽略仙女座的线程建议。虽然他是好意,我建议你不要在后台线程做画。只需动车与你的挥杆定时器作为你在干什么。背景线程有它的用途,但不是在这里,作为一个定时器将工作得很好。您将需要使用一个后台线程,当你有一个长期运行的过程,阻塞调用线程,这东西你不要在你目前的code有,所以不需要一个线程修复,实际上是的,如果你不采取极端的照顾,使Swing事件线程上挥杆通话问题的潜在来源。对我们来说,未知,虽然是你的代理人在做什么。如果调用长时间运行code或code。与视频下载(...)等待() / 通知()在里面,那么,你就需要使用背景线程。

  • 但同样,我们知道那不是你的首要问题,因为你的问题只增加重点采集卡后,就开始 - 这些Jbutton。再次,这是强烈的迹象表明,你的主要问题是没有线程,但使用KeyListeners和他们的重点要求的。

  • Your main problem is one of focus -- When a JButton gets focus and the JPanel loses focus, the JPanel's KeyListener won't work, since the KeyListener requires that the listened to component have the focus, no exception.
  • A bad solution is to force the JPanel to retain the focus at all times. This will be bad if your window has JButtons and will be disaster if you need to display JTextFields, JTextAreas, or other text components.
  • A better solution is not to use a KeyListener as it has lots of problems with Swing applications and in particular it has focus issues as noted above. Use Key Bindings instead. Google the tutorial for the gory details on this.
  • Don't use == to compare Strings, use equals(...) or equalsIgnoreCase(...) instead. The problem is that == checks for object equality, is String A the same object as String B, and you don't care about this. You want to know if the two Strings hold the same chars in the same order which is where the two methods come in.
  • Don't dispose() of a Graphics object given you by the JVM as this may mess up the painting of a component's borders, children, and have even other side effects.
  • don't draw in the JPanel's paint(...) method but rather in its paintComponent(...) method just as the tutorials tell you to do. Drawing in paint(...) can have side effects on a component's borders and children if you're not careful, and also does not have the benefit of default double buffering which is important for smooth animation. paintComponent(...) fixes all these problems.
  • Speaking of which, you should Google and read the Swing graphics tutorials. You can't make stuff up and hope that it will work, and graphics programming will require a whole different approach from what you're used to.
  • Ignore Andromeda's threading suggestion. While he means well, I suggest that you don't do painting in a background thread. Just move the car with your Swing Timer as you're doing. Background threading has its uses, but not here, as a Timer will work just fine. You will need to use a background thread when you have a long-running process that blocks the calling thread, something that you don't have in your current code, and so a thread "fix" is not needed and in fact is a potential source of problems if you don't take extreme care to make your Swing calls on the Swing event thread. The unknown for us though is what your "agent" is doing. If it is calling long-running code or code with Thread.sleep(...) or wait()/notify() in it, then yes, you will need to use background threading.
  • But again, we know that's not your primary problem, since your problems began only after adding focus grabbers -- the JButtons. Again this is strong indication that your primary problem is not threading but is use of KeyListeners and their focus requirement.

例如:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.*;
import java.util.EnumMap;
import javax.swing.*;

@SuppressWarnings("serial")
public class KeyBindingPanel extends JPanel {
   private static final int PREF_W = 800;
   private static final int PREF_H = PREF_W;
   private static final Stroke THICK_STROKE = new BasicStroke(5f,
         BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
   private static final int OVAL_WIDTH = 30;
   private static final int OVAL_HEIGHT = 30;
   private static final Color OVAL_COLOR = Color.red;
   private static final Color BKGRD_COLOR = Color.black;
   private static final int TIMER_DELAY = 20;
   public static final int STEP = 2;
   private int myX = 0;
   private int myY = 0;
   private JButton[] buttons = new JButton[3];
   private int condition = WHEN_IN_FOCUSED_WINDOW;
   private InputMap inputMap = getInputMap(condition);
   private ActionMap actionMap = getActionMap();
   private EnumMap<Direction, Boolean> directionMap = new EnumMap<Direction, Boolean>(
         Direction.class);

   public KeyBindingPanel() {
      for (int i = 0; i < buttons.length; i++) {
         buttons[i] = new JButton(new ButtonAction());
         add(buttons[i]);
      }
      setBackground(BKGRD_COLOR);

      for (final Direction direction : Direction.values()) {
         directionMap.put(direction, Boolean.FALSE);

         Boolean[] onKeyReleases = { Boolean.TRUE, Boolean.FALSE };
         for (Boolean onKeyRelease : onKeyReleases) {
            KeyStroke keyStroke = KeyStroke.getKeyStroke(
                  direction.getKeyCode(), 0, onKeyRelease);
            inputMap.put(keyStroke, keyStroke.toString());
            actionMap.put(keyStroke.toString(), new DirAction(direction,
                  onKeyRelease));
         }
      }

      new Timer(TIMER_DELAY, new GameTimerListener()).start();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);

      Graphics2D g2b = (Graphics2D) g.create();
      g2b.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2b.setStroke(THICK_STROKE);
      g2b.setColor(OVAL_COLOR);
      g2b.drawOval(myX, myY, OVAL_WIDTH, OVAL_HEIGHT);

      g2b.dispose(); // since I created this guy
   }

   private class GameTimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         for (Direction direction : Direction.values()) {
            if (directionMap.get(direction)) {
               myX += STEP * direction.getRight();
               myY += STEP * direction.getDown();
            }
         }
         repaint();
      }
   }

   private class DirAction extends AbstractAction {
      private Direction direction;
      private boolean onRelease;

      public DirAction(Direction direction, boolean onRelease) {
         this.direction = direction;
         this.onRelease = onRelease;
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         directionMap.put(direction, !onRelease); // it's the opposite!
      }
   }

   private class ButtonAction extends AbstractAction {
      public ButtonAction() {
         super("Press Me!");
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         JButton thisBtn = (JButton) e.getSource();
         for (JButton btn : buttons) {
            if (btn == thisBtn) {
               btn.setEnabled(false);
            } else {
               btn.setEnabled(true);
            }
         }
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("KeyBindingPanel");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new KeyBindingPanel());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

enum Direction {
   UP(KeyEvent.VK_UP, -1, 0), DOWN(KeyEvent.VK_DOWN, 1, 0), LEFT(
         KeyEvent.VK_LEFT, 0, -1), RIGHT(KeyEvent.VK_RIGHT, 0, 1);

   private int keyCode;
   private int down;
   private int right;

   private Direction(int keyCode, int down, int right) {
      this.keyCode = keyCode;
      this.down = down;
      this.right = right;
   }

   public int getKeyCode() {
      return keyCode;
   }

   public int getDown() {
      return down;
   }

   public int getRight() {
      return right;
   }

}

这篇关于Java的最后添加按钮允许agent.move,不要休息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆