I'm using Java Swing. Initially I want to read a file (which is quite big). So the frame gets displayed after the file is completely. Whereas I want the frame to first load (displayed) and then the file should be read.
class Passwd {
JFrame jfrm;
// other elements
Passwd() {
start();
// Display frame.
jfrm.setVisible(true);
}
public void start() {
// Create a new JFrame container.
jfrm = new JFrame("Password Predictability & Strength Measure");
// Specify FlowLayout for the layout manager.
//jfrm.setLayout(new FlowLayout());
jfrm.setLayout(null);
// Give the frame an initial size.
jfrm.setSize(450, 300);
// align window to center of screen
jfrm.setLocationRelativeTo(null);
// Terminate the program when the user closes the application.
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// some elements
File file = new File("file.txt");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// operation
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
// Create the frame on the event dispatching thread.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Passwd();
}
});
}
}
How can I read the file after the frame is displayed?
The JFrame should display immediately, so that's not the problem. The problem is that you're reading in the file on the Swing event thread, and this blocks its ability to display the JFrame. The solution is to not do this, to instead read the file in a background thread, such as via a SwingWorker. This way the JFrame can display unimpeded, and the file reading will not interfere with Swing functioning.
So if the file reading will not change the state of Swing components, use a simple background thread:
new Thread(() -> {
File file = new File("file.txt");
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// operation
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
If the reading in will change the state of the GUI as the reading occurs, again, use a SwingWorker.
Side issue: avoid using null layouts as they'll come back to bite you.
Related
I'm writing a sort of web applet emulator. I read a web page, find the applet parameters, download the applet and run it. It is very important that the applet runs in its own process (i.e. not the emulator process). It should, however, render in the emulator process window.
How does the Java plugin do it? When the separate_jvm flag is set, the plugin loads the applet in a separate JVM process but the applet still appears in the same browser panel.
I've made some progress by creating a loader class that, on another JVM, adds the target Applet to an undecorated, invisible frame and messages the frame's window handle to the emulator JVM. The latter binds it to a Canvas instance with user32.SetParent via JNA, and the display works perfectly.
However, only mouse events are being sent: keyboard input is not forwarded. The applet reports Component#isFocusOwner as false, and requestFocusInWindow does not make it the focus owner, returning false. How can I pass keyboard focus to the Applet window handle? My current approach involves a server (the emulator), which receives window handles from the client (the applet). Only mouse events appear to work, since the Applet cannot gain focus.
The server class handles the display of the applet.
import com.sun.jna.*;
import com.sun.jna.platform.win32.User32;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import static com.sun.jna.platform.win32.User32.*;
public class Loader {
private static final String APPLET_DIRECTORY = ""; // TODO: Set this to the directory containing the compiled applet
private static ServerSocket serverSocket;
private static JFrame frame;
private static Canvas nativeDisplayCanvas;
public static void main(String[] argv) throws Exception {
nativeDisplayCanvas = new Canvas();
frame = new JFrame("Frame redirect");
frame.setLayout(new BorderLayout());
frame.add(nativeDisplayCanvas, BorderLayout.CENTER);
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
(new Thread() {
public void run() {
try {
serve();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
spawnAltJVM(APPLET_DIRECTORY, "AppletDemo");
}
public static void serve() throws Exception {
serverSocket = new ServerSocket(6067);
serverSocket.setSoTimeout(10000);
while (true) {
try {
System.out.println("Waiting for applet on port " + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Connected to " + server.getRemoteSocketAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
DataOutputStream out = new DataOutputStream(server.getOutputStream());
while (true) {
String msg = in.readLine();
if (msg != null && msg.startsWith("child_hwnd")) {
windowCreatedHandler(msg);
out.writeUTF("hwnd_recv\n");
out.flush();
}
}
} catch (IOException ex) {
System.out.println("Something happened to the socket...");
break;
}
}
}
public static void windowCreatedHandler(String message) {
String[] tokens = message.split(":");
final User32 user32 = User32.INSTANCE;
HWND child_applet = new HWND(Pointer.createConstant(Long.parseLong(tokens[1])));
final HWND child_frame = new HWND(Pointer.createConstant(Long.parseLong(tokens[2])));
frame.addComponentListener(
new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
user32.SetWindowPos(child_frame, new HWND(Pointer.NULL), 0, 0, frame.getWidth(), frame.getHeight(), 0);
}
}
);
HWND parent = new HWND(Native.getComponentPointer(nativeDisplayCanvas));
user32.SetParent(child_applet, parent);
int style = user32.GetWindowLong(child_frame, GWL_STYLE) & ~WS_POPUP | (WS_CHILD | WS_VISIBLE);
user32.SetWindowLong(child_applet, GWL_STYLE, style);
user32.SetWindowPos(child_applet, new HWND(Pointer.NULL), 0, 0, nativeDisplayCanvas.getWidth(), nativeDisplayCanvas.getHeight(), 0);
}
public static void spawnAltJVM(String cp, String clazz) throws IOException, InterruptedException, ClassNotFoundException {
ProcessBuilder processBuilder = new ProcessBuilder(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java", "-cp", cp, clazz);
Process applet = processBuilder.start();
final BufferedReader in = new BufferedReader(new InputStreamReader(applet.getInputStream()));
final BufferedReader err = new BufferedReader(new InputStreamReader(applet.getErrorStream()));
(new Thread() {
public void run() {
while (true) {
try {
System.out.println("[client] " + in.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
Meanwhile, the client class just instantiates and messages the handles.
import sun.awt.windows.WComponentPeer;
import javax.swing.*;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingDeque;
public class AppletDemo extends Applet {
private Canvas canvas;
private static Color backgroundColor = Color.RED;
public AppletDemo() {
setLayout(new BorderLayout());
canvas = new Canvas();
add(canvas, BorderLayout.CENTER);
setBackground(Color.CYAN);
canvas.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
refreshColors();
}
});
canvas.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
refreshColors();
}
});
}
private void refreshColors() {
SwingUtilities.invokeLater(
new Runnable() {
#Override
public void run() {
backgroundColor = (backgroundColor == Color.RED ? Color.GREEN : Color.RED);
canvas.setBackground(backgroundColor);
}
}
);
}
public static void main(String[] argv) throws Exception {
System.setErr(System.out);
final AppletDemo app = new AppletDemo();
Frame frame = new Frame("AppletViewer");
frame.setLayout(new BorderLayout());
frame.add(app, BorderLayout.CENTER);
frame.setUndecorated(true);
frame.pack(); // Create the native peers
frame.setSize(300, 200);
final Socket client = new Socket("localhost", 6067);
final LinkedBlockingDeque<String> messageQueue = new LinkedBlockingDeque<>();
final DataOutputStream out = new DataOutputStream(client.getOutputStream());
final BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
(new Thread() {
public void run() {
while (true) {
try {
out.writeBytes(messageQueue.take() + "\n");
out.flush();
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
}
}).start();
(new Thread() {
public void run() {
while (true) {
try {
if ("hwnd_recv".equals(in.readLine())) {
// Attempt to grab focus in the other process' frame
System.out.println("Trying to request focus...");
System.out.println(app.requestFocusInWindow());
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}).start();
messageQueue.add("child_hwnd:" + ((WComponentPeer) app.getPeer()).getHWnd() + ":" + ((WComponentPeer) frame.getPeer()).getHWnd());
}
}
They're both a bit lengthy because they require some socket work, but they are compilable and should demonstrate the issue. They require JNA to compile. I've shortened them as much as possible at the cost of some good practices.
When Loader is ran, a window redirecting the AppletDemo's canvas should appear. Mouse events are sent: the canvas toggles between red and green on a mouse press. Ideally, the same behavior should occur for keystrokes too.
I've used WinSpy to get the handles of a notepad.exe window and text pane, and hardcoding the handles into Loader. Keyboard focus works perfectly with the multiline edit control, but not with the toplevel window itself. Why? Is this related to the issue I'm having?
I opened up a Chrome window running an applet in WinSpy, and found that the plugin creates no dummy Frame — the applet canvas is directly set as a child of Chrome. However, I haven't been able to create a native peer for the Applet, since it seems to require it to be displayable.
I've read about the dangers of cross-process parent/child or owner/owned window relationship, but I can't think of a better way to graft the child applet into the emulator.
Since what you really want is to create the applet as a child window, the easy solution would be to convince the applet to be your children, not forcefully adopting it, and working against both Windows and the JVM.
Luckily, the Sun/Oracle Java VM comes with a class called WComponentFrame (Windows-only as implied from the name). It can constructed from an hwnd, which you can send from your parent process. The applet can then be added as a child of your window.
import sun.awt.windows.WComponentPeer;
frame = new WEmbeddedFrame(hwnd);
frame.setLayout(new BorderLayout());
frame.add(applet, BorderLayout.CENTER);
It looks like you are trying to pass the event to the Canvas object, which you do not explicitly setFocusable(true) for.
If this is the case, then in your AppletDemo constructor, try:
canvas.setFocusable(true);
canvas.requestFocus();
Also it seems like you want to pass key events to your Applet rather than your Canvas from your question.
In this case, try this in your AppletDemo constructor:
this.setFocusable(true);
this.requestFocus();
After that, you should receive keyboard input by default to the component that is focused.
With JNA it is as easy as
HWND hwnd1 = User32.INSTANCE.FindWindow(null, "JFrame1");
HWND hwnd2 = User32.INSTANCE.FindWindow(null, "JFrame2");
HWND hwnd3 = User32.INSTANCE.SetParent(hwnd2, hwnd1);
see also
Good or evil - SetParent() win32 API between different processes
I want to display different images in a same frame within a loop. String pathName[] contains the different paths of the images. When running this code, only last image i.e image at path pathname[last] is getting displayed on frame instead I want all images to be displayed in a continuous way (have given delay of 1sec ). Help is appreciated.
public void actionPerformed(ActionEvent event) {
int i=0;
while(i<5){
if(i>0){
Container labelParent = receiverImageLabel.getParent();
labelParent.remove(receiverImageLabel);
labelParent.validate();
labelParent.repaint();
}
try {
imageR = ImageIO.read(new File(pathName[i++])).getScaledInstance(512,512 , BufferedImage.SCALE_SMOOTH);
receivedImage = new ImageIcon(imageR);
}catch (IOException e) {
e.printStackTrace();
}
receiverImageLabel = new JLabel(receivedImage);
receiverFrame.getContentPane().add(BorderLayout.EAST,receiverImageLabel);
receiverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
receiverFrame.setSize(800,700);
receiverFrame.setVisible(true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Your problem is a common one: you're calling Thread.sleep(...) in a Swing GUI on the event thread and are essentially thus putting the entire GUI to sleep.
Solution: Google the Swing Timer and use this in place of your while loop/Thread.sleep(...)
Also, if the images aren't too big, then consider reading them all in at once (in a background thread), putting them into ImageIcons, and then swapping out a JLabel's ImageIconsand in your Swing Timer.
For example, you could do something like:
ImageIcon[] icons = new ImageIcon[IMAGE_COUNT];
for (int i = 0; i < IMAGE_COUNT; i++) {
BufferedImage img = ImageIO.read(...); // read in the appropriate image
// ...... here manipulate the image if desired such as re-size it
icons[i] = new ImageIcon(img); // put it into an icon
}
elsewhere:
int timerDelay = 1000;
new Timer(timerDelay, new ActionListener(){
int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (count < IMAGE_COUNT) {
someLabel.setIcon(icons[count]);
count++;
} else {
// stop the timer
((Timer)e.getSource()).stop();
}
}
}).start();
Note: code not compiled nor tested and is posted only as a general example of steps to consider.
Using a swing button, I'm trying to download an html file and write it to a new html file, while doing a progress bar. When I click the button, my program seems to freeze until the download finishes, and then the progress bar is suddenly 100%. I'm not quite sure how to fix this problem as I am new to java.
private void jButton2MouseReleased(java.awt.event.MouseEvent evt) {
try {
URL oracle = new URL("http://mywebsite.com");
URLConnection yc = oracle.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
String inputLine;
String input_path = "d:/website/updatedsite.html";
WriteFile data = new WriteFile(input_path, false);
int length = yc.getContentLength();
int current = 0;
jProgressBar1.setMaximum(length);
jProgressBar1.setValue(0);
while ((inputLine = in.readLine()) != null) {
data.writeToFile(inputLine);
int i = 0;
for (i = 0; i < length; i++) {
jProgressBar1.setValue(i);
}
}
in.close();
}
catch (java.io.IOException e) {
JOptionPane.showMessageDialog(Frame1.this, "Error " + e.getMessage());
}
}
This is because you're both downloading and updating the progress bar in the same thread - that's why the gui gets actually updated AFTER the download is finished.
Use a separate worker thread for downloading like explained here and it should work.
I'd suggest using a SwingWorker. It's made for problems such as this. Here is a snippet from some code from my codebase that uses an indeterminate progress bar, but it'll help give you a general idea of what to do (vui is a JFrame):
vui.clearOutput();
vui.setOutput("Waiting for items to copy...\n"
+ "This could take several minutes. Please standby...");
vui.disableExit();
vui.disableInput();
vui.disableNext();
vui.showProgressBar();
// make thread so you can disable all options when zipping and enable progress bar
SwingWorker transferWorker = new SwingWorker() {
#Override
protected Void doInBackground() throws Exception {
try {
Process p = Runtime.getRuntime().exec("resources/bin/transferCopier.bat");
StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(), "OUTPUT");
errorGobbler.start();
outputGobbler.start();
p.waitFor();
} catch (IOException ex) {
Logger.getLogger(VaderController.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ie) {
Logger.getLogger(VaderController.class.getName()).log(Level.SEVERE, null, ie);
}
return null;
}
#Override
public void done() {
vui.hideProgressBar();
vui.clearOutput();
vui.setOutput("Transfer Complete!\n\n"
+ "Push \"Exit\" to quit.\n\n");
vui.enableExit();
mode = VaderMode.END;
}
};
transferWorker.execute();
When transferWorker.execute(); is performed, doInBackground() is invoked. Once doInBackground() is done doing its computations, done() is then invoked. done() is where you would do any final updates to the GUI.
The key things to note about my code above is that I enable the progress bar before executing the SwingWorker then when the SwingWorker is done executing, I disable the progress bar.
Resources:
http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
I create a file like this:
PrintWriter out = new PrintWriter(
new FileOutputStream(
new File("C:/Users/.../Desktop/Server Recipe Log.txt"),
true));
out.println("serverText");
out.close();
But I don't want to save the file on my desktop - I want to open the save as dialog to choose the place where I want to save the file.
I have tried out some tutorials with Frames but I don't want to create any frame, I want to use the native system dialog.
..want to use the native system dialog.
You are using the wrong language. The closest Java offers is a java.awt.FileDialog or a javax.swing.JFileChooser using the native PLAF.
E.G.
import java.awt.*;
import javax.swing.*;
class FileDialogs {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
FileDialog fd = new FileDialog((Frame)null);
fd.setVisible(true);
JFileChooser fc = new JFileChooser();
fc.showSaveDialog(null);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
JFileChooser jl = new JFileChooser();
jl.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int save = jl.showSaveDialog(null);
if (JFileChooser.APPROVE_OPTION == save){
PrintWriter out = new PrintWriter(
new FileOutputStream(
new File(jl.getSelectedFile().getAbsolutePath()+"/name.txt"),
true));
out.println("serverText");
out.close();
}
I have a problem showing my progress bar when reading a file in Java.
All works as intended, user choose a file, the program must show the progress bar (but it loads an empty blank frame), process the file and then load the results on another window.
I can't get the program to show the content of the progress bar dialog.
A little help here would be really appreciated.
Here is the code of the 3 methods involved.
//this method reads the file
public void processFile(File arch) {
aFile = arch;
Thread threadForSearch = new Thread() {
#Override
public void run() {
try{
listaProveedoresTango = controladoraConsultas.traerProveedores();
listaProveedoresAFIP = new LinkedList();
BufferedReader data = new BufferedReader(new FileReader(aFile));
String s;
while ((s = data.readLine()) != null) {
//long task
}
data.close();
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
}
}
};
interfacesController.loadProgressBar();
threadForSearch.start();
try {
threadForSearch.join();
} catch (InterruptedException ex) {
Logger.getLogger(Controladora.class.getName()).log(Level.SEVERE, null, ex);
}
this.interfacesController.closeProgressBar();
this.interfacesController.loadResults(someStuff);
}
//load a progress bar
public void loadProgressBar(){
JProgressBar pb = new JProgressBar(0,100);
pb.setPreferredSize(new Dimension(175,20));
pb.setString("Processing Data");
pb.setStringPainted(true);
pb.setIndeterminate(true);
JLabel infoLabel = new JLabel("Reading File: ");
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent evt) {
exitSystem();
}
});
cancelButton.setVerticalAlignment(SwingConstants.CENTER);
JPanel center_panel = new JPanel();
center_panel.add(infoLabel);
center_panel.add(pb);
center_panel.add(cancelButton);
center_panel.setLayout(new BoxLayout(center_panel,BoxLayout.Y_AXIS));
dialog = new JDialog((JFrame)null, "Processing ...");
dialog.getContentPane().add(center_panel, BorderLayout.CENTER);
dialog.setSize(100, 100);
dialog.setLocationRelativeTo(null);
dialog.pack();
dialog.setVisible(true);
}
//close the open progress bar
public void closeProgressBar(){
this.dialog.dispose();
}
Solved with SwingWorker, i post a summarized code:
public void processFile(File arch) {
aFile = arch;
final SwingWorker searchOnFile = new SwingWorker(){
#Override
protected Object doInBackground() throws Exception {
try{
BufferedReader data = new BufferedReader(new FileReader(aFile));
String s;
while ((s = data.readLine()) != null) {
//long task
}
data.close();
}catch (Exception e){ //Catch exception if any
System.err.println("Error: " + e.getMessage());
}
interfacesController.closeProgressBar();
interfacesController.loadResults(someStuff);
return null;
}
};
interfacesController.showProgressBar();
searchOnFile.execute();
}
interfacesController contains all the methods to work with GUIs, showProgressBar() is used to show the bar and closeProgressBar() do the opposite. Thank you guys!
Short of more useful code, I suggest using a SwingWorker.
An abstract class to perform lengthy GUI-interaction tasks in a background thread. Several background threads can be used to execute such tasks. ..
Given the nature of the task, you might also look at ProgressMonitorInputStream.
..creates a progress monitor to monitor the progress of reading the input stream. If it's taking a while, a ProgressDialog will be popped up to inform the user. If the user hits the Cancel button an InterruptedIOException will be thrown on the next read. All the right cleanup is done when the stream is closed.