I have Swing application on Windows 10. Also I added Low Level Keyboard hook which should intercept keyboard events and remap for example 'z' to 's' button.
This is needed to hook keyboard events outside my java application. I have implemented it using JNA version 5.6.0 and jna-platform version 5.6.0. It works fine but not inside my Swing application.
My problem is when the hook is ON, swing application a kind of locked. I can not press to any Jbutton and even close Jframe at all.
My guess is that it has something to do with threads, but I'm very weak at threads and multithreading.
Reproducible example.
TestFrame class:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TestFrame extends JFrame {
public static void main(String [] args) {
TestFrame frame = new TestFrame();
JTextField textField=new JTextField();
textField.setBounds(50,50, 150,20);
JButton button=new JButton("Click Here");
button.setBounds(50,100,95,30);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
ReMapper reMapper = new ReMapper();
reMapper.reMapOn();
textField.setText("Is my frame locked?");
}
});
frame.add(button);
frame.add(textField);
frame.setSize(400,400);
frame.setLayout(null);
frame.setVisible(true);
}
}
ReMapper class:
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.*;
public class ReMapper {
private static WinUser.HHOOK hHook;
final User32 user32Library = User32.INSTANCE;
WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
static WinUser.INPUT input = new WinUser.INPUT();
public void reMapOn() {
WinUser.LowLevelKeyboardProc keyboardHook = new WinUser.LowLevelKeyboardProc() {
#Override
public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT kbDllHookStruct) {
if (nCode >= 0) {
if (wParam.intValue() == WinUser.WM_KEYDOWN) {
if (kbDllHookStruct.vkCode == 90) { // 90 is key code = z
sendKey(83); // 83 is key code = s
return new WinDef.LRESULT(1);
}
}
}
Pointer ptr = kbDllHookStruct.getPointer();
long peer = Pointer.nativeValue(ptr);
return user32Library.CallNextHookEx(hHook, nCode, wParam, new WinDef.LPARAM(peer));
}
};
hHook = user32Library.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);
int result;
WinUser.MSG msg = new WinUser.MSG();
while ((result = user32Library.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
break;
} else {
user32Library.TranslateMessage(msg);
user32Library.DispatchMessage(msg);
}
}
}
static void sendKey(int keyCode) {
input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
input.input.setType("ki"); // Because setting INPUT_INPUT_KEYBOARD is not enough: https://groups.google.com/d/msg/jna-users/NDBGwC1VZbU/cjYCQ1CjBwAJ
input.input.ki.wScan = new WinDef.WORD(0);
input.input.ki.time = new WinDef.DWORD(0);
input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
// Press
input.input.ki.wVk = new WinDef.WORD(keyCode); // 0x41
input.input.ki.dwFlags = new WinDef.DWORD(0); // keydown
User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
// Release
input.input.ki.wVk = new WinDef.WORD(keyCode); // 0x41
input.input.ki.dwFlags = new WinDef.DWORD(2); // keyup
User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
}
}
Here is the screen with locked Jframe after clicking 'Click Here' button:
ReMapper class works fine separately from Swing application.
reMapOn() allows to remap 'z' to 's'. But I need it to work inside my Swing app and not block it..
Does anyone know what the problem might be and how to fix it?
Looking at your reMapOn code, it has a while loop and that points to the fact that it could run indefinitely and block the applications UI.
What you need to do is simply in your addActionListener method call the reMapOn method on its own thread. This can be done either using a simple Thread or Swing Worker:
Swing Worker example (preferred solution as you can override done and manipulate swing components if needed in that method when the remapper had ended):
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
ReMapper reMapper = new ReMapper();
reMapper.reMapOn();
return null;
}
}.execute();
textField.setText("Is my frame locked?");
Thread example:
new Thread(() -> {
ReMapper reMapper = new ReMapper();
reMapper.reMapOn();
}).start();
textField.setText("Is my frame locked?");
Some other points are:
Don't use a null/AbsoluteLayout rather use an appropriate LayoutManager
Don't call setBounds() or setSize() on components, if you use a correct layout manager this will be handled for you
Call JFrame#pack() before setting the frame to visible when using a LayoutManager
Dont extend the JFrameclass unnecessarily
All Swing components should be called on the EDT via SwingUtilities.invokeLater
Related
I'm writing my Tetris using Java Swing. The Game class revolves around a JFrame (frame), which consists of a TetrisPanel extending JPanel (panel) where the blocks fall, a JLabel (pontok) point counter, a JTextArea (rekord_text) showing high scores, and another JPanel (kovi) showing the next block to fall. My idea is that the game has 3 difficulty levels, where the blocks fall with different speed.
I thought the best way of approaching this problem is to create a new JFrame with the components above, but with the blocks' speed set different. I am able to close the old JFrame. However, when the new JFrame opens up, it is only a blank frame, and it won't respond to closing the window.
I should add that TetrisPanel is running a thread, but I am 90% sure I stop that with a volatile boolean.
Constructor of the Game class:
this.difSet(nehezseg); //this function sets the falling velocity
TetrisPanel.stopped = true; //this static member is the volatile boolean responsible for stopping the thread
new_game = false;
frame = new JFrame("Tetris_alpha");
frame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
panel = new TetrisPanel();
TetrisPanel.stopped = false;
new Thread(panel).start();
frame.add(panel, c);
pontok = new JLabel ("0");
frame.add(pontok, c);
rekord_text = new JTextArea();
//i set up the area
frame.add(rekord_text, c);
kovi = new NextAktualPanel();
frame.add(kovi, c);
menu = new MyMenu(this);
frame.setJMenuBar(menu);
frame.addWindowListener(new WindowAdapter()
{
#Override
public void windowClosing(WindowEvent e)
{
rekordok.add(panel.getPont());
rekordok.write(f);
e.getWindow().dispose();
System.exit(0);
}
}
);
frame.pack();
frame.setVisible(true);
}
The Game.start() function containing the game loop:
public void start()
{
//game_loop
while (!panel.GameOver() && !new_game)
{
if (panel.aktualLeertDetector())
{
panel.addAktualToBlocks();
panel.addNewAktual(next);
Elem temp = new Elem(0,0,rand.nextInt(7));
while (temp.getTipus() == next.getTipus())
temp = new Elem(0,0,rand.nextInt(7));
next = temp;
kovi.setNextAktual (next);
}
if (!paused)
pontok.setText(Integer.toString(panel.getPont()));
kovi.repaint();
panel.repaint();
}
The function which opens the new frame:
Public void newGame (Game g)
{
Game.new_game = true;
g.frame.dispose();
Game new_game = new Game("easy");
g = new_game;
g.start();
}
And the run() function of TetrisPanel:
public static volatile boolean stopped = false;
#Override
public void run() {
while (!stopped)
{
aktual.zuhan();
this.sorTeleAction();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Any help would be appreciated, including ideas about different a approach.
Do not use volatile boolean as status variable, use AtomicBoolean instead, volatile it's not the correct way to do this kind of things, and it does not either cause "immediate variable updating"... this is not volatile purpose.
It's not a good idea to start a thread on main AWT thread, you still have to use SwingUtilities.invokeLater(Runnable runnableAction). You can use something like this when launching a Gui Thread:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new Thread(threadAction).start();
} catch (Exception e) {
}
}
});
Hope that this will solve you problem!
I have a main(screen) gui window and need to open a few "multi input" windows (jdialog or when not possible jframe), for example to add preferences (4 textfields with 2 filechoosers and 2 radiobuttons).
When pressing OK/Cancel in these JDialogs (or JFrames), my entire application closes.
I don't want that. How can I prevent that?
First try: I tried the intelliJ option "New -> Create Dialog class", which gives me a JDialog with OK/Cancel button. Pressing one of the buttons closes the JDialog and my entire application.
Second try: I wrote a class "by hand" which creates a JDialog (and also tried JFrame). Again: Pressing one of the buttons closes the JDialog and my entire application.
I removed "dispose()" and "setVisible(false)" options from theJDialog (JFrame), but still my entire application is closed.
main class method
public class mainScreen {
// Menu action listener (only relevant options)
class MenuActionListener implements ActionListener {
// menuListener
public void actionPerformed(ActionEvent ev) {
//myVariables myVars = new myVariables();
String[] dummy = null;
System.out.println("Selected: " + ev.getActionCommand());
switch(ev.getActionCommand()) {
case "Preferences":
showPreferencesDialog();
case "Exit":
System.exit(0);
break;
}
// method that opens the external class (see below in following code block)
private void showPreferencesDialog() {
prefJDialog myprefs = new prefJDialog(prefsPanel);
myprefs.showDialog();
boolean okPressed = myprefs.isOkPressed();
if (okPressed) {
JOptionPane.showMessageDialog(mainScreen.this.rootPanel,"OK pressed","About jExifToolGUI",JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(mainScreen.this.rootPanel,"Cancel pressed","About jExifToolGUI",JOptionPane.INFORMATION_MESSAGE);
}
}
// This is the class which is mention in the manifest
public mainScreen(JFrame frame) {
boolean preferences = false;
Preferences prefs = Preferences.userRoot();
createmyMenuBar(frame);
groupRadiobuttonsandListen();
fileNamesTableListener();
try {
myUtils.DisplayLogo(mainScreen.this.iconLabel);
} catch(IOException ex) {
System.out.println("Error reading Logo");
}
preferences = check_preferences();
if (!preferences) {
myUtils.checkExifTool(mainScreen.this.rootPanel);
}
programButtonListeners();
}
// main method in my main class for my project
public static void main(String[] args) {
JFrame frame = new JFrame("jExifToolGUI");
frame.setContentPane(new mainScreen(frame).rootPanel);
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
The JDialog class/method that is called from the main class
package org.hvdw.jexiftoolgui;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class prefJDialog extends JDialog {
private JButton okButton;
private JButton cancelButton;
private JPanel prefsPanel;
private boolean okPressed;
public prefJDialog(JPanel prefsPanel) {
super(JOptionPane.getFrameForComponent(prefsPanel), true);
this.prefsPanel = prefsPanel;
setTitle("Preferences");
initDialog();
}
public void showDialog() {
setSize(800, 768);
double x = getParent().getBounds().getCenterX();
double y = getParent().getBounds().getCenterY();
setLocation((int) x - getWidth() / 2, (int) y - getHeight() / 2);
setVisible(true);
}
private void initDialog() {
JPanel pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
pane.setBorder(BorderFactory.createEmptyBorder(10, 10, 5, 10));
add(pane);
pane.add(Box.createVerticalGlue());
FlowLayout l = new FlowLayout(FlowLayout.RIGHT);
JPanel buttonsPane = new JPanel(l);
okButton = new JButton("Save"); //$NON-NLS-1$
buttonsPane.add(okButton);
pane.getRootPane().setDefaultButton(okButton);
cancelButton = new JButton("CANCEL"); //$NON-NLS-1$
buttonsPane.add(cancelButton);
buttonsPane.setMaximumSize(new Dimension(Short.MAX_VALUE, (int) l.preferredLayoutSize(buttonsPane).getHeight()));
pane.add(buttonsPane);
addListeners();
}
private void addListeners() {
okButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//saveProperties();
setVisible(false);
okPressed = true;
//close();
// dispose();
}
});
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
//dispose();
//close();
okPressed = false;
}
});
}
public boolean isOkPressed() {
return okPressed;
}
/*public void close() {
WindowEvent winClosingEvent = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(winClosingEvent);
}*/
}
So how do I prevent that upon clicking OK or Cancel in the JDialog, the entire application closes. That needs to stay open until the user clicks the "window close" X in the top-right, or from the menu "File -> Exit"
I have searched Google for several days, but can't find a solution (and one same question without answer).
Edit:
After Patrick's answer I changed the close method to
public void close() {
this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
}
And removed the /* and */.
I also activated the close(); in the listeners again, but it doesn't make a difference. My main app is still closed.
switch(ev.getActionCommand()) {
case "Preferences":
showPreferencesDialog();
case "Exit":
System.exit(0);
break;
And the problem is that you don't have a break statement in your switch case so the code falls through to the "Exit" logic and does a System.exit(0)
This is why we need a proper "MCVE" with every question. When you post random pieces of code we can't see the entire logic flow.
I need to run a background thread in my Java GUI that only runs when I click a button and pauses when I click that button again. I am not exactly sure how to set this up, but I have placed a thread in my constructor and the while loop within is set to go through when I set a specific boolean to TRUE. One button switches from setting this boolean TRUE or FALSE.
Everything else I have in this GUI works fine. When I tried debugging the thread, it actually works as I step through the thread but nothing when I try running the GUI completely. The GUI is rather large so I'm gonna put up a portion of the constructor and the action listener of the button. The rest of the code is unnecessary since it works just fine. I need to know what I am doing wrong here:
public BasketballGUI() {
// certain labels and buttons
Thread runningSim = new Thread() {
public void run() {
while(simRun) {
// do stuff here
}
}
};
runningSim.start();
}
// other GUI stuff
// actionListener that should run the thread.
class SimButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
if(!simRun) {
simRun = true;
sim.setText("Pause Simulator");
}
else if(simRun) {
simRun = false;
sim.setText("Run Simulator");
}
// other stuff in this actionListener
}
}
Establish a Swing based Timer with an ActionListener that will be called repeatedly.
In the actionPerformed(ActionEvent) method call repaint().
Start the timer (Timer.start()) when the user clicks Start
Stop the timer (Timer.stop()) when the user clicks Stop
If you cannot get it working from that description, I suggest you post an SSCCE of your best attempt.
I thought I had one 'lying around'.. Try this working SSCCE which uses images created in this SSCCE.
I could see this background thread useful for a Java GUI when handling button events to affect something like a text area or progress bar.
For the sake of argument, I will build you a tiny GUI that affects a Text Area. I hope this helps you.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.*;
public class TestClass extends JPanel {
super("TestClass - Title");
private AtomicBoolean paused;
private JTextArea jta;
private JButton btn;
private Thread thread;
public TestClass() {
paused = new AtomicBoolean(false);
jta = new JTextArea(100, 100);
btn = new JButton();
initialize();
}
public void initialize() {
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
add(new JScrollPane(jta));
btn.setPreferredSize(new Dimension(100, 100));
btn.setText("Pause");
btn.addActionListener(new ButtonListener());
add(btn);
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
if(paused.get()) {
synchronized(thread) {
try {
thread.wait();
} catch(InterruptedException e) {
}
}
}
}
jta.append(Integer.toString(i) + ", ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
};
thread = new Thread(runnable);
thread.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 30);
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
if(!paused.get()) {
btn.setText("Start");
paused.set(true);
} else {
btn.setText("Pause");
paused.set(false);
synchronized(thread) {
thread.notify();
}
}
}
}
}
Main class to call everything.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainClass {
public static void main(final String[] arg) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestClass());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
I did not test this code to see if it works exactly, Its main goal is to break you through your coders block and use my components to fix your issue. Hope this helped. Need anything else Email me at DesignatedSoftware#gmail.com
I want to implement a method where the user needs to hold the left and right mouse buttons at the same time.
I'm using Swing and Java 1.7. I've tried this, but it doesn't detect the both-buttons case like I'd expect it to:
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && SwingUtilities.isRightMouseButton(e)){
///code here
}
}
i tried to separate methods and use bool values to decide if the mouse button is pressed and then i set a condition to find out if both of them are pressed at the same time , but that didint work out too ..
This is an SSCCE that does what you want... i.e. if I understood your question correctly.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class StackOverflow15957076 extends MouseAdapter
{
private JLabel status;
private boolean isLeftPressed;
private boolean isRightPressed;
public StackOverflow15957076 ()
{
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel (new FlowLayout (FlowLayout.CENTER));
status = new JLabel ("waiting for both mouse buttons...");
status.addMouseListener (this);
panel.add (status);
frame.add (panel);
frame.pack ();
frame.setVisible (true);
isLeftPressed = false;
isRightPressed = false;
}
#Override
public void mousePressed (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = true;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = true;
}
if (isLeftPressed && isRightPressed)
{
status.setText ("both buttons are pressed");
}
}
#Override
public void mouseReleased (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = false;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = false;
}
status.setText ("waiting for both mouse buttons...");
}
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override
public void run ()
{
new StackOverflow15957076 ();
}
});
}
}
It seems that it's not possible do it directly, since mouse events are fired sequentially. See, for example, this SO question/answers.
So you will need to decide what "at the same time" actually means to you (i.e. how close in time thay should be). Then you can capture two separate events and compare their getWhen() values.
Robot is part of the AWT library, but it seems quite different from most all the rest of the library. I am creating a Swing GUI that mixes Swing with Java Native Access (JNA) and Robot to allow Java to drive some MS Windows/Citrix work programs. My gut feeling is that since Robot will queue events on the "platform's native input queue" that the last thing I want to do is to run it on the EDT, but on the other hand, most of the classes in the AWT and Swing libraries should be run on the Swing event thread. So to try clarify this in my mind for me let me ask as specific a question as possible:
Should Robot methods (in particular key presses and releases, mouse moves, mouse presses and releases) be run on or off of the Swing event dispatch thread (the EDT)?
The Robot methods you mentioned should not be run on the EDT. Taking a look at the source code revealed that each one of these "event" methods has one thing in common (the afterEvent call):
public synchronized void keyPress(int keycode) {
checkKeycodeArgument(keycode);
peer.keyPress(keycode);
afterEvent();
}
public synchronized void mousePress(int buttons) {
checkButtonsArgument(buttons);
peer.mousePress(buttons);
afterEvent();
}
// etc
private void afterEvent() {
autoWaitForIdle();
autoDelay();
}
private void autoWaitForIdle() {
if (isAutoWaitForIdle) {
waitForIdle();
}
}
public synchronized void waitForIdle() {
checkNotDispatchThread();
/* snip */
}
private void checkNotDispatchThread() {
if (EventQueue.isDispatchThread()) {
throw new IllegalThreadStateException("Cannot call method from the event dispatcher thread");
}
}
If you call any of these methods on the EDT while Robot.isAutoWaitForIdle is true, an exception will be thrown. This stands to reason that even if isAutoWaitForIdle is false, these methods shouldn't be called from the EDT.
API quite exactly talks, then I'm understand that that Robot should be ignore if is invoked from EDT or not
Using the class to generate input events differs from posting events to the AWT event queue or AWT components in that the events are generated in the platform's native input queue.
I'm rellative new in Java, my first touch was Java1.6.009, then I can't compare changes for AWT and (when born) Swing in Java1.3 and rest in Java1.4
my example
import javax.imageio.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class CaptureScreen implements ActionListener {
private JFrame f = new JFrame("Screen Capture");
private JPanel pane = new JPanel();
private JButton capture = new JButton("Capture");
private JDialog d = new JDialog();
private JScrollPane scrollPane = new JScrollPane();
private JLabel l = new JLabel();
private Point location;
public CaptureScreen() {
capture.setActionCommand("CaptureScreen");
capture.setFocusPainted(false);
capture.addActionListener(this);
capture.setPreferredSize(new Dimension(300, 50));
pane.add(capture);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pane);
f.setLocation(100, 100);
f.pack();
f.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createPicContainer();
}
});
}
private void createPicContainer() {
l.setPreferredSize(new Dimension(700, 500));
scrollPane = new JScrollPane(l,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBackground(Color.white);
scrollPane.getViewport().setBackground(Color.white);
d.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
d.add(scrollPane);
d.pack();
d.setVisible(false);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("CaptureScreen")) {
Dimension d1 = Toolkit.getDefaultToolkit().getScreenSize(); // gets the screen size
Robot r;
BufferedImage bI;
try {
r = new Robot(); // creates robot not sure exactly how it works
Thread.sleep(1000); // waits 1 second before capture
bI = r.createScreenCapture(new Rectangle(d1)); // tells robot to capture the screen
showPic(bI);
saveImage(bI);
} catch (AWTException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
private void saveImage(BufferedImage bI) {
try {
ImageIO.write(bI, "JPG", new File("screenShot.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
private void showPic(BufferedImage bI) {
ImageIcon pic = new ImageIcon(bI);
l.setIcon(pic);
l.revalidate();
l.repaint();
d.setVisible(false);
location = f.getLocationOnScreen();
int x = location.x;
int y = location.y;
d.setLocation(x, y + f.getHeight());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
d.setVisible(true);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CaptureScreen cs = new CaptureScreen();
}
});
}
}
Amplifying on #mKorbel's thoughtful answer, and confirming his empirical result, note how the various Robot methods delegate to an internal instance of the RobotPeer interface, the native implementation of which varies by platform. Moreover, the methods are synchronized. The synthetic events all arrive on the EventQueue, irrespective of the source.