How do I draw string from user input in a JFrame Java - java

Couldn't find what I was looking for from the search function, I might have just been formulating the title badly.
Anyways, right now I can click on my JFrame and it will draw whatever the user types into the console and when you hit Enter it will stop the sentence.
But what I want is for the user to just type directly into the JFrame and then when you hit enter you end the input.
This is what I have now:
public void drawString(MouseEvent e) throws IOException {
if(textClick==true) {
int xLoc = e.getX();
int yLoc = e.getY();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String accStr;
System.out.println("Enter your Account number: ");
accStr = br.readLine();
g2.drawString(accStr, xLoc, yLoc);
textClick=false;
}
}
So you click somewhere on the JFrame. It will then display whatever the user is typing at that location, without having to go into the console and type there.

Don't mix console input with a Swing GUI as this can lead to a threading nightmare. Instead get the input by some other means. Myself, I'd use a JOptionPane.showInputDialog(...) to get a user's input String. Also, don't use Graphics like you're doing outside of a paint or paintComponent method as that's a recipe for a NullPointerException or some other GUI failure. Instead display the text in a JLabel or a text component such as a JTextArea or JTextField.
Something like:
public void drawString(MouseEvent e) throws IOException {
if(textClick) { // none of this == true stuff please
int xLoc = e.getX();
int yLoc = e.getY();
String prompt = "Enter your Account Number:";
String input = JOptionPane.showInputDialog(someComponent, prompt);
// !!! no
// g2.drawString(accStr, xLoc, yLoc); // no don't do this
myJLabel.setText(input);
textClick=false;
}
}
If you absolutely must draw the String using Graphics, then in the method above, set a field of the object, perhaps something like private String textToDraw, call repaint() on your GUI, and in your JPanel's protected void paintComponent(Graphics g) method draw the text.
Here's a kludge code that puts a JTextField at the mousepressed location, and then converts the JTextField into a JLabel either on enter press or on focus lost:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class AddingText extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
public AddingText() {
addMouseListener(new MyMouse());
setLayout(null); // one of the few times this may be ok
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private void convertToLabel(final JTextField textField) {
JLabel label = new JLabel(textField.getText());
label.setSize(label.getPreferredSize());
label.setLocation(textField.getLocation());
remove(textField);
add(label);
repaint();
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
final JTextField textField = new JTextField(20);
textField.setSize(textField.getPreferredSize());
textField.setLocation(e.getPoint());
add(textField);
revalidate();
repaint();
textField.requestFocusInWindow();
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
convertToLabel((JTextField) e.getComponent());
}
});
textField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
convertToLabel((JTextField) e.getSource());
}
});
}
}
private static void createAndShowGui() {
AddingText mainPanel = new AddingText();
JFrame frame = new JFrame("AddingText");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Attempt two: where I draw directly in the JPanel by overridding paintComponent and by using a JOptionPane. The text is placed into a Map<Point, String> and then this text is drawn within paintComponent by iterating through this map. This way we avoid the dreaded null layout.
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.*;
public class AddingText2 extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private Map<Point, String> pointTextMap = new LinkedHashMap<>();
public AddingText2() {
addMouseListener(new MyMouse());
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(getFont().deriveFont(Font.BOLD));
for (Point p : pointTextMap.keySet()) {
String text = pointTextMap.get(p);
g.drawString(text, p.x, p.y);
}
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
String prompt = "Please add text to display";
String input = JOptionPane.showInputDialog(AddingText2.this, prompt);
pointTextMap.put(e.getPoint(), input);
repaint();
}
}
private static void createAndShowGui() {
AddingText2 mainPanel = new AddingText2();
JFrame frame = new JFrame("AddingText2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

If i understood your problem right, you basicly want a KeyListener:
public class MyWindow extends JFrame {
private int x, y;
private String text;
private boolean shouldGetText = false;
private KeyListener keyboard = new KeyAdapter() {
public void keyTyped(KeyEvent evt) {
if(!shouldGetText)
return;
text = text + evt.getChar(); // or evt.getKeyChar()... not sure about the name of this method
}
public void keyPressed(KeyEvent evt) {
if (shouldGetText && evt.getKeyCode() == KeyEvent.VK_ENTER)
shouldGetText = false;
}
}
private MouseListener mouse = new MouseAdapter() {
public void mouseMoved(MouseEvent evt) {
if (shouldGetText)
return;
x = evt.getX();
y = evt.getY();
}
public void mousePressed(MouseEvent evt) {
shouldGetText = true;
text = "";
}
}
public MyWindow() {
addKeyListener(keyboard);
addMouseListener(mouse);
addMouseMotionListene(mouse);
// Do other stuff
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawString(text, x, y);
}
}

Related

Java - Access datas of a MouseListener from another Component

I'm currently working on a level editor for a game. Currently, to create an Entity, you have to click on a creation JButton, then a form appears, where you enter its coordinate and its size.
I would like to implement a mouse fonction. The user click on the creation JButton, then have to press the mouseButton somewhere on the JPanel where the level is previewed, then drag to set the size of the object, and finally release the button. The object is then created where the button was pressed.
I add a MouseListener to the previewPanel (to get the correct coordinates).
My problem is : what should I do when I click on the button ?Inside the actionPerformed method ?
bascially, the procedure would be :
1) Wait the button to be pressed
2) get coordinates
3) Wait the button to be released
4) Get new coordinates to make the size of the object
5) Create object
How should I proceed to do it properly ?
Thanks in advance
My problem is : what should I do when I click on the button ?
Inside the actionPerformed method ?
Activate the MouseListener. This can be by adding the MouseListener and MouseMotionListener (a MouseAdapater can do both) to the drawing JPanel on button click, or by changing the state of an already added MouseAdapater (my preference), again one that has already been added to the JPanel. This could be as simple as switching a boolean variable to true, and then have the mousePressed, mouseDragged, mouseReleased methods check the state of this boolean before doing any of their actions.
Note that if you go the first route -- by adding a MouseListener/MouseMotionListener on button press, you risk adding multiple listeners if you don't take care to remove them when you're through. That is why I prefer the 2nd approach.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class ActivateMouse extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Color DRAW_RECT_COLOR = Color.pink.brighter();
private static final Color DRAW_ALL_RECTS_COLOR = Color.red;
private boolean mouseActive = false;
private Shape drawRect = null;
private List<Shape> shapeList = new ArrayList<>();
private ButtonAction buttonAction = new ButtonAction("Create New Rectangle", KeyEvent.VK_C);
public ActivateMouse() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
add(new JButton(buttonAction));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (drawRect != null) {
g2.setColor(DRAW_RECT_COLOR);
g2.draw(drawRect);
}
g2.setColor(DRAW_ALL_RECTS_COLOR);
for (Shape shape : shapeList) {
g2.draw(shape);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouseAdapter extends MouseAdapter {
private Point firstPt;
#Override
public void mousePressed(MouseEvent e) {
if (mouseActive && e.getButton() == MouseEvent.BUTTON1) {
firstPt = e.getPoint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (!mouseActive || firstPt == null) {
return;
}
drawRect = createRect(e.getPoint());
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (!mouseActive || firstPt == null) {
return;
}
shapeList.add(createRect(e.getPoint()));
repaint();
mouseActive = false;
}
private Shape createRect(Point p) {
int x = Math.min(firstPt.x, p.x);
int y = Math.min(firstPt.y, p.y);
int width = Math.abs(firstPt.x - p.x);
int height = Math.abs(firstPt.y - p.y);
return new Rectangle(x, y, width, height);
}
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
mouseActive = true;
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ActivateMouse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ActivateMouse());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Repaint without painting every component again

i have an application containing a jframe, this jframe then adds a jpanel which constains an image. the jpanel is displayed for a given time, then removed from the jframe and another jpanel is added.
I want to fade in and out between the images, and ive done this using a timer
private void fadeOut() {
ActionListener fadeOutAc = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
opacity += 10;
if (opacity >= 255) {
opacity = 255;
fadeOutT.stop();
}
repaint();
}
};
fadeOutT = new Timer(20, fadeOutAc);
fadeOutT.start();
}
private void fadeIn() {
ActionListener fadeInAc = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
opacity -= 10;
if (opacity <= 0) {
opacity = 0;
fadeInT.stop();
}
repaint();
}
};
fadeInT = new Timer(10, fadeInAc);
fadeInT.setInitialDelay(200);
fadeInT.start();
}
public void paint(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(picColor.getRed(), picColor.getGreen(), picColor.getBlue(), opacity));
g.fillRect(0, 0, presWin.getWidth(), presWin.getHeight());
}
i recently moved the fading in/out from the jpanel to the jframe instead. The problem is, that in the jpanel, the repaint only had to draw an image, now it has to repaint the entire jpanel each time. Is there a way to call repaint without having the paint the components, only the rectangel?
To me, it seems a bit silly to put the functionality in the JFrame when what you seem to want is a container which can fade it's content in and out. This way you can isolate the responsibility to a single container/class which can be placed or used in what ever way you want in isolation to the rest of the UI.
Basically, this example uses a FadingPane (based on a JPanel) to control the fading process, but onto which I place JLabel which holds the actual images.
Fading is controlled through the use of a AlphaComposite, meaning that this panel will actually physically fade in and out, not just change fill color ;)
There is also a FadingListener which provides additional notifications about the fading process, really only interested in fadeOutDidComplete, so you can switch the images and fade the panel back in, but you never know...
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private FadingPane fadingPane;
private File[] pictures;
private int index;
public TestPane() {
// Just for show
setBackground(Color.RED);
fadingPane = new FadingPane(new FadeListener() {
#Override
public void fadeDidStart(FadingPane panel) {
}
#Override
public void fadeDidStop(FadingPane panel) {
}
#Override
public void fadeOutDidComplete(FadingPane panel) {
nextPicture();
fadingPane.fadeIn();
}
#Override
public void fadeInDidComplete(FadingPane panel) {
}
});
setLayout(new BorderLayout());
fadingPane.setLayout(new BorderLayout());
label = new JLabel();
fadingPane.add(label);
add(fadingPane);
JButton next = new JButton("Next");
add(next, BorderLayout.SOUTH);
next.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fadingPane.fadeOut();
}
});
pictures = new File("/Volumes/Disk02/Dropbox/MegaTokyo/thumnails").listFiles(new FileFilter() {
#Override
public boolean accept(File pathname) {
String name = pathname.getName().toLowerCase();
return name.endsWith(".jpg") || name.endsWith(".png");
}
});
nextPicture();
}
protected void nextPicture() {
index++;
if (index >= pictures.length) {
index = 0;
}
try {
BufferedImage img = ImageIO.read(pictures[index]);
label.setIcon(new ImageIcon(img));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public interface FadeListener {
public void fadeDidStart(FadingPane panel);
public void fadeDidStop(FadingPane panel);
public void fadeOutDidComplete(FadingPane panel);
public void fadeInDidComplete(FadingPane panel);
}
public class FadingPane extends JPanel {
private float delta;
private float alpha = 1f;
private Timer timer;
private FadeListener fadeListener;
public FadingPane(FadeListener fadeListener) {
this.fadeListener = fadeListener;
// This is important, as we may not always be opaque
// and we don't want to stuff up the painting process
setOpaque(false);
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
float alpha = getAlpha() + delta;
if (alpha < 0.001f) {
alpha = 0f;
timer.stop();
fadeListener.fadeOutDidComplete(FadingPane.this);
} else if (alpha >= 1.0f) {
alpha = 1.0f;
timer.stop();
fadeListener.fadeInDidComplete(FadingPane.this);
}
setAlpha(alpha);
}
});
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float value) {
if (alpha != value) {
this.alpha = Math.min(1.0f, Math.max(0.0f, value));
repaint();
}
}
#Override
public void paint(Graphics g) {
// I don't normally recomamned overriding paint, but in this case,
// I want to affect EVERYTHING that might be added to this panel
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(getAlpha()));
super.paint(g2d);
g2d.dispose();
}
public void fadeIn() {
timer.stop();
fadeListener.fadeDidStop(FadingPane.this);
delta = 0.05f;
timer.restart();
fadeListener.fadeDidStart(FadingPane.this);
}
public void fadeOut() {
timer.stop();
fadeListener.fadeDidStop(FadingPane.this);
delta = -0.05f;
timer.restart();
fadeListener.fadeDidStart(FadingPane.this);
}
}
}
Thats totaly normal, moving your function to the JFrame and calling repaint function would actualy call repaint of your JFrame.
I think the best solution would be to pass panel as an argument to your fadeIn and fadeOut function and call its repaint methode for example fadeIn :
private void fadeIn(JPanel panelParam) {
ActionListener fadeInAc = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
opacity -= 10;
if (opacity <= 0) {
opacity = 0;
fadeInT.stop();
}
panelParam.repaint(); // here call repaint of the panel.
}
};
fadeInT = new Timer(10, fadeInAc);
fadeInT.setInitialDelay(200);
fadeInT.start();
}
With that you can apply your effect on any other panel.
Hope it helped.

Doing an animation in Java

I am doing a java assignment for next Saturday.
Its going really well, however I'm struggling with one section.
Here I want to reveal a set of numbers in a String, one at a time.
I tried slowing down the loop with 'Thread.sleep(1000);'
however nothing is displaying until the thread is finished
the following is a section of the graphics class where the problem is occuring
is there something I'm missing?
public void paint(Graphics g)
{
setSize(550, 300);
//this draws all the random numbers, revealing the ans to the user
if (revealNum == 0)
{
g.setColor(Color.BLUE);
g.drawString(randomNumber, 20, 20); //draw String ("the String", x, y)
}
//this reveals the numbers 1 by 1 to the user at the start of the game
if (revealNum==1)
{
for (int x = 0; x < limit; x++)
{
g.setColor(Color.BLUE);
g.drawString(""+x, 20, 20); //draw String ("the String", x, y)
try{
Thread.sleep(1000);
}catch(InterruptedException ex){
System.out.print("Error");
}
repaint();
}
//slow down the loop to show the user
}
Since yours is a GUI, calling Thread.sleep will put the entire app to sleep. Instead use a Swing Timer. Inside the Timer's ActionListener, add another letter to the displayed String, and then stop the Timer via the stop() method once the String is complete.
e.g.,
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class SimpleAnimation extends JPanel {
public static final int TIMER_DELAY = 1000;
private JTextField textField = new JTextField(10);
private JLabel displayLabel = new JLabel("", SwingConstants.CENTER);
public SimpleAnimation() {
Action btnAction = new DoItBtnAction("Do It!", KeyEvent.VK_D);
JPanel topPanel = new JPanel();
topPanel.add(textField);
topPanel.add(new JButton(btnAction));
textField.addActionListener(btnAction);
setLayout(new GridLayout(2, 1));
add(topPanel);
add(displayLabel);
}
private class DoItBtnAction extends AbstractAction {
private String textFieldText = "";
public DoItBtnAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
displayLabel.setText("");
setEnabled(false);
textFieldText = textField.getText();
new Timer(TIMER_DELAY, new ActionListener() {
private int i = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (i >= textFieldText.length()) {
((Timer) e.getSource()).stop();
DoItBtnAction.this.setEnabled(true);
} else {
displayLabel.setText(displayLabel.getText() + textFieldText.charAt(i));
i++;
}
}
}).start();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleAnimation());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also,
If yours is a Swing GUI, it would be easier to display your text in a JLabel or a JTextField rather than trying to paint it on the GUI.
If this is Swing, don't override paint(Graphics g) but rather the paintComponent(Graphics g) method of a JPanel or JComponent.
You should use a javax.swing.Timer
Here is an example
JLabel l = ...;
Timer t = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (l.getText().equals("1")) l.setText("2");
else if (l.getText().equals("2)) l.setText("1");
}
});

How to add new Graphic element to JPanel and use its link to change its position in loop?

I need only one ring to be created on MyPanel (extends JPanel) initialization. Then I need to change (in a loop iterate() ) position of ring on MyPanel. How and what to add to this code?
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
public class mull {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel p = createAndShowGUI();
iterate(p);
// "The method iterate(MyPanel) in the type mull is not applicable for the arguments (JPanel)"
}
});
}
private static JPanel createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// how to grab link to this panel - in order to use it in iteration loop ?
MyPanel p = new MyPanel();
f.add(p);
// f.add(new MyPanel());
f.pack();
f.setVisible(true);
return p;
}
private static void iterate(JPanel p){
// the loop should change square position on each iteration
// how to implement ?
for (int i = 0; i < 999; i++){
((MyPanel) p).moveSquare(100 + i*10, 200 + i*10); // here is problem:
//"Cannot make a static reference to the non-static method moveSquare(int, int) from the type MyPanel"
}
}
}
class MyPanel extends JPanel {
private int squareX = 50;
private int squareY = 50;
private int squareW = 200;
private int squareH = 200;
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
}
// originally this method was private - in orger to access it within mull, it vas changed to public
public void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(900,700);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}

JLabel mouse events for Drag and Drop

I want to enable the drag and drop feature over a JLabel by overriding mouse events over it , but when I define the drag and drop in mousePressed event ,the mouseReleased does not take effect on that JLabel. Am I doing something wrong ?
Thumbnails[I_Loop].setText("1");
Thumbnails[I_Loop].setTransferHandler(new TransferHandler("text"));
Thumbnails[I_Loop].addMouseListener( new MouseAdapter() {
public void mouseReleased(MouseEvent me) {
System.out.println("here mouse released");
}
public void mousePressed(MouseEvent me) {
System.out.println("here mouse pressed");
JComponent comp = (JComponent) me.getSource();
TransferHandler handler = comp.getTransferHandler();
handler.exportAsDrag(comp, me, TransferHandler.COPY);
});
*Thumbnails is array of JLabel
When running the program , the drag and drop works but the statement "here mouse released" does not get printed. However, When I remove the code responsible for DND from the mousePressed() method, "here mouse released" is printed.
What is the wrong in this code?
#Thomas is correct, but two alternatives are worth noting:
This example shows how to drag a component using JLayeredPane; this variation expands on the concept; this more recent example uses a similar approach.
The code below shows how to use a MouseMotionListener; this more complex example uses the same principle.
Code:
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see https://stackoverflow.com/a/5312702/230513 */
public class MouseDragTest extends JPanel {
private static final String TITLE = "Drag me!";
private static final int W = 640;
private static final int H = 480;
private Point textPt = new Point(W / 2, H / 2);
private Point mousePt;
public MouseDragTest() {
this.setFont(new Font("Serif", Font.ITALIC + Font.BOLD, 32));
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int dx = e.getX() - mousePt.x;
int dy = e.getY() - mousePt.y;
textPt.setLocation(textPt.x + dx, textPt.y + dy);
mousePt = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w2 = g.getFontMetrics().stringWidth(TITLE) / 2;
g.drawString(TITLE, textPt.x - w2, textPt.y);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame(TITLE);
f.add(new MouseDragTest());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Well, if I remember correctly, the drag and drop machinery catches all mouse events and processes them itself. Thus, the normal MouseEvents are not thrown anymore. You'd need to register a DropTargetListener on the JLabel's DropTarget.
Does it have to be a JLabel? I made a class with a string that might get you started..
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class mainProgram extends JPanel implements Runnable
{
private static final long serialVersionUID = 1L;
public static boolean MOUSE_DOWN = false;
public static String str;
public mainProgram()
{
JFrame win = new JFrame("Window");
win.add(this);
win.setSize(700,500);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.setVisible(true);
str = "Drag me!";
new Thread(this).start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(MOUSE_DOWN)
{
g.drawString(str, MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y);
}
}
#Override
public void run()
{
Thread t = Thread.currentThread();
this.addMouseListener(new MouseListener()
{
#Override
public void mouseClicked(MouseEvent arg0)
{
}
#Override
public void mouseEntered(MouseEvent arg0)
{
}
#Override
public void mouseExited(MouseEvent arg0)
{
}
#Override
public void mousePressed(MouseEvent arg0)
{
MOUSE_DOWN = true;
}
#Override
public void mouseReleased(MouseEvent arg0)
{
MOUSE_DOWN = false;
}
});
while(t==Thread.currentThread())
{
if(MOUSE_DOWN)
repaint();
try {Thread.sleep(10);}
catch (InterruptedException e) {e.printStackTrace();}
}
}
}

Categories