So I have a JPanel called contentPanel that holds 2 inner containers. The first is a scorePanel that holds a few buttons, a slider and a label. The other is a buttonPanel which is a grid of JButtons.
In my contentPanel class, I have implemented the MouseMotionListener interface and added this listener to buttonPanel called buttons.
The issue I'm having is that the mouseMoved method never gets called and I cannot get mouse coordinates while the mouse is hovering over a button. If instead I add the listener to each button, I get the mouse coordinates, but only as they relate to the origin of the button it's hovering inside of. Additionally if I add the listener to the contentPanel, I get the mouse coordinates starting from the origin of that container, but it does not trigger the event over the buttons.
Can anyone explain how to mitigate this problem and get the mouse coordinates from the origin of the button panel without JButton obstruction?
Tia.
*UPDATE: * I have made one change that has enabled the correct behavior I'm seeking, however only with a caveat. I adjusted the padding space between the buttons in the GridLayout to 15px and now when the mouse enters those in-between regions, the mouseEvent triggers. This will enable the same effect as what I seek.
I located some research about JButton's or other components consuming MouseEvents and not passing the event onto their parents. The solution was recommended by a member of the team at Sun/Oracle, which is to re-dispatch the event to the parent of the JComponent, which would be its container.
This was achieved with the following code:
JComponent subComponent = new JButton("JButton");
MouseAdapter redispatcher = new MouseAdapter()
{
#Override
public void mouseEntered(MouseEvent evt)
{
dispatchMouseEvent(evt);
}
#Override
public void mouseExited(MouseEvent evt)
{
dispatchMouseEvent(evt);
}
#Override
public void mouseMoved(MouseEvent evt)
{
dispatchMouseEvent(evt);
}
#Override
public void mousePressed(MouseEvent evt)
{
dispatchMouseEvent(evt);
}
private void dispatchMouseEvent(MouseEvent evt)
{
Container parent = evt.getComponent().getParent();
parent.dispatchEvent(SwingUtilities.convertMouseEvent(evt.getComponent(), evt, parent));
}
};
subComponent.addMouseListener(redispatcher);
subComponent.addMouseMotionListener(redispatcher);
Which was inevitably a great solution to passing events along. (http://www.jyloo.com/news/?pubId=1315817317000)
Related
Basically I am making an application that allows you to draw shapes. I am working on a feature that would allow you to "undo a draw". All drawing occurs on the drawing panel. I got the algorithm part of the undo down, move to a stack...., but I can't get the undo button to disable after there are no more shapes to draw in the collection.(can't undo any more )
These are my two collections that I use to store my shapes
//to store shapes that have been drawn
private final List<ShapeColorThickness> myShapesToDraw
//store shapes that have been "undone"
private final Stack<ShapeColorThickness> myUndoShapes;
This is the AbstractAction class used to handle clicks to the undo button.
public class UndoAction extends AbstractAction{
private final DrawingPanel myDrawingPanel;
public UndoAction(String name, DrawingPanel panel) {
super(name);
myDrawingPanel = panel;
//I don't want the button to be enabled in the beginning.
setEnabled(false);
}
#Override
public void actionPerformed(ActionEvent arg0) {
myDrawingPanel.undo();
boolean canUndo = myDrawingPanel.canUndo();
setEnabled(myDrawingPanel.canUndo());
}
}
This is where I initialized the undo button
new JButton(new UndoAction("Undo", myDrawingPanel)
And pertinent code in DrawingPanel.java
public boolean canUndo() {
//if there are no shapes left in shapes drawn, you cannot undo
return !myShapesToDraw.isEmpty();
}
public void undo() {
myUndoShapes.push(myShapesToDraw.remove(myShapesToDraw.size() - 1));
repaint();
}
When I add a Shape and proceed to remove it, the undo button stays enabled. I've been trying to debug this but just cant figure it out. I put a breakpoint next to
boolean canUndo = myDrawingPanel.canUndo();
And saw that it evaluated to false when i pressed the undo button and stepped through the code. But the button still remains enabled. What's even stranger is that the undo button disables itself perfectly fine if i add 2 shapes and remove them both. Does anyone know what this issue could be?
What I think cause the issue was that when i constructed the button with the action, I did something like
JButton button = new JButton(new UndoAction(.....));
And later in some part of my code, I called
button.setEnabled(true);
I am not sure how the setEnabled on the button affects the action enabled state but after i made sure that all calls that affected state came from the Action class, I managed to fix my issue.
drag a jframe window from it's content area is simple, but here is the problem.
when i added a label onto the frame, it's still ok even drag on the label,
but when i add mouseclicked event for the label, even no codes actually proccessed in the adapter, the dragging can't happen when i drag on the label, but drag on the rest area of the window is fine.
another thing is I want to make the window's opacity varies with the mouse motion,
with this.setOpacity(0.9f);
after the label's mouseclicked event set, the label won't respond to this also..
anyone knows how the solve this?
private void formMousePressed(java.awt.event.MouseEvent evt) {
offsetX = evt.getX();
offsetY = evt.getY();
}
private void formMouseDragged(java.awt.event.MouseEvent evt) {
java.awt.Component c = (Component) evt.getSource();
c.setLocation(evt.getXOnScreen() - offsetX, evt.getYOnScreen()- offsetY);
}
private void jLabel1MouseClicked(java.awt.event.MouseEvent evt) {
// nothing actually done in the Label's mouse handler
}
private void formMouseEntered(java.awt.event.MouseEvent evt) {
this.setOpacity(0.9f);
}
private void formMouseExited(java.awt.event.MouseEvent evt) {
this.setOpacity(0.4f);
}
it's still ok even drag on the label, but when i add mouseclicked event for the label, even no codes actually proccessed in the adapter
Correct, the MouseEvent is only passed to one component, so the label stops the event from being passed to the window.
So you need to add the MouseListener to the window and the label in order to drag the window.
Check out Moving Windows. It is a listener that will allow you to move any component relative to its parent. So you can create a ComponentMover and then register the root pane of your window to allow you to drag the window. But you will also need to register the label.
I want to get the mouse position of my JFrame. But when mouse is on its child component (such as a table, button that is added to the JFrame) MouseMotion event is no more listening. How can I get the mouse position?
I was trying to make a Sidebar on my Swing application, where sidebar is an undecorated JFrame. I have set to dispose it when mouse exits. But when I move the mouse over a component added to the sidebar, it disappears. Idea may be dumb I am new to Java.
You could implement mouseExited as kleopatra suggests, but do it similar to this:
MouseListener closer = new MouseAdapter() {
public void mouseExited(MouseEvent e) {
// obtain source frame and see if mouse has left it
Container cnt;
if (e.getSource() instanceof JFrame) {
// our frame, no conversion needed
cnt = (Container) e.getSource();
} else {
// inside a descendant
cnt = SwingUtilities.getAncestorOfClass(
JFrame.class, e.getComponent());
// convert mouse event to make it appear
// as if the frame generated it (I think :D)
e = SwingUtilities.convertMouseEvent(
e.getComponent(), e, (Component) cnt);
}
Rectangle r = new Rectangle(cnt.getSize());
if (!r.contains(e.getPoint())) {
cnt.setVisible(false);
// or whatever
}
}
};
This is meant to be set for all descendant components of your sidebar and itself. It should check if your mouse is still inside your sidebar no matter over which of it's children/descendants the mouse is hovering.
You should also consider using an undecorated JDialog instead of a JFrame.
The reason why your sidebar is disappearing might be that you only added a mouse listener to it and not to any of it's children. It might be counter-intuitive, but when your mouse pointer enters a child/descendant of the sidebar, a mouseExited event is generated for the sidebar and then a mouseEntered event is generated for whichever child/descendant the mouse has entered. This is just how Swing mouse events are designed to work and there ain't much you can do about it.
Assuming the use-case in your comment is the real issue to solve, the answer is to implement the mouseExited such that it checks whether the mouse is still somewhere over the frame and hide it only if not.
Something like:
MouseListener closer = new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
Rectangle r = new Rectangle(sideBar.getSize());
if (!r.contains(e.getPoint())) {
sideBar.setVisible(false);
}
}
};
I have drag and drop working for my jlabels, but I want to show the actual labels being dragged. So I when they are dragged, I don't want the normal hand with a square under it. So it should disappear from its starting position, and follow the mouse. I tried setting the location but it's not working, the mouse still shows the usual icons. I can make it disappear from its starting location but not completely move.
Would it work if I used a layered pane to make another pane on top and set the locations of the labels there?
private class DragMouseAdapter extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
JComponent c = (JComponent)e.getSource();
TransferHandler handler = c.getTransferHandler();
c.setLocation(MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().x);
//c.setOpaque(true);
handler.exportAsDrag(c, e, TransferHandler.COPY);
}
}
I want to write a code to draw a filled oval where ever the mouse is clicked inside a panel. I used to develop some codes but unfortunately when I tried to do the next click the whole panel blanked and new point appeared. I want to keep the previous points and add some new ones by the next user’s click on the panel. How do I implement the paint component of MyPanel? Here is my code; it does not work properly, because it produces some small points instead of rectangle.
class MyPanel extends JPanel {
Point pointClicked;
public MyPanel() {
this.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
pointClicked = e.getPoint();
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(pointClicked.x, pointClicked.y, 1, 1);
}
}
I want to keep the previous points and add some new ones by the next user’s click on the panel.
You need to keep track of each oval painted and repaint all ovals each time the paintComponent() method is called.
Check out Custom Painting Approaches for two different ways to do this