JPopupMenu doesn't dissapear/move when minimising/moving the JFrame it is in - swing

I am making an mp3 player, with several JLists in my JFrame. When I right click on a JList item, a popup with some options for that song appears. But when this popup is visible, and I minimise my JFrame, this popup stays visible! Also, when the popup is visible, and I drag my JFrame to somewhere else on the screen, the popup stays on it's original position (so it does not stay on the same position relative to the JFrame)... Can someone please help me out with this? I tried to strip down this class as much as possible :)
I would be really grateful if someone could help me out !!
Joe
public class playListPanel extends JPanel implements MouseListener {
private DefaultListModel model;
private Interface interFace;
private JList list;
private boolean emptyPlaylist;
private ArrayList<Song> currentPlayList;
private Song rightClickedSong;
private JPopupMenu popup;
private Point panelLocation;
public playListPanel(Interface interFace) // Interface extends JFrame,
// playListPanel is a part of
// this JFrame.
{
this.interFace = interFace;
this.panelLocation = new Point(559, 146);
setBackground(SystemColor.controlHighlight);
setBorder(new TitledBorder(null, "", TitledBorder.LEADING,
TitledBorder.TOP, null, null));
setBounds((int) panelLocation.getX(), (int) panelLocation.getY(), 698,
368);
setLayout(null);
currentPlayList = new ArrayList<Song>();
model = new DefaultListModel();
list = new JList(model);
list.setVisible(true);
list.addMouseListener(this);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setBounds(5, 5, 688, 357);
add(scrollPane);
emptyPlaylist = true;
}
private void openMenuPopup(Point point)
{
removePopup();
popup = new JPopupMenu();
int x = (int) point.getX();
int y = (int) point.getY();
popup.setLocation((int) (x+panelLocation.getX()),(int) (y+panelLocation.getY()));
//popup.setLabel("popup voor playlist");
JMenuItem removeSong;
popup.add(removeSong = new JMenuItem("Remove Song from Playlist", new ImageIcon("image.jpg")));
ActionListener menuListener = new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(event.getActionCommand().equals("Remove Song from Playlist"))
{
System.out.println("Remove Song from Playlist");
interFace.getPlaylistManager().removeOneSong(rightClickedSong);
removePopup();
}
};
//ADD THE LISTENERS TO THE MENU ITEMS
removeSong.addActionListener(menuListener);
popup.setVisible(true);
}
public void removePopup()
{
if(popup!==null)
{
popup.setVisible(false);
System.out.println("popup removed");
}
}
private int getRow(Point point) {
return list.locationToIndex(point);
}
public void refreshPlayList(ArrayList<Song> playlist) {
this.currentPlayList = playlist;
model.clear();
for (Song song : playlist) {
model.add(model.getSize(), song.getPlaylistString());
}
list.setVisible(true);
}
public void highlightSong(int index) {
list.setSelectedIndex(index);
}
public int getRowOfList(Point point) {
return list.locationToIndex(point);
}
#Override
public void mouseClicked(MouseEvent e) {
interFace.getPlaylistManager().doubleClickOnPlaylist(e);
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
rightClickedSong = currentPlayList.get(getRow(e.getPoint()));
openMenuPopup(e.getPoint());
System.out.println("should open popup at "
+ e.getPoint().toString());
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}

There are some basic flaws in the way you are handling click for showing popup.
It is not advisable to call popup.setVisible in simple scenarios like this. Instead, you may rely on its default behavior. Also, better to use e.isPopupTrigger() than to check SwingUtilities.isRightMouseButton(e) to show popup.
You may do something like the following :
//at classlevel,
private JPopupMenu popup = new JPopupMenu();
//create a Popuplistener
PopupListener pl = new PopupListener();
list.addMouseListener(pl);
//Implementation of your popuplistener
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger())
//e.getSource - and construct your popup as required.
//and then.
popup.show(((JApplet) e.getComponent()).getContentPane(), e
.getX(), e.getY());
}
}

Related

Adding another movable image in Swing

I have stumpled upon a problem. What I'm trying to do is to add another movable image in JPanel, movable as in that one could drag it with the mouse. This program only can view one image at the time and drag it arround. So how could I do to have more than one picture in my program?
=)
Here is my code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
public class test2 {
public static void main(String[] args) {
new test2();
}
public test2() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
Bild bild = new Bild();
frame.add(new DragMyIcon("katt.gif"));
frame.setSize(640,460);
frame.setVisible(true);
}
});
}
protected class DragMyIcon extends JPanel {
public static final long serialVersionUID = 172L;
private JLabel label;
public DragMyIcon(String path) {
setLayout(null);
ImageIcon icon = null;
icon = new ImageIcon(path);
label = new JLabel(icon);
label.setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
setBounds(0,0,icon.getIconWidth(), icon.getIconHeight());
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
add(label);
MouseHandler handler = new MouseHandler();
label.addMouseListener(handler);
label.addMouseMotionListener(handler);
}
}
protected class MouseHandler extends MouseAdapter {
private boolean active = false;
private int xDisp;
private int yDisp;
#Override
public void mousePressed(MouseEvent e) {
active = true;
JLabel label = (JLabel) e.getComponent();
xDisp = e.getPoint().x - label.getLocation().x;
yDisp = e.getPoint().y - label.getLocation().y;
label.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
#Override
public void mouseReleased(MouseEvent e) {
active = false;
JLabel label = (JLabel) e.getComponent();
label.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
#Override
public void mouseDragged(MouseEvent e) {
if (active) {
JLabel label = (JLabel) e.getComponent();
Point point = e.getPoint();
label.setLocation(point.x - xDisp, point.y - yDisp);
label.invalidate();
label.repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) {
}
}}
What I'm trying to do is to add another movable image in JPanel,
Where? I don't see any code?
You only add a single label to the panel. If you want to drag more than one then you need to add more than one label to the panel.
This program only can view one image at the time and drag it arround.
Well maybe you need a method like addImage(Image image, int x, int y). Then when you invoke this method you:
create a JLabel using the image for the Icon
set the bounds of the label using the x/y and the image size
add the listeners to the label
add the label to the panel

Libgdx different way for fling gesture detection

In my game I implement fling gesture detection. Everything work fine , but I want to modify fling detection
From documentation for fling: https://github.com/libgdx/libgdx/wiki/Gesture-detection
fling: A user dragged the finger across the screen, then lifted it. Useful to implement swipe gestures.
I want to modify this and fling to work without lifting touch, only when user drag some distance not lifting it.
Here is my code:
public class SimpleDirectionGestureDetector extends GestureDetector {
public interface DirectionListener {
void onLeft();
void onRight();
void onUp();
void onDown();
}
public SimpleDirectionGestureDetector(DirectionListener directionListener) {
super(new DirectionGestureListener(directionListener));
}
private static class DirectionGestureListener extends GestureAdapter{
DirectionListener directionListener;
public DirectionGestureListener(DirectionListener directionListener){
this.directionListener = directionListener;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
if(Math.abs(velocityX)>Math.abs(velocityY)){
if(velocityX>0){
directionListener.onRight();
}else{
directionListener.onLeft();
}
}else{
if(velocityY>0){
directionListener.onDown();
}else{
directionListener.onUp();
}
}
return super.fling(velocityX, velocityY, button);
}
}
}
public SimpleDirectionGestureDetector gestureDetector = new SimpleDirectionGestureDetector(
new SimpleDirectionGestureDetector.DirectionListener() {
#Override
public void onUp() {
onUpSwipe();
}
#Override
public void onRight() {
onRightSwipe();
}
#Override
public void onLeft() {
onLeftSwipe();
}
#Override
public void onDown() {
onDownSwipe();
}
});
Any help would be appreciated
Thanks

Vaadin Drag Drop Component

We are creating a web application using Vaadin. Our application contains alot of drag and drop features.
We have an object which is drag-able.
We can click on it to open its menu as well.
Sometimes that when we click that item it behaves as if it is dragged.
When this happens we are unable to open its menu because the component is in dragmode.
All components with the same functionality behave the same however in development environment, when we restart the tomcat the problem disappeared?
I noticed that when the components start showing me this behavior the webpage in FireFox the behavior is fine there?
A simple solution to this could be to introduce a drag mode/edit button which would allow the user to switch the drag mode on and off.
This would mean the user could interact with the components and then enter this "drag mode" when they wished to drag them. Hence reducing the frustration of trying to interact with the component and it starting to "drag" instead.
I've create a simple example program to try out below.
public class DemoUI extends UI {
HorizontalSplitPanel splitPanel;
DragAndDropWrapper wrapperA;
DragAndDropWrapper wrapperB;
DragAndDropWrapper splitPaneWrapper;
Button buttonA;
Button buttonB;
private boolean isDragMode = false;
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = DemoUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
Button buttonA = new Button("Button A");
Button buttonB = new Button("Button B");
final DragAndDropWrapper wrapperA = new DragAndDropWrapper(buttonA);
final DragAndDropWrapper wrapperB = new DragAndDropWrapper(buttonB);
final VerticalLayout leftPanel = new VerticalLayout();
final VerticalLayout rightPanel = new VerticalLayout();
DragAndDropWrapper leftPanelWrapper = new DragAndDropWrapper(leftPanel);
DragAndDropWrapper rightPanelWrapper = new DragAndDropWrapper(rightPanel);
buttonA.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Notification.show("Button A was clicked");
}
});
buttonB.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
Notification.show("Button B was clicked");
}
});
leftPanelWrapper.setDropHandler(new DropHandler() {
#Override
public void drop(DragAndDropEvent event) {
leftPanel.addComponent(event.getTransferable().getSourceComponent());
}
#Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
});
rightPanelWrapper.setDropHandler(new DropHandler() {
#Override
public void drop(DragAndDropEvent event) {
rightPanel.addComponent(event.getTransferable().getSourceComponent());
}
#Override
public AcceptCriterion getAcceptCriterion() {
return AcceptAll.get();
}
});
final Button dragMode = new Button("Drag Mode On");
dragMode.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
isDragMode = !isDragMode;
if (isDragMode) {
dragMode.setCaption("Drag Mode Off");
wrapperA.setDragStartMode(DragStartMode.WRAPPER);
wrapperB.setDragStartMode(DragStartMode.WRAPPER);
} else {
dragMode.setCaption("Drag Mode On");
wrapperA.setDragStartMode(DragStartMode.NONE);
wrapperB.setDragStartMode(DragStartMode.NONE);
}
}
});
leftPanel.setSizeFull();
rightPanel.setSizeFull();
leftPanelWrapper.setSizeFull();
rightPanelWrapper.setSizeFull();
leftPanel.addComponent(wrapperA);
rightPanel.addComponent(wrapperB);
splitPanel.setFirstComponent(leftPanelWrapper);
splitPanel.setSecondComponent(rightPanelWrapper);
splitPanel.setSizeFull();
VerticalLayout layout = new VerticalLayout();
layout.addComponent(dragMode);
layout.addComponent(splitPanel);
layout.setSizeFull();
this.setContent(layout);
this.setSizeFull();
}
.
All the best.

How to run a javaFX MediaPlayer in swing?

I've made a simple Media Player for an application I'm working on, the problem is that I thought that you could simply integrate JavaFX into Swing. Which is not the case. I have been searching for a solution to this problem and tried to use this website: http://docs.oracle.com/javafx/2/swing/jfxpub-swing.htm
The problem is that even though I have the website that explains how to put the code together, I still don't understand how. Here is the mediaplayer and I plan to integrate it into my Swing code, so that I can call the media player when a button is clicked. Here is all my code for the media player and if anyone can share some light on how to integrate it into my Swing code i.e my GUI, I would probably have to kiss you through the computer.
public class Player extends Application{
private boolean atEndOfMedia = false;
private final boolean repeat = false;
private boolean stopRequested = false;
private Duration duration;
private Label playTime;
private Slider volumeSlider;
#Override
public void start(final Stage stage) throws Exception {
stage.setTitle("Movie Player");//set title
Group root = new Group();//Group for buttons etc
final Media media = new Media("file:///Users/Paul/Downloads/InBruges.mp4");
final MediaPlayer playa = new MediaPlayer(media);
MediaView view = new MediaView(playa);
//Slide in and out and what causes that.
final Timeline slideIn = new Timeline();
final Timeline slideOut = new Timeline();
root.setOnMouseEntered(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(MouseEvent t) {
slideIn.play();
}
});
root.setOnMouseExited(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(MouseEvent t) {
slideOut.play();
}
});
final VBox vbox = new VBox();
final Slider slider = new Slider();
final Button playButton = new Button("|>");
root.getChildren().add(view);
root.getChildren().add(vbox);
vbox.getChildren().add(slider);
vbox.getChildren().add(playButton);
vbox.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 400, 400, Color.BLACK);
stage.setScene(scene);
stage.show();
// Play/Pause Button
playButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
Status status = playa.getStatus();
if (status == Status.UNKNOWN || status == Status.HALTED)
{
// don't do anything in these states
return;
}
if ( status == Status.PAUSED
|| status == Status.READY
|| status == Status.STOPPED)
{
// rewind the movie if we're sitting at the end
if (atEndOfMedia) {
playa.seek(playa.getStartTime());
atEndOfMedia = false;
}
playa.play();
} else {
playa.pause();
}
}
});
//Listeners and Shit for Play Button
playa.setOnPlaying(new Runnable() {
#Override
public void run() {
if (stopRequested) {
playa.pause();
stopRequested = false;
} else {
playButton.setText("||");
}
}
});
playa.setOnPaused(new Runnable() {
#Override
public void run() {
playButton.setText(">");
}
});
playa.play();
playa.setOnReady(new Runnable() {
#Override
public void run(){
int v = playa.getMedia().getWidth();
int h = playa.getMedia().getHeight();
stage.setMinWidth(v);
stage.setMinHeight(h);
vbox.setMinSize(v, 100);
vbox.setTranslateY(h-50);
//slider and graphical slide in/out
slider.setMin(0.0);
slider.setValue(0.0);
slider.setMax(playa.getTotalDuration().toSeconds());
slideOut.getKeyFrames().addAll(
new KeyFrame(new Duration(0),
new KeyValue(vbox.translateYProperty(), h-100),
new KeyValue(vbox.opacityProperty(), 0.9)
),
new KeyFrame(new Duration(300),
new KeyValue(vbox.translateYProperty(), h),
new KeyValue(vbox.opacityProperty(), 0.0)
)
);
slideIn.getKeyFrames().addAll(
new KeyFrame(new Duration(0),
new KeyValue(vbox.translateYProperty(), h),
new KeyValue(vbox.opacityProperty(), 0.0)
),
new KeyFrame(new Duration(300),
new KeyValue(vbox.translateYProperty(), h-100),
new KeyValue(vbox.opacityProperty(), 0.9)
)
);
}
});
//Slider being current and ability to click on slider.
playa.currentTimeProperty().addListener(new ChangeListener<Duration>(){
#Override
public void changed(ObservableValue<? extends Duration> observableValue, Duration duration, Duration current){
slider.setValue(current.toSeconds());
}
});
slider.setOnMouseClicked(new javafx.event.EventHandler<javafx.scene.input.MouseEvent>() {
#Override
public void handle(javafx.scene.input.MouseEvent t) {
playa.seek(Duration.seconds(slider.getValue()));
}
});
}
Use JFXPanel:
public class Test {
private static void initAndShowGUI() {
// This method is invoked on Swing thread
JFrame frame = new JFrame("FX");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setVisible(true);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// This method is invoked on JavaFX thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
}
where method createScene() is start(final Stage stage) from your code.
Just instead of putting scene to stage you return it.

What is the best way to trigger a combo-box cell editor by typing in a JTable cell?

In other words, I want JTable to drop-down a combo-box whenever user types in a cell that has a JComboBox (or any other JComboBox-based cell-editor) editor associated to it.
Basically, you have to install an appropriate listener on the combo and open the popup explicitly. First candidate for "appropriate" is an AncestorListener, which invokes showing the popup in its ancestorAdded method.
Unfortunately that doesn't seem to be the whole story: works if the table's surrenderFocus property is false. If it is true works only for not-editable combos. After some digging, the reason for the not-working part turns out to be an internal focustransfer (from the combo to the textfield) after the popup is opened by the ancestorListener. In that case, we need a second listener which opens the popup once the editor's editingComponent got the focus permanently.
Multiple listeners routinely step onto each other's feet, so best to not install both permanently but do it on each call to getEditorComp, and let them uninstall themselves once they showed the popup. Below is a working example of how-to do it, just beware: it's not formally tested!
public static class DefaultCellEditorX extends DefaultCellEditor {
private AncestorListener ancestorListener;
private PropertyChangeListener focusPropertyListener;
public DefaultCellEditorX(JComboBox comboBox) {
super(comboBox);
}
/**
* Overridden to install an appriate listener which opens the
* popup when actually starting an edit.
*
* #inherited <p>
*/
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
super.getTableCellEditorComponent(table, value, isSelected, row, column);
installListener(table);
return getComponent();
}
/**
* Shows popup.
*/
protected void showPopup() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
getComponent().setPopupVisible(true);
}
});
}
/**
* Dynamically install self-uninstalling listener, depending on JComboBox
* and JTable state.
* #param table
*/
private void installListener(JTable table) {
if (getComponent().isEditable() && table.getSurrendersFocusOnKeystroke()) {
installKeyboardFocusListener();
} else {
installAncestorListener();
}
}
private void installAncestorListener() {
if (ancestorListener == null) {
ancestorListener = new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
getComponent().removeAncestorListener(ancestorListener);
showPopup();
}
#Override
public void ancestorRemoved(AncestorEvent event) {
}
#Override
public void ancestorMoved(AncestorEvent event) {
}
};
}
getComponent().addAncestorListener(ancestorListener);
}
private void installKeyboardFocusListener() {
if (focusPropertyListener == null) {
focusPropertyListener = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
LOG.info("property: " + evt.getPropertyName());
if (focusManager().getPermanentFocusOwner() !=
getComponent().getEditor().getEditorComponent()) return;
focusManager()
.removePropertyChangeListener("permanentFocusOwner", focusPropertyListener);
showPopup();
}
};
}
focusManager().addPropertyChangeListener("permanentFocusOwner", focusPropertyListener);
}
/**
* Convience for less typing.
* #return
*/
protected KeyboardFocusManager focusManager() {
return KeyboardFocusManager.getCurrentKeyboardFocusManager();
}
/**
* Convenience for type cast.
* #inherited <p>
*/
#Override
public JComboBox getComponent() {
return (JComboBox) super.getComponent();
}
}
JTable table = new JTable(data, columns);
table.putClientProperty("terminateEditOnFocusLost", true);
JScrollPane scrollPane = new JScrollPane(table);
final JXComboBox editorComboBox = new JXComboBox(array);
editorComboBox.addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent event) {
//make sure combobox handles key events
editorComboBox.requestFocusInWindow();
}
public void ancestorMoved(AncestorEvent event) {}
public void ancestorRemoved(AncestorEvent event) {}
});
AutoCompleteDecorator.decorate(editorComboBox);
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellEditor(new ComboBoxCellEditor(editorComboBox));