I'm currently trying to add some images from a decoded video to a TableView row and they are not appearing. Only empty TableColumns. The TableView has been designed in JavaFx Scene Builder along with the Label.
Here's what I got so far:
public class MainScreenController implements Initializable {
#FXML
private Label previewBoxLabel;
#FXML
private TableView tableView;
private ObservableList<ImageView> imageList = FXCollections.observableArrayList();
#FXML
public void AddClipBeta(){
//Code which uses an external class in order to decode video (Variables Frames, width and height are not shown but are present in the actual code)
VideoSegment clip = new VideoSegment(0, file.getPath(), 0, Frames, width, height);
//Opens the file in decoding class - ready to output frames
try{clip.openFile();} catch(Exception e){}
//First frame is updated on the preview box
previewBoxLabel.setGraphic(new ImageView(convertToFxImage(clip.getThumbnail())));
System.out.println(file.getPath());
int i =0;
//While loop in test phase to see whether or not 10 frames will be visible in the table
while(i != 10){
//Creates and sets columns to tableView
TableColumn<ImageView, ImageView> col = new TableColumn<ImageView, ImageView>();
col.setPrefWidth(100); //Set width of column
tableView.getColumns().add(col);
col.setCellFactory(new Callback<TableColumn<ImageView, ImageView>, TableCell<ImageView, ImageView>>() {
#Override
public TableCell<ImageView, ImageView> call(TableColumn<ImageView, ImageView> p) {
TableCell<ImageView, ImageView> cell = new TableCell<ImageView, ImageView>(){
};
return cell;
}
});
//Adds current frame to list
imageList.add(new ImageView(convertToFxImage(clip.getThumbnail())));
//Gets next video frame
try{clip.getNextFrame();} catch(Exception e){}
//Updates counter
i++;
}
//Sets list of frames on the table
tableView.setItems(imageList);
}
// There is a problem with this implementation: transparent pixels on the BufferedImage aren't converted to transparent pixels on the fxImage.
public static javafx.scene.image.Image convertToFxImage(java.awt.image.BufferedImage awtImage) {
if (Image.impl_isExternalFormatSupported(BufferedImage.class)) {
return javafx.scene.image.Image.impl_fromExternalImage(awtImage);
} else {
return null;
}
}
I've been struggling understanding how the TableView works the last couple of days and it would be a real breakthrough if we could get to the bottom of this.
Thanks for reading and any help in advance!
When setting a CellFactory, you need to take in to account that it will override some default bevaiours such as setting text and images.
For example. I had to create a ListView of Applications that launched on double click. I had to set a CellFactory in order to add a listener to the mouse click of each individual cell.
applications.setCellFactory(new Callback<TreeView<Application>, TreeCell<Application>>() {
#Override
public TreeCell<Application> call(TreeView<Application> param) {
return new TreeCell<Application>() {
#Override
protected void updateItem(Application item, boolean empty) {
//call the origional update first
super.updateItem(item, empty);
//the root item in my list is null, this check is required to keep a null pointer from happening
if (item != null) {
// text and graphic are stored in the Application object and set.
this.setText(item.getApplicationListName());
this.setGraphic(item.getGraphic());
// registers the mouse event to the cell.
this.setOnMouseClicked((MouseEvent e) -> {
if (e.getClickCount() == 2) {
try {
this.getItem().launch(tabBar);
} catch (UnsupportedOperationException ex) {
Dialogs.create().nativeTitleBar().masthead("Comming Soon™").message("Application is still in development and will be available Soon™").nativeTitleBar().title("Unavailable").showInformation();
}
} else {
e.consume();
}
});
}else if(empty){
this.setText(null);
this.setGraphic(null);
this.setOnMouseClicked(null);
}
}
};
}
});
This was pieced together from some other code so if there is anything else you would like explained, let me know!
I managed to sort this out with the help of you guys. Basically, what I did was make a class with a bunch of setters and getters and a constructor that takes in ImageViews and sets it to a variable in the class via it's constructors. Then I went back to my code and added the following:
Class with Getters and Setters:
import javafx.scene.image.ImageView;
public class tableDataModel {
private ImageView image;
public tableDataModel(ImageView image){
this.image = image;
}
public ImageView getImage(){
return image;
}
public void setImage(ImageView image){
this.image = image;
}
}
Code from MainScreenController:
TableColumn<tableDataModel, ImageView> col = new TableColumn<>();
tableView.getColumns().add(col);
imageList.add(new tableDataModel(new ImageView(convertToFxImage(clip.getThumbnail()))));
col.setPrefWidth(50);
col.setCellValueFactory(new PropertyValueFactory<tableDataModel, ImageView>("image"));
int i = 0;
while (i != 10) {
try {
imageList.add(new tableDataModel(new ImageView(convertToFxImage(clip.getNextFrame()))));
} catch (Exception e) {
}
i++;
}
tableView.setItems(imageList);
Related
I'm currently creating an inventory system in which the user can select an item from their inventory list collection, and the icon on the right will update.
As of now, I've implemented a ClickListener to get the currently selected item from the inventory list and called the .getImage() method that I created to get the icon of the selected item.
I used table.add(image); to add the icon to the table. However, when the icon is added to the table, it fills up that space, and another column is created to the right when the user selects on another item. This is the issue.
How do I get the image area to update when the user selects another item, rather than creating another column to the right?
This is currently how it is: https://imgur.com/a/O6SW8gi
I want the area where the sword is to be updated with the latest item that the user has clicked on.
Here is my code:
package com.sps.game.inventory;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.*;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.sps.game.controller.InventoryController;
import com.sps.game.controller.PlayerController;
import java.util.ArrayList;
public class PlayerInventory {
public Stage stage;
public SpriteBatch sb;
private Viewport viewport;
private Skin skin = new Skin(Gdx.files.internal("core/assets/pixthulhuui/pixthulhu-ui.json"));
private List<Item> inventory;
private List<Image> itemImages;
private InventoryController inventoryController;
private InputProcessor oldInput;
Table table = new Table(skin);
public PlayerInventory(SpriteBatch sb, PlayerController playerController) {
this.sb = sb;
viewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), new OrthographicCamera());
stage = new Stage(viewport, sb);
inventoryController = new InventoryController();
inventory = inventoryController.getInventoryList();
// itemImages = inventoryController.getImageList();
}
//THIS IS WHERE THE IMAGE IS ADDED
private void formatting() {
stage = new Stage();
Label inventoryLabel = new Label("Inventory", skin);
final Label imageLabel = new Label("Item", skin);
table.setDebug(true);
table.defaults();
table.center();
table.setFillParent(true);
table.add(inventoryLabel);
table.add(imageLabel);
table.row();
table.add(inventory); //need a way to get the current item selected
inventory.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
Item clickedItem = inventory.getSelected();
Image clickedImage = clickedItem.getImage();
table.add(clickedImage);
System.out.println(clickedItem.getName());
}
});
// stage.addActor(itemImages);
stage.addActor(table);
}
public void setInput() {
oldInput = Gdx.input.getInputProcessor(); //Get the old input from the user.
Gdx.input.setInputProcessor(stage); //Set the input to now work on the inventory.
}
public void update() {
if (Gdx.input.isKeyPressed(Input.Keys.I) && oldInput == null) {
formatting();
setInput();
}
if (Gdx.input.isKeyPressed(Input.Keys.O) && oldInput != null) {
stage.dispose();
Gdx.input.setInputProcessor(oldInput);
oldInput = null;
}
}
public void dispose() {
stage.dispose();
}
}
The image is added in the formatting method()-
inventory.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
Item clickedItem = inventory.getSelected();
Image clickedImage = clickedItem.getImage();
table.add(clickedImage);
System.out.println(clickedItem.getName());
}
I found the problem, looking into the LibGDX Wiki Table - Adding Cells it seems you are using the add() method that does not replace the previous actor in the cell, it only adds another one in the row. Instead, you should save your displayed image apart from the List
public class PlayerInventory {
[..........................]
Item clickedItem; // This will save your clicked item
Image clickedImage; // This will save your clicked image;
[..........................]
inventory.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
if (clickedItem == null && clickedImage == null) {
clickedItem = inventory.getSelected(); // This line changed
clickedImage = clickedItem.getImage(); // This line changed
table.add(clickedImage);
} else {
clickedItem = inventory.getSelected(); // This line changed
clickedImage = clickedItem.getImage(); // This line changed
}
System.out.println(clickedItem.getName());
}
}
This will add the image if there was no image before and replace the image if there was one before. Hope this helps!
Solved. You shouldn't use table.add(clickedImage) every time the screen is clicked. add() creates a new cell. Instead, add a placeholder Image just once during initial layout and keep a reference to it. In my ClickListener, i used clickedImage.setDrawable() instead to change what image is displayed.
I have a JavaFX table column which I would like to display a comma-separated list of strings, unless the text does not fit within the current bounds of the cell, at which point it would display, for example, "Foo and 3 others...", or "3 Bars", i.e. reflecting the number of elements in the list.
Is there a way to check, when building a CellValueFactory for a table column, whether the text would overrun the cell, so I could switch between these two behaviors?
You can specify an overrun style for Labeled controls like TableCells.
Overrun style ELLIPSIS will automatically add these ellipses as needed to indicate if the content would have extended outside of the label.
I recommend doing this in a cell factory, like so:
column.setCellFactory(() -> {
TableCell<?, ?> cell = new TableCell<>();
cell.setTextOverrun(OverrunStyle.ELLIPSIS);
return cell;
});
So you would need to use the cell factory instead of the cell value factory.
The reason I recommend cell factory is because the table creates and destroys cells on its own as needed, so you'd have a hard time getting all those instances and setting their overrun behavior if you didn't have control of those cells creation like you do with the cell factory.
New attempt
Try something along these lines, you might need to tweak the method to get the length of your string, and you might want to try to figure out the current length of the table cell whenever you update it, but this should get you started. Think it's a decent approach?
public class TestApplication extends Application {
public static void main(String[] args) {
Application.launch(args);
}
public void start(final Stage stage) {
stage.setResizable(true);
TestTableView table = new TestTableView();
ObservableList<String> items = table.getItems();
items.add("this,is,short,list");
items.add("this,is,long,list,it,just,keeps,going,on,and,on,and,on");
Scene scene = new Scene(table, 400, 200);
stage.setScene(scene);
stage.show();
}
/**
* Note: this does not take into account font or any styles.
* <p>
* You might want to modify this to put the text in a label, apply fonts and css, layout the label,
* then get the width.
*/
private static double calculatePixelWidthOfString(String str) {
return new Text(str).getBoundsInLocal().getWidth();
}
public class TestTableView extends TableView<String> {
public TestTableView() {
final TableColumn<String, CsvString> column = new TableColumn<>("COL1");
column.setCellValueFactory(cdf -> {
return new ReadOnlyObjectWrapper<>(new CsvString(cdf.getValue()));
});
column.setCellFactory(col -> {
return new TableCell<String, CsvString>() {
#Override
protected void updateItem(CsvString item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
String text = item.getText();
// get the width, might need to tweak this.
double textWidth = calculatePixelWidthOfString(text);
// might want to compare against current cell width
if (textWidth > 100) {
// modify the text here
text = item.getNumElements() + " elements";
}
setText(text);
}
}
};
});
this.getColumns().add(column);
}
}
private static class CsvString {
private final String text;
private final String[] elements;
public CsvString(String string) {
Objects.requireNonNull(string);
this.text = string;
this.elements = string.split(" *, *");
}
public int getNumElements() {
return elements.length;
}
public String getText() {
return text;
}
}
}
I would like to make my own method that controles when a component is 'isSelected'.
I have a JList containing multiple JPanel. The constructing class of the JPanel extends ListCellRenderer<>.
To show that one of the JList-component (the JPanels) is selected i use;
#Override
public Component getListCellRendererComponent(..., boolean isSelected, ...) {
if(isSelected){
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
I would like a method that keeps a selected item 'selected' eventhough I choose to select another. I understand this can be done by holding down CTRL, but .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); does not quite do the trick. I would rather like to select multiple by clicking on them, and deselect by clicking on them.
For this i have worked with the ListSelectionMode, but i cant find a way.
When done the above I would like to implement a method that only selects a component in the list when clicked in a certain area (instead of the whole component which is preset). I have made this method, which returns true if the correct area is clicked, else false. But since I cant figure out how to override the mouseevent that makes the components 'isSelected' this has been tricky.
Here is the code for the method I would like to override the 'isSelected' method;
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent evt) {
if(ActionHandler.mouseClickedPrebuild(evt.getPoint())){
//This code runs if that special place is clicked!
//So now the component should be 'isSelected' or
//deselected if it already was 'isSelected'.
}
}
});
This code is in the constructor of my JList
And the mouseClickedPrebuild method;
public static boolean mouseClickedPrebuild(Point point) {
int index = theJList.locationToIndex(point);
Rectangle bounds = theJList.getCellBounds(index,index);
Point p = bounds.getLocation();
return ( ... long list of greater than & less than ...);
//This gives the certain area which is accepted to return true
I solved the issue!
So I get my view showing by running this line;
// UI Class JScrollPane Custom JList
UIConstructor.listview.setViewportView(new ListView( -insert ArrayList here- ));
Here is my ListView. The custom DefaultListSelectionModel I used to solve my problem was posted by #FuryComptuers right here;
JList - deselect when clicking an already selected item
I had to make a few changes to the code, since the two methods in the selectionModel will run before my mouseevent. I saved the variabels staticly, so instead of running the code in setSelectionInterval I did it inside my mousePressed.
I then could add the boolean isSelected which returns true, if a curtain area within a specific list element is clicked.
public class ListViewd extends JList {
static boolean isSelected;
static Point point;
static boolean gS = false;
static int in0;
static int in1;
#Override
public Dimension getPreferredScrollableViewportSize() {
Dimension size = super.getPreferredScrollableViewportSize();
size.setSize(new Dimension(0,0));
return size;
}
public ListView(ArrayList<System> items) {
DefaultListModel<System> list = new DefaultListModel<System>();
for (System item : items) {
list.addElement(item);
}
this.setSelectionModel(new DefaultListSelectionModel() {
boolean gestureStarted = false;
#Override
public void setSelectionInterval(int index0, int index1) {
gS = gestureStarted;
in0 = index0;
in1 = index1;
gestureStarted = true;
}
#Override
public void setValueIsAdjusting(boolean isAdjusting) {
if (!isAdjusting) {
gestureStarted = false;
}
}
});
ListSelectionModel selectionModel = this.getSelectionModel();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
point = e.getPoint();
isSelected = ActionHandler.mouseClickedPrebuild(point);
if(!gS && isSelected){
if (isSelectedIndex(in0)) {
selectionModel.removeSelectionInterval(in0, in1);
} else {
selectionModel.addSelectionInterval(in0, in1);
}
}
}
});
setModel(list);
setCellRenderer(new ListModelPrebuild());
}
List<ColumnConfig<Vo, ?>> l = new ArrayList<ColumnConfig<Vo, ?>>();
l.add(numColumn);
l.add(subjectColumn);
l.add(nameColumn);
l.add(dateColumn);
ColumnModel<Vo> cm = new ColumnModel<Vo>(l);
Grid<Vo> grid = new Grid<Vo>(store, cm) {
#Override
protected void onAfterFirstAttach() {
super.onAfterFirstAttach();
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
loader.load();
}
});
}
};
grid.addCellClickHandler(new CellClickHandler() {
#Override
public void onCellClick(CellClickEvent event) {
// TODO Auto-generated method stub
contentPanel.clear();
contentPanel.add(readPanel(contentPanel));
}
});`
When I click on cell, I want to get the data in the cell corresponding.
The current state,
When you click on of the cell, switch to a different view of the structure.
And I succeeded to connect to the database.
However, I want to get the data of cell or row.
How to get values of grid in GXT?
(example Site:http://www.sencha.com/examples/#ExamplePlace:paginggrid)
GXT Grid works with data stores, more precisely it is a ListStore I think. So that, to get Values of the grid either use that store by grid.getStore(), and after that you basically have a collection of the objects in your grid (grid.getStore().getAll() return List), or you can use Grid's SelectionModel to deal with the grid selected item like this:
grid.getSelectionModel().addSelectionChangedHandler(new SelectionChangedHandler<Vo>() {
#Override
public void onSelectionChanged(SelectionChangedEvent<Vo> event) {
if (grid.getSelectionModel().getSelectedItem() != null) {
// Do whatever you want
} else {
}
}
});
I hope it will help.
If you want to get the value of a single cell you can try this inside the cellClickHandler :-
ListGridRecord record = event.getRecord();
int colNum = event.getColNum();
String fieldName=grid.getFieldName(colNum);
String cellValue=record.getAttribute(fieldName);
cellValue will have the desired value.
I am putting together a slideshow program that will measure a user's time spent on each slide. The slideshow goes through several different magic tricks. Each trick is shown twice. Interim images are shown between the repetition. Transition images are shown between each trick.
On the first repetition of a trick the JPanel color flashes on the screen after a click before the next image is shown. This doesn't happen during the second repetition of the same trick. It's possible that the image is taking too long to load.
Is there an easy way to pre-load the images so that there isn't a delay the first time through?
NOTE: Original code deleted.
EDIT 1/10/2013: This code now works on slower machines. trashgod's second addendum helped the most. The mouseClick control structure periodically asks SwingWorker classes to load 40 images or less of the current trick while also setting the used images to null. I have simplified my code down for this to just two Image[]s and added a main method so it stands alone. Images are still required to run though. This is now pretty bare bones code, and if you're trying to make a slideshow with a lot of images I think it would be a good place to start.
NOTE: I think I figured out how to properly implement SwingWorker while still using multiple Image[]s. trashgod and kleopatra is this implementation in-line with what you were suggesting? I didn't end up using publish and process since I couldn't figure out how to get that to work appropriately with an indexed array, but because the StringWorker doesn't load all images in the array (only 40), and the code calls StringWorker every 20 images, there should be a pretty good buffer.
EDIT 1/10/2013 Changed out MouseListener by instead extending MouseAdapter on my Mouse class. Also fixed my paintComponent method to include a call to super.paintComponent(g).
Added publish/process methods to my SwingWorker class ImageWorker. Added a wrapper class, ArrayWrapper to allow passing imageArray[i] and its corresponding index int i with publish to process.
package slideshow3;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.util.List;
public class SlideShow3 extends JFrame
{
//screenImage will be replaced with each new slide
private Image screenImage;
private int width;
private int height;
//Create panel for displaying images using paintComponent()
private SlideShow3.PaintPanel mainImagePanel;
//Used for keybinding
private Action escapeAction;
//Image array variables for each trick
private Image[] handCuffs; //h
private Image[] cups; //c
//Used to step through the trick arrays one image at a time
private int h = 0;
private int c = 0;
//Used by timeStamp() for documenting time per slide
private long time0 = 0;
private long time1;
public SlideShow3()
{
super();
//Create instance of each Image array
handCuffs = new Image[50];
cups = new Image[176];
//start(handCuffsString);
start("handCuffs");
try
{
screenImage = ImageIO.read(new File("images/begin1.jpg"));
}
catch (IOException nm)
{
System.out.println("begin");
System.out.println(nm.getMessage());
System.exit(0);
}
/******************************************
* Removes window framing. The next line sets fullscreen mode.
* Once fullscreen is set width and height are determined for the window
******************************************/
this.setUndecorated(true);
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
width = this.getWidth();
height = this.getHeight();
//Mouse click binding to slide advance control structure
addMouseListener(new Mouse());
//Create panel so that I can use key binding which requires JComponent
mainImagePanel = new PaintPanel();
add(mainImagePanel);
/******************************************
* Key Binding
* ESC will exit the slideshow
******************************************/
// Key bound AbstractAction items
escapeAction = new EscapeAction();
// Gets the mainImagePanel InputMap and pairs the key to the action
mainImagePanel.getInputMap().put(KeyStroke.getKeyStroke("ESCAPE"), "doEscapeAction");
// This line pairs the AbstractAction enterAction to the action "doEnterAction"
mainImagePanel.getActionMap().put("doEscapeAction", escapeAction);
/******************************************
* End Key Binding
******************************************/
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
SlideShow3 show = new SlideShow3();
show.setVisible(true);
}
});
}
//This method executes a specific SwingWorker class to preload images
public void start(String e)
{
if(e.equals("handCuffs"))
{
new ImageWorker(handCuffs.length, h, e).execute();
}
else if(e.equals("cups"))
{
new ImageWorker(cups.length, c, e).execute();
}
}
//Stretches and displays images in fullscreen window
private class PaintPanel extends JPanel
{
#Override
public void paintComponent(Graphics g)
{
if(screenImage != null)
{
super.paintComponent(g);
g.drawImage(screenImage, 0, 0, width, height, this);
}
}
}
/******************************************
* The following SwingWorker class Pre-loads all necessary images.
******************************************/
private class ArrayWrapper
{
private int i;
private Image image;
public ArrayWrapper(Image image, int i)
{
this.i = i;
this.image = image;
}
public int getIndex()
{
return i;
}
public Image getImage()
{
return image;
}
}
private class ImageWorker extends SwingWorker<Image[], ArrayWrapper>
{
private int currentPosition;
private int arraySize;
private String trickName;
private Image[] imageArray;
public ImageWorker(int arraySize, int currentPosition, String trick)
{
super();
this.currentPosition = currentPosition;
this.arraySize = arraySize;
this.trickName = trick;
}
#Override
public Image[] doInBackground()
{
imageArray = new Image[arraySize];
for(int i = currentPosition; i < currentPosition+40 && i < arraySize; i++)
{
try
{
imageArray[i] = ImageIO.read(new File("images/" + trickName + (i+1) + ".jpg"));
ArrayWrapper wrapArray = new ArrayWrapper(imageArray[i], i);
publish(wrapArray);
}
catch (IOException e)
{
System.out.println(trickName);
System.out.println(e.getMessage());
System.exit(0);
}
}
return imageArray;
}
#Override
public void process(List<ArrayWrapper> chunks)
{
for(ArrayWrapper element: chunks)
{
if(trickName.equals("handCuffs"))
{
handCuffs[element.getIndex()] = element.getImage();
}
else if(trickName.equals("cups"))
{
cups[element.getIndex()] = element.getImage();
}
}
}
#Override
public void done()
{
try
{
if(trickName.equals("handCuffs"))
{
handCuffs = get();
}
else if(trickName.equals("cups"))
{
cups = get();
}
}
catch(InterruptedException ignore){}
catch(java.util.concurrent.ExecutionException e)
{
String why = null;
Throwable cause = e.getCause();
if(cause != null)
{
why = cause.getMessage();
}
else
{
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
}
/******************************************
* End SwingWorker Pre-Loading Classes
******************************************/
//Prints out time spent on each slide
public void timeStamp()
{
time1 = System.currentTimeMillis();
if(time0 != 0)
{
System.out.println(time1 - time0);
}
time0 = System.currentTimeMillis();
}
/******************************************
* User Input Classes for Key Binding Actions and Mouse Click Actions
******************************************/
private class EscapeAction extends AbstractAction
{
#Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
public class Mouse extends MouseAdapter
{
#Override
public void mouseClicked(MouseEvent e)
{
if(!(h<handCuffs.length) && !(c<cups.length))
{
timeStamp();
System.exit(0);
}
else if(h<handCuffs.length)
{
timeStamp();
screenImage = handCuffs[h];
repaint();
System.out.print("handCuffs[" + (h+1) + "]\t");
h++;
//purge used slides and refresh slide buffer
if(h == 20 || h == 40)
{
for(int i = 0; i < h; i++)
{
handCuffs[i] = null;
}
start("handCuffs");
}
if(h == 45)
{
start("cups");
}
}
else if(c<cups.length)
{
timeStamp();
screenImage = cups[c];
repaint();
System.out.print("cups[" + (c+1) + "]\t");
c++;
//purge used slides and refresh slide buffer
if(c == 20 || c == 40 || c == 60 || c == 80 || c == 100 || c == 120 || c == 140 || c == 160)
{
for(int i = 0; i < c; i++)
{
cups[i] = null;
}
start("cups");
}
}
}
}
/******************************************
* End User Input Classes for Key Binding Actions and Mouse Click Actions
******************************************/
}
This example uses a List<ImageIcon> as a cache of images returned by getImage(). Using getResource(), the delay is imperceptible. The next and previous buttons are bound to the Space key by default.
Addendum: You can control navigation by conditioning a button's setEnabled() state using an instance of javax.swing.Timer, for example.
Addendum: Your second example waits until the mouse is clicked to begin reading an image, an indeterminate process that may return a copy immediately or may not complete until after repaint(). Instead, begin reading the images in the background using ImageIO.read(), as shown here. You can process() your List<Image> and show progress, as seen here. The SwingWorker can be launched from the initial thread, running while you subsequently build your GUI on the EDT. You can display the first image as soon as it is processed.