I am learning Java Swing. I am trying to develop as simple app for learning purpose. There is are multiple issues in following code. I try to read a csv file and populate JComboBox on button click.
public class MyForm {
private JButton btnRead;
private JButton btnRead2;
private JComboBox cbCodes;
private JPanel mainPanel;
private DefaultComboBoxModel comboBoxModel;
public MyForm(){
// issue 1: I always get null pointer exception in this line
comboBoxModel = new DefaultComboBoxModel();
cbCodes = new JComboBox(comboBoxModel);
btnRead.addActionListener( e -> {
List<String[]> data = readData();
comboBoxModel.removeAllElements();
data.forEach(item -> comboBoxModel.addElement(item));
});
// issue 2: Since DefaultComboBoxModel was not working. I tried without it. As this I get correct data in the array. But when I make JComboBox with array. Nothing is filled. It is empty.
btnRead2.addActionListener( e -> {
List<String[]> data = readData();
String[] array = new String[data.size()];
data.toArray(array);
cbCodes = new JComboBox(array);
});
}
// issue 3: I can't complie the code without this empty method. Why do I need it?
// error: Form contains components with Custom Create option but no createUIComponents() method
void createUIComponents(){
}
public List<String[]> readData() {
String file = "data.csv";
List<String[]> content = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
String line = "";
while ((line = br.readLine()) != null) {
if(line.contains("\"")){
content.add(line.split(" "));
}
content.add(line.split(","));
}
} catch (FileNotFoundException e) {
//Some error logging
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
public static void main(String[] args) {
JFrame frame = new JFrame("MyForm");
frame.setContentPane(new MyForm().mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
I make my question in the source code with the comment to show exactly here those issues are involved.
You don't get the NullPointerException in the lines you indicated, but in the line btnRead.addActionListener( e -> { because btnRead has not been initialized yet!
When you create a new JComboBox, you have to add it to the panel, too. Just creating it with new will not display it. But the real problem behind it is: you're using the model wrong. Write
comboBoxModel.removeAllElements();
for (final String string : array) {
comboBoxModel.addElement(string);
}
to solve that.
The problem you have here does not lie within the code you provided, but from another component. At some point, someone used a UI designer. Those designers usually create initialization methods, just like createUIComponents. See where that method gets called.
Synopsis:
All in all, your code is really chaotic. Restructure from new, this will clean up a lot of problems.
And initialize UI components as soon as possible, best do it in the declaration line: private final JButton btnRead = new JButton("Read!");
I strongly recommend using an IDE like Eclipse or IntelliJ that will help you write clean code and see and correct problems easier.
This has been driving me up the wall for 2 days now. I can't seem to make the JProgressBar update properly and I'm not sure why. I've read through the concurrency and SwingWorker tutorials, I've tested outside of my program and been able to get it working fine using simple code. I understand the concepts, and am just not seeing why it's not working as the code has been re-written in many different ways and still I can't make it work. I'll post a SSCE using as much code from my program as I can, and explain things best I can here as well.
Basically I have a auto-updater/Installer program to update and/or install World of Warcraft addons to our customers computers. The first thing the 'updater' does is check the server to see if it's version is the same as the version of the updater installer on the server. This works swimmingly! In fact the entire updater works great except for this one issue. If the updater sees that the server has a different version number than the updater it downloads the installer (in a zip) from the server, unzips it, starts the installation from the exe that was contained in the zip and closes the currently open updater so the install can complete properly.
So I have a progress bar on the card (using cardLayout to show the three different cards for the updater, SelfUpdate, Login, and AddonList) for the self updater. as well as a JTextArea below the JProgressBar and that's all that shows on the particular SelfUpdate card. It query's the server for the version number on the server and it compares that version to the version number on the updater currently installed. If the version is the same it changes to the Login card and moves along to the next bits of the program, which work great so far, if the versions are different it sends a query to the server and the server sends the zip file back to the updater for processing.
This is where it's not working. The zip is a decent size and of course I want to show the progress of this download. The zip file download works fine (it runs in the SwingWorker doInBackground() method), the updater then unzips the installer.exe file to a folder on the customers system drive, fires off using Runtime and starts the installer.exe which pops up the installer screen, then closes the current updater using System.exit(0). again, all this works but the JProgressBar itself will NOT update. it sits at 0% for the whole thing. Also, the taskOutput JTextArea doesn't get updated either, but the main problem is the progressbar not updating. I can live with that getting fixed and the JTextArea not updating. (tried a JLabel in place of a textarea as well and no joy)
So I know I'm doing something wrong, but I can't imagine what. Here's the bits where the magic happens. :) Forgive me if I explain as I go along here.
So Controller.java handles all the flow of the program here's the parts you need to see.
// Imports packages needed for use in this file.
import javax.swing.*;
import java.awt.CardLayout;
import java.io.*;
// class instantiation
public class Controller {
// Variables needed for use in this class
private static Updater util;
private static int loginReturnState = 0;
/**
* Single contructor for this class
*/
public Controller() {
}
/**
* Main method which runes everything in the updater program
*
*/
public static void main(String[] args) {
util = new Updater();
// Schedule a job for the event dispatch thread.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// setup a new GUI
util.createGUI();
JFrame rFrame = util.getRootFrame();
JPanel gFrame = util.getCardLayoutFrame();
CardLayout cards = (CardLayout) gFrame.getLayout();
cards.show(gFrame, "UpdateUpdaterPanel");
rFrame.pack();
rFrame.setLocationRelativeTo(null);
rFrame.setVisible(true);
SelfUpdater selfUp = new SelfUpdater();
int needUpdate = selfUp.checkForUpdate(); if (needUpdate == 2) {// Update available for download. Download it.
selfUp.downloadUpdate();
}
}
});
}
}
OK Next file is the Updater class. To put code in here that will hopefully compile and show the issue I need to put this class in there or the utility methods I have in the uPdater class will not be around to be called and I use them extensively.
// Packages needed for use in this file
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.CardLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseAdapter;
import java.io.*;
// Class instantiation
public class Updater {
// These final variables are set to the path for each of the images used
public static final String BG_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\background.png";
public static final String APP_ICON_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\app-icon.png";
public static final String CLOSE_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\close.png";
public static final String FINOFF_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\FinishedOff.png";
public static final String FINON_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\FinishedOn.png";
public static final String ICON_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\icon.png";
public static final String ICON64_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\icon64x64.png";
public static final String ICON256_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\icon256x256.png";
public static final String INSTOFF_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\InstallUpdatesOFF.png";
public static final String INSTON_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\InstallUpdatesON.png";
public static final String LOGO_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\logo.png";
public static final String MIN_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\minimize.png";
public static final String PROGBACK_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\ProgressBackground.png";
public static final String PROGBAR_IMAGE_PATH = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\ProgressBar.png";
public static final String INSTRUCTIONS_BUTTON = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\instructions.png";
public static final String PURCHASE_BUTTON = "F:\\Java Programs\\Updater\\src\\com\\dynastyaddons\\updater\\images\\Purchase.png";
// These are various final variables for use throughout the updater
public static final String URL_CONNECT = "http://dynastyaddons.com/api/index2.php?";
public static final String TITLE_TEXT = "Dynasty Updater";
public static final int BUFFER_SIZE = 4096;
public static final double UPDATER_VERSION = 1.1;
// Public variables needed for this class workings
private static JFileChooser fc;
private static JFrame rootFrame;
// Private variables for this class use alone
private static String PHPSessionID;
private static boolean debugToggle = true;
private CardLayout cards;
private JPanel guiFrame;
private Point mouseDownCompCoords;
private Login login;
private Addons addons;
/**
* Sole contructor. (For invocation by subclass contructors, typically implicit.)
*/
public Updater() {
// First instantiate any variables needed
PHPSessionID = "notset";
guiFrame = new JPanel();
cards = new CardLayout();
guiFrame.setLayout(cards);
}
// Various methods follow
/**
* This will create the root gui for showing in the main method
*
*/
public void createGUI() {
rootFrame = new JFrame();
SpringLayout rootLayout = new SpringLayout();
// setup root frame
rootFrame.setUndecorated(true);
rootFrame.setBackground(new Color(0,0,0,0));
rootFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
rootFrame.setPreferredSize(new Dimension(800,600));
rootFrame.setTitle(TITLE_TEXT);
// add the background image
JLabel bg = new JLabel(new ImageIcon(BG_IMAGE_PATH));
bg.setLayout(rootLayout);
rootFrame.add(bg);
// setup title bar
mouseDownCompCoords = null;
mouseDownCompCoords = null;
rootFrame.addMouseListener(new MouseListener() {
public void mouseReleased(MouseEvent e){ mouseDownCompCoords = null; }
public void mousePressed(MouseEvent e){ mouseDownCompCoords = e.getPoint(); }
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){ }
public void mouseClicked(MouseEvent e){ }
});
rootFrame.addMouseMotionListener(new MouseMotionListener() {
public void mouseMoved(MouseEvent e){}
public void mouseDragged(MouseEvent e){
Point currCoords = e.getLocationOnScreen();
rootFrame.setLocation(currCoords.x - mouseDownCompCoords.x, currCoords.y - mouseDownCompCoords.y);
}
});
// Display and place the logo
JLabel logo = new JLabel(new ImageIcon(LOGO_IMAGE_PATH));
bg.add(logo);
// add Close and Minimize buttons
JPanel cmButt = createCloseAndMinButtons();
bg.add(cmButt);
// create card frame
guiFrame.setPreferredSize(new Dimension(800, 435));
guiFrame.setOpaque(false);
bg.add(guiFrame);
// Constrain the parts of your BG
rootLayout.putConstraint(SpringLayout.WEST, logo, 30, SpringLayout.WEST, rootFrame);
rootLayout.putConstraint(SpringLayout.NORTH, logo, 70, SpringLayout.NORTH, rootFrame);
rootLayout.putConstraint(SpringLayout.NORTH, cmButt, 0, SpringLayout.NORTH, rootFrame);
rootLayout.putConstraint(SpringLayout.EAST, cmButt, 0, SpringLayout.EAST, rootFrame);
rootLayout.putConstraint(SpringLayout.SOUTH, guiFrame, 0, SpringLayout.SOUTH, rootFrame);
rootLayout.putConstraint(SpringLayout.WEST, guiFrame, 0, SpringLayout.WEST, rootFrame);
rootLayout.putConstraint(SpringLayout.EAST, guiFrame, 0, SpringLayout.EAST, rootFrame);
// Create self updater panel and get it ready to show
SelfUpdater selfUp = new SelfUpdater();
JPanel selfUpd = selfUp.getSelfUpdatePanel();
// get the cardlayout and add the three panels to it, then show the self-updater to begin.
guiFrame.add(selfUpd, "UpdateUpdaterPanel"); }
/**
* Creates a panel which has the close and minimize buttons on it.
*/
private static JPanel createCloseAndMinButtons() {
JPanel a = new JPanel();
SpringLayout closeLO = new SpringLayout();
a.setLayout(closeLO);
a.setPreferredSize(new Dimension(150,150));
a.setOpaque(false);
// Close Button
JButton cButt = new JButton(new ImageIcon(Updater.CLOSE_IMAGE_PATH));
cButt.setBorderPainted(false);
cButt.setContentAreaFilled(false);
cButt.setFocusPainted(false);
cButt.setOpaque(false);
cButt.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) { System.exit(0); }
});
a.add(cButt);
// Minimize Button
JButton mButt = new JButton(new ImageIcon(Updater.MIN_IMAGE_PATH));
mButt.setBorderPainted(false);
mButt.setContentAreaFilled(false);
mButt.setFocusPainted(false);
mButt.setOpaque(false);
mButt.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) { rootFrame.setState(JFrame.ICONIFIED); }
});
a.add(mButt);
// Constrain parts on panel
closeLO.putConstraint(SpringLayout.EAST, cButt, 12, SpringLayout.EAST, a);
closeLO.putConstraint(SpringLayout.NORTH, cButt, -2, SpringLayout.NORTH, a);
closeLO.putConstraint(SpringLayout.EAST, mButt, 30, SpringLayout.WEST, cButt);
closeLO.putConstraint(SpringLayout.NORTH, mButt, -2, SpringLayout.NORTH, a);
// Return the jframe
return a;
}
/**
* Returns the guiFrame which holds the cardlayout for the changing of the panels.
*
* #return JPanel Returns the frame which holds the cardlayout.
*/
public JPanel getCardLayoutFrame() {
return guiFrame;
}
/**
* This will return the cardlayout for use in the controller.
*
* #return CardLayout Returns the cardlayout for use in the Controller.
*/
public CardLayout getCardLayout() { return cards; }
/**
* Returns the current version of this updater as a double
*
* #return the version of this updater as a double.
*/
public double getUpdaterVersion() { return UPDATER_VERSION; }
/**
* Returns a string that tells if the customer is useing windows or mac
*
* #return the operating system in use by the customer
*/
public static String getOSType() {
String retString = "";
String oST = System.getProperty("os.name").toLowerCase();
int spacePos = oST.indexOf(" ");
if (spacePos > 0) {
retString = oST.substring(0, spacePos);
}
retString.trim();
return retString;
}
/**
* Returns the main root frame for display purposes in controller.java
*
* #return JFrame returns rootFrame.
*/
public JFrame getRootFrame() { return rootFrame; }
}
OK< Keep in mind this class really just does some utility stuff in the background and likely isn't involved in anything other than creatin the background gui and tellin the SelfUpdate card to show up.
Finally here's the SelfUpdater.java file which displays the SelfUpdater panel with the progress bar in it and does all the server querying which works fine again. Pay attention to the System.out.println debug statements I have in the downloadUpdate method (which is called in the controller file), as they work fine and print out in the console no problem. The selfUpdateProgress.setValue(int) and taskOutput.setText(txt) statements in that method do nothing .Also I've put a println in the doInBackground where it does setProgress(int) and that prints to the console fine but the bar doesn't update with setProgress. Here it is.
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.zip.*;
// Create and start class
public class SelfUpdater extends JPanel {
// These are the variables needed for use in this class
private JPanel selfUpdatePanel;
private JProgressBar selfUpdateProgress;
private Task task;
private JTextArea taskOutput;
private Updater util;
/**
* Default class constructor, instantiates variables and sets up GUI.
*
*
**/
public SelfUpdater() {
// Progress Bar
selfUpdateProgress = new JProgressBar(0, 100);
selfUpdateProgress.setValue(0);
selfUpdateProgress.setStringPainted(true);
selfUpdateProgress.setPreferredSize(new Dimension(470,29));
// Layout
SpringLayout selfUpdateLayout = new SpringLayout();
SpringLayout pBarLayout = new SpringLayout();
// Font and color setup for Task Output
Font myFont = new Font("Serif", Font.BOLD, 16);
Color myColor = new Color(255, 170, 0);
// Description of progress pane
taskOutput = new JTextArea("Checking server for updates to the updater.", 1, 39);
taskOutput.setFont(myFont);
taskOutput.setForeground(myColor);
taskOutput.setEditable(false);
taskOutput.setOpaque(false); // this is false after setting up the window.
//extras needed for the class workings
util = new Updater();
// Images for progress bar setup
JLabel pBar = new JLabel(new ImageIcon(util.PROGBACK_IMAGE_PATH));
pBar.setOpaque(false);
//pBar.setLayout(pBarLayout);
//pBar.add(taskOutput);
//pBar.add(selfUpdateProgress);
// Main panel
selfUpdatePanel = new JPanel();
selfUpdatePanel.setPreferredSize(new Dimension(800, 435));
selfUpdatePanel.setLayout(selfUpdateLayout);
selfUpdatePanel.setOpaque(false);
selfUpdatePanel.add(taskOutput);
selfUpdatePanel.add(selfUpdateProgress);
selfUpdatePanel.add(pBar);
// Constrain your bits.
// First constrain PBar to the self update panel
selfUpdateLayout.putConstraint(SpringLayout.SOUTH, pBar, -40, SpringLayout.SOUTH, selfUpdatePanel);
selfUpdateLayout.putConstraint(SpringLayout.WEST, pBar, 150, SpringLayout.WEST, selfUpdatePanel);
selfUpdateLayout.putConstraint(SpringLayout.SOUTH, taskOutput, -50, SpringLayout.SOUTH, selfUpdatePanel);
selfUpdateLayout.putConstraint(SpringLayout.WEST, taskOutput, 175, SpringLayout.WEST, selfUpdatePanel);
selfUpdateLayout.putConstraint(SpringLayout.SOUTH, selfUpdateProgress, -84, SpringLayout.SOUTH, selfUpdatePanel);
selfUpdateLayout.putConstraint(SpringLayout.WEST, selfUpdateProgress, 171, SpringLayout.WEST, selfUpdatePanel); }
/**
* Will return the jpanel that contains the gui elements for the Self-Update
*
* #return JPanel The Self-Update gui.
*
*/
public JPanel getSelfUpdatePanel() { return selfUpdatePanel; }
/**
* This will check the server to see if an update is available for the updater
*
* #return int Returns an int that will describe the answer from the server.
* Possible Return values:
* 0 = Problem checking for update: Server return NULL
* 1 = Second type of problem checking for update: Server returned empty string
* 2 = Update available.
* 3 = Update not needed.
*
*/
public int checkForUpdate() {
// ask the server what version it's updater is.
String serverUpdaterVersion = "";
try {
HttpConnect conn = new HttpConnect();
String urlRequest = util.URL_CONNECT + "action=get_updater&platform=" + util.getOSType();
serverUpdaterVersion = conn.textRequest(urlRequest, 1);
} catch (MalformedURLException e) {
JOptionPane.showMessageDialog(null, "We were unable to connect to the server while checking for an updater update, please check your internet connection.", "Attention!",JOptionPane.ERROR_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "We were unable to open the connection to the server while checking for an updater update, please check your internet connection.", "Attention!",JOptionPane.ERROR_MESSAGE);
}
// check for errors and return proper int.
if (serverUpdaterVersion == null) { // There is an error if the server returns null, return 0
return 0;
} else if (serverUpdaterVersion.equals("")) { // if the server returns an empty string return 1 for an error
return 1;
} else { // not null or empty string. check versions
// Check version of this updater to servers version
double sVers = Double.parseDouble(serverUpdaterVersion);
if((double)sVers == util.getUpdaterVersion()) { // return 3 if no update needed here.
return 3;
} else { // otherwise return 2 so we can get the update
return 2;
}
}
}
/**
* This will download the update from the server.
*
* #return File The downloaded file from the server. A zip file usually.
*
*/
public void downloadUpdate() {
// turn on wait cursor
util.getRootFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// start a new task which does the download
// Instances of javax.swing.SwingWorker are not reusuable, so
// we create new instances as needed.
task = new Task();
// add a property listener to the task so it knows to update the progress meter.
task.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
switch(evt.getPropertyName()) {
case "progress":// set the progress value and the task output value.
selfUpdateProgress.setIndeterminate(false);
int prg = (Integer) evt.getNewValue();
selfUpdateProgress.setValue(prg);
taskOutput.setText("Downloading and unzipping update. Progress = " + prg + "%");
System.out.println("Percent progress: " + prg + "%");
break;
}
}
});
// execute or start the task.
task.execute();
}
/**
* This method will unzip the downloaded file, and start the installation.
* Then it will close this program while the installation completes.
*
*
*/
public void unzipNewUpdater() {
// create strings for naming the zip file to open up and where to put it.
String zipFile = "NewUpdater.zip";
String outputFolder = System.getenv("SystemDrive") + "\\DynastyAddons";
// Try the unzipping and catch any errors.
try {
// Setup the input stream and get the entry ready to unzip.
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile));
ZipEntry ze = zis.getNextEntry();
// loop to open each entry and output it to the output folder and file.
while(ze!=null) {
// Get the name
String entryName = ze.getName();
// get the file to unzip
File f = new File(outputFolder + File.separator + entryName);
// Create folders needed to hold the unzipped stuff
f.getParentFile().mkdirs();
// get output stream setup to copy the file to from the zip
FileOutputStream fos = new FileOutputStream(f);
// get length of file to make sure we get the whole thing moved
int len;
byte buffer[] = new byte[1024];
// loop thru the entry writing the whole file to the output directory
while((len = zis.read(buffer)) > 0){
fos.write(buffer, 0, len);
}
// close the output stream and get the next entry ready for the next iteration of the loop.
fos.close();
ze = zis.getNextEntry();
}
// close the entry and input stream since we're done.
zis.closeEntry();
zis.close();
} catch (FileNotFoundException ex) {
// throw error
} catch (IOException ex) {
// throw error
}
}
// This private class handles the download and unzip of the new updater if needed.
class Task extends SwingWorker<Void, Void> {
#Override
public Void doInBackground() {
try {
HttpConnect conn = new HttpConnect();
String downloadURL = util.URL_CONNECT + "action=download_updater&platform=" + util.getOSType();
conn.downloadFile(downloadURL);
InputStream inputStream = conn.getInputStream();
FileOutputStream outputStream = new FileOutputStream(System.getenv("SystemDrive") + "\\DynastyAddons\\NewUpdater.zip");
byte[] buffer = new byte[util.BUFFER_SIZE];
int bytesRead = -1;
long totalBytesRead = 0;
int percentCompleted = 0;
long fileSize = conn.getContentLength();
taskOutput.setText("Downloading Newest Updater.");
//setProgress(0);
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
percentCompleted = (int) (totalBytesRead * 100 / fileSize);
setProgress(percentCompleted);
}
outputStream.close();
conn.disconnect();
} catch (IOException ex) {
JOptionPane.showMessageDialog(util.getRootFrame(), "Error downloading Updater file. Please send this entire error to support#dynastyaddons.com. \n Error: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
setProgress(0);
}
return null;
}
#Override
public void done() {
// Create msg window saying update downloaded.
JOptionPane.showMessageDialog(util.getRootFrame(), "The new updater has been downloaded. \nClick OK to close this updater and start the installation of the new version.", "Attention", JOptionPane.PLAIN_MESSAGE);
// Unzip the updater
unzipNewUpdater();
// Tell the cursor we're not busy anymore
setProgress(100);
selfUpdateProgress.setValue(100);
taskOutput.setText("Done Downloading New Updater. Installing...");
util.getRootFrame().setCursor(null);
// Create command used to open the udpater installer.
String cmd = "cmd /c " + System.getenv("SystemDrive") + "\\DynastyAddons\\InstallDynastyAddonsUpdater.exe";
// Here is where we run the exe that will install the new updater.
try{
Runtime.getRuntime().exec(cmd);
}catch (FileNotFoundException ex){
// handle this error
}catch (IOException ex) {
// handle this error
}
// Now close this updater so the new one can install.
System.exit(0);
}
}
}
I'm hopin it'll all compile properly if you need to see it working. If not let me know and i'll update stuff to make it work on a compile. So I've tried a number of things, making the SelfUpdater class implement PropertyChangeListener and implementing PropertyChange(event), I've tried feeding the JProgressBar to a constructor in the Task class. I've tried outputting an Integer in the SwingWorker and using Publish and Process to update the taskOutput and JProgressBar, I've tried re-writing the whole damn class to fix up the code and make it eaiser to pick out issues. I've done tests using the tutorials and some of my code to make it work (they worked great) but every time I come back to my updater code here, the darn progressbar wont update. I'm really prayin someone can give me a bit of insight on this problem so I can wrap up this project and start on something new! This is the very last thing I have to fix (unless there's problems on the Mac) and I'm done it and can go back to testing and getting it distributed to our customers.
Feel more than free to comment on any part of the code as well (anything I maybe did stupid or something) I'm always lookin for critisim on my code especially if I'm not doing something according to good design and.. ugh brain froze forgot the word here. and definitely if more info is needed I can easily just paste in all the code in the 7 classes that make up this updater.
It all compiles, and works fine, except this jprogressbar wont display the progress, even tho I can get it to pring out in the console. Thank you in advance, sorry for the mini-novel here, Haven't had to ask a question yet, and have been able to figure everything eout from other peoples questions and answers, just stumped now and ready to be done with this! :D
I apologize in advance if I've screwed something up in the post here, remember it's my first post and while I've read hundreds of them, I'm sure my noobness has messed something up so feel free to castigate me for my mistakes so I can fix them. :)
EDIT Updated the selfUpdater.java to reflect using of only one spring layout.
What you have there are layout problems, not anything SwingWorker related. The JProgressBar is updating nicely, you just can't see it.
Check your main method. You are creating two instances of SelfUpdater, adding one to your GUI and updating the other.
public static void main(String[] args) {
util = new Updater(); // <-- don't do this, it calls Swing code from a thread that is not EDT
// Schedule a job for the event dispatch thread.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// setup a new GUI
util.createGUI(); // <-- creates an instance of SelfUpdater and adds it to GUI
JFrame rFrame = util.getRootFrame();
JPanel gFrame = util.getCardLayoutFrame();
CardLayout cards = (CardLayout) gFrame.getLayout();
cards.show(gFrame, "UpdateUpdaterPanel");
rFrame.pack();
rFrame.setLocationRelativeTo(null);
rFrame.setVisible(true);
SelfUpdater selfUp = new SelfUpdater(); // <-- creates another instance
int needUpdate = selfUp.checkForUpdate();
if (needUpdate == 2) {// Update available for download. Download it.
selfUp.downloadUpdate();
}
}
});
}
You can't expect components to be shown, if they are not added anywhere. :)
Have you tried to put the updating code of the jProgressBar in an extra thread? http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
I had a similar problem once, the progressbar didn't progress and when it was all done, the progressbar showed 100%.
I am using java and trying to write a simple sudo mouse recorder that will store the mouse position when the space key is pressed. The only key I need to detect is the space key (Although if another key is easier, that will work).
I need the whole mouse recorder to be written in java, but it is OK if the function for the keypress is in another language. And I will be runing this in Windows 7.
What is the simplest way to do what has been described? All of the methods I have found require at minimum 20 lines of code. This is OK, except I don't understand how to implement them. I have an example source below:
import java.awt.MouseInfo;
import javax.swing.JOptionPane;
public class MouseRecorder {
public static void main (String[] args)
{
int slot = 0;
int xLoc[10];
int yLoc[10];
while (slot <= 10)
{
if (keyPressed(KEY_SPACE)) //<<<<This obviously won't work, but I'm looking for the simplest way to code this
{
xLoc[slot] = MouseInfo.getPointerInfo().getLocation().x;
yLoc[slot] = MouseInfo.getPointerInfo().getLocation().y;
slot++;
}
}
//The mouse information can now be utilized
}
}
Again your question is not clear since you have not addressed my comment:
It smells like to me that you might want a system-wide key logger that only responds to one key press, and that doesn't need a GUI. If this is so, then your best solution is to not use Java to create your application but to use a tool that can get closer to the OS. AutoIt comes to mind if this is for a Windows project. Please define your needs better.
and this forces us to guess at the problem and its solution.
If you are interested in creating a Swing GUI, having it take focus, and have it listen to key events, then the solution is to do this:
Create your Swing GUI and display it, leaving it as the active windowed application while your application is running.
Using Key Bindings have it listen for space bar presses
And then log the mouse location when the space bar is pressed.
As noted, this will not be achievable in 5 lines of code, so put that idea to the side.
If on the other hand your desire is to not have a GUI but rather listen for hot-key presses while any and all applications are running, then
The possible platforms used will be critical since your solution will require OS-specific code since creating a hot-key means having to create a keyboard handler routine, often in C, and doing this for each platform, and then linking it in to Java using JNI or JNA.
Or as noted another way is to link your Java program with an OS specific utility program or script such as AutoIt.
If you need more specific help, then please clarify your question.
Edit
You state:
Thank you for the answer, but as I have described above: "Changing languages is out of the question although it seems like that might be easier." and "I dont want a gui, if I can avoid it"
Then my second answer is what you're looking for. How adept are you at C/C++, JNI or JNA, and how good is your knowledge of operating system libraries? If you want a Java only solution, I would consider your requirements far above beginner or intermediate Java and into the realm of advanced -- or at least beyond my abilities at the moment, although I am sure that I could come up with some solutions after several days to a week or two of study.
... or consider getting rid of your "changing languages" requirement and instead allow at least meshing Java together with a scripting utility, like AutoIt. That could allow creation of solutions in a shorter period of time, at least for me. A limitation though is that these would be platform specific solutions. What is your purpose behind all of this? Could this be an XY problem in disguise?
Edit 2
I decided to try to solve this with a small AutoIt utility that I meshed with Java, and this is what I came up with.
My AutoIt program is called CaptureHotKey.au3, and it is compiled to an exe before use:
$key = $CmdLine[1]
HotKeySet($key, "hotKeyFunction")
While 1
Sleep(100)
WEnd
Func hotKeyFunction()
ConsoleWrite(#CRLF)
EndFunc
There's not much to it. All it does is set a hot-key from the first command line parameter, provides an endless while loop so that it will continue to run, and a hotkey function that is quite simple and only sends a carriage-return/line-feed to the console (which will be the standard output).
Then a Java class to help interact with this. It uses SwingPropertyLanguageSupport to allow addition of PropertyChangeListeners that respond on the Swing thread (in case I want to use this with a GUI).
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import javax.swing.event.SwingPropertyChangeSupport;
public class CaptureHotKey implements Runnable {
public static final String HOT_KEY = "hot key";
private String hotKey;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private Scanner scanner;
private CaptureHotKeyFromAutoIt capture;
public CaptureHotKey(final String hotKey) throws IOException {
this.hotKey = hotKey;
capture = new CaptureHotKeyFromAutoIt(hotKey);
scanner = new Scanner(capture.getReadable());
}
public void startCapturing() {
new Thread(this).start();
}
public void exit() {
if (capture != null) {
capture.exit();
}
if (scanner != null) {
scanner.close();
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public String getHotKey() {
return hotKey;
}
#Override
public void run() {
while (scanner != null && scanner.hasNextLine()) {
scanner.nextLine();
pcSupport.firePropertyChange(HOT_KEY, true, false);
}
}
private static class CaptureHotKeyFromAutoIt {
public static final String AUTO_IT_APP_PATH = "CaptureHotKey.exe";
private Process process = null;
private ProcessBuilder pb;
public CaptureHotKeyFromAutoIt(String hotKey) throws IOException {
List<String> cmdList = new ArrayList<>();
cmdList.add(AUTO_IT_APP_PATH);
cmdList.add(hotKey);
pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
process = pb.start();
}
public void exit() {
if (process != null) {
process.destroy();
}
}
public Readable getReadable() {
if (process != null) {
return new InputStreamReader(process.getInputStream());
}
return null;
}
}
}
Finally a Java class to test this set up:;
This adds a PropertyChangeListener to the class above to allow it to be notified if the hot-key is pressed:
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.Scanner;
public class CaptureHotKeyTest {
public static final String CTRL_R = "^r"; // "{SPACE}" works for spacebar
private static final String EXIT = "exit";
private CaptureHotKey capture;
public CaptureHotKeyTest() {
try {
capture = new CaptureHotKey(CTRL_R);
capture.addPropertyChangeListener(new HotKeyPropertyChngListener());
capture.startCapturing();
Scanner scan = new Scanner(System.in);
System.out.println("Press control-r to get mouse position.");
System.out.println("Type \"exit\" to exit program");
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.equalsIgnoreCase(EXIT)) {
scan.close();
capture.exit();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private class HotKeyPropertyChngListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(CaptureHotKey.HOT_KEY)) {
System.out.println("hot key pressed");
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
System.out.println("Mouse: " + pointerInfo.getLocation());
}
}
}
public static void main(String[] args) {
new CaptureHotKeyTest();
}
}
You should use KeyListener: http://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html
It works fine with Swing
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//Return the string "stats" to gameLoop() as cmd
}
});
public void gameLoop(){
Scanner lineScanner = new Scanner(System.in);
cmd = "";
System.out.print(getBoard().printBoard(false));
while (!cmd.equals("quit")) {
System.out.print(">");
Scanner wordScanner = new Scanner(lineScanner.nextLine());
if (wordScanner.hasNext()) {
cmd = wordScanner.next();
if (cmd.equals("board")) {
System.out.print(getBoard().printBoard(false));
} else if (cmd.equals("ships")) {
System.out.print(getBoard().printBoard(true));
} else if (cmd.equals("help")) {
printHelp();
} else if (cmd.equals("stats")) {
printStats();
} else if (cmd.equals("fire")) {
if(fire(wordScanner)) {
printStats();
cmd = "quit";
}
} else if (cmd.equals("quit")) {
} else if (!cmd.equals("")) {
System.out.println(ILLEGAL_COMMAND);
}
}
}
}
What I'm trying to do is that when the user clicks the statsButton, the String cmd in the gameLoop would be changed to "stats". The statsButton and the gameLoop() are located in two different classes. Anyone can give me an idea how to do it? (I've attempted pipedreader/pipedwriter) and I just can't seem to get it right.
*I'm basically trying to make my console application into a GUI application without changing the original console application.
Edit: What I've tried
Class textBased
PipedInputStream in = new PipedInputStream()
public void gameLoop(){
try{
in.connect(GUIclass.out);
Scanner lineScanner = new Scanner(in);`
Class GUIclass
PipedOutputStream out = new PipedOutputStream();
PrintWriter writer;
public GUIclass(){
final PrintWriter writer = new PrintWriter(out);
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
writer.println("stats");
}
});
that's what I tried writing but it doesn't seem to work.
Regarding
I'm basically trying to make my console application into a GUI application without changing the original console application..."
My advice is simple: "don't do it".
The two applications have completely different structure, one being linear, the other being event-driven, and are not directly translatable to each other. Better to make a new GUI program from the ground up. Now if your non-GUI application contains some well-structured and behaved object-oriented classes, then by all means use those classes in your GUI's "model" or logic section, but don't try to directly translate the program flow of one type of application to the other.
Edit
Based on your posted requirements:
"You should be able to play your Battleship game through your GUI interface. In addition, the text-based front-end you wrote for project 1 should still "work" and be playable."
Correct me if I'm wrong, but I'm betting that you have several classes involved here, and only one of them is the "text-based front-end". If so, then use the non front-end classes as the model of your GUI as I suggested above, but do not use the text-based front-end for anything GUI related, and do not try to emulate it in your GUI.
Have the console application instantiate the button ActionListener and pass it to the UI. When the action event is fired, the listener will tell the console app that it happened. The method in the ActionListener will tell it what to do.
I agree with Hovercrafts comment (changed to a reply).
But in general for problems like this I would change the method signature of your gameLoop(). I would use:
public void gameLoop(Reader reader)
Then you can pass different types of readers to the loop depending on the requirement.
For a console you might do something like:
gameloop( new InputStreamReader( System.in ) );
For a GUI you could do something like:
gameLoop ( new StringReader("some text") );
Edit:
Without changing the method signature you can redirect System.in to come from the String retrieved by the ActionListener:
public class Test
{
public static void main(String args[]) throws Exception
{
String text = "some text";
System.setIn( new ByteArrayInputStream( text.getBytes() ) );
// gameloop();
Scanner lineScanner = new Scanner(System.in);
System.out.println( lineScanner.nextLine() );
}
}
If you have something like this :
class B {
public void gameLoop(){
..
}
}
and
class A{
statsButton.addActionListener(new ActionListener() {
...
});
}
You can declare reference to B in A with final . In that case it's will be visible in inner class ActionListener.
class A{
final B b = ...; //final variable is visible in inner class
statsButton.addActionListener(new ActionListener() {
b.gameLoop();
...
});
}
hi i have a full screen program which i dont want people to close unless they have a password i have this code at the moment
public void windowClosing(WindowEvent arg0)
{
System.out.println("HERE");
String inputValue = JOptionPane.showInputDialog("Please input the closeword");
if (inputValue != "closeplz")
{
}
}
in the if statement i want it to stop the method so that the program doesent close. any help would be greatly aprecheated thanks ste
You have to call
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
on (or within) the JFrame instance. Then the frame will not close unless you do it manually, though windowClosing() will still be called. Inside it, you can then conditionally call
System.exit(1);
which will end the application. Be sure to do any necessary cleanup first.
Check out Closing an Applicaton for a simple class to help you with this. You would need to provide the custom close action that prompts the user for the password.
Using your simple example the code would be:
Action ca = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
JFrame frame = (JFrame)e.getSource();
String inputValue = JOptionPane.showInputDialog("Please input the closeword");
if (! inputValue.equals("closeplz"))
{
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
}
}
};
CloseListener cl = new CloseListener(ca);