I'm just learning java and I have a project where I want to be able to move a JLabel around a window with my mouse.
I set up a class called BasicWindow1, implemented a MouseMotionListener, instantiated a JFrame container, added a JLabel to the JFrame, set up a mouseDragged method, hooked up the setBounds method of the JLabel to the MouseEvent information, compiled it and it ran ...
BUT ......
when I dragged the JLabel a second GHOST label appeared above it and moved happily along with its virtual brother.
I've included the code below and I'm hoping someone will take an interest and straighten me out. I'm guessing it's probably a simple beginner's mistake, but it's driving me crazy.
On the debugging level, I inserted a println(e) with the MouseEvent in the mouseDragged method and it showed that the MOUSE_DRAGGED x,y elements were oscillating between 2 distinct x,y paths, one for the GHOST and one for its virtual brother.
Thanks for looking,
Mike
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BasicWindow1 implements MouseMotionListener {
JFrame jf = new JFrame();
JLabel label2 = new JLabel("label2");
public BasicWindow1(String string) {
//JFrame
jf.setTitle(string);
jf.setSize(400,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLayout(null);
jf.setVisible(true);
label2.setOpaque(true);
label2.setBackground(Color.cyan);
label2.setBounds(0,150,75,25);
label2.addMouseMotionListener(this);
jf.add(label2);
}//end constructor
public void mouseDragged(MouseEvent e) {
label2.setBounds(e.getX(),e.getY(),75,25);
System.out.println("e = " + e);
}
public void mouseMoved(MouseEvent e) {}
public static void main(String[] args) {
BasicWindow1 mybw = new BasicWindow1("Basic Window for Stack Overflow");
}
}
Your problem is that you added the MouseMotionListener to the wrong component. You need to add it to the parent of label2, which is the content pane of jf.
Try the following code.
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class BasicWindow1 implements MouseMotionListener {
JFrame jf = new JFrame();
JLabel label2 = new JLabel("label2");
public BasicWindow1(String string) {
// JFrame
jf.setTitle(string);
jf.setSize(400, 400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLayout(null);
jf.setVisible(true);
label2.setOpaque(true);
label2.setBackground(Color.cyan);
label2.setBounds(0, 150, 75, 25);
jf.getContentPane().addMouseMotionListener(this); // CHANGE HERE
jf.add(label2);
}// end constructor
public void mouseDragged(MouseEvent e) {
label2.setLocation(e.getX(), e.getY()); // CHANGE HERE
}
public void mouseMoved(MouseEvent e) {
}
public static void main(String[] args) {
BasicWindow1 mybw = new BasicWindow1("Basic Window for Stack Overflow");
}
}
Method getX() and getY(), in class MouseEvent, return the location of the mouse pointer in the coordinate space of the component that you added the MOuseMotionListener to. In your case this is the location of the mouse pointer inside the JLabel but that's not what you want. You want the location of the mouse pointer in the coordinate space of the component that you want to drag the JLabel around in which is the JFrame or more precisely the content pane of the JFrame.
For an alternative solution, refer to dragging a jlabel around the screen
Related
This code displays x and y points based on where you click. I want to add a JPanel so that the frame does not start measuring from the title bar which is unreachable to the user.
Every time I switch from Frame to JFrame I get this:
example
The previous click does not disappear... What is the easiest way to fix this or am i able to add a JPanel on a Frame?
Below is my code:
************************************************************/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.Color;
public class Proj07Runner {
Proj07Runner(){
System.out.println(
"Terminal text");
GUI gui = new GUI(); //instantiate a GUI
}//end main
}
**Here is where switching from Frame to JFrame causes the change**
class MyFrame extends JFrame{
int clickX;
int clickY;
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.drawString(
"" + clickX + ", " + clickY, clickX, clickY);
}//end paint()
}
class GUI {
public GUI(){//constructor
//Create a new JFrame object, set size, title, etc.
MyFrame displayWindow = new MyFrame();
JPanel myPanel = new JPanel();
displayWindow.setSize(300,100);
displayWindow.setTitle("Title");
myPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
displayWindow.setVisible(true);
//Instantiate and register an anonymous Listener;
// object which will terminate the program when the;
// user closes the JFrame.
displayWindow.addWindowListener(new WProc1());
myPanel.addMouseListener(
new MouseProc(displayWindow));
displayWindow.addMouseListener(
new MouseProc(displayWindow));
}
}
//This listener class monitors for mouse presses and;
// displays the coordinates of the mouse pointer when the
// mouse is pressed on the source object. Note that this
// class extends is an adapter class.
class MouseProc extends MouseAdapter{
MyFrame refToWin; //save a reference to the source here
MouseProc(MyFrame inWin){//constructor
refToWin = inWin;//save ref to window
}//end constructor
//Override the mousePressed method to determine and;
// display the coordinates when the mouse is pressed.
public void mousePressed(MouseEvent e){
//Get X and Y coordinates of mouse pointer and store
// in an instance variable of the JFrame object
refToWin.clickX = e.getX();
refToWin.clickY = e.getY();
//refToWin.clearRect(0,0,300,100);
// Force the JFrame object to be repainted in order to
// display the coordinate information.
refToWin.repaint();
}//end mousePressed()
}
//The following listener is used to terminate the program
// when the user closes the frame. Note that this class
// extends an adapter class.
class WProc1 extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
The coordinates look awkward because the MouseListener is on the Frame, not the Panel. The coordinates will always be in the component's coordinate system that the listener is attached to.
So if you do the rendering in the JPanel, why not attach the MouseListener to that JPanel?
While AWT is a heavy weight UI framework (every AWT component has some native UI representation such as X Widget or a Windows 'window'), Swing is a lightweight framework. Only the root component JWindow, JFrame or JDialog have native representations, the rest is within the JVM. When mixing components you need to know about this difference.
See also https://en.wikipedia.org/wiki/Abstract_Window_Toolkit#Mixing_AWT_and_Swing_components
Ummmm, I just learned that the problem I was referring to may have been fixed since Java 6...
Somehow I felt like creating a small demo using Swing only:
package com.mycompany.test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestPanel extends JPanel {
private Point clickPosition;
public TestPanel() {
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
clickPosition = e.getPoint();
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (clickPosition != null) {
g.setColor(Color.BLACK);
g.drawLine(clickPosition.x-5, clickPosition.y, clickPosition.x+5, clickPosition.y);
g.drawLine(clickPosition.x, clickPosition.y-5, clickPosition.x, clickPosition.y+5);
g.drawString(String.format("(%d, %d)", clickPosition.x, clickPosition.y), clickPosition.x+5, clickPosition.y-5);
}
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TestPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Beginner programming student here. Trying to simply create JFrame object that allows me to click on the boundaries of the window and display the coordinates where I click. However, whenever I click a new location, the previous coordinates need to disappear. I have been told that one way to do this is by adding a JPanel to the center of the JFrame object. However when I do so I am getting an error that says that I am adding a window to a container. I may be extending something incorrectly from what I have read but I can't seem to figure it out.
public class Proj07 {
public static void main(String[] args){
new Proj07Runner();
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Proj07Runner{
GUI gui = new GUI();
}
class MyFrame extends JFrame{
int XCoor;
int YCoor;
public void paint(Graphics g){
g.drawString("x = " + XCoor + ", y = " + YCoor, XCoor, YCoor);
}
}
class GUI{
public GUI(){
MyFrame displayWindow = new MyFrame();
displayWindow.setSize(300,100);
displayWindow.setTitle("Insert name here");
displayWindow.addWindowListener(new WProc1());
JPanel myPanel = new JPanel();
displayWindow.getContentPane().add(myPanel, "Center");
displayWindow.setVisible(true);
}
}
class MouseProc extends MouseAdapter{
public void mousePressed(MouseEvent e){
((MyFrame)e.getComponent()).XCoor = e.getX();
((MyFrame)e.getComponent()).YCoor = e.getY();
e.getComponent().repaint();
}
}
class WProc1 extends WindowAdapter{
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
Thank you guys for your help!
I am not 100% sure but I think the problem is where you put the listener:
You need to do everything on the JPanel, not the frame that is the container, so you should replace the declares with:
MyFrame displayWindow = new MyFrame();
displayWindow.setSize(300,100);
displayWindow.setTitle("Insert name here");
displayWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel myPanel = new JPanel();
myPanel.setSize(300,100);
myPanel.addMouseListener(new myMouse)
displayWindow.getContentPane().add(myPanel, "Center");
displayWindow.setVisible(true);
And then create a mouseListener instead of a mouseAdapter to add in the JPanel.
Also remove the last WindowsAdapter thing, just use exitonclose.
Edit:
When it comes down to what the frame should do it should only contain the panel, so you also need to move everything you were doing on the frame to the panel (such as the public void paint() and stuff).
I would go as far as saying that if you want to add multiple panels on a frame, you should consider putting all panels inside another panel (as a container) and then putting that panel inside the frame.
I'm practising to draw a shape on a JPanel by clicking on a Jbutton, but I cannot. It's been five hours that I'm surfing the web, but I cannot find the way to do it.
This is what I want to do: if I click on "Rectangle" button a rectangle appears under the buttons and if I click on "Circle" button a circle appears.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Shape extends JFrame {
JButton rec, circle;
static String botSelected;
Shape (){
frameSet ();
}
void frameSet(){
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600,300);
rec = new JButton ("Rectangle");
circle = new JButton("Circle");
JPanel panel = new JPanel();
frame.add(panel);
panel.add(rec);
panel.add(circle);
Click clk = new Click();
rec.addActionListener(clk);
circle.addActionListener(clk);
}
public void paint (Graphics g){
super.paint(g);
if (botSelected.equals("Rectangle"))
g.fillRect(50,50,50,50);
else if (botSelected.equals("Circle"))
g.fillOval(50,50,50,50);
}
public static void main (String [] arg){
Shape s = new Shape();
}
}
class Click implements ActionListener{
public void actionPerformed (ActionEvent e){
Shape.botSelected = e.getActionCommand();
}
}
The first thing I would do is have a read through Painting in Swing and Performing custom painting to better understand how the painting process works.
Next you need to understand that JFrame is a bad choice for painting to. Why? Because it's multilayered.
A JFrame contains a JRootPane, which contains a JLayeredPane the contentPane, glassPane and the JMenuBar and in your example, it also contains a JPanel.
With the (default) exception of the glassPane, all these components are opaque.
While it's possible to have something drawn in the paint method show it, if any of the other components paint themselves, it will be wiped clean - this is because Swing components can actually be painted independently of each other, with having to have the parent paint itself first.
A better solution is to start by extending from JPanel and override its paintComponent method.
For simplicity, I'd also encourage you to implement the ActionListener against this class as well, it will allow the actionPerformed method to access the properties of the component and, in your case, call repaint to trigger a paint cycle when you want to update the UI.
Here is a derived example from your code.
As #MadProgrammer said, don't extend JFrame.
In the following example, here are the major changes :
give a non-null value to botSelected, or the first calls to paintComponent will give you a NullPointerException
the class now extends JPanel, and overrides paintComponent for custom painting
the ActionListener is an anonymous class, because you don't need a separate class, and it has direct access to the fields from Shape
botSelected is no longer static (see above point)
.
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Shape extends JPanel {
JButton rec, circle;
String botSelected = "";// don't let it be null, it would make paintComponent crash on startup
Shape() {
frameSet();
}
void frameSet() {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600, 300);
rec = new JButton("Rectangle");
circle = new JButton("Circle");
frame.add(this);
this.add(rec);
this.add(circle);
// anonymous class, has access to fields from the outer class Shape
ActionListener clk = new ActionListener() {
public void actionPerformed(final ActionEvent e) {
botSelected = e.getActionCommand();
repaint();
}
};
rec.addActionListener(clk);
circle.addActionListener(clk);
}
//custom painting of the JPanel
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if (botSelected.equals("Rectangle")) {
g.fillRect(50, 50, 50, 50);
} else if (botSelected.equals("Circle")) {
g.fillOval(50, 50, 50, 50);
}
}
public static void main(final String[] arg) {
Shape s = new Shape();
}
}
What I want to do:
I want to write a small application that can display an image. The user has to be able to zoom in and out of the image, move it around, and mark points on the image. Further down the line I want to analyze the points clicked, but I'm not there yet.
What I have so far:
In order to track down my problem I wrote a MVCE:
GUI class for handling the JFrame (and other UI elements later):
import javax.swing.*;
import java.net.MalformedURLException;
import java.net.URL;
public class MCVE_GUI {
public static void main(String[] args) throws MalformedURLException {
MCVE_ZoomPane zp = new MCVE_ZoomPane(new URL("https://fiji.sc/site/logo.png"));
JFrame f = new JFrame("PictureMeasurement");
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
f.setContentPane(zp);
f.pack();
f.setLocationRelativeTo(null);
f.revalidate();
f.repaint();
f.setVisible(true);
}
}
ZoomPanel for handling the image and zooming:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
class MCVE_ZoomPane extends JPanel implements MouseMotionListener {
MCVE_ZoomPane(URL url){
JLabel image = new JLabel();
JScrollPane jsp = new JScrollPane(image);
//image.setIcon(new ImageIcon(url)); // picture, no input
//jsp.setPreferredSize(new Dimension(300,300)); //picture, no input
jsp.setPreferredSize(image.getPreferredSize()); //depends on position of image.setIcon
image.setIcon(new ImageIcon(url)); //no picture, input
this.add(jsp);
this.setPreferredSize(image.getPreferredSize());
this.addMouseMotionListener(this);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
}
public void mouseDragged(MouseEvent e) {
System.out.format("Dragged X:%d Y:%d\n",e.getX(), e.getY());
}
public void mouseMoved(MouseEvent e) {}
}
The problem:
Depending on where I put the image.setIcon(new ImageIcon(url)) I get either the image displayed or can listen to mouse clicks, but not both together. If I set the JScrollPane to a fixed preferred size without calling image.getPreferredSize() I always get a picture but no input.
Apparently I'm stupid. The JScrollPane/JLabel covered the JPanel which was the only component which had a MouseMotionListener. The solution is to add the single line of image.addMouseMotionListener(this);.
I thought about and tried different soltuions to this for at least three hours now. It's a hobby project, so no time constaints, but man do I feel stupid now.
I am wondering why the drawing area I have created is not showing up in my second panel. I have checked their locations uses getX and getY (250, 0, which is I am assuming the correct area for it to be since that would be the top left of the second panel), but I cannot seem to figure out what is wrong. I'm assuming this is a problem with some fundamental learning aspect of this that I do not have right, but cannot seem to figure out what the issue is. If you could explain to me what is going wrong and the proper direction as to where I would go about fixing it, that would be appreciated. I do have the drawing area working when I have it standalone; the issue is that I cannot get it to appear when working with other GUI components.
Thank you ^^
Code:
package Drawing;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DrawingApp extends JFrame{
public static void main(String[] args) {
GridLayout grid = new GridLayout(1, 2);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final DrawingComponent drawingArea = new DrawingComponent();
drawingArea.setSize(600, 250);
JPanel leftPanel = new JPanel();
JPanel rightPanel = new JPanel();
JSlider greSlider = new JSlider();
JSlider bluSlider = new JSlider();
JSlider redSlider = new JSlider();
Point leftLocation = new Point(0, 0);
Point rightLocation = new Point(250, 0);
JLabel greLabel = new JLabel("Green");
JLabel bluLabel = new JLabel("Blue");
JLabel redLabel = new JLabel("Red");
rightPanel.setLocation(rightLocation);
drawingArea.setLocation(rightLocation);
// JButton button = new JButton("Hello");
leftPanel.setSize(250, 600);
//leftPanel.setLocation(leftLocation);
leftPanel.setBorder((BorderFactory.createLineBorder(Color.black)));
rightPanel.setSize(250, 600);
//rightPanel.setLocation(rightLocation);
rightPanel.setBorder((BorderFactory.createLineBorder(Color.green)));
leftPanel.add(greLabel);
leftPanel.add(greSlider);
leftPanel.add(bluLabel);
leftPanel.add(bluSlider);
leftPanel.add(redLabel);
leftPanel.add(redSlider);
rightPanel.add(drawingArea);
frame.add(leftPanel);
frame.add(rightPanel);
//rightPanel.add(button);
frame.setSize(500, 600);
frame.setLayout(grid);
leftPanel.setVisible(true);
rightPanel.setVisible(true);
frame.setVisible(true);
class SlideClickListener implements ChangeListener
{
ChangeListener slideListener = new ChangeListener(){
#Override
public void stateChanged(ChangeEvent e){
if(e.getSource() == greSlider){
}
}
};
public void stateChanged(ChangeEvent ce) {
throw new UnsupportedOperationException("Not supportedyet.");
}
}
class MouseClickListener implements MouseListener
{
public void mouseClicked(MouseEvent event)
{
int x = event.getX();
int y = event.getY();
System.out.println(x + " " + y);
drawingArea.drawPoints(x,y);
}
// Donothing methods
public void mouseReleased(MouseEvent event) {}
public void mousePressed(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
}
MouseListener listener = new MouseClickListener();
drawingArea.addMouseListener(listener);
}
}
I can include the DrawingComponent class if needed, but assuming that it isn't since I know for sure that the class is working.
I'm assuming this is a problem with some fundamental learning aspect of this that I do not have right,
You don't appear to understand how layout managers work:
leftPanel.setSize(250, 600);
//leftPanel.setLocation(leftLocation);
rightPanel.setSize(250, 600);
//rightPanel.setLocation(rightLocation);
None of those statements will do anything. It is the job of the layout manager to determine the size and location of components added to the panel. In your case you are trying to use a GridLayout. So the components added to the grid will be given a size AFTER the decorations of the frame are taken into consideration. So even though the frame may be (500, 600), the space available to the panel will be less (because you need to account for the title bar and borders of the frame).
Also, you should assign the layout manager to the panel BEFORE you add components to the panel.
leftPanel.setVisible(true);
rightPanel.setVisible(true);
Swing components (except top level containers like JFrame, JDialog) are visible by default so the above code does nothing.
I can include the DrawingComponent class if needed,
Until a problem is solved you don't know what is or isn't relative to the problem. My guess is the your DrawingComponent is the problem. Again, the default layout manager of a JPanel is the FlowLayout which respects the preferred size of any component added to it. I'm guessing your DrawingPanel doesn't implement the getPreferredSize() method to the preferred size is (0, 0) so there is nothing to paint.
Read the section from the Swing tutorial on Custom Painting for more information and working examples to get you started.
I would suggest you also look at the Layout Managers section of the tutorial for layout basics and working examples.