In my program, I have a jPanel with a jLabel inside of it. I added this code to make the jPanel draggable, and it works perfectly.
private void formMousePressed(java.awt.event.MouseEvent evt) {
prevX = evt.getXOnScreen();
}
private void formMouseDragged(java.awt.event.MouseEvent evt) {
this.setLocation(this.getX() + evt.getXOnScreen() - prevX, this.getY());
prevX = evt.getXOnScreen();
// this.labBirthDate.setText(Integer.toString(this.getX()));
}
However, when I added the commented-out code, which updates the label to show the position of the panel, it's stopped working. Specifically, when I click and drag to move the panel, instead of following the mouse, the panel just sort of stutters, and the text changes to a value of ~10, changing whenever I move the mouse.
Making things ever more confusing, if I instead change it so that it just sets the text to "blah", it doesn't produce the error. As well, if I just set a variable to be equal to this.getX(), it doesn't produce the error. If I then set the label to be the value of that local variable, the error comes back.
Does anyone know why this might be happening? Is there a workaround I can use to get the same effect?
When you invoke the setText() method on the label the revalidate() and repaint() methods are invoked on the label. This will cause the layout manager to be invoked and I'm guessing the layout manager will reset the panel to its default position.
If you want to be able to randomly move components around a screen then you need to use a null layout on the parent of the panel that is being dragged. Once you do this you will also need to manually set the size and location of your components.
You might find the Drag Layout handy to use in this case.
Related
I'm having a problem when an event will change the content of a component, like changing a JLabel's name, removing buttons from a Jpanel then adding another component.
Here is my initial JFrame.
Here is what my JFrame looks when components overlaps every time there is an event.
I'm using this code to temporarily solve my problem, but of course this is not a good idea by just resizing.
setSize(panelWidth + 1, panelHeight + 1);
setSize(panelWidth, panelHeight);
I'm wondering what causes this problem and how can I address this?
NOTE: I'm using layout manager. The panel with buttons is using Grid Layout and most of other is using Grid Bag Layout.
UPDATE:Removing setOpaque(true) fix the overlapping on the panel at top. What remains is the panel with the buttons. I'm using GridLayout with only 1 column.
Here is some of my code for displaying the buttons at pnlButtons.
private void initializeShoppingModeButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnManualInput);
pnlButtons.add(btnCheckOut);
}
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
one of possible issues is very simple code snipped
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
}
should be
private void initializeProductMenuButtons() {
pnlButtons.removeAll();
pnlButtons.add(btnSearchProduct);
pnlButtons.add(btnViewIndividual);
pnlButtons.add(btnAlternative);
pnlButtons.add(btnDisplayInfo);
pnlButtons.add(btnCancel);
pnlButtons.revalidate();
pnlButtons.repaint();
}
Swings APIs haven't any notifier that content of container is changed
e.g. JComponents are removed, removed and added, some kinds of relayout (change ordering of, e.i.)
revalidate(); and repaint(); will notify used LayoutManager, use that as last code lines, after all changes to Swing GUI are done
nothing cleaver without your SSCCE, MCVE/MCTRE
Edit 1st.
have look at use CardLayout for switching between views
I'm trying to build a program that displays random shapes and random text. This is my code inside my class that extends JPanel.
#Override
protected void paintComponent(Graphics g) {
// draw all shapes
super.paintComponent(g); // clears the background
this.add(new JLabel(new RandomText().getRandomSentence()));
for (RandomShape shape : shapes) {
shape.draw(g);
}
}
I use a JPanel instead of g.drawString() to in the future display HTML code. I also have a button that "regenerates" the window, by calling the repaint() method. However, when I push the regenerate button, thus calling the repaint() method, the shapes change (like they're supposed to), the text however does not. What I find even stranger is when I resize the window new labels are continously added to my panel (with random text like they're supposed to).
Does super.paintCompnent(g) not clear components added to the panel? If so, why does calling repaint() myself not add extra labels, like resizing the window does?
Resizing the window also forces validate() to be called which lays out the components on the panel again - simply repainting does not.
However, in your painting method you're adding a new JLabel each time and not removing any, which almost certainly isn't what you want to do. You should keep track of the JLabel in a separate variable and either change it's position when you repaint (preferably) or remove it before adding a new one.
This adds a new label to the panel at every repaint:
this.add(new JLabel(new RandomText().getRandomSentence()));
Instead, you should add one label once to the panel, perhaps in the constructor of your class. Then setText(aRandomSentence) for it, when the button is pressed. Do not modify components in paintComponent().
when super.paintComponent(..); is called it wipes out the graphics elements. It however does not change the objects that have been added to it. You will be adding a new label to the panel every time repaint is called.
When you call repaint(); yourself, it's not guarenteed to call the paintComponent of all components. But when you resize it HAS to since everything is going to be different.
This happens because you're constantly adding new JLabels to the JPanel.
Keep track of your JLabel and change it's text instead of adding new JLabels.
I have some code to resize a chatpanel dynamically, but it does not move according to the mouse. What happens is the mouse moves at a faster rate than the panel gets resized. For example, how I want it to be, is in any application, when you click on the border between two windows, and drag it, the mouse stays along with the piece you are clicking on, and currently this is not happening. here is my code. please let me know if you need more
public void mouseDragged(MouseEvent e) {
if(getCursor().getType() == Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR).getType()) {
owner.adjust((int)MouseInfo.getPointerInfo().getLocation().getY());
System.out.println("vertpanel: "+(int)MouseInfo.getPointerInfo().getLocation().getY());
}
}
public void adjust(int adjustment) {
int height = this.getHeight();
System.out.println((((double)(adjustment))/height)+":"+(((double)(height-adjustment))/height));
output.setHeightPercent((((double)(adjustment))/height));
output.componentResized(new ComponentEvent(this, 1));
input.setHeightPercent((((double)(height-adjustment))/height));
input.componentResized(new ComponentEvent(this, 2));
}
there is one main panel, a chatpanel, and within it, there are two smaller panels, a chat input and a chat output
Can't tell exactly what you are doing based on your code.
I would suggest that you should NOT be manually setting the dimensions of the output and input coponents. You should let the layout manager determine how to resize each component as the parent container is resized.
So in your resize code you would need to invoke revalidate() on the parent container as it is resized.
Check out Resizing Components. You should be able to use the ComponentResizer class as long as you use setAutoLayout(true).
I'm using the MouseInputListener (MouseListener + MouseMotionListener) to drag and drop multiple JLabels in a JPanel. Here is an outline of what I do;
MouseClicked: check if there is any
JLabel within the clicked area of
JPanel; if yes, select it (paint it to
a color,etc). If not, do nothing.
MouseDragged: If a JLabel is selected,
setLocation of that JLabel using
e.getX() and e.getY() of the event. If
nothing is selected, do nothing.
MouseReleased: If a JLabel is
selected, paint it back to its
original color. Select nothing (maybe
null). If not, do nothing.
These are all in JPanel; JPanel implements MouseInputListener.
So here is the problem: When the inital position of a JLabel is 0,0 say I move it to 10,10. And after the mouse release and nothing is selected, when I click on 0,0 it selects that JLabel; however it was supposed to select it if I click at 10,10 because this is its new position.
Now I think this might be because I'm using the wrong coordinates; I've heard that the coordinate values in JPanel are relative, so I have to do a subtraction (i.e. final-initial coordinates) everytime to get the correct coordinates. I did it, but it did not work either. Another possibility might be that Java is storing all the historical X and Y coordinates (so that everytime I click on a previous coord, I select that object) which is purely imagination!
What are your suggestions?
Thanks in advance.
Add the MouseMotionListener to each of the labels instead of adding it to the panel. Then you don't need to determine whether you clicked on a label or not.
See the Component Mover for a general implementation. You would need to customize it to support the coloring requirement.
Edit:
If you add the listener to the panel then the coordinates will always be relative to the panel, not the label, so I'm not sure what the problem is. If you want to find if you clicked on a component then use the Container.getComponentAt(Point) method.
If you need more help then post your SSCCE that demonstrates the problem.
I have problem with mouseListener in JPanel.
I add JLabel which contain image(size 600 x 600) on JPanel, and I add mouseListener for the JPanel.
Everytimes I click on the image, the image should change to another image, and this is working fine. However, the problem is that, only if I click on the right side or at the center of the image, then the image will change to another image. The image doesn't change when I click on the top or on the left side. This make me confused. I want the image to change to another image when I click everywhere within the image display.
private final int SECOND= 1;
private final int FIRST = 0;
int imageCounter = 0;
JLabel picture;
JPanel panel;
...
private mainLayout () {
GridBagLayout m = new GridBagLayout();
Container c = (Container)getContentPane();
GridBagConstraints con;
c.setLayout (m);
picture = new JLabel();
picture.setIcon(getImages(myImage.get(imageCounter).get(FIRST))); //first Image
panel = new JPanel();
con = new GridBagConstraints();
con.anchor=GridBagConstraints.CENTER;
con.gridy = 1; con.gridx = 0;
m.setConstraints(panel, con);
c.add(panel);
panel.add(picture); //add the pictures
panel.addMouseListener(l);
....
}
MouseListener l = new MouseAdapter(){
public void mouseClicked (MouseEvent e)
{
Point p = e.getPoint();
if((panel.getBounds().contains(p))
picture.setIcon(getImages(myImage.get(imageCounter).get(SECOND)));
}
};
The problem looks as if it might be in this unnecessary code:
Point p = e.getPoint();
if((panel.getBounds().contains(p))
The mouse listener is on the panel, so the mouse coordinates will be relative to the panel top left. panel.getBounds() gets the bounds of the panel relative to whatever its parent container is.
It's worth noting the mouse event behave very strangely. They "bubble up" until they hit a component with a mouse listener attached. So, adding a mouse listener actually changes the behaviour of a component. Adding the listener to a parent will potentially miss events depending upon the exact way the component is set up (which may change arbitrarily). There are a number of ways around this, none of them good.
The likely problem you have is the same I have encountered, that your event is getting gobbled up in your hierarchy as a previous poster implied. In reference to camickr's reply, it really doesn't matter if you extend JPanel or JLabel as long as you're aware of the consequences. JPanel offers you a lot more capability and has many useful things already built into it. But let's take the simple example where you have the following:
A JFrame that contains a JPanel, call it's JParent. JParent has a set of mouse listeners dedicated to it.
JParent contains a child JPanel that's added to its components, called JChild. JChild also has its own set of mouse listeners.
What happened when you click on an area that is not occupied by JChild? You get the response of JParent's listeners. If you click in an area with JChild visible, only JChild's mouse events will fire.
So be very careful in debugging as Java's swing may have different behavior than you may be used to from other implementations of drawing simple forms/GUIs. Events are basically one-shot and the lowest level component gets first dibs. If you try to fire the parent's events anyway, your x/y coords will be based on the child and not the parent. I'm still trying to come up with a good work around myself because I need access specifically to the parent to move an object elsewhere.
The best I can think of that isn't a mess to debug/think about are these two ideas:
a) have each of your individual components contain their own exclusive set of events and try to prevent the 'bubbling up' effect from coming into play.
b) handle all events on the parent
I'd prefer a as it avoids nasty things such as checking component classes just to figure out what kind of reaction you want (i.e. things like what kind of right-click menu to show).
Edit: So you can handle this either way I've discovered. You can use the dispatchEvent message to forward the events back upward the chain. In my case I have to gobble up the first event (or alter it) and send the x-y positions as if they are relative to the parent (using offsets). I'd say the better way to do it is through forwarding because then all your individual components can be encapsulated.
Are you positive that you are actually clicking? The mouse click event only fires if the mouse is pressed and released in the exact same spot. If your mouse is moving even minimally while you are clicking, the event won't be fired.
Out of curiosity, why are you using a JLabel to display an image? You may be better off writing an ImagePanel class that extends JPanel and overrides the paint() method to do your own drawing. Then you can attach MouseListeners right to the panel.