J'utilise java.awt.Robot
pour les tests d'intégration de mon application Swing, mais j'ai du mal à exécuter mes actions dans le bon ordre. Comment puis-je dire au thread qui appelle robot.mousePressed(...)
pour bloquer jusqu'à ce que Swing ait fini de distribuer cet événement ? Apparemment, robot.setAutoWaitForIdle(true)
ne sert à rien.
Voici ma démo. Je m'attends à ce que le message "robot terminé !" arrive toujours après "Action terminée de bloquer.", mais au lieu de cela, il arrive souvent trop tôt.
import java.awt.AWTException;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.sql.Date;
import java.text.DateFormat;
import java.util.logging.ConsoleHandler;
import java.util.logging.Formatter;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class RobotWaitForIdleDemo {
/**
* Create the device that contains the given point in screen coordinates.
* Robot has to be constructed differently for each monitor.
*/
public static GraphicsDevice getDevice(Point p) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
// Search the devices for the one that draws the specified point.
for (GraphicsDevice device : gs) {
GraphicsConfiguration configuration = device.getDefaultConfiguration();
Rectangle bounds = configuration.getBounds();
if (bounds.contains(p)) {
return device;
}
}
return null;
}
public static final Logger logger = Logger.getLogger(RobotWaitForIdleDemo.class.getName());
public static void main(String[] args) {
LogManager.getLogManager().reset();
Formatter formatter = new Formatter() {
@Override
public String format(LogRecord arg0) {
Date date = new Date(arg0.getMillis());
DateFormat.getTimeInstance().format(date);
return String.format("%s %s %s %s%n",
DateFormat.getTimeInstance().format(date),
arg0.getLoggerName(),
arg0.getLevel(),
arg0.getMessage());
}
};
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setFormatter(formatter);
logger.addHandler(consoleHandler);
final JFrame jframe = new JFrame("Robot experiment");
GroupLayout groupLayout = new GroupLayout(jframe.getContentPane());
final JButton jbutton = new JButton("Click me!");
jbutton.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
// Simulate a heavy Swing event handler.
logger.info("(swing thread) Action starting to block...");
try {
Thread.sleep(500);
} catch (InterruptedException e1) {}
logger.info("(swing thread) Action finished blocking.");
}
});
JButton tryAgainBUtton = new JButton("Automatically click above button.");
tryAgainBUtton.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
new Thread(new Runnable() {
@Override public void run() {
try {
Point point = new Point(jbutton.getWidth()/2,jbutton.getHeight()/2);
SwingUtilities.convertPointToScreen(point, jbutton);
GraphicsDevice device = getDevice(point);
Point offset = device.getDefaultConfiguration().getBounds().getLocation();
Robot robot = new Robot(device);
robot.setAutoWaitForIdle(true);
robot.setAutoDelay(30);
robot.mouseMove(point.x - offset.x, point.y - offset.y);
String threadName = Thread.currentThread().getName();
logger.info(String.format("(%s) robot.mousePress(%d)", threadName, InputEvent.BUTTON1_MASK));
robot.mousePress(InputEvent.BUTTON1_MASK);
logger.info(String.format("(%s) robot.mouseRelease(%d)", threadName, InputEvent.BUTTON1_MASK));
robot.mouseRelease(InputEvent.BUTTON1_MASK);
logger.info(String.format("(%s) robot finished!", threadName, InputEvent.BUTTON1_MASK));
} catch (AWTException ex) {
ex.printStackTrace();
}
}
}, "robot thread").start();
}
});
jframe.getContentPane().setLayout(groupLayout);
groupLayout.setAutoCreateGaps(true);
groupLayout.setAutoCreateContainerGaps(true);
groupLayout.setVerticalGroup(
groupLayout.createSequentialGroup()
.addComponent(jbutton)
.addComponent(tryAgainBUtton));
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup()
.addComponent(jbutton)
.addComponent(tryAgainBUtton) );
jframe.setSize(300, 300);
jframe.setVisible(true);
jframe.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
}
J'utilise Java 1.6 sur Ubuntu.