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've met a problem and I've been struggling last 2 days. I have a compiled program that runs some simulations and visualizes the results in an SVG file. The file is replaced every 2 seconds with a new one, until the simulation is done.
Wanting to visualize the results, I made a java swing program which uses batik and JSVGCanvas to display the svg file and update it every 2 seconds.
The code I use is:
// In the main part of my code
svgCanvas = new JSVGCanvas();
oneLineInnerPanel.add("Center", svgCanvas);
(new Thread() {
#Override
public void run() {
try {
Thread.sleep(2000);
File f = new File("file_that_shows_simulation_still_running");
while (f.exists()) {
svgReloadButtonActionPerformed(null);
Thread.sleep(2000);
}
} catch (InterruptedException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
// -----------------------------------------------
private void svgReloadButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
svgCanvas.loadSVGDocument(SVGFile.toURL().toString());
} catch (MalformedURLException ex) {
Logger.getLogger(testUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
It works fine with the exception that every 30-40 updates, it happens that the loadSVGDocument tries to read the document while it's being written by the simulator and thus I get a jdialog error:
XML document structures must start and end within the same entity.
org.apache.batik.dom.util.SAXIOException: XML document structures must start and end within the same entity.
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:437)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:349)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:200)
at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createSVGDocument(SAXSVGDocumentFactory.java:124)
at org.apache.batik.bridge.DocumentLoader.loadDocument(DocumentLoader.java:106)
at org.apache.batik.swing.svg.SVGDocumentLoader.run(SVGDocumentLoader.java:84)
Caused by: org.xml.sax.SAXParseException; systemId: file:/tmp/tempDir9189341730639722289/svgOut.svg; lineNumber: 272; columnNumber: 2; XML document structures must start and end within the same entity.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:431)
... 5 more
This doesn't affect the whole procedure, but it's ugly. I get 2-3 of these jdialogs throughout the simulation. I cannot lock the file I/O, because I don't have access to the simulator code. If I lock from java only, the simulator crashes saying it cannot access the file.
What I want is that if there is an error while loading the svg file to somehow catch it internally and not have a jdialog. I can accept missing an update every 30-40 times (60-80 secs).
Now, JSVGCanvas gives you the option to provide a useragent and overwrite the displayError() method to do as you like. I tried that but the dialogs still occur. The problem is that the dialogs are not produced by the svgUserAgent I provide but by an internal BridgeUserAgent:
public JSVGComponent(SVGUserAgent ua, boolean eventsEnabled,
boolean selectableText) {
super(eventsEnabled, selectableText);
svgUserAgent = ua;
userAgent = new BridgeUserAgentWrapper(createUserAgent());
addSVGDocumentLoaderListener((SVGListener)listener);
addGVTTreeBuilderListener((SVGListener)listener);
addSVGLoadEventDispatcherListener((SVGListener)listener);
if (updateOverlay != null)
getOverlays().add(updateOverlay);
}
public void loadSVGDocument(String url) {
String oldURI = null;
if (svgDocument != null) {
oldURI = svgDocument.getURL();
}
final ParsedURL newURI = new ParsedURL(oldURI, url);
stopThenRun(new Runnable() {
public void run() {
String url = newURI.toString();
fragmentIdentifier = newURI.getRef();
loader = new DocumentLoader(userAgent);
nextDocumentLoader = new SVGDocumentLoader(url, loader);
nextDocumentLoader.setPriority(Thread.MIN_PRIORITY);
Iterator it = svgDocumentLoaderListeners.iterator();
while (it.hasNext()) {
nextDocumentLoader.addSVGDocumentLoaderListener
((SVGDocumentLoaderListener)it.next());
}
startDocumentLoader();
}
});
}
Can anyone help me get out of this mess, please?
Thanks in advance!
Finally solved the issue. Extended JSVGCanvas, override the createUserAgent() method to provide a bridgeuseragent of my own. This useragent extends the JSVGCanvas user agent but overrides the displayError methods. Here's the code:
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.swing.JSVGCanvas;
import org.apache.batik.util.XMLConstants;
/**
*
* #author
*/
public class myJSVGCanvas extends JSVGCanvas{
#Override
protected UserAgent createUserAgent() {
return new myCanvasUserAgent();
}
protected class myCanvasUserAgent extends CanvasUserAgent
implements XMLConstants {
/**
* Displays an error message in the User Agent interface.
*/
#Override
public void displayError(String message) {
if (svgUserAgent != null) {
super.displayError(message);
} else {
System.out.println(message);
// JOptionPane pane =
// new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
// JDialog dialog =
// pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
/**
* Displays an error resulting from the specified Exception.
*/
#Override
public void displayError(Exception ex) {
if (svgUserAgent != null) {
super.displayError(ex);
} else {
ex.printStackTrace();
// JErrorPane pane =
// new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
// JDialog dialog = pane.createDialog(myJSVGCanvas.this, "ERROR");
// dialog.setModal(false);
// dialog.setVisible(true); // Safe to be called from any thread
}
}
}
}
Hope it helps somebody. If anyone has a better idea for dealing with the problem, than just hiding it, I'd be glad to hear it!
I'm desperatly trying to implement a customized copy/paste in a JTextPane in HTML mode.
The most part is working well, I get the html content using EditorKit.write(), I paste it using editorKit.read(). Perfect world.
BUT, when I have : <p> test </p> in my editor and I try to copy "es" to obtain
<p> tesest </p>, I obtain instead
<p>tes</p>
<p>es</p>
<p>t</p>
Knowing that, I m trying to figure out a way to paste "inline" the part supposed to be inline, and in block the part which was in block during the copy. Typically,
if I have :
<p>mon beau sapin</p>
<p>roi des forêts</p>
<p>que j'aime ta verdure</p>
And if I copy :
beau sapin</p>
<p>roi des forêts</p>
<p>que
And paste it after "mon", I expect :
<p>mon beau sapin</p>
<p>roi des forêts</p>
<p>que beau sapin</p>
<p>roi des forêts</p>
<p>que j'aime ta verdure</p>
And I obtain instead :
<p>mon</p>
<p>beau sapin</p>
<p>roi des forêts</p>
<p>que</p>
<p>beau sapin</p>
<p>roi des forêts</p>
<p>que j'aime ta verdure</p>
I tried various approach, like removing the <p></p> of the first and last lines (EditorKit.read add it back by itself), using editorKit.insertHTML (but what kind of Tag should I put ?), insert line by line (most part of times, I obtain a p inside another p) etc.
but the real problem that it's impossible to write what you want in the htmlDocument. How can I write sapin</p> <p>roi at a specified position ?
EditorKit.read ? it will add <p>sapin</p> <p>roi</p>
Editorkit.insertHTML ? I need to precise a wrapping Tag...
I show you my last try :
private static void insertHTMLContent(JMathTextPane jtp, String html, int offset) {
Document doc = Jsoup.parse(html);
Elements elts = doc.body().children();
//unwrap the last and first element
if(elts.size()>2) { elts.last().unwrap(); }
if(elts.size()>=1) { elts.first().unwrap(); }
//We add a fake DIV element and remove it just at the next line
editorKit.insertHTML(jtp.htmlDoc, offset, "<div id='copie'>"+doc.body().html()+"</div>", 0, 0, HTML.Tag.DIV);
jtp.getHTMLdoc().setOuterHTML(jtp.getHTMLdoc().getElement("copie"),doc.body().html());
}
I can't show you the result : EditorKit.write tries to fix the html by itself. But the HTMLDocument is completely messy.
For you to try :
public class Test {
private static JTextPane editor = new Editor();
private static JMenuBar menu = new Menu();
private static String clipboard = "";
private static Action copy = new Copy();
private static Action paste = new Paste();
public static void main(String[] args) {
JFrame f = new JFrame();
f.setContentPane(editor);
f.setJMenuBar(menu);
f.setSize(600, 400);
f.setVisible(true);
}
public static class Editor extends JTextPane {
public Editor() {
this.setDocument(new HTMLDocument());
this.setEditorKit(new HTMLEditorKit());
}
}
public static class Menu extends JMenuBar {
public Menu() {
add(new JButton(copy));
add(new JButton(paste));
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK), "copy");
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), "paste");
getActionMap().put("copy", copy);
getActionMap().put("paste", paste);
}
}
public static class Copy extends AbstractAction {
public Copy() {super("copy");}
#Override
public void actionPerformed(ActionEvent e) {
StringWriter w = new StringWriter();
try {
editor.getEditorKit().write(w, editor.getDocument(), editor.getCaretPosition(), editor.getSelectedText().length());
} catch (Exception ex) {Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);}
clipboard = w.toString();
}
}
public static class Paste extends AbstractAction {
public Paste() {super("paste");}
#Override
public void actionPerformed(ActionEvent e) {
try {
editor.getEditorKit().read(new StringReader(clipboard), editor.getDocument(), editor.getCaretPosition());
} catch (Exception ex) {Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);}
}
}
}
Sorry I was long. I accept any help.
I am afraid there is no easy way. When you paste you would like to keep original paragraph and avoid new <p> creation, right? The problem is current paragraph and copied one may have different attributes. E.g. current is left aligned but copied one has right alignment.
How to resolve the case? To simplify this kit just creates <p> element.
You can try to create an independent HTMLDocument from the clipboard content and iterate through the Document's structure extracting elements (paragraphs and texts) and inserting them in the original document.
For further readers, I solved it with a very easy trick. I just removed the \n added before and after the pasted text when needed.
public static void copyContent(JTextPane jtp, String text, int offset) {
try {
boolean start = offset>0 ? !jtp.getText(offset-1, 1).equals("\n") : false;
Position p = jtp.getDocument().createPosition(offset);
new HTMLEditorKit().read(new StringReader(html), jtp.getHTMLdoc(), offset);
if(start) {jtp.getDocument().remove(offset, 1);}
if(offset>0) {jtp.getDocument().remove(p.getOffset()-1, 1);}
} catch (IOException | BadLocationException ex) {
Logger.getLogger(EditeurIO.class.getName()).log(Level.SEVERE, null, ex);
}
}