Icon images not loading fast enough - java

I have an array of JPanel with JLabel with icons that represent a seat at a theater, all of them are generated using loop.
Upon loading the seats, those that are already booked need to have a different image icon. So if(){} check is performed on all the seats to change the label icon if the seat is booked, after they are generated.
But the image icon I have on my disk is not loading fast enough so sometimes the panel adds only to the last one booked or not at all.
Every of those panels that represent the chairs has also MouseListener interfaces added to them. So also on mouse hover or click ImageIcon objects added to the panels are changed, there is too much delay when this happens. I'm thinking that has to do with the images being on the disk!.
How can I load and store those icon images 2,78 KB in size in memory and refer to it in memory, so it wont be delayed reading them?
When a seat is clicked I need to change the label image of that seat and remove mouse listener from that seat. Is there a way to remove the mouse listener to that particular seat without referring to a specific mouse listener. I needed to do that outside of the mouse listener itself!
panel.removeAll();
Does not remove the mouse listener added upon generating the panels.
public void drawSeats(int ammountSeat, int localLength, int localWidth) {
pnlSeatsHolder = new JPanel();
pnlSeatsHolder.setPreferredSize(new Dimension(localLength * 40,localLength * 45));
pnlSeatsHolder.setLayout(new FlowLayout());
for (int d = 0; d <= (ammountSeat); d++) {
imgIconYellow = new ImageIcon("seatYellow.png");
imgIconBlue = new ImageIcon("seatBlue.png");
imgIconRed = new ImageIcon("seatRed.png");
JButton chairs = new JButton();
chairs.setPreferredSize(new Dimension(30, 40));
pnlSeatsHolder.add(chairs);
chairs.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
for (int i = 0; i < listSeatsObjects.size(); i++) {
if (listSeatsObjects.get(i).equals(e.getSource())) {
/*I need to do this also outside of this method! how can i refer to this MouseListener
* to forexample do the equivalent of chairs.removeMouseListener(this);*/
chairs.removeAll();
chairs.setIcon(imgIconRed);
chairs.repaint();
chairs.removeMouseListener(this);
// send information of the chair somewhere else
}
}
}
public void mouseEntered(MouseEvent e) {
// chairs.setBackground(Color.blue);
chairs.removeAll();
chairs.setIcon(imgIconBlue);
chairs.repaint();
}
public void mouseExited(MouseEvent e) {
// chairs.setBackground(Color.BLACK);
chairs.removeAll();
chairs.setIcon(imgIconYellow);
chairs.repaint();
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
});
}
}
so this is the method it self that draws the seats when called. I did some modification as #AndrewThompson suggested, instead of JPanels i use now JButtons, but what happens is that the images are not loaded at all on to the buttons.. what am i missing? neither on mouse hover either.. tho it does work if i had for example charis.setBackgroundColor(); on hover or click.. so i now i need to rather change the buttons images when clicked and on hover, i've tried chairs.chairs.setRolloverIcon(); and .setIcon(); both not working as well. what is wrong. my images are in the same directory as the class files.. so that cant be the issue..
int localLength, int localWidth is the size of the the rooms that seats will be drawn in. about 1m^2/seat

For three images, load them when the class is initialized and store them as attributes of the class. Of course, each of the 3 images can be used in as many icons as needed.

Related

How to make buttons change on different click amounts java

I am trying to make a game in java where if you click on a button once it turns red, and if you click on it twice it turns blue, but I'm running into an issue where when I click one square once and it becomes red, if I click another once it turns blue, when I want the effect isolated to each square at a time(e.g. if I click one square once its red, click another twice its blue, and another square once its red). I also want it to reset after 3 clicks.
Here is my actions listener so far
JFrame frame = new JFrame(); //creates frame
JButton[][] grid; //names the grid of buttons
int clicked = 0;
public ButtonGrid(int width, int length) { //constructor
frame.setLayout(new GridLayout(width, length)); //set layout
grid = new JButton[width][length]; //allocate the size of grid
for(int y = 0; y < length; y++) {
for(int x = 0; x < width; x++) {
grid[x][y] = new JButton(); //creates a button
grid[x][y].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(clicked == 0) {
((JButton)e.getSource()).setBackground(Color.red);
clicked++;
} else if(clicked == 1) {
((JButton)e.getSource()).setBackground(Color.blue);
clicked++;
}
}
});
frame.add(grid[x][y]); //adds new button to grid
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack(); //sets appropriate size for frame
frame.setVisible(true); //makes frame visible
// ...
}
In your current implementation, clicked is a instance field of the parent class, which all your buttons/ActionListeners are using.
Instead, you need to isolate the property so that it can be better associated with a single button.
Now, you could create a custom class which extends from JButton, but IMHO, that's a little heavy handed and locks you into a single use case. Personally, I'd look towards implementating a concrete implementation of the ActionListener to provide this side effect.
For example...
public class CounterActionListener implements ActionListener {
private int counter;
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof JButton) {
JButton button = (JButton)source;
clicked++;
if(clicked == 0) {
button.setBackground(Color.red);
} else if(clicked == 1){
button.setBackground(Color.blue);
}
}
}
}
Then in your code, you just apply the listener to the button, for example...
grid[x][y] = new JButton(new CounterActionListener());
You could also follow this by making use of a "delegate", which actually performed the required operations, based on the number of clicks, which could be held in a model, but that's beyond the scope of the question ;)
You have one global clicked for all of them. Because of that actions are not isolated.
int clicked = 0;
Shouldnt be in class.
Your problem is that clicked is attached to the frame, not to the button. That means that there is only a single value of clicked for your entire application.
The easiest thing to do here would be to write a new class GregoryWeigelButton (or whatever) which extends JButton and has a int clicked=0 inside it (and probably a getter and setter). Then just check what the clicked value for that particular button is.

Replacement of a JPanel element without adding to the end of the panel?

I posted a question earlier about this but the solution never worked and now it's under different circumstances. I'm making a "penny pitch" program, that, when the "confirm" button is pressed, a randomized number will dictate which spot on the board(the board is fill with image icons) the "penny" will fall, and in the process it removes the image icon that use to occupant the chosen space.
I set up a GridBagLayout to constrain each icon down, and my button has no problem removing the chosen spot, but it can not find a way for it to add a new icon in it's place. It just gets adds onto the end of the JPanel.
Heres my coding for the button:
private class AddListener implements ActionListener {
public void actionPerformed(ActionEvent a){
if (a.getSource()== confirm) {
if (numberToss >0){
thrown = pitch.nextInt(25) + 1;
System.out.println(thrown);
//kol is an array to check for repeated numbers in randomization
if (kol.contains(thrown)==false){
input.remove(spot.get(thrown));
//spot is a map to set icons down with a association with number
spot.put(thrown, bSet);
input.add((spot.put(thrown, bSet)));
repaint();
kol.add(thrown);
}
else {
JOptionPane.showMessageDialog(null, "Your toss landed onto an occupied spot; you receive no points");
}
numberToss--;
}
else{
JOptionPane.showMessageDialog(null, "Out of tosses.");
}
}
}
Anyone happen to know how to replace the new icon (bSet) with the former? Thanks in advance!

JTable#scrollRectToVisible in combination with JSplitPlane shows the wrong row

When I call JTable#scrollRectToVisible, the row I want to show is hidden underneath the header in certain situations.
The rest of this question only makes sense when using the following code. This is a very simply program which I use to illustrate the problem. It shows a UI containing a JSplitPane with in the upper part some control buttons, and the lower part contains a JTable wrapped in a JScrollPane (see screenshots at the bottom of this post).
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
public class DividerTest {
private final JSplitPane fSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
private final JTable fTable;
private final JScrollPane fScrollPane;
private boolean fHideTable = false;
public DividerTest() {
fTable = new JTable( createTableModel(50));
fScrollPane = new JScrollPane(fTable);
fSplitPane.setBottomComponent(fScrollPane);
fSplitPane.setTopComponent(createControlsPanel());
fSplitPane.setDividerLocation(0.5);
}
private JPanel createControlsPanel(){
JPanel result = new JPanel();
result.setLayout(new BoxLayout(result, BoxLayout.PAGE_AXIS));
final JCheckBox checkBox = new JCheckBox("Make table invisible before adjusting divider");
checkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
fHideTable = checkBox.isSelected();
}
});
result.add(checkBox);
JButton upperRow = new JButton("Select row 10");
upperRow.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
selectRowInTableAndScroll(10);
}
});
result.add(upperRow);
JButton lowerRow = new JButton("Select row 45");
lowerRow.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
selectRowInTableAndScroll(45);
}
});
result.add(lowerRow);
JButton hideBottom = new JButton("Hide bottom");
hideBottom.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (fHideTable) {
fScrollPane.setVisible(false);
}
fSplitPane.setDividerLocation(1.0);
}
});
result.add(hideBottom);
JButton showBottom = new JButton("Show bottom");
showBottom.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fScrollPane.setVisible(true);
fSplitPane.setDividerLocation(0.5);
}
});
result.add(showBottom);
return result;
}
private void selectRowInTableAndScroll( int aRowIndex ){
fTable.clearSelection();
fTable.getSelectionModel().addSelectionInterval(aRowIndex, aRowIndex);
fTable.scrollRectToVisible(fTable.getCellRect(aRowIndex, 0, true));
}
public JComponent getUI(){
return fSplitPane;
}
private TableModel createTableModel(int aNumberOfRows){
Object[][] data = new Object[aNumberOfRows][1];
for( int i = 0; i < aNumberOfRows; i++ ){
data[i] = new String[]{"Row" + i};
}
return new DefaultTableModel(data, new String[]{"Column"});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test frame");
frame.getContentPane().add(new DividerTest().getUI());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
});
}
}
Unwanted behavior
Run the above code
Press the "Select row 10": row 10 is selected and visible
Press the "Select row 45": row 45 is selected and visible
Click the "Hide bottom" button. This will adjust the divider of the JSplitPane so that only the upper panel is visible
Click the "Select row 10" button. You see of course nothing because the table is not yet visible
Click the "Show bottom" button. The divider is adjusted, but row 10 is hidden underneath the header. I expected it to be visible without needing to scroll.
Wanted behavior
Repeat the steps from above, but make sure the "Make table invisible before adjusting divider" checkbox is selected. This will call setVisible(false) on the JScrollPane around the JTable before hiding the bottom panel.
By doing this, in the last step row 10 will be visible as the top most row, which is what I want. I just do not want to turn the scrollpane invisible: in my real application, the divider is adjusted in an animated way and as such you want to keep the table visible during the animation.
Screenshots
Unwanted: row 10 is invisible after performing the aforementioned steps
Wanted: row 10 is visible after performing the aforementioned steps
Environment
I do not think it will matter, but just in case: I am using JDK7 on a Linux system.
This seems to be caused by the way how the JViewport handles the scrollRectToVisible calls for the cases that its size is smaller than the desired rectangle. It contains a (somewhat fuzzy, but probably related) comment in the JavaDocs:
Note that this method will not scroll outside of the valid viewport; for example, if contentRect is larger than the viewport, scrolling will be confined to the viewport's bounds.
I did not go though the complete code and do all the maths and check all the cases. So a warning: The following explainations contain quite same hand-waving. But a simplified description of what this means for me in this particular case:
When the bottom part is hidden (by setting the divider location accordingly), then this height of the JScrollPane and its JViewport is 0. Now, when requesting to scrollRectToVisible with a rectangle that has a height of 20 (for one table row, as an example), then it will notice that this does not fit. Depending on the current view position of the JViewport, this may cause to viewport to be scrolled so that the bottom of this rectangle is visible.
(You can observe this: Drag the divider location manually, so that approximately half of one table row is visible. When clicking the "Select row 45" button, the upper half of the row will be visible. When clicking the "Select row 10" button, then the lower half of the row will be visible)
One pragmatic solution here that seemed to work for me was to make sure that it will always scroll so that the top of the rectangle is visible (even when the rectangle does not at all fit into the viewport!). Like this:
private void selectRowInTableAndScroll(int aRowIndex)
{
fTable.clearSelection();
fTable.getSelectionModel().addSelectionInterval(aRowIndex, aRowIndex);
Rectangle r = fTable.getCellRect(aRowIndex, 0, true);
r.height = Math.min(fScrollPane.getHeight(), r.height);
fTable.scrollRectToVisible(r);
}
But I can't promise that this will have the desired effect for you, when an animation comes into play...
Not exactly sure what the scrollRectToVisible() is doing.
You might be able to use the JViewport.setViewPosition(...) method.
Rectangle r = fTable.getCellRect(aRowIndex, 0, true);
Point p = new Point(r.x, r.y);
fScrollPane.getViewport().setViewPosition( p );
In this case the selected row will always be shown at the top of the viewport (if possible). So the viewport will always scroll unless the selected row is current at the top. Using this approach if the first row is at the top of the viewport and you select the 10th row the viewport will scroll to display the 10th row at the top.
However, this behaviour is slightly different than using the scrollRectToVisible() method. When using the scrollRectToVisible() method the viewport when only scrolled when the rectangle is not in the visible part of the viewport. Using this approach if the first row is at the top of the viewport and you select the 10th row the viewport will NOT scroll since the 10th row is already visible in the viewport.
Don't know if this change in functionality is acceptable or not.
Note if you don't want to viewport to automatically scroll when you select a row you could try something like:
JViewport viewport = fScrollPane.getViewport();
Rectangle viewRect = viewport.getViewRect();
Rectangle r = fTable.getCellRect(aRowIndex, 0, true);
Point p = new Point(r.x, r.y);
if (! viewRect.contains(p))
viewport.setViewPosition( p );

How to change make tabbed panels change on their own every few seconds?

I am currently learning Swing and am trying to create a simple program that stores information about different sports teams.
I have created multiple tabbed panels which all hold various information about each team. I would like to be able to have a button that when press displays each tabbed panel say every 10 seconds or so - sort of a slide show effect.
I have read up on action listeners but have not spent a lot of time on them as of yet so i am having trouble implementing this. I would be very grateful if anyone could maybe help me or just give me a push in the right direction. I have posted a snippet of code that i have atempted but i am at a loss about what to actually put inside the loop to achieve this.
slides.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent actionEvent){
for(int i = 0; i<arrayList.size(); i++)
{
//code that changes the tabbed panels every few seconds.
}
}
});
I have created multiple tabbed panels which all hold various various information about each team.
Rather you should focus on creating a JPanel that can display team stats, and not so much JTabbedPanes. The JPanel can then be displayed in a JTabbedPane if desired.
I would use a CardLayout to swap JPanels, and then a Swing Timer to do the swapping. However if you use a single JPanel to display the stats, then you could even display one single JPanel and simply change the model (Team Stats information) that is displayed in it rather than swap JPanels.
As to what to put in your ActionListener, it will not be a for loop at all, but rather a Swing Timer, and you can read about it here: Swing Timer Tutorial.
e.g.,
slides.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent){
int timerDelay = 10 * 1000; // 10 seconds
new Timer(timerDelay, new ActionListener() {
private int count = 0;
public void actionPerformed(ActionEvent evt){
if (count < maxCount) {
// code to show the team data for the count index
count++;
} else {
((Timer) evt.getSource()).stop(); // stop timer
}
}
}).start();
}
});

disable mouseEvent for a specific JButton in a group of JButtons

The flow of the program is like this : Image from 1st set of buttons (leftButtonArea) is dragged to the 2nd set of buttons (rightButtonArea).
Each image has a unique name via setName(). The name of the image that was dragged over will be compared with the name of the button which it is dragged to.
If the name matches, I wish to disable that particular button from reacting to any hover event.
.setHoverEnabled(false) doesn't work =/
A similar SO thread regarding the disabling of event listeners, but it seems like the solutions such a using a glass pane are for whole components ?
link
Edit:
Somehow this works, but I am not sure of any side effects from this method
source.removeMouseListener(source.getMouseListeners()[1]);
Edit2:
Found something interesting.. This could be the reason why disabled buttons still reacts to mouseEvents.
"low-level: Component, Container, Focus, Key, Mouse, Paint, Window
semantic: Action, Adjustment, Item, Text
Only semantic events are affected by disabling any component. That is because they are directly handled by the component itself which is aware that it is enabled or not.
Low level events can't be affected by disabling. If you stop to think about this when you disabled your label was it still visible. If it was then the paint event must have happened. Low level events will always happen and it is up to your handlers to query the component if it is enabled or not."
// 1st set of 4 buttons
for(int a=0; a<4; a++){
leftButtonArea[a] = new JleftButtonArea(new ImageIcon(image));
TransferHandler transfer = new TransferHandler("icon");
leftButtonArea[a].setTransferHandler(transfer);
leftButtonArea[a].addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
JleftButtonArea leftButtonArea = (JleftButtonArea)e.getSource();
TransferHandler handle = leftButtonArea.getTransferHandler();
handle.exportAsDrag(leftButtonArea, e, TransferHandler.COPY);
// get unique name for the image that is dragged
// to rightButtonArea
name1 = e.getComponent().getName();
}
});
}
// creates 2nd set of 4 buttons
for(int b=0; b<4; b++){
rightleftButtonAreaArea[b] = new JleftButtonArea();
// <---- creates unique name for each leftButtonArea ----->
cc2 += 1;
id2+="a"+cc2;
rightleftButtonAreaArea[b].setName(id2);
// <---- creates unique name for each leftButtonArea ----->
TransferHandler transfer1 = new TransferHandler("icon");
rightleftButtonAreaArea[b].setTransferHandler(transfer1);
rightleftButtonAreaArea[b].addMouseListener(new MouseAdapter(){
#Override
public void mouseExited(MouseEvent me){
JleftButtonArea source = (JleftButtonArea)me.getSource();
try{
// compare unique name of image and the button in rightButtonArea
// if they are the same, disable hover for the button
if( name1.equals(source.getName())){
// this doesn't work
source.getName().setHoverEnabled(false);
// Somehow this works, but I am not sure of any side effects from this
source.removeMouseListener(source.getMouseListeners()[1]);
}
else{
source.setIcon(null);
}
}
catch (NullPointerException e)
{
}
}
});
}
for Buttons JComponents are MouseEvent are implemented in the ButtonModel
use implemented methods for Icon in the JButton API
examples JButton & Icon, JButton & ButtonModel
try
button.setRolloverEnabled(false);

Categories

Resources