The part of the application that I am currently having trouble getting to work is being able to scroll through and display a list of images, one at a time. I'm getting a directory from the user, spooling through all of the files in that directory, and then loading an array of just the jpegs and pngs. Next, I want to update a JLabel with the first image, and provide previous and next buttons to scroll through and display each image in turn. When I try to display the second image, it doesn't get updated... Here's what I've got so far:
public class CreateGallery
{
private JLabel swingImage;
The method that I'm using to update the image:
protected void updateImage(String name)
{
BufferedImage image = null;
Image scaledImage = null;
JLabel tempImage;
try
{
image = ImageIO.read(new File(name));
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// getScaledImage returns an Image that's been resized proportionally to my thumbnail constraints
scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
tempImage = new JLabel(new ImageIcon(scaledImage));
swingImage = tempImage;
}
Then in my createAndShowGUI method that puts the swingImage on...
private void createAndShowGUI()
{
//Create and set up the window.
final JFrame frame = new JFrame();
// Miscellaneous code in here - removed for brevity
// Create the Image Thumbnail swingImage and start up with a default image
swingImage = new JLabel();
String rootPath = new java.io.File("").getAbsolutePath();
updateImage(rootPath + "/images/default.jpg");
// Miscellaneous code in here - removed for brevity
rightPane.add(swingImage, BorderLayout.PAGE_START);
frame.add(rightPane, BorderLayout.LINE_END);
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
UIManager.put("swing.boldMetal", Boolean.FALSE);
new CreateGalleryXML().createAndShowGUI();
}
});
}
If you've gotten this far, the first image is my default.jpg, and once I get the directory and identify the first image in that directory, that's where it fails when I try to update the swingImage. Now, I've tried to swingImage.setVisible() and swingImage.revalidate() to try to force it to reload. I'm guessing it's my tempImage = new JLabel that's the root cause. But I'm not sure how to convert my BufferedImage or Image to a JLabel in order to just update swingImage.
Instead of creating a New Instance of the JLabel for each Image, simply use JLabel#setIcon(...) method of the JLabel to change the image.
A small sample program :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SlideShow extends JPanel
{
private int i = 0;
private Timer timer;
private JLabel images = new JLabel();
private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
UIManager.getIcon("OptionPane.errorIcon"),
UIManager.getIcon("OptionPane.warningIcon")};
private ImageIcon pictures1, pictures2, pictures3, pictures4;
private ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
i++;
System.out.println(i);
if(i == 1)
{
pictures1 = new ImageIcon("image/caIcon.png");
images.setIcon(icons[i - 1]);
System.out.println("picture 1 should be displayed here");
}
if(i == 2)
{
pictures2 = new ImageIcon("image/Keyboard.png");
images.setIcon(icons[i - 1]);
System.out.println("picture 2 should be displayed here");
}
if(i == 3)
{
pictures3 = new ImageIcon("image/ukIcon.png");
images.setIcon(icons[i - 1]);
System.out.println("picture 3 should be displayed here");
}
if(i == 4)
{
pictures4 = new ImageIcon("image/Mouse.png");
images.setIcon(icons[0]);
System.out.println("picture 4 should be displayed here");
}
if(i == 5)
{
timer.stop();
System.exit(0);
}
revalidate();
repaint();
}
};
public SlideShow()
{
JFrame frame = new JFrame("SLIDE SHOW");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.getContentPane().add(this);
add(images);
frame.setSize(300, 300);
frame.setVisible(true);
timer = new Timer(2000, action);
timer.start();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new SlideShow();
}
});
}
}
Since you doing it with ImageIO, here is a good example related to that JLabel using ImageIO
Information relating to your case, as to what is happening :
Inside your createAndShowGUI() method you initializing your JLabel (swingImage), and you added that to your JPanel by virtue of which indirectly to the JFrame.
But now inside your updateImage() method, you are initializing a new JLabel, now it resides in some another memory location, by writing tempImage = new JLabel(new ImageIcon(scaledImage)); and after this you pointing your swingImage(JLabel) to point to this newly created JLabel, but this newly created JLabel was never added to the JPanel, at any point. Hence it will not be visible, even if you try revalidate()/repaint()/setVisible(...). Hence either you change the code for your updateImage(...) method to this :
protected void updateImage(String name)
{
BufferedImage image = null;
Image scaledImage = null;
JLabel tempImage;
try
{
image = ImageIO.read(new File(name));
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// getScaledImage returns an Image that's been resized
// proportionally to my thumbnail constraints
scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
tempImage = new JLabel(new ImageIcon(scaledImage));
rightPane.remove(swingImage);
swingImage = tempImage;
rightPane.add(swingImage, BorderLayout.PAGE_START);
rightPane.revalidate();
rightPane.repaint(); // required sometimes
}
Or else use JLabel.setIcon(...) as mentioned earlier :-)
UPDATED THE ANSWER
Here see how a New JLabel is placed at the position of the old one,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SlideShow extends JPanel
{
private int i = 0;
private Timer timer;
private JLabel images = new JLabel();
private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
UIManager.getIcon("OptionPane.errorIcon"),
UIManager.getIcon("OptionPane.warningIcon")};
private ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
i++;
System.out.println(i);
if(i == 4)
{
timer.stop();
System.exit(0);
}
remove(images);
JLabel temp = new JLabel(icons[i - 1]);
images = temp;
add(images);
revalidate();
repaint();
}
};
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("SLIDE SHOW");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
this.setLayout(new FlowLayout(FlowLayout.LEFT));
add(images);
frame.getContentPane().add(this, BorderLayout.CENTER);
frame.setSize(300, 300);
frame.setVisible(true);
timer = new Timer(2000, action);
timer.start();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new SlideShow().createAndDisplayGUI();
}
});
}
}
And for your Question : Of the two options that I have tried, is one better than the other?
setIcon(...) has an edge over the other way, in the sense, you doesn't have to bother about revalidate()/repaint() thingy after adding/remove JLabel. Moreover, you don't need to remember the placement of your JLabel everytime, you add it. It remains at it's position, and you simply call the one method to change the image, with no strings attached and the work is done, without any headaches.
And for Question 2 : I had a bit of doubt, as to what is Array of Records ?
Related
I have a rectangle, and I am trying to grow it like a graph of some sorts, but it does not show it growing in real time, it just has a white screen then I see a rectangle. Any help would be appreciated, thanks. The code I am having a problem with is under the ¨Animates the bar¨ comment.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Main extends JPanel {
static String[] mainArr;
static int start;
static boolean done = false;
static double datapoint1;
static double datapoint2;
static int jPlaceholder;
public static void main(String[] args) throws Exception {
// Creating the window
JFrame panel = new JFrame();
panel.setSize(450,250);
// Creating the window that shows the animation
JFrame drawingFrame = new JFrame();
drawingFrame.setSize(450,250);
JPanel jp = new JPanel();
jp.setLayout(null);
jp.setBackground(Color.red);
drawingFrame.add(jp);
// Creating all the text fields
JTextField dataTypesTextField = new JTextField("This box is currently not in use. Please do not type anything into this box");
dataTypesTextField.setBounds(50,50, 400,30);
panel.add(dataTypesTextField);
JTextField yearStartTextField = new JTextField("Type in this box what year your data starts in:");
yearStartTextField.setBounds(50,100, 400,30);
panel.add(yearStartTextField);
JTextField yearEndTextField = new JTextField("Type in this box what year your data ends in:");
yearEndTextField.setBounds(50,150, 400,30);
panel.add(yearEndTextField);
// Creating the button to submit the data
JButton enterButton = new JButton("Enter");
enterButton.setBounds(50,200, 100, 30);
panel.add(enterButton);
// =================================== ActionListener for enter button ========================================
enterButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (done==false) {
// Creating the variables to store the data the user just inputted
start = Integer.parseInt(yearStartTextField.getText());
int end = Integer.parseInt(yearEndTextField.getText());
mainArr = new String[end-start+1];
// Gets the data points
dataTypesTextField.setText("Datapoints you will use in order, space between each: ");
done = true;
} else {
// Getting all the data needed
mainArr = dataTypesTextField.getText().split(" ");
double[] datapoints = new double[mainArr.length];
for (int i=0; i<datapoints.length; i++) {
datapoints[i] = Double.parseDouble(mainArr[i]);
}
under here is where I had my problems I am pretty sure, but I could have screwed up somewhere else.
// Animates the bar
for (int i=0; i<datapoints.length-1; i++) {
// Getting all the datapoints
datapoint1 = datapoints[i];
datapoint2 = datapoints[i+1];
int j = 0;
while(j<50) {
j++;
int width = (int) (datapoint1+((datapoint2-datapoint1)/50)*j);
JPanel rectangle = new JPanel();
rectangle.setBackground(Color.black);
rectangle.setBounds(50, 50, width, 30);
jp.add(rectangle);
drawingFrame.setVisible(true);
rectangle.repaint();
System.out.println("The width is: "+width);
at first I thought it was because there was no pause between each ¨frame¨ but it still just shows a white screen, then it shows the rectangle.
try {
Thread.sleep(20);
} catch (Exception exp) {
}
}
}
}
}
});
// =====================================================================================================
// Finishes up both the windows
panel.setLayout(null);
panel.setVisible(true);
}
}
I am trying to change what image is shown in the JLabels of my User Interfaces.
The following class is a very simple test of the concept. The UI takes a folder full of images (the field imageFolderPath) and displays the first image, resized, in the only JLabel; clicking on the image prompts the UI to display the following image in the folder.
At least, it should. In reality, no image is shown. The fault is obviously of the method reloadImage(), either while rescaling the image or while repainting the JLabel, but I have not managed to find or correct the problem. Any idea?
public class Test extends JFrame {
private JPanel contentPane;
private JLabel boardImage;
private ImageIcon icon;
public String imageFolderPath = "C:\\modify\\it\\to\\suit\\your\\needs\\";
public File[] files;
public int indexImage = 0;
public int imageResolution = 450;
// =========================================================
// TODO | Constructors
/**
* Create the frame.
*/
public Test() {
if( !new File(imageFolderPath).exists() )
new File(imageFolderPath).mkdir();
this.files = new File(imageFolderPath).listFiles();
System.out.println("Can show:");
for( File file : files )
System.out.println("\t"+file.getName());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, imageResolution, imageResolution);
contentPane = new JPanel();
contentPane.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
// Every time the image is clicked, another one is shown
indexImage++;
reloadImage();
}
});
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
boardImage = new JLabel();
boardImage.setBounds(0, 0, imageResolution, imageResolution);
reloadImage();
contentPane.add(boardImage);
}
// =========================================================
// TODO | Support methods
/** Reloads the image of the {#link ChessBoard} at its current state. */
public void reloadImage() {
if( files[indexImage % files.length].exists() )
System.out.println("The file " + files[indexImage % files.length].getName() + " exists");
else System.out.println("The file " + files[indexImage % files.length].getName() + " doesnt exists");
// Reload the image - resized
BufferedImage buffer = null;
try {
buffer = ImageIO.read( files[indexImage % files.length] );
} catch (IOException e) { e.printStackTrace(); }
Image rescaledImage = buffer.getScaledInstance(imageResolution, imageResolution, Image.SCALE_SMOOTH);
icon = new ImageIcon(rescaledImage);
boardImage = new JLabel(icon);
// boardImage.setText( files[indexImage % files.length].getName() );
System.out.println("Is now showing " + files[indexImage % files.length].getName() );
boardImage.repaint();
}
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test frame = new Test();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
In reality, no image is shown.
boardImage = new JLabel(icon);
Don't create a new JLabel. The instance of that JLabel hasn't been added to the frame.
Instead just change the Icon of the existing JLabel:
//boardImage = new JLabel(icon);
boardImage.setIcon( icon );
The label will automatically repaint itself with the new Icon.
I'm developing a Java Swing app for an award winning password protection system, and I need a large custom cursor [ 80 x 80 ], you might ask why so large, there is an online web demo you may look at to learn why it needs to be so large : http://gatecybertech.net
That large cursor is used on the login page in the above link. Of course you need to create a test password first before you can try the login process.
But anyway, in my Swing app, I hit a limit of 32 x 32 for the largest possible custom cursor, my code looks like the following :
Image cursorImage = toolkit.getImage("Cursor_Crosshair.PNG");
Tabular_Panel.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(cursorImage,new Point(0,0),"custom cursor"));
The image size of Cursor_Crosshair.PNG is : 80 x 80
But what shows up in the screen is a shrinked version of it at : 32 x 32
So my question is : how can I bypass the size limit on customer cursor image, and make the cursor to show up at the size of 80 x 80 ?
I know the OS might be the reason for the limit, is there a way to overcome it ?
Here's my take on the glass pane painting approach. This is set up to behave pretty much like setting a custom cursor. The default "arrow" cursor is hidden while the custom cursor is shown, and the custom cursor is hidden when a component has some other cursor set, such as a text box.
Unfortunately, it ended up seeming to require quite a bit of Swing black magic, so I don't like it very much, but it does seem to work correctly. I've done a cursor like this before, but it was for something simpler, so I didn't run in to these issues.
Some of the problems I ran in to are:
The glass pane intercepts cursor changes (described e.g. on SO here). The only solution I've been able to find is to override Component.contains(int,int) to return false (described here, shown here), but why that works and doesn't seem to break anything else is mysterious.
Mouse exit events sometimes return a location inside the bounds of the component, so I don't think there's a reliable way to know when the mouse leaves the window except to use a timer.
package mcve;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;
public class LargeCursor {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
JPanel glass = new CustomGlassPane();
glass.add(new CursorPanel(), BorderLayout.CENTER);
frame.setGlassPane(glass);
// This next call is necessary because JFrame.setGlassPane delegates to the root pane:
// - https://docs.oracle.com/javase/9/docs/api/javax/swing/RootPaneContainer.html#setGlassPane-java.awt.Component-
// - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JFrame.java#l738
// And JRootPane.setGlassPane may call setVisible(false):
// - https://docs.oracle.com/javase/9/docs/api/javax/swing/JRootPane.html#setGlassPane-java.awt.Component-
// - http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/javax/swing/JRootPane.java#l663
glass.setVisible(true);
JPanel content = createTestPanel();
content.setCursor(BlankCursor.INSTANCE);
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
static class CustomGlassPane extends JPanel {
CustomGlassPane() {
super(new BorderLayout());
super.setOpaque(false);
}
#Override
public boolean contains(int x, int y) {
return false;
}
}
static class CursorPanel extends JPanel {
final BufferedImage cursorImage;
Point mouseLocation;
CursorPanel() {
try {
cursorImage = createTransparentImage(
ImageIO.read(new URL("https://i.stack.imgur.com/9h2oI.png")));
} catch (IOException x) {
throw new UncheckedIOException(x);
}
setOpaque(false);
long mask = AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener((AWTEvent e) -> {
switch (e.getID()) {
case MouseEvent.MOUSE_ENTERED:
case MouseEvent.MOUSE_EXITED:
case MouseEvent.MOUSE_MOVED:
case MouseEvent.MOUSE_DRAGGED:
capturePoint((MouseEvent) e);
break;
}
}, mask);
// This turned out to be necessary, because
// the 'mouse exit' events don't always have
// a Point location which is outside the pane.
Timer timer = new Timer(100, (ActionEvent e) -> {
if (mouseLocation != null) {
Point p = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(p, this);
if (!contains(p)) {
setMouseLocation(null);
}
}
});
timer.setRepeats(true);
timer.start();
}
void capturePoint(MouseEvent e) {
Component comp = e.getComponent();
Point onThis = SwingUtilities.convertPoint(comp, e.getPoint(), this);
boolean drawCursor = contains(onThis);
if (drawCursor) {
Window window = SwingUtilities.windowForComponent(this);
if (window instanceof JFrame) {
Container content = ((JFrame) window).getContentPane();
Point onContent = SwingUtilities.convertPoint(comp, e.getPoint(), content);
Component deepest = SwingUtilities.getDeepestComponentAt(content, onContent.x, onContent.y);
if (deepest != null) {
if (deepest.getCursor() != BlankCursor.INSTANCE) {
drawCursor = false;
}
}
}
}
setMouseLocation(drawCursor ? onThis : null);
}
void setMouseLocation(Point mouseLocation) {
this.mouseLocation = mouseLocation;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mouseLocation != null) {
int x = mouseLocation.x - (cursorImage.getWidth() / 2);
int y = mouseLocation.y - (cursorImage.getHeight() / 2);
g.drawImage(cursorImage, x, y, this);
}
}
}
static final class BlankCursor {
static final Cursor INSTANCE =
Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
new Point(),
"BLANK");
}
static JPanel createTestPanel() {
JPanel panel = new JPanel(new GridLayout(3, 3));
panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
for (int i = 0; i < 9; ++i) {
if ((i % 2) == 0) {
JTextField field = new JTextField("Text Field");
field.setHorizontalAlignment(JTextField.CENTER);
panel.add(field);
} else {
panel.add(new JButton("Button"));
}
}
return panel;
}
static BufferedImage createTransparentImage(BufferedImage img) {
BufferedImage copy =
GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice()
.getDefaultConfiguration()
.createCompatibleImage(img.getWidth(),
img.getHeight(),
Transparency.TRANSLUCENT);
for (int x = 0; x < img.getWidth(); ++x) {
for (int y = 0; y < img.getHeight(); ++y) {
int rgb = img.getRGB(x, y) & 0x00FFFFFF;
int bright = (((rgb >> 16) & 0xFF) + ((rgb >> 8) & 0xFF) + (rgb & 0xFF)) / 3;
int alpha = 255 - bright;
copy.setRGB(x, y, (alpha << 24) | rgb);
}
}
return copy;
}
}
OK, after some research and modification, I found the answer :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.event.MouseInputAdapter;
public class Demo_Large_Custom_Cursor
{
static private MyGlassPane myGlassPane;
// Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread.
private static void createAndShowGUI()
{
//Create and set up the window.
JFrame frame=new JFrame("Demo_Large_Custom_Cursor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Start creating and adding components.
JCheckBox changeButton=new JCheckBox("Custom Cursor \"visible\"");
changeButton.setSelected(false);
//Set up the content pane, where the "main GUI" lives.
Container contentPane=frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(changeButton);
JButton Button_1=new JButton("<Html><Table Cellpadding=7><Tr><Td>A</Td><Td>B</Td></Tr><Tr><Td>C</Td><Td>D</Td></Tr></Table></Html>");
Button_1.setPreferredSize(new Dimension(80,80));
Button_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Out("Button 1"); } });
contentPane.add(Button_1);
JButton Button_2=new JButton("<Html><Table Cellpadding=7><Tr><Td>1</Td><Td>2</Td></Tr><Tr><Td>3</Td><Td>4</Td></Tr></Table></Html>");
Button_2.setPreferredSize(new Dimension(80,80));
Button_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { Out("Button 2"); } });
contentPane.add(Button_2);
//Set up the menu bar, which appears above the content pane.
JMenuBar menuBar=new JMenuBar();
JMenu menu=new JMenu("Menu");
menu.add(new JMenuItem("Do nothing"));
menuBar.add(menu);
frame.setJMenuBar(menuBar);
//Set up the glass pane, which appears over both menu bar
//and content pane and is an item listener on the change
//button.
myGlassPane=new MyGlassPane(changeButton,menuBar,frame.getContentPane());
changeButton.addItemListener(myGlassPane);
frame.setGlassPane(myGlassPane);
//Show the window.
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private static void out(String message) { System.out.print(message); }
private static void Out(String message) { System.out.println(message); }
public static void main(String[] args)
{
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
/**
We have to provide our own glass pane so that it can paint.
*/
class MyGlassPane extends JComponent implements ItemListener
{
Point point;
//React to change button clicks.
public void itemStateChanged(ItemEvent e)
{
setVisible(e.getStateChange()==ItemEvent.SELECTED);
}
protected void paintComponent(Graphics g)
{
try
{
if (point!=null)
{
// g.setColor(Color.red);
// g.fillOval(point.x-10,point.y-10,20,20);
BufferedImage image=ImageIO.read(new File("C:/Cursor_Crosshair.PNG"));
g.drawImage(image,point.x-39,point.y-39,null);
}
}
catch (Exception e) { }
}
public void setPoint(Point p)
{
point=p;
}
public MyGlassPane(AbstractButton aButton,JMenuBar menuBar,Container contentPane)
{
CBListener listener=new CBListener(aButton,menuBar,this,contentPane);
addMouseListener(listener);
addMouseMotionListener(listener);
}
}
/**
Listen for all events that our check box is likely to be interested in. Redispatch them to the check box.
*/
class CBListener extends MouseInputAdapter
{
Toolkit toolkit;
Component liveButton;
JMenuBar menuBar;
MyGlassPane glassPane;
Container contentPane;
public CBListener(Component liveButton,JMenuBar menuBar,MyGlassPane glassPane,Container contentPane)
{
toolkit=Toolkit.getDefaultToolkit();
this.liveButton=liveButton;
this.menuBar=menuBar;
this.glassPane=glassPane;
this.contentPane=contentPane;
}
public void mouseMoved(MouseEvent e)
{
// redispatchMouseEvent(e,false);
redispatchMouseEvent(e,true);
}
public void mouseDragged(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseClicked(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseEntered(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseExited(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mousePressed(MouseEvent e)
{
redispatchMouseEvent(e,false);
}
public void mouseReleased(MouseEvent e)
{
redispatchMouseEvent(e,true);
}
//A basic implementation of redispatching events.
private void redispatchMouseEvent(MouseEvent e,boolean repaint)
{
Point glassPanePoint=e.getPoint();
Container container=contentPane;
Point containerPoint=SwingUtilities.convertPoint(glassPane,glassPanePoint,contentPane);
if (containerPoint.y<0)
{ //we're not in the content pane
if (containerPoint.y+menuBar.getHeight()>=0)
{
//The mouse event is over the menu bar.
//Could handle specially.
}
else
{
//The mouse event is over non-system window
//decorations, such as the ones provided by
//the Java look and feel.
//Could handle specially.
}
}
else
{
//The mouse event is probably over the content pane.
//Find out exactly which component it's over.
Component component=SwingUtilities.getDeepestComponentAt(container,containerPoint.x,containerPoint.y);
// if ((component!=null) && (component.equals(liveButton)))
if ((component!=null))
{
//Forward events over the check box.
Point componentPoint=SwingUtilities.convertPoint(glassPane,glassPanePoint,component);
component.dispatchEvent(new MouseEvent(component,e.getID(),e.getWhen(),e.getModifiers(),componentPoint.x,componentPoint.y,e.getClickCount(),e.isPopupTrigger()));
}
}
//Update the glass pane if requested.
if (repaint)
{
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
}
}
And the Cursor_Crosshair.PNG is like this :
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I am working on this program that calculates the Beats per Minute (BPM) when you click the button. When you click two times, it is supposed to display the current BPM, and display the new one with every click after that. What the problem is, though, is that the display isn't changing. What do I need to do?
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class BPM extends JPanel implements ActionListener {
JLabel label;
public String display;
public int bpm;
public int buttonPressed;
public int time1;
public int time2;
public int time3;
public int counter[];
public void addComponents(Container pane) {
JPanel buttons = new JPanel();
JButton bpmButton = new JButton("Click");
bpmButton.setSize(new Dimension(100, 50));
bpmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPressed++;
counter = new int[2];
if (buttonPressed == 1) {
counter[0] = (int)(System.currentTimeMillis());
} else if (buttonPressed == 2) {
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
} else {
counter[0] = counter[1];
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
}
}
});
display = "0";
label = new JLabel(display, SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(100.0f)); // original 45
pane.add(label, BorderLayout.PAGE_START);
pane.add(bpmButton, BorderLayout.CENTER);
}
// Calculates the difference between the two saved clicks
public void calculateTimeBetweenClicks() {
if (buttonPressed == 1) {
time1 = counter[0];
} else {
time1 = counter[0];
time2 = counter[1];
}
time3 = time2 - time1;
}
// Calculates the BPM and changes the display accordingly
public void setTime() {
bpm = 60000 / time3;
display = "" + bpm + "";
label.setText(display);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
public static void createAndShowGUI() {
// Creates the window
JFrame frame = new JFrame("BPM Calculator");
frame.setPreferredSize(new Dimension(300, 200)); // original (250, 130)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Adds the components to the content pane
BPM window = new BPM();
window.addComponents(frame.getContentPane());
//Displays the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Turns off bold text
UIManager.put("swing.boldMetal", Boolean.FALSE);
// Allows the components to be used and interacted with
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The problem is in your addComponents method, you are creating a new array on each and every button click (so you end up with a new and empty array). This is throwing off your calculation. Simply move the instantiation of your array to somewhere outside of the ActionListener like this...
public void addComponents(Container pane) {
JPanel buttons = new JPanel();
counter = new int[2]; //Move this line to here...
JButton bpmButton = new JButton("Click");
bpmButton.setSize(new Dimension(100, 50));
bpmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPressed++;
if (buttonPressed == 1) {
counter[0] = (int)(System.currentTimeMillis());
} else if (buttonPressed == 2) {
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
} //Removed the else - see edit below :-)
}
});
Additional
Your code as-is seems to get a litle confused after the 2nd click (the first BPM calculation) as it seems to take that 2nd click as the first click of the next set of 2 clicks if you get what I mean. I'm not sure if this is intended behaviour, but if not, I would reset everything in the calculateTimeBetweenClicks method after you've calculated the correct bpm ready for a new set of 2 clicks...
// Calculates the difference between the two saved clicks
public void calculateTimeBetweenClicks() {
if (buttonPressed == 1) {
time1 = counter[0];
} else {
time1 = counter[0];
time2 = counter[1];
//Reset here ready for next 2 clicks...
counter[0]=0;
counter[1]=0;
buttonPressed = 0;
}
time3 = time2 - time1;
}
I've got a "status" JLabel in one class (named Welcome) and the timer in another one (named Timer). Right now, the first one displays the word "status" and the second one should be doing the countdown. The way I would like it to be, but don't know how to - display 10, 9, 8, 7 ... 0 (and go to the next window then). My attempts so far:
// class Welcome
setLayout(new BorderLayout());
JPanel area = new JPanel();
JLabel status = new JLabel("status");
area.setBackground(Color.darkGray);
Font font2 = new Font("SansSerif", Font.BOLD, 25);
status.setFont(font2);
status.setForeground(Color.green);
area.add(status, BorderLayout.EAST); // can I put it in the bottom-right corner?
this.add(area);
and the timer:
public class Timer implements Runnable {
// public void runThread() {
// new Thread(this).start();
// }
public void setText(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setText(text); // link to status here I guess
}
});
}
public void run() {
for (int i = 10; i > 0; i--) {
// set the label
final String text = "(" + i + ") seconds left";
setText(text);
// // sleep for 1 second
// try {
// Thread.currentThread();
// Thread.sleep(1000);
// } catch (Exception ex) {
// }
}
// go to the next window
UsedBefore window2 = new UsedBefore();
window2.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
// runThread();
}
} // end class
I agree that you should consider using a "Java" Timer as per Anh Pham, but in actuality, there are several Timer classes available, and for your purposes a Swing Timer not a java.util.Timer as suggested by Anh would suit your purposes best.
As for your problem, it's really nothing more than a simple problem of references. Give the class with the label a public method, say setCountDownLabelText(String text), and then call that method from the class that holds the timer. You'll need to have a reference of the GUI class with the timer JLabel in the other class.
For example:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Welcome extends JPanel {
private static final String INTRO = "intro";
private static final String USED_BEFORE = "used before";
private CardLayout cardLayout = new CardLayout();
private JLabel countDownLabel = new JLabel("", SwingConstants.CENTER);
public Welcome() {
JPanel introSouthPanel = new JPanel();
introSouthPanel.add(new JLabel("Status:"));
introSouthPanel.add(countDownLabel);
JPanel introPanel = new JPanel();
introPanel.setPreferredSize(new Dimension(400, 300));
introPanel.setLayout(new BorderLayout());
introPanel.add(new JLabel("WELCOME", SwingConstants.CENTER), BorderLayout.CENTER);
introPanel.add(introSouthPanel, BorderLayout.SOUTH);
JPanel usedBeforePanel = new JPanel(new BorderLayout());
usedBeforePanel.setBackground(Color.pink);
usedBeforePanel.add(new JLabel("Used Before", SwingConstants.CENTER));
setLayout(cardLayout);
add(introPanel, INTRO);
add(usedBeforePanel, USED_BEFORE);
new HurdlerTimer(this).start();
}
private static void createAndShowUI() {
JFrame frame = new JFrame("Welcome");
frame.getContentPane().add(new Welcome());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
public void setCountDownLabelText(String text) {
countDownLabel.setText(text);
}
public void showNextPanel() {
cardLayout.next(this);
}
}
class HurdlerTimer {
private static final int TIMER_PERIOD = 1000;
protected static final int MAX_COUNT = 10;
private Welcome welcome; // holds a reference to the Welcome class
private int count;
public HurdlerTimer(Welcome welcome) {
this.welcome = welcome; // initializes the reference to the Welcome class.
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text);
}
public void start() {
new Timer(TIMER_PERIOD, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (count < MAX_COUNT) {
count++;
String text = "(" + (MAX_COUNT - count) + ") seconds left";
welcome.setCountDownLabelText(text); // uses the reference to Welcome
} else {
((Timer) e.getSource()).stop();
welcome.showNextPanel();
}
}
}).start();
}
}
Since you're using Swing you should use the javax.swing.Timer, not the java.util.Timer. You can set the timer to fire at 1 second (1000 ms) intervals and have your listener do the updating. Since Swing updates must take place in the event dispatch thread your listener is the perfect place for status.setText.
there's already a Timer class in java: http://www.exampledepot.com/egs/java.util/ScheduleRepeat.html
Why not put the setText method in the welcome class and just do 'status.setText(text)'?
And you might try BorderLayout.SOUTH or .PAGE END or .LINE END to get the timer in the lower right corner