How to load large text file in JTextArea [duplicate] - java

In a Swing application, I sometimes need to support read-only access to large, line-oriented text files that are slow to load: logs, dumps, traces, etc. For small amounts of data, a suitable Document and JTextComponent are fine, as shown here. I understand the human limitations of browsing large amounts of data, but the problematic stuff seems like it's always in the biggest file. Is there any practical alternative for larger amounts of text in the 10-100 megabyte, million-line range?

Because of the size, you'll surely want to load the file in the background to avoid blocking the event dispatch thread; SwingWorker is a common choice. Instead of using a Document, consider updating a TableModel and displaying the lines of text in the rows of a JTable. This offers several advantages:
Results will begin appearing immediately, and there will be reduced perceived latency.
JTable uses the flyweight pattern for rendering, which scales well into the multi-megabyte, million-line range.
You can parse the input as it is being read to create an arbitrary column structure.
You can leverage the sorting and filtering features of JTable, for example.
You can use TablePopupEditor to focus on a single line.
Addendum: The example below uses DefaultTableModel for convenience. To reduce overhead, extend AbstractTableModel and manage a List<String> or List<RowData>, as shown here. The example displays indeterminate progress; changes to display intermediate progress are shown here.
Code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
/**
* #see https://stackoverflow.com/a/25526869/230513
*/
public class DisplayLog {
private static final String NAME = "/var/log/install.log";
private static class LogWorker extends SwingWorker<TableModel, String> {
private final File file;
private final DefaultTableModel model;
private LogWorker(File file, DefaultTableModel model) {
this.file = file;
this.model = model;
model.setColumnIdentifiers(new Object[]{file.getAbsolutePath()});
}
#Override
protected TableModel doInBackground() throws Exception {
BufferedReader br = new BufferedReader(new FileReader(file));
String s;
while ((s = br.readLine()) != null) {
publish(s);
}
return model;
}
#Override
protected void process(List<String> chunks) {
for (String s : chunks) {
model.addRow(new Object[]{s});
}
}
}
private void display() {
JFrame f = new JFrame("DisplayLog");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
JProgressBar jpb = new JProgressBar();
f.add(jpb, BorderLayout.NORTH);
f.add(new JScrollPane(table));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
LogWorker lw = new LogWorker(new File(NAME), model);
lw.addPropertyChangeListener((PropertyChangeEvent e) -> {
SwingWorker.StateValue s = (SwingWorker.StateValue) e.getNewValue();
jpb.setIndeterminate(s.equals(SwingWorker.StateValue.STARTED));
});
lw.execute();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new DisplayLog().display();
});
}
}

I would separate the problem.
The first one is model - Document building speed
The second is the Document rendering - building tree of views to represent the Document.
A question is whether you need font effects like keywords colorizing?
I would start from Document building part. IMHO reading the file via EditorKit.read() should be fast even for big files. I would use the PainDocument for the purpose and check whether the pure model is built fast enough for your application. If yes it's fine just use the Document as model. If not implement your own Document interface because AbstractDocument has plenty of methods for update processing (e.g. writeLock).
When we have the Document loading fast enough we have to solve the Document rendering. BY default the views used in javax.swing.text are really flexible. They are designed as base classes to be extended - thus has a lot of code we don't need. E.g. measuring.
For the feature I would use Monospaced font, we don't need wrap so measurements of the view widht is fast = longest row char count * char widht.
The height is also char height * amount of lines.
So our PLainTextViewReplacement is really fast. Also we don't have to render the whole view but just a fragment visible in our scroll pane. Thus rendering could be mmuch much faster.
Of course there should be a lot of work to provide correct caret navigation, selection etc.

As I was struggeling with a similar use case I implemented a simple paging solution. It is far from perfect but works maybe someone finds it helpful.
In combination with a jtextarea it works ok but with a JEditorPane the performance is miserable.
If someone comes up with a better solution I would like to know about.
package net.ifao.tools.arcticrequester.gui.panel;
import java.awt.Adjustable;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringReader;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
/**
* A class that manages the visibility of file content visualized with a textarea within a scrollbar.
* Approx. 2050 lines from the file are visible at a time. Data is loaded from a file and
* displayed while the user is scrolling. The chunks are loaded dynamically.
*
* #author dostricki
*
*/
public class VisibilityManager
implements AdjustmentListener
{
private int lastLoadedLineFrom;
private int lastLoadedLineTo;
private int numberOfLines = 0;
private File file;
private boolean enabled = false;
private boolean showLines = false;
// load 1000 lines before the first visible line
// and 1000 lines after the last vissible line
private static final int LOAD_LINES_BEFORE_AND_AFTER_VIEWPORT = 1000;
// margin until when no load is triggered.
// moving the viewport more then 900 lines up or down should trigger a reload
private static final int VIEWPORT_LINES_MOVE_THRASHOLD = 900;
private JScrollPane scrollPane;
private JTextComponent textComponent;
private final BlockingQueue<Adjustable> queue;
public VisibilityManager(JScrollPane scrollPane, JTextComponent textArea)
{
this.scrollPane = scrollPane;
this.textComponent = textArea;
queue = new LinkedBlockingDeque<>();
startConsumer();
scrollPane.getVerticalScrollBar().addAdjustmentListener(this);
}
private void startConsumer()
{
Thread scrollEventConsumer = new Thread()
{
#Override
public void run()
{
while (true) {
try {
// if multiple events occured just process one
queue.take();
if (!queue.isEmpty()) {
List<Adjustable> events = new ArrayList<>();
queue.drainTo(events);
//System.out.println("Handling scroll event. " + events.size() + " queued events dropped");
}
doHandleScrollEvent();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
scrollEventConsumer.start();
}
public void setFile(File file)
{
this.file = file;
try {
this.numberOfLines = countNumberOfLines(file);
}
catch (IOException e1) {
e1.printStackTrace();
}
int showLineMax = Math.min(getNumberOfLines(), 100);
// show the first chunk immediately
showLinesBuffererdReader(1, showLineMax, 0);
this.enabled = true;
}
/**
* precalculates the number of lines in the document - necessary
* to replace the correct amount of preceeding and following
* lines with EOL's so that the height of the scrollpane does never change.
*
* #param file
* #return
* #throws IOException
*/
private int countNumberOfLines(File file)
throws IOException
{
int numberOfLines = 0;
//#formatter:off
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),StandardCharsets.UTF_8));) {
while (reader.ready()) {
reader.readLine();
++numberOfLines;
}
}
//#formatter:on
return numberOfLines;
}
/****************************************
* Getter
****************************************/
public int getNumberOfLines()
{
return numberOfLines;
}
public int getNumberOfLinesBuffer()
{
return LOAD_LINES_BEFORE_AND_AFTER_VIEWPORT;
}
public boolean isEnabled()
{
return enabled;
}
/****************************************
* Setter
****************************************/
public void setLastLoadedLines(int lineFrom, int lineTo)
{
this.lastLoadedLineFrom = lineFrom;
this.lastLoadedLineTo = lineTo;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public void setShowLines(boolean showLines)
{
this.showLines = showLines;
}
/****************************************
* Calculation
****************************************/
private boolean needsUpdate(int fromLine, int toLine)
{
boolean isBefore = fromLine < (this.lastLoadedLineFrom - VIEWPORT_LINES_MOVE_THRASHOLD);
boolean isAfter = toLine > (this.lastLoadedLineTo + VIEWPORT_LINES_MOVE_THRASHOLD);
if (isBefore || isAfter) {
return true;
} else {
return false;
}
}
private void showLinesBuffererdReader(int from, int to, int firstLineVisible)
{
//load also the buffer lines before
from = from - getNumberOfLinesBuffer();
//make sure it's valid
from = Math.max(1, from);
// load also the buffer lines after
to = to + getNumberOfLinesBuffer();
//make sure it's valid
to = Math.min(getNumberOfLines(), to);
FileChannel fileChannel = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
StringBuffer content = new StringBuffer();
int newCaretPosition = 0;
// fill leading empty lines
for (long i = 1; i < from; ++i) {
if (i == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(i).append(": ");
}
content.append('\n');
}
// read/write lines with content
int j = 0;
while (reader.ready() && j <= to) {
++j;
String line = reader.readLine();
if (j >= from && j <= to) {
if (j == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(j).append(": ");
}
content.append(line).append('\n');
}
}
// fill trailing empty lines
for (int i = to + 1; i <= getNumberOfLines(); ++i) {
if (i == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(i).append(": ");
}
content.append('\n');
}
updateTextInUI(content);
// workaround for page up/down - it changes the caret position
// so we are re-setting it to the first visible line
// scrolling by scrollbars does not change the caret
//textComponent.setCaretPosition(newCaretPosition);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (fileChannel != null) {
fileChannel.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* #param content
* #throws IOException
*/
private void updateTextInUI(StringBuffer content)
throws IOException
{
if (textComponent instanceof JEditorPane) {
JEditorPane edit = ((JEditorPane) textComponent);
EditorKit editorKit = edit.getEditorKit();
Document createDefaultDocument = editorKit.createDefaultDocument();
createDefaultDocument.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
try {
editorKit.read(new StringReader(content.toString()), createDefaultDocument, 0);
}
catch (Exception e) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
edit.setText(new String(out.toByteArray()));
}
edit.setDocument(createDefaultDocument);
} else {
textComponent.setText(content.toString());
}
}
/****************************************
* Eventing
****************************************/
/**
* fired when scrolling happens in any of the cases and ways.
* Events are cached through a queue so that simultanious events
* don't trigger unnecessary update actions
* #see java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event.AdjustmentEvent)
*/
#Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
Adjustable source = evt.getAdjustable();
if (evt.getValueIsAdjusting()) {
return;
}
if (source != null) {
try {
queue.put(source);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void doHandleScrollEvent()
{
// determine which lines to request to be loaded into the
int height = this.scrollPane.getVerticalScrollBar().getMaximum();
int lines = getNumberOfLines();
if (lines == 0) {
return;
}
float heightPerLine = height / lines;
int visibleLines = Math.round(this.scrollPane.getVerticalScrollBar().getVisibleAmount() / heightPerLine);
int firstLineVisible = (int) Math.ceil(this.scrollPane.getVerticalScrollBar().getValue() / heightPerLine);
int fromLine = Math.max(firstLineVisible, 1);
if (fromLine > lines) {
fromLine = lines;
}
int toLine = Math.min(firstLineVisible + visibleLines, lines);
if (needsUpdate(fromLine, toLine)) {
if (enabled) {
setLastLoadedLines(fromLine, toLine);
showLinesBuffererdReader(fromLine, toLine, firstLineVisible);
}
}
}
}
usage:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.text.DefaultCaret;
import net.ifao.tools.arcticrequester.gui.panel.VisibilityManager;
public class TestFrame
extends JFrame
implements MouseListener
{
private VisibilityManager visibilityManager;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestFrame()
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 650, 500);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
JTextArea textArea = new JTextArea();
textArea.setEditable(false);
textArea.addMouseListener(this);
textArea.setAutoscrolls(false);
textArea.setCaretPosition(0);
DefaultCaret caret = (DefaultCaret) textArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
JScrollPane scrollPane = new JScrollPane(textArea);
contentPane.add(scrollPane);
visibilityManager = new VisibilityManager(scrollPane, textArea);
visibilityManager.setShowLines(true);
File file = new File("C:/iFAO/workspaces/polaris2/git/requester/ArcticRequester/src/test/java/responseview_20200603.tmp");
visibilityManager.setFile(file);
this.dispose();
}
/**
* #see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
#Override
public void mouseClicked(MouseEvent e)
{
boolean doScroll = !visibilityManager.isEnabled();
this.visibilityManager.setEnabled(doScroll);
System.out.println("scrolling set to " + doScroll);
}
/**
* #see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
#Override
public void mousePressed(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
*/
#Override
public void mouseReleased(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
#Override
public void mouseEntered(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
#Override
public void mouseExited(MouseEvent e)
{
// TODO Auto-generated method stub
}
}

Related

JList repaint single element

I've got a JList whose elements consist of image files for which I'm creating thumbnails (in a background Thread). When these thumbnails become available, I'd like to force a repaint of just that item. However, I find that when I use the listModel's fireDataChanged method (see below), all the visible items in the list are repainted (using my custom ListCellRenderer).
public void updateElement(int index) {
frame.listModel.fireContentsChanged(frame.listModel, index, index);
}
Is there any way to cause ONLY the indexed item to be repainted?
Without some kind of runnable example which demonstrates your issue, it's impossible to make any concrete recommendations.
The following simple example makes use of a SwingWorker to change the value of the elements within the ListModel. To make it look more realistic, I've shuffled the List of indices and applied a short delay between each.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private DefaultListModel<String> model = new DefaultListModel<>();
public TestPane() {
setLayout(new BorderLayout());
add(new JScrollPane(new JList(model)));
JButton load = new JButton("Load");
add(load, BorderLayout.SOUTH);
load.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
load.setEnabled(false);
model.removeAllElements();
for (int index = 0; index < 100; index++) {
model.addElement("[" + index + "] Loading...");
}
LoadWorker worker = new LoadWorker(model);
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println(evt.getPropertyName() + " == " + evt.getNewValue());
if ("state".equals(evt.getPropertyName())) {
Object value = evt.getNewValue();
if (value instanceof SwingWorker.StateValue) {
SwingWorker.StateValue stateValue = (SwingWorker.StateValue) value;
if (stateValue == SwingWorker.StateValue.DONE) {
load.setEnabled(true);
}
}
}
}
});
worker.execute();
}
});
}
}
public class LoadResult {
private int index;
private String value;
public LoadResult(int index, String value) {
this.index = index;
this.value = value;
}
public int getIndex() {
return index;
}
public String getValue() {
return value;
}
}
public class LoadWorker extends SwingWorker<Void, LoadResult> {
private DefaultListModel model;
public LoadWorker(DefaultListModel model) {
this.model = model;
}
public DefaultListModel getModel() {
return model;
}
#Override
protected void process(List<LoadResult> chunks) {
for (LoadResult loadResult : chunks) {
model.set(loadResult.index, loadResult.value);
}
}
#Override
protected Void doInBackground() throws Exception {
int count = model.getSize();
List<Integer> indicies = new ArrayList<>(count);
for (int index = 0; index < count; index++) {
indicies.add(index);
}
Collections.shuffle(indicies);
for (int index : indicies) {
Thread.sleep(15);
publish(new LoadResult(index, "[" + index + "] Has been loaded"));
}
return null;
}
}
}
The above is a linear progression, meaning it's processing each item in sequence, one at a time.
Because image loading can take time and is CPU intensive process, you could make use of a ExecutorService and use a pool of threads to help spread the load.
For example:
Java - Multithreading with ImageIO
Make images fetched from server display in real time
Extracting images from a text file of 100 image urls using java
I find that when I use the listModel's fireDataChanged method (see below), all the visible items in the list are repainted
You should NOT invoke that method manually. The fireXXX(...) methods should only be invoked by the model itself.
You should be updating the model by using the:
model.set(...);
The set(...) method will then invoke the appropriate method to notify the JList to repaint the cell.
Here is my attempt at a simple Thumbnail app. It attempts to add performance improvements by:
loading the model with a default Icon so the list doesn't continually need to resize itself
Use a ExecutorService to take advantage of multiple processors
Using an ImageReader to read the file. The sub sampling property allows you to use fewer pixels when scaling the image.
Just change the class to point to a directory containing some .jpg files and give it a go:
ThumbnailApp:
import java.io.*;
import java.util.concurrent.*;
import java.awt.*;
//import java.awt.datatransfer.*;
import java.awt.event.*;
import javax.swing.*;
class ThumbnailApp
{
private DefaultListModel<Thumbnail> model = new DefaultListModel<Thumbnail>();
private JList<Thumbnail> list = new JList<Thumbnail>(model);
public ThumbnailApp()
{
}
public JPanel createContentPane()
{
JPanel cp = new JPanel( new BorderLayout() );
list.setCellRenderer( new ThumbnailRenderer<Thumbnail>() );
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(-1);
Icon empty = new EmptyIcon(160, 160);
Thumbnail prototype = new Thumbnail(new File("PortugalSpain-000.JPG"), empty);
list.setPrototypeCellValue( prototype );
cp.add(new JScrollPane( list ), BorderLayout.CENTER);
return cp;
}
public void loadImages(File directory)
{
new Thread( () -> createThumbnails(directory) ).start();
}
private void createThumbnails(File directory)
{
try
{
File[] files = directory.listFiles((d, f) -> {return f.endsWith(".JPG");});
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool( processors - 2 );
long start = System.currentTimeMillis();
for (File file: files)
{
Thumbnail thumbnail = new Thumbnail(file, null);
model.addElement( thumbnail );
// new ThumbnailWorker(file, model, model.size() - 1).execute();
service.submit( new ThumbnailWorker(file, model, model.size() - 1) );
}
long duration = System.currentTimeMillis() - start;
System.out.println(duration);
service.shutdown();
}
catch(Exception e) { e.printStackTrace(); }
}
private static void createAndShowGUI()
{
ThumbnailApp app = new ThumbnailApp();
JFrame frame = new JFrame("ListDrop");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane( app.createContentPane() );
frame.setSize(1600, 900);
frame.setVisible(true);
// File directory = new File("C:/Users/netro/Pictures/TravelSun/2019_01_Cuba");
File directory = new File("C:/Users/netro/Pictures/TravelAdventures/2018_PortugalSpain");
app.loadImages( directory );
}
public static void main(String[] args)
{
javax.swing.SwingUtilities.invokeLater(() -> createAndShowGUI());
}
}
ThumbnailWorker:
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;
//import java.util.concurrent.*;
import javax.imageio.*;
import javax.imageio.stream.*;
import javax.swing.*;
class ThumbnailWorker extends SwingWorker<Image, Void>
{
private File file;
private DefaultListModel<Thumbnail> model;
private int index;
public ThumbnailWorker(File file, DefaultListModel<Thumbnail> model, int index)
{
this.file = file;
this.model = model;
this.index = index;
}
#Override
protected Image doInBackground() throws IOException
{
// Image image = ImageIO.read( file );
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = readers.next();
ImageReadParam irp = reader.getDefaultReadParam();
// irp.setSourceSubsampling(10, 10, 0, 0);
irp.setSourceSubsampling(5, 5, 0, 0);
ImageInputStream stream = new FileImageInputStream( file );
reader.setInput(stream);
Image image = reader.read(0, irp);
int width = 160;
int height = 90;
if (image.getHeight(null) > image.getWidth(null))
{
width = 90;
height = 160;
}
BufferedImage scaled = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = scaled.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(image, 0, 0, width, height, null);
g2d.dispose();
image = null;
return scaled;
}
#Override
protected void done()
{
try
{
ImageIcon icon = new ImageIcon( get() );
Thumbnail thumbnail = model.get( index );
thumbnail.setIcon( icon );
model.set(index, thumbnail);
System.out.println("finished: " + file);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
ThumbnailRenderer
import java.awt.Component;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class ThumbnailRenderer<E> extends JLabel implements ListCellRenderer<E>
{
public ThumbnailRenderer()
{
setOpaque(true);
setHorizontalAlignment(CENTER);
setVerticalAlignment(CENTER);
setHorizontalTextPosition( JLabel.CENTER );
setVerticalTextPosition( JLabel.BOTTOM );
setBorder( new EmptyBorder(4, 4, 4, 4) );
}
/*
* Display the Thumbnail Icon and file name.
*/
public Component getListCellRendererComponent(JList<? extends E> list, E value, int index, boolean isSelected, boolean cellHasFocus)
{
if (isSelected)
{
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else
{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
//Set the icon and filename
Thumbnail thumbnail = (Thumbnail)value;
setIcon( thumbnail.getIcon() );
setText( thumbnail.getFileName() );
return this;
}
}
Thumbnail:
import java.io.File;
import javax.swing.Icon;
public class Thumbnail
{
private File file;
private Icon icon;
public Thumbnail(File file, Icon icon)
{
this.file = file;
this.icon = icon;
}
public Icon getIcon()
{
return icon;
}
public void setIcon(Icon icon)
{
this.icon = icon;
}
public String getFileName()
{
return file.getName();
}
}
I tested on a directory with 302 images. Using the ExecutorService got the load time down from 2:31 to 0:35.

JFrame appears blank after the first time calling it

This JFrame the first time I call it when the application is running, works perfectly. But when I try to open a new file, the progress bar is meant to return to the screen. See the screen grabs to see how it should look at how it looks thereafter.
public ArrayList<Data> handleData(File fileToOpen) throws FileNotFoundException {
ArrayList<Data> handle = new ArrayList<Data>();
//clear the arraylist the second time round
handle.clear();
BufferedReader reader = new BufferedReader(new FileReader(fileToOpen));
//buffer used for scanner
int lines = 0;
//find out the value of lines here
JFrame loader = new JFrame();
JPanel loadPanel = new JPanel();
JProgressBar progressBar = new JProgressBar(0, lines);
JLabel label = new JLabel();
loader.setDefaultCloseOperation(EXIT_ON_CLOSE);
label.setText("Loading Data...");
loadPanel.add(label);
loadPanel.add(progressBar);
loader.add(loadPanel);
loader.pack();
loader.setVisible(true);
//Do a load of stuff which increments the progress bar
loader.setVisible(false);
return handle;
}
This is how the progress bar and JFrame should look:
This Is how the progress bar looks the second time:
All code:
package Default;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ReadIn extends JFrame {
public File openFile() {
File fileToOpen = null;
JFileChooser fileChooser = new JFileChooser();
int modalToComponent = fileChooser.showOpenDialog(this);
if (modalToComponent == JFileChooser.APPROVE_OPTION) {
fileToOpen = fileChooser.getSelectedFile();
} else if (modalToComponent == JFileChooser.CANCEL_OPTION) {
System.exit(1);
}
return fileToOpen;
}
public ArrayList<Data> handleData(File fileToOpen) throws FileNotFoundException {
ArrayList<Data> handle = new ArrayList<Data>();
handle.clear();
BufferedReader reader = new BufferedReader(new FileReader(fileToOpen));
int lines = 0;
try {
while (reader.readLine() != null)
lines++;
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
Scanner sc = new Scanner(fileToOpen);
System.out.println(sc.nextLine());
System.out.println(sc.nextLine());
System.out.println("Reading Data...");
sc.nextLine();
String split = sc.nextLine();
Scanner splitter = new Scanner(split);
JDialog loader = new JDialog();
JPanel loadPanel = new JPanel();
JProgressBar progressBar = new JProgressBar(0, lines);
JLabel label = new JLabel();
loader.setDefaultCloseOperation(HIDE_ON_CLOSE);
label.setText("Loading Data...");
loadPanel.add(label);
loadPanel.add(progressBar);
loader.add(loadPanel);
loader.pack();
loader.setVisible(true);
while (splitter.hasNext()) {
String peek = splitter.next();
if (peek.equals("Timestamp")) {
peek = peek + splitter.next();
}
Data temp = new Data();
temp.setHeading(peek);
handle.add(temp);
}
while (sc.hasNextDouble()) {
progressBar.setValue(progressBar.getValue() + 1);
for (int i = 0; i < handle.size(); i++) {
handle.get(i).getValues().add(sc.nextDouble());
}
}
System.out.println("Data Loaded");
splitter.close();
sc.close();
loader.setVisible(false);
System.out.println("On EDT?: " + SwingUtilities.isEventDispatchThread());
return handle;
}
}
Without your posting a valid minimal example program, it's impossible for us to know with absolute surety the cause of your problem, the image suggests that it's a Swing threading problem, that you've got long-running code, probably here:
//Do a load of stuff which increments the progress bar
that is blocking the Swing event thread, and that this is causing the Swing GUI not to paint itself.
If so, the solution is to improve your code so that it respects the Swing event thread, so that long-running code is run in a background thread such as via a SwingWorker.
Other issues: that window you display looks to be a "dependent" window and not a main application window. If so, it should not be created as a JFrame but rather as a JDialog, either modal or non-modal depending on your needs.
Also -- why does it work the first time? Likely the first time, the code above is not run on the Swing event thread, the EDT, while the second time that code is called, it is in fact run on the EDT. You can test this by calling SwingUtilities.isEventDispatchThread() and printing out the result. e.g.,
System.out.println("On EDT?: " + SwingUtilities.isEventDispatchThread());
For example:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class UpdateDataEg extends JPanel {
protected static final int MAX_LINES = 200;
public UpdateDataEg() {
setPreferredSize(new Dimension(500, 400));
add(new JButton(new UpdateDataAction("Update Data", KeyEvent.VK_U)));
}
// this must be a void method as you'll get the result from a callback, not
// from this method
public void handleData(final File fileToOpen) {
int lines = 0;
// find out the value of lines here
Window window = SwingUtilities.getWindowAncestor(UpdateDataEg.this);
JDialog loader = new JDialog(window, "Progress", ModalityType.APPLICATION_MODAL);
JPanel loadPanel = new JPanel(new BorderLayout());
final JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
JLabel label = new JLabel();
label.setText("Loading Data...");
loadPanel.add(label, BorderLayout.PAGE_START);
loadPanel.add(progressBar);
loader.add(loadPanel);
loader.pack();
loader.setLocationRelativeTo(window);
final SwingWorker<ArrayList<Data>, Void> myWorker = new SwingWorker<ArrayList<Data>, Void>() {
#Override
protected ArrayList<Data> doInBackground() throws Exception {
ArrayList<Data> handle = new ArrayList<Data>();
// clear the arraylist the second time round
handle.clear();
int lines = 0;
// !! BufferedReader reader = new BufferedReader(new FileReader(fileToOpen));
// !! long code here to do calculations and place into ArrayList<Data>
// emulated by Thread.sleep
// !! set progress property here so that listener can update
while (lines < MAX_LINES) {
lines += (int) (10 * Math.random());
int myProgress = (int) ((lines * 100) / MAX_LINES);
myProgress = Math.min(100, myProgress);
setProgress(myProgress);
Thread.sleep(200);
}
return handle;
}
};
// our callback
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals("progress")) {
int progress = myWorker.getProgress();
progressBar.setValue(progress);
} else if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
// if the worker has finished
loader.setVisible(false);
try {
ArrayList<Data> data = myWorker.get();
// use data here
} catch (InterruptedException | ExecutionException e) {
// TODO handle the exceptions
e.printStackTrace();
}
}
}
});
myWorker.execute();
// if the dialog is modal, this must be last
loader.setVisible(true);
// delete this call as this would be done from the callback
// loader.setVisible(false);
// delete this as this is obtained in the callback
// return handle;
}
private class UpdateDataAction extends AbstractAction {
public UpdateDataAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
handleData(new File("Foobar.txt"));
}
}
private static void createAndShowGui() {
UpdateDataEg mainPanel = new UpdateDataEg();
JFrame frame = new JFrame("UpdateDataEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Data {
}

JTextField: Records inputs history like from Terminal

I would like to develop a Swing application that may contain text field which will act like Terminal (the console from Unix/Linux systems).
Whenever a user entered a command, it will save into a container, then will be accessed thru up or down arrow (↑/ ↓).
I know it is possible but I still don't have the idea in implementing it right. My first implementation is to store the commands into a single text file, then accessed it in reverse order so that last input will be retrieve first.
My problem is that how will I know if I'm in the specified index (e.g. 2 ↑ arrows will go into length-2 index of file).
A very basic example but working fine.you can take user inputs when pressing enter and add them to a collection like arraylist ,vectors .i used vector in this example.when user hit enter store them in a collection and when user press (↑/ ↓) ,take from it back and show in textarea.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
public class terminal extends JFrame {
Vector v = new Vector();
JTextArea area;
int pos = 0;
public terminal() {
setTitle("my terminal");
JPanel j = new JPanel();
setLayout(new GridLayout(1, 1));
setSize(400,250);
j.setLayout(new GridLayout(1, 1));
area = new JTextArea("terminal");
area.setBackground(Color.black);
area.setForeground(Color.white);
area.setCaretColor(Color.white);
area.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
area(evt);
}
private void area(KeyEvent evt) {
int keyCode = evt.getKeyCode();
if (keyCode == 38) {
try {
String store = (String) v.get(v.size() - 1 - pos);
replacer(store);
} catch (Exception ex) {
//ex.printStackTrace();
}
pos++;
evt.consume();
} else if (keyCode == 40) {
try {
String store = (String) v.get(v.size() - 1 - pos);
replacer(store);
} catch (Exception ex) {
//ex.printStackTrace();
}
pos--;
evt.consume();
} else if (keyCode == 10) {
v.add(linetext());
}
}
});
j.add(area);
add(j);
setVisible(true);
}
void replacer(String rep) {
try {
int caretOffset = area.getCaretPosition();
int lineNumber = area.getLineOfOffset(caretOffset);
int startOffset = area.getLineStartOffset(lineNumber);
int endOffset = area.getLineEndOffset(lineNumber);
area.replaceRange(rep, startOffset, endOffset);
} catch (BadLocationException ex) {
//ex.printStackTrace();
}
}
String linetext() {
String text = null;
try {
JTextArea ta = area;
int offset = ta.getLineOfOffset(ta.getCaretPosition());
int start = ta.getLineStartOffset(offset);
int end = ta.getLineEndOffset(offset);
text = ta.getText(start, (end - start));
} catch (BadLocationException ex) {
//ex.printStackTrace();
}
return text;
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
terminal terminal = new terminal();
}
});
}
}
output>>

Downloading file/files in Java. Multithreading, this works?

First, everyone needs to know i'm relatively new to Java coding. To be more precise i'm completely new to Object Oriented Programming.
To the question.
I am trying to create a download class that updates a progress bar it was given to show its progress. And possibly anything else I decide to give it in the future to update.
The issue currently is that, in my head, this shouldn't work. I can do anything i want on the "main" method and the GUI is still responsive and quick. In my experience in past programming, this is not possible unless i thread the GUI. Why is this?
Since it works, is this ok to do it this way?
Class Main
package atomicElectronics;
import java.io.IOException;
import atomicElectronics.physical.AtomFrame;
import atomicElectronics.utility.Download;
public class Initial {
static AtomFrame atomLauncher;
public static void main(String[] args) {
atomLauncher = new AtomFrame();
atomLauncher.start();
System.out.println(Integer.MAX_VALUE);
Download theDownload = new Download();
theDownload.fileProgressBar(atomLauncher.progressBar);
try {
theDownload.exicute("http://download.videolan.org/pub/videolan/vlc/last/win64/vlc-2.1.3-win64.exe", "C:\\Users\\TrinaryAtom\\AppData\\Roaming");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Add Download Methods
// theDownload.updateBarTotal(JProgressBar);
// theDownload.updateLabelSpeed(String);
// theDownload.updateLabelTotal(String);
// theDownload.addFile(File);
// theDownload.addFiles(Files);
}
}
Class AtomFrame
package atomicElectronics.physical;
import javax.swing.JFrame;
import java.awt.FlowLayout;
import javax.swing.JProgressBar;
public class AtomFrame extends JFrame{
public JProgressBar progressBar;
private static final long serialVersionUID = 4010489530693307355L;
public static void main(String[] args){
AtomFrame testFrame = new AtomFrame();
testFrame.start();
}
public AtomFrame(){
initializeComponents();
}
public void initializeComponents(){
this.setSize(400, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Atom Launcher");
this.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
progressBar = new JProgressBar();
this.add(progressBar);
//this.pack();
}
public void start() {
this.setVisible(true);
}
public void close() {
this.dispose();
}
}
Class Download
package atomicElectronics.utility;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.swing.JProgressBar;
public class Download {
private static final int BUFFER_SIZE = 4096;
private JProgressBar fileProgressBar;
public Download() {
}
public void fileProgressBar(JProgressBar fileBar) {
fileProgressBar = fileBar;
}
public void exicute(String fileURL, String saveDir) throws IOException {
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
double contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 9,
disposition.length());
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
double totalRead = 0;
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalRead += bytesRead;
System.out.println((totalRead / contentLength) * 100);
fileProgressBar.setValue((int)((totalRead / contentLength) * 100));
}
outputStream.close();
inputStream.close();
System.out.println("File downloaded");
} else {
System.out.println("No file to download. Server replied HTTP code: " + responseCode);
}
httpConn.disconnect();
}
}
Suggestions:
Use a SwingWorker to do your background thread work.
Inside your SwingWorker, set its progress "bound" property via setProgress(int progress). The value should be between 1 and 100.
Don't have your SwingWorker/file downloader hold the JProgressBar or any Swing components.
Add a PropertyChangeListener to your SwingWorker and monitor changes in the progress property.
Never make your Swing fields (or most and and all fields) public. Limit access, and instead change object state via methods.
Read the tutorial Concurrency in Swing for the necessary details.
For example, the code below is a gross simplification and downloads no files, but should give you the idea:
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.*;
public class Initial {
static AtomFrame atomLauncher;
public static void main(String[] args) {
atomLauncher = new AtomFrame();
atomLauncher.start();
System.out.println(Integer.MAX_VALUE);
final Download theDownload = new Download();
theDownload.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if ("progress".equals(pcEvt.getPropertyName())) {
int progress = theDownload.getProgress();
atomLauncher.setProgress(progress);
}
}
});
theDownload.execute();
}
}
class AtomFrame extends JFrame {
// ********* should be private!
private JProgressBar progressBar;
private static final long serialVersionUID = 4010489530693307355L;
public static void main(String[] args) {
AtomFrame testFrame = new AtomFrame();
testFrame.start();
}
public void setProgress(int progress) {
progressBar.setValue(progress);
}
public AtomFrame() {
initializeComponents();
}
public void initializeComponents() {
this.setSize(400, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Atom Launcher");
this.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
progressBar = new JProgressBar();
this.add(progressBar);
// this.pack();
}
public void start() {
this.setVisible(true);
}
public void close() {
this.dispose();
}
}
class Download extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 300;
private Random random = new Random();
#Override
protected Void doInBackground() throws Exception {
int myProgress = 0;
while (myProgress < 100) {
myProgress += random.nextInt(10);
setProgress(myProgress);
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {}
}
return null;
}
}

SwingWorker ProgressBar

I am trying to get a progress bar to accurately reflect my SwingWorker. But I really can't figure out how to do it. I got the bar to just do a static animation until the operation has completed but I want a real active bar.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package frglauncher;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
/**
*
* #author KYLE-LAPTOP
*/
class DownloadWorker extends SwingWorker<String, Object> {
private String game;
private JProgressBar bar;
private JLabel label;
public DownloadWorker(JProgressBar bar, String game, JLabel label) {
this.game = game;
this.bar = bar;
this.label = label;
}
#Override
public String doInBackground() {
// Download here
label.setText("test");
try {
// ProgressBar/Install
System.out.println("FILELOCATION:\n----------");
String URL_LOCATION = "http://www.futureretrogaming.tk/gamefiles/ProfessorPhys.jar";
String LOCAL_FILE = ("\\" + game + "\\");
File localfile = new File(LOCAL_FILE);
if (localfile.exists()) {
System.out.println("Directory exists!");
}
else {
System.out.println("Directory doesn't exist! Creating...");
localfile.mkdir();
if (localfile.exists()) {
System.out.println("Directory created!");
}
}
System.out.println("LOCALFILE:\n-------");
System.out.println(LOCAL_FILE);
URL website = new URL(URL_LOCATION);
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(LOCAL_FILE + "\\ProfessorPhys.jar\\");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
System.out.println("--------\nDone Downloading\n---------");
RandomAccessFile randomAccessFile = null;
File file = new File(LOCAL_FILE + "ProfessorPhys.jar\\");
JarFile jar = new JarFile(file);
Enumeration enum1 = jar.entries();
while (enum1.hasMoreElements()) {
JarEntry file1 = (JarEntry) enum1.nextElement();
System.out.println("Directory to extract: " + LOCAL_FILE);
System.out.println("\n" + file1.getName() + "\n");
File f = new File(file1.getName());
if (file1.isDirectory()) { // If it's a directory, create it
f.mkdir();
continue;
}
try (InputStream is1 = jar.getInputStream(file1)) {
FileOutputStream fos1 = new FileOutputStream(f);
while (is1.available() > 0) { // Write contents of 'is' to 'fos'
fos1.write(is1.read());
}
fos1.close();
}
}
}
catch (FileNotFoundException ex) {
Logger.getLogger(DownloadWorker.class.getName()).log(Level.SEVERE, null, ex);
}
catch (MalformedURLException ex) {
Logger.getLogger(DownloadWorker.class.getName()).log(Level.SEVERE, null, ex);
}
catch (IOException ex) {
Logger.getLogger(DownloadWorker.class.getName()).log(Level.SEVERE, null, ex);
}
return "done";
}
#Override
protected void done() {
// Done
label.setText("Download of " + game + "is done.");
System.exit(0);
}
}
Several things:
There are four rules to follow with SwingWorker. You can refer to this diagram: .
So, this code:
#Override
public String doInBackground() {
//download here
label.setText("test");
violates that rule. Your label.setText() should be moved to the constructor.
To send "updates" to Swing components (like your progress bar) you want to use the process() method, which you invoke using publish() from inside your doInBackground(). Your second SwingWorker parameter reflects the type of value you want to pass. I've attached two SSCCEs. One passes an Integer to the process() method, the other passes a String. Should give you an idea of what's going on.
SSCCE using Integer:
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
*
* #author Ryan
*/
public class Test {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
go();
}
});
}
public static void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JLabel label = new JLabel("Loading...");
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(false);
int max = 1000;
jpb.setMaximum(max);
panel.add(label);
panel.add(jpb);
frame.add(panel);
frame.pack();
frame.setSize(200,90);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Task_IntegerUpdate(jpb, max, label).execute();
}
static class Task_IntegerUpdate extends SwingWorker<Void, Integer> {
JProgressBar jpb;
int max;
JLabel label;
public Task_IntegerUpdate(JProgressBar jpb, int max, JLabel label) {
this.jpb = jpb;
this.max = max;
this.label = label;
}
#Override
protected void process(List<Integer> chunks) {
int i = chunks.get(chunks.size()-1);
jpb.setValue(i); // The last value in this array is all we care about.
System.out.println(i);
label.setText("Loading " + i + " of " + max);
}
#Override
protected Void doInBackground() throws Exception {
for(int i = 0; i < max; i++) {
Thread.sleep(10); // Illustrating long-running code.
publish(i);
}
return null;
}
#Override
protected void done() {
try {
get();
JOptionPane.showMessageDialog(jpb.getParent(), "Success", "Success", JOptionPane.INFORMATION_MESSAGE);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
SSCCE using String:
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
*
* #author Ryan
*/
public class Test2 {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
go();
}
});
}
public static void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JLabel label = new JLabel("Loading...");
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(true);
panel.add(label);
panel.add(jpb);
frame.add(panel);
frame.pack();
frame.setSize(200,90);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Task_StringUpdate(label).execute();
}
static class Task_StringUpdate extends SwingWorker<Void, String> {
JLabel jlabel;
public Task_StringUpdate(JLabel jlabel) {
this.jlabel = jlabel;
}
#Override
protected void process(List<String> chunks) {
jlabel.setText(chunks.get(chunks.size()-1)); // The last value in this array is all we care about.
System.out.println(chunks.get(chunks.size()-1));
}
#Override
protected Void doInBackground() throws Exception {
publish("Loading Step 1...");
Thread.sleep(1000);
publish("Loading Step 2...");
Thread.sleep(1000);
publish("Loading Step 3...");
Thread.sleep(1000);
publish("Loading Step 4...");
Thread.sleep(1000);
return null;
}
#Override
protected void done() {
try {
get();
JOptionPane.showMessageDialog(jlabel.getParent(), "Success", "Success", JOptionPane.INFORMATION_MESSAGE);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}
}
}

Categories