Get a components location on its current monitor - java

I want to set the location of a JPopupMenu depending of the y location of the button that opens the menu. My code works fine on my first monitor, but fails on my second monitor, wich has a different height.
The problem is getLocationOnScreen() delivers the location relative to the main screen, not the actual screen on which the component is shown.
My code:
// screenSize represents the size of the screen where the button is
// currently showing
final Rectangle screenSize = dateButton.getGraphicsConfiguration().getBounds();
final int yScreen = screenSize.height;
int preferredY;
// getLocationOnScreen does always give the relative position to the main screen
if (getLocationOnScreen().y + dateButton.getHeight() + datePopup.getPreferredSize().height > yScreen) {
preferredY = -datePopup.getPreferredSize().height;
} else {
preferredY = getPreferredSize().height;
}
datePopup.show(DateSpinner.this, 0, preferredY);
How can I get the location of a component on its actual monitor?

I got a solution for this using the bounds of the second screen, it's quite simple:
public static Point getLocationOnCurrentScreen(final Component c) {
final Point relativeLocation = c.getLocationOnScreen();
final Rectangle currentScreenBounds = c.getGraphicsConfiguration().getBounds();
relativeLocation.x -= currentScreenBounds.x;
relativeLocation.y -= currentScreenBounds.y;
return relativeLocation;
}
Thanks for your answers!

Usually when you call "getLocationOnScreen()" it gets the location of the component "this" (from the code I don't quite understand who "this" is).
Maybe you can try to get location of the button by using "button.getLocationOnScreen()".

Here is a small snippet that shows how to position elements relatively to another one. It displays a popup menu below the button, and a JDialog to its left. I tested it on a multi-screen environment where secondary screen is on the right of the main one.
Also, use getSize(), getWidth() and getHeight() instead of getPreferredSize(). getSize(), getWidth and getHeight return the actual dimensions of the component, while getPreferredSize() is only an indicator to the LayoutManager to what the component wishes to have.
If you use the method JPopupMenu.show() make sure to use coordinates and sizes relative to the invoker component.
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
public class Test2 {
public static void main(String[] args) {
final JFrame frame = new JFrame();
final JButton button = new JButton("Hello");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add(new JMenuItem("Some test"));
System.err.println(button.getLocationOnScreen());
popupMenu.show(button, 0, button.getHeight());
JDialog dialog = new JDialog(frame);
dialog.setSize(100, 30);
Point locationOnScreen = button.getLocationOnScreen();
locationOnScreen.x += button.getWidth();
dialog.setLocation(locationOnScreen);
dialog.setVisible(true);
}
});
frame.addComponentListener(new ComponentListener() {
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public void componentResized(ComponentEvent e) {
info(button);
}
private void info(final JButton button) {
if (button.isShowing()) {
System.err.println(button.getLocationOnScreen());
System.err.println(button.getGraphicsConfiguration().getBounds());
}
}
#Override
public void componentMoved(ComponentEvent e) {
info(button);
}
#Override
public void componentHidden(ComponentEvent e) {
}
});
button.setPreferredSize(new Dimension(200, 60));
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}

Related

image to show up when I press the button in java swing (error in frame.add( ) )

Hello first of all when I run the program a button appear , when I press the button the image will go from top to down.
I try the code when the image go from top to down , it work very well
BUT when I put all the codes together there is an error in ( frame.add(new AnimationPane() ); )
Question : How to add AnimationPane() to the frame ???
because this is my problem.
The idea that I want to make two scenes , the first one have a button to make go to the second scene which will have an image (it must be pushed from top until reach down ).
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package maincontentpaneswitching;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MainContentPaneSwitching {
private static class ChangeContentPaneListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// I want to put the image here
JPanel newFrameContents = new JPanel(); //Uses FlowLayout by default.
newFrameContents.add(new JLabel("You have successfully changed the content pane of the frame!", JLabel.CENTER));
/*We assume that the source is a JButton and that the Window is of type JFrame, hence
the following utility method call is possible without letting any errors appear:*/
JFrame frame = (JFrame) SwingUtilities.getWindowAncestor((JButton) e.getSource());
frame.setSize(600, 300);
frame.setContentPane(newFrameContents); //Change the content pane of the frame.
frame.revalidate(); //Notify the frame that the component hierarchy has changed.
frame.add(new AnimationPane() );
frame.pack(); //Resize the frame as necessary in order to fit as many contents as possible in the screen.
frame.setLocationRelativeTo(null); //Place the frame in the center of the screen. As you can tell, this needs its size to calculate the location, so we made sure in the previous line of code that it is set.
frame.repaint(); //Repaint frame with all its contents.
}
}
public class AnimationPane extends JPanel {
private BufferedImage boat;
private int yPos = 0;
private int direction = 1;
public AnimationPane() {
try {
boat = ImageIO.read(new URL("https://i.stack.imgur.com/memI0.png"));
Timer timer = new Timer(50, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
yPos += direction;
if (yPos + boat.getHeight() > getHeight()) {
yPos = getHeight() - boat.getHeight();
direction *= +1;
} else if (yPos < 0) {
yPos = 0;
direction *= +1;
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return boat == null ? super.getPreferredSize() : new Dimension(boat.getHeight()*2 , boat.getWidth() *2);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = getWidth() - boat.getWidth();
g.drawImage(boat, x, yPos, this);
}
}
private static class MainRunnable implements Runnable {
#Override
public void run() {
JButton changeContentPaneButton = new JButton("Click to go to the next image!");
changeContentPaneButton.addActionListener(new ChangeContentPaneListener());
JPanel frameContents = new JPanel(); //Uses FlowLayout by default.
frameContents.add(changeContentPaneButton);
JFrame frame = new JFrame("My application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Tells the frame that when the user closes it, it must terminate the application.
frame.setContentPane(frameContents); //Add contents to the frame.
frame.pack(); //Resize the frame as necessary in order to fit as many contents as possible in the screen.
frame.setLocationRelativeTo(null); //Place the frame in the center of the screen. As you can tell, this needs its size to calculate the location, so we made sure in the previous line of code that it is set.
frame.setVisible(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainRunnable()); //Swing code must always be used in the Event Dispatch Thread.
}
}
Introduction
As I said in my comment, I couldn't get the image animation to work properly. At least this code would give you a solid foundation to start with.
Here's the GUI I came up with.
Here's the GUI after you left-click on the button.
If you're going to add comments to your code, put the comments on separate lines from the code. Not everyone has a large monitor and can read 200+ character lines of code.
Explanation
Oracle has a rad tutorial, Creating a GUI With Swing. Skip the Netbeans section.
When I create a Swing GUI, I use the model/view/controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the application at a time.
In Swing, the MVC pattern means:
The view reads information from the model
The view may not update the model
The controller updates the model and repaints/revalidates the view.
There's usually not one controller to "rule them all". Each listener controls its portion of the model and the view.
When I put together an application, I code one tiny tiny piece of it, then run tests. I probably ran two to three dozen tests, and this was mostly coded by you.
Model
I created a BoatImage class to read the boat image. It's a separate class, so I can read the image before I start to construct the GUI.
View
I created a JFrame. I created a main JPanel with a CardLayout.
I use a CardLayout to layout the button JPanel and the image JPanel. This way, the JFrame is not constantly changing size.
I create the JFrame and JPanels as separate methods/classes. This makes it much easier for people, including yourself, to read and understand the view code.
Controller
I coded the ChangeContentPaneListener to change from the button JPanel to the image JPanel. This is where you would put your image animation code.
Code
Here's the complete runnable code. I made all the additional classes inner classes so I could post this code as one block.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MainContentPaneSwitching implements Runnable {
public static void main(String[] args) {
// Swing code must always be used in the Event Dispatch Thread.
SwingUtilities.invokeLater(new MainContentPaneSwitching());
}
private AnimationPane animationPane;
private BoatImage boatImage;
private CardLayout cardLayout;
private JPanel mainPanel;
public MainContentPaneSwitching() {
this.boatImage = new BoatImage();
}
#Override
public void run() {
JFrame frame = new JFrame("My application");
// Tells the frame that when the user closes it, it
// must terminate the application.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.mainPanel = createMainPanel();
frame.add(mainPanel, BorderLayout.CENTER);
// Resize the frame as necessary in order to fit as many contents
// as possible in the screen.
frame.pack();
// Place the frame in the center of the screen. As you can tell, this
// needs its size to calculate the location, so we made sure in the
// previous line of code that it is set.
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel() {
cardLayout = new CardLayout();
JPanel panel = new JPanel(cardLayout);
panel.add(createButtonPanel(), "button");
animationPane = new AnimationPane(boatImage);
panel.add(animationPane, "image");
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton changeContentPaneButton = new JButton(
"Click to go to the next image!");
changeContentPaneButton.addActionListener(
new ChangeContentPaneListener(this, boatImage));
panel.add(changeContentPaneButton);
return panel;
}
public JPanel getAnimationPane() {
return animationPane;
}
public void repaint() {
animationPane.repaint();
}
public class AnimationPane extends JPanel {
private static final long serialVersionUID = 1L;
private BoatImage boat;
public AnimationPane(BoatImage boat) {
this.boat = boat;
BufferedImage image = boat.getBoat();
this.setPreferredSize(new Dimension(image.getWidth(),
image.getHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage image = boat.getBoat();
int x = getWidth() - image.getWidth();
g.drawImage(image, x, boat.getyPos(), this);
}
}
private class ChangeContentPaneListener implements ActionListener {
private int direction, yPos;
private final MainContentPaneSwitching view;
private final BoatImage model;
public ChangeContentPaneListener(MainContentPaneSwitching view,
BoatImage model) {
this.view = view;
this.model = model;
this.direction = 1;
this.yPos = 0;
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(mainPanel, "image");
}
}
public class BoatImage {
private int yPos;
private BufferedImage boat;
public BoatImage() {
try {
URL url = new URL("https://i.stack.imgur.com/memI0.png");
boat = ImageIO.read(url); // boat.jpg
} catch (MalformedURLException e) {
e.printStackTrace();
boat = null;
} catch (IOException e) {
e.printStackTrace();
boat = null;
}
this.yPos = 0;
}
public BufferedImage getBoat() {
return boat;
}
public void setyPos(int yPos) {
this.yPos = yPos;
}
public int getyPos() {
return yPos;
}
}
}

Paint Component seems to be causing cursor and Mouse Listener of Label to not work

Using LayerUI to add labels to the upper corner of a tabbed pane. Would like to allow these labels to display as hyperlinks, so I set the color blue, the cursor to a hand and I added a mouselistener.
Howev,er when I paint the component the cursor customization and mouse listener are not not working.
sample image
Sample Application:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.plaf.LayerUI;
public class TopRightCornerLabelLayerUITest {
public static JPanel makeUI() {
JPanel resultPanel = new JPanel();
resultPanel.setLayout( new BorderLayout());
resultPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.add("Tab 1", new JPanel());
tabbedPane.add("Tab 2", new JPanel());
resultPanel.add(new JLayer<JComponent>(tabbedPane, new TopRightCornerLabelLayerUI()), BorderLayout.CENTER);
return resultPanel;
}
private static void initandShow()
{
JDialog dialog = new JDialog();
dialog.getContentPane().add(makeUI());
dialog.setSize(520, 240);
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
initandShow();
}
});
}
}
class TopRightCornerLabelLayerUI extends LayerUI<JComponent> {
private JPanel rubberStamp = new JPanel();
#Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
JLabel layoutHyperlink = new JLabel("<html><a href=''>File Layout and Descriptions</a></html>");
JLabel templateHyperlink = new JLabel("<html><a href=''>Download Template</a></html>");
layoutHyperlink.setForeground(Color.BLUE.darker());
layoutHyperlink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
layoutHyperlink.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// the user clicks on the label
System.err.println("clicked");
}
});
templateHyperlink.setForeground(Color.BLUE.darker());
templateHyperlink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
templateHyperlink.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
// the user clicks on the label
System.err.println("clicked");
}
});
// Add components
Dimension templateDimension = templateHyperlink.getPreferredSize();
int x = c.getWidth() - templateDimension.width - 5;
SwingUtilities.paintComponent(g, templateHyperlink, rubberStamp, x, 2, templateDimension.width , templateDimension.height);
Dimension layoutDimension = layoutHyperlink.getPreferredSize();
x = c.getWidth() - layoutDimension.width - 15 - templateDimension.width;
SwingUtilities.paintComponent(g, layoutHyperlink, rubberStamp, x, 2, layoutDimension.width, templateDimension.height);
}
}
I was actually unaware of class JLayer until I read your question. I don't have a complete answer but I think it's enough to give you a push in the right direction. I was helped by the lesson in Oracle's Java tutorial: How to Decorate Components with the JLayer Class. That lesson has a section entitled Responding to Events which helped me to figure out how to partially solve your issue. Basically you are just painting the labels and not actually adding them as components and therefore they will not respond to mouse events. Since the labels can be considered part of the JLayer component that is added as a component, you can configure that JLayer to respond to mouse events. As stated in the tutorial lesson, you need to override some other methods in your TopRightCornerLabelLayerUI class. The code below contains two of those methods. Add them to your code and see if they give you the expected result.
public void installUI(JComponent c) {
super.installUI(c);
((JLayer<?>) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
protected void processMouseEvent(MouseEvent e, JLayer l) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
Point pt = e.getPoint();
if (pt.x >= xTemplateHyperlink && pt.x <= (xTemplateHyperlink + widthTemplateHyperlink)) {
System.out.println("clicked");
}
}
}
EDIT:
Forgot to mention that I added the following members to your TopRightCornerLabelLayerUI class...
private int xTemplateHyperlink;
private int yTemplateHyperlink;
private int widthTemplateHyperlink;
private int heightTemplateHyperlink;
And set their values in method paint() like so...
Dimension templateDimension = templateHyperlink.getPreferredSize();
xTemplateHyperlink = c.getWidth() - templateDimension.width - 5;
yTemplateHyperlink = 2;
widthTemplateHyperlink = templateDimension.width;
heightTemplateHyperlink = templateDimension.height;
which explains the code in method processMouseEvent().

How would I change the JFrame background image while project is running

I set my background with
static JLabel board = new JLabel(new ImageIcon("img/rsz_board.png"));
frame.setContentPane(board);
And I tried to change the background with a button by doing this:
static JLabel board2 = new JLabel(new ImageIcon("img/board.png"));
JButton button2 = new JButton("Test");
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame.setContentPane(board2);
}
});
When I click the button, nothing will happen. If I click the button and then resize the window by dragging it with my cursor, the background will change but all my buttons will disappear. What am I doing wrong?
I think you should use revalidate() and repaint() after changing the background.
try this:
static JLabel board2 = new JLabel(new ImageIcon("img/board.png"));
JButton button2 = new JButton("Test");
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
frame.setContentPane(board2);
frame.revalidate();
frame.repaint();
}
});
If I click the button and then resize the window by dragging it with my cursor, the background will change but all my buttons will disappear
That is because all the buttons have been added to the "board" component not the "board2" component.
I tried to change the background with a button by doing this:
Don't change the label that is being used as the content pane. Instead change the Icon of the label:
//frame.setContentPane(board2);
board.setIcon( new ImageIcon("img/board.png") );
Perhaps a better way to do what you want: create a JPanel that draws the image in the background within its paintComponent method, that has its own layout manager which helps allow you to add components to the JPanel in any fashion you deem appropriate. You would give this class an Image field, and then within the paintComponent method, draw whatever image is being referenced by that field. Or if you want to swap a collection of images, give it an ArrayList<Image> field (below called images), and then draw the current image that is referenced by an index to that list (in my code below called imageIndex).
Comments on your code:
You're using static variables for some Swing components, and that suggests that you should re-think your design. Only declare static that which makes sense being static, and Swing GUI components are almost never in that category.
When you use a JLabel as you're using it, the label always sizes to the image and the text it holds (if any) which is OK for some applications, but dangerous for others. A JPanel will set its preferred size to that of the components it holds depending on the layout. That all changes of course if you explicitly change its getPreferredSize() method as I have done.
For example, compile and run the complete program code below:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ChangeBackground extends JPanel {
public static final String ROOT_PATH = "https://upload.wikimedia.org/wikipedia/commons/thumb/";
public static final String[] IMG_PATHS = {
"0/01/Sundomecloseup.JPG/640px-Sundomecloseup.JPG",
"3/31/Hanalei,_Kauai_HI.JPG/640px-Hanalei,_Kauai_HI.JPG",
"a/a3/Castle_of_Vajdahunyad.jpg/640px-Castle_of_Vajdahunyad.jpg",
"d/d6/HeratFridayMosque.jpg/640px-HeratFridayMosque.jpg",
"1/16/Hebridean_ram.jpg/640px-Hebridean_ram.jpg",
"1/11/Ouagadougou_Maison_du_peuple.jpg/640px-Ouagadougou_Maison_du_peuple.jpg",
"9/96/Menger-Schwamm-einfarbig.jpg/640px-Menger-Schwamm-einfarbig.jpg",
"4/4f/Olympias.1.JPG/640px-Olympias.1.JPG",
"1/18/Uscapitolindaylight.jpg/640px-Uscapitolindaylight.jpg",
"9/9a/Below_Golden_Gate_Bridge.jpeg/640px-Below_Golden_Gate_Bridge.jpeg",
"2/29/Eiffel_Tower_(2962488972).jpg/640px-Eiffel_Tower_(2962488972).jpg",
"8/8f/Notre-Dame_Cathedral_Basilica.jpg/640px-Notre-Dame_Cathedral_Basilica.jpg"
};
private static final int PREF_W = 640;
private static final int PREF_H = 480;
private List<Image> images = new ArrayList<>();
private int imageIndex = 0;
public ChangeBackground(List<Image> images) {
this.images = images;
add(new JButton(new NextImageAction("Next Image")));
}
public void nextImage() {
imageIndex++;
imageIndex %= images.size();
repaint();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class NextImageAction extends AbstractAction {
public NextImageAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent arg0) {
nextImage();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(images.get(imageIndex), 0, 0, this);
}
private static void createAndShowGui(final List<Image> images) {
ChangeBackground mainPanel = new ChangeBackground(images);
JFrame frame = new JFrame("ChangeBackground");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
final List<Image> imgs = new ArrayList<>();
for (String imagePath : IMG_PATHS) {
imagePath = ROOT_PATH + imagePath;
try {
URL imgUrl = new URL(imagePath);
imgs.add(ImageIO.read(imgUrl));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
SwingUtilities.invokeLater(() -> createAndShowGui(imgs));
}
}

Java Jlabel Update Text

1.I am making a cookie click clone i know so mature I'm only 12 and I'm testing my abilities. I have a problem I'm trying to get a label to update but it just won't
tried everything
Also sorry in advance for weird indentation and messiness I'm not great at making good looking code
class
package learning;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.JPanel;
public class Learning extends JFrame implements MouseListener {
int clicks;
boolean Update;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new Learning().start();
}
public void start(){
ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
add(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setSize(600,600);
setResizable(false);
JLabel Click = new JLabel("Clicks: " + clicks);
Click.setFont(new Font("Arial",Font.PLAIN , 20));
panel.add(Click);
Click.setSize(100,100);
Click.setVisible(true);
addMouseListener(this);
if(Update == true){
Click.setText("Clicks: "+ clicks);
System.out.println("Reached");
}
}
#Override
public void mouseClicked(MouseEvent e) {
clicks += 1;
System.out.println(clicks);
Update = true;
if(Update = true){
Update = false;
}
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Other picture class
package learning;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImageImplement extends JPanel {
private Image img;
public ImageImplement(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
#Override
public void paintComponent(Graphics g){
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
}
Problem #1
Swing, like most GUI's, is event driven, that is something happens and you respond to it. This makes your program non-linear (the code doesn't progress in a straight line).
Events can happen at any time for a multitude of reasons, depending on the event. This means...
if(Update == true){
Click.setText("Clicks: "+ clicks);
System.out.println("Reached");
}
Will never be true, because the event has not occurred at the time the program interprets this command
Problem #2
To over come this issue, your mouseClicked event handler will need to know about the objects you want to update. Currently, you are declaring your variables within a local scope, within the start method...
public void start(){
//...
ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
//...
JLabel Click = new JLabel("Clicks: " + clicks);
}
You will need to change these so that they are accessible at a class instance level
public class Learning extends JFrame implements MouseListener {
int clicks;
boolean Update;
private ImageImplement panel;
private JLabel Click
public void start(){
//...
//ImageImplement panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
panel = new ImageImplement(new ImageIcon("Cookie.jpg").getImage());
//...
//JLabel Click = new JLabel("Clicks: " + clicks);
Click = new JLabel("Clicks: " + clicks);
}
This will allow you to access these objects from any method within any instance of the current class.
Then, within your mouseClicked handler, you can update the Click label...
#Override
public void mouseClicked(MouseEvent e) {
clicks += 1;
Click.setText("Clicks: "+ clicks);
}
Problem #3
Mouse events are contextual to the component that the MouseListener is registered. This means a few things, but in your case, it's possible that the JLabel and ImageImplement could potentially block block mouse events from reaching the component that the MouseListener is registered to.
Instead, it might be better to add the MouseListener to the ImageImplement instead...
addMouseListener(panel);
Additional
JLabel is capable of displaying images, unless you're playing on doing some kind of image manipulation or graphical effect, it might just be easier to use it instead.
You should be calling super.paintComponent in your ImageImplement's paintComponent before doing any additional painting.
You should avoid using setPreferred/Minimum/MaximumSize and instead, override these methods as you need to achieve your desired results

JFrame getLocation and setLocation deal with system border differently

I am creating a multi-user Swing GUI application, and want the user's window location and size settings to persist when they log out and back in. I am currently getting the window location and size using the getLocation() and getSize() methods on my parent JFrame when the user logs out and saving them to a file, and then when the user logs back in I read those values back in and set the window size and location using setLocation() and setSize().
The problem that I am having is that getLocation() and getSize() appear to be subtracting off the system border (e.g. if I put the window in the upper left corner getLocation returns (1,54) instead of (0,0)), but setLocation() and setSize() don't. The result is that every time I logout and log back in, the window appears slightly offset and slightly smaller than it did when I closed it.
Does anybody know why this might be happening or how I can get around it? Is there some other method I should be using to get and set the window location and size?
I'm running java 1.7.0_45 on Ubuntu 12.04, if that helps.
Thanks!
EDIT:
The following example replicates the issue I am seeing:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class JFrameTest
{
private JFrame frame;
private JButton button;
private Point lastLocation;
private Dimension lastSize;
private void run()
{
button = new JButton("Test");
button.addActionListener(listener);
lastLocation = new Point(0, 0);
lastSize = new Dimension(200, 200);
initFrame();
}
private void initFrame()
{
frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.getContentPane().add(button);
frame.setLocation(lastLocation);
frame.setPreferredSize(lastSize);
frame.pack();
frame.setVisible(true);
}
private ActionListener listener = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == button)
{
lastLocation = frame.getLocationOnScreen();
lastSize = frame.getSize();
frame.dispose();
initFrame();
}
}
};
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable() {
public void run()
{
new JFrameTest().run();
}
});
}
}
Also, I see the same issue when I use getLocationOnScreen() instead of getLocation().
You can use getLocationOnScreen()
Gets the location of this component in the form of a point specifying
the component's top-left corner in the screen's coordinate space.

Categories