Cant see Overwrinting Cursor when i create new Line - java

I'm trying to create an overwriting Cursor. I've got it except when I click an earlier line the caret disappears, then when I hit 'enter' for a new line it appears again.
what should I change in my Code to solve this issue?
here is my Caret Class:
public class Mycaret extends DefaultCaret {
protected static final int MIN_WIDTH = 8;
protected DefaultCaret dc = null;
JTextComponent com = null;
public Mycaret(int rate, DefaultCaret dc) {
this.dc = dc;
super.setBlinkRate(rate);
}
protected synchronized void damage(Rectangle r) {
if (r != null) {
try {
JTextComponent comp = getComponent();
TextUI mapper = comp.getUI();
char dotChar = 0;
if(comp.getText().length()>0){
dotChar = comp.getText().charAt(comp.getText().length()-1);
}
this.com = comp;
Rectangle r2 = mapper.modelToView(comp, getDot() + 1);
int width = r2.x - r.x;
if (width == 0 ) {
width = MIN_WIDTH;
}
comp.repaint(r.x, r.y, width, r.height);
this.x = r.x;
this.y = r.y;
this.width = width;
this.height = r.height;
}
catch (BadLocationException e) {
}
}
}
public void paint(Graphics g) {
char dotChar;
if (isVisible()) {
try {
JTextComponent comp = getComponent();
TextUI mapper = comp.getUI();
Rectangle r1 = mapper.modelToView(comp, getDot());
Rectangle r2 = mapper.modelToView(comp, getDot() + 1);
g = g.create();
g.setColor(comp.getForeground());
g.setXORMode(comp.getBackground());
int width = r2.x - r1.x;
dotChar = comp.getText(getDot(), 1).charAt(0);
if (width == 0 ) {
width = MIN_WIDTH;
}
g.fillRect(r1.x, r1.y, width, r1.height);
g.dispose();
} catch (BadLocationException e) {
}
}
}
}
this is a Sample:
public class MyFrameSample extends JFrame {
DefaultCaret caret=null;
public MyFrameSample() {
JTextArea text = new JTextArea(10,20);
caret = new DefaultCaret();
text.setCaret(new Mycaret(500, caret));
add(text);
pack();
setVisible(true);
}
public static void main(String[] args) {
new MyFrameSample();
}
}

Based on #user1803551 observation I noticed that the width could be negative so I just changed your if condition to "<=" in the paint() and damage() methods:
if (width <= 0 )
{
width = MIN_WIDTH;
}

As I mentioned in the comments, the problem comes from newline characters (\n). When the caret is placed before \n in a non-empty line, it doesn't appear because it tries to take the width of a \n. Hence, I added a check for if a \n is at the same position the caret is.
Mid-write edit: #camickr figured out a better way by finding that somehow the width of \n is negative (anyone, why? See comments).
public class Mycaret extends DefaultCaret {
protected static final int MIN_WIDTH = 8;
public Mycaret(int rate) {
super.setBlinkRate(rate);
}
protected boolean isBeforeNewLine() throws BadLocationException {
PlainDocument doc = (PlainDocument) getComponent().getDocument();
if (doc.getText(getDot(), 1).equals("\n"))
return true;
return false;
}
#Override
protected synchronized void damage(Rectangle r) {
if (r != null) {
try {
JTextComponent comp = getComponent();
Rectangle r2 = comp.getUI().modelToView(comp, getDot() + 1);
int width = r2.x - r.x;
if (width == 0 || isBeforeNewLine()) {
width = MIN_WIDTH;
}
comp.repaint(r.x, r.y, width, r.height);
this.x = r.x;
this.y = r.y;
this.width = width;
this.height = r.height;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
#Override
public void paint(Graphics g) {
if (isVisible()) {
try {
JTextComponent comp = getComponent();
g.setColor(comp.getForeground());
g.setXORMode(comp.getBackground());
Rectangle r1 = comp.getUI().modelToView(comp, getDot());
Rectangle r2 = comp.getUI().modelToView(comp, getDot() + 1);
int width = r2.x - r1.x;
if (width == 0 || isBeforeNewLine()) {
width = MIN_WIDTH;
}
g.fillRect(r1.x, r1.y, width, r1.height);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
}
Explanation:
The isBeforeNewLine method get the text at the caret's position from the document. For a JTextArea it is a PlainDocument. If it's a \n then the width is set to MIN_WIDTH. This has to be done for both the paint and damage methods. It is also important to note that \n is the line separator for a JTextArea system-independently, but other text components might have it set differently.
Notes:
When catching an exception, the least you can do is print the stack trace.
I don't see a reason to create a new Graphics object in paint, use the one which is given.
Use #Override when applicable.
I just had to do some cleaning (refactoring), you might want to take something from this. I also changed the constructor since you don't need to pass a DefaultCaret to your class which extends it.

Related

ubuntu java swing jtextfield caret invisible since java8 (setXORMode bug ?)

Why does caret becomes invisible (after key pressed, or left-arrow) under java8 (oracle and openjdk) and higher ? (it works under java7). I am on ubuntu. It works fine on mac-os jdk1.8.0_51 and windows jdk1.8.0_65.
Seems to be linked to this bug. It is spécific to JTextField (does not occur on JTextArea).
from OverwritableTextField
public class OverWriteCaret extends DefaultCaret {
protected static final int MIN_WIDTH = 8;
private static final Logger logger = Logger.getLogger(OverWriteCaret.class.getName());
public static void main(String[] args) {
JFrame f = new JFrame("Big caret");
JTextField tf = new JTextField(20);
tf.setCaret(new OverWriteCaret());
f.getContentPane().add(tf, "North");
f.pack();
f.setVisible(true);
}
#Override
protected synchronized void damage(Rectangle r) {
if (r == null)
return;
try {
JTextComponent comp = getComponent();
TextUI mapper = comp.getUI();
Rectangle r2 = mapper.modelToView(comp, getDot() + 1);
int largeur = r2.x - r.x;
if (largeur == 0)
largeur = MIN_WIDTH;
comp.repaint(r.x, r.y, largeur, r.height);
this.x = r.x;
this.y = r.y;
this.width = largeur;
this.height = r.height;
} catch (Exception e) {
logger.info(e);
}
}
#Override
public void paint(Graphics g) {
if (isVisible())
try {
JTextComponent comp = getComponent();
TextUI mapper = comp.getUI();
Rectangle r1 = mapper.modelToView(comp, getDot());
Rectangle r2 = mapper.modelToView(comp, getDot() + 1);
g = g.create();
g.setColor(comp.getForeground());
g.setXORMode(comp.getBackground());
int largeur = r2.x - r1.x;
if (largeur == 0)
largeur = MIN_WIDTH;
g.fillRect(r1.x, r1.y, largeur, r1.height);
g.dispose();
} catch (Exception e) {
logger.info(e);
}
}
}
found another caret, ok with it
public class FancyCaret extends DefaultCaret {
private static final Logger logger = Logger.getLogger(FancyCaret.class.getName());
protected synchronized void damage(Rectangle r) {
if (r == null)
return;
x = r.x;
y = r.y;
height = r.height;
if (width <= 0)
width = getComponent().getWidth();
repaint(); // calls getComponent().repaint(x, y, width, height)
}
#Override
public void paint(Graphics g) {
JTextComponent comp = getComponent();
if (comp == null)
return;
int dot = getDot();
Rectangle r;
char dotChar;
try {
r = comp.modelToView(dot);
if (r == null)
return;
dotChar = comp.getText(dot, 1).charAt(0);
} catch (Exception e) {
logger.info(e);
return;
}
if ((x != r.x) || (y != r.y)) {
repaint(); // erase previous location of caret
x = r.x; // Update dimensions (width gets set later in this method)
y = r.y;
height = r.height;
}
if (dotChar == '\n') {
width = r.height / 2;
if (isVisible())
g.fillRect(r.x, r.y, width, r.height);
return;
}
g.setColor(comp.getCaretColor());
g.setXORMode(comp.getBackground()); // do this to draw in XOR mode
width = g.getFontMetrics().charWidth(dotChar);
if (isVisible())
g.fillRect(r.x, r.y, width, r.height);
}
}

Select buttons with a mouse rather then keyboard

Hi I made a pause menu for my game, and you navigate through it with the arrow keys on the keyboard. My question is how do I make it so I can navigate with my mouse, and click the buttons rather then having to use the arrow keys?
here is the code:
public class InGameMenu implements KeyListener {
private String[] string = { "Resume Game", "Options", "Save Game", "Load Game", "Exit Game" };
private String[] optionStrings = { "Help", "Back" };
public static int selected = 0;
private int space = 25;
public int width = 800;
public int height = 600;
public static boolean isInMenu = true;
public static boolean isInOptions = false;
public static boolean saving = false;
public static boolean loading = false;
public InGameMenu() {
}
public void tick() {
}
public void render(Graphics g) {
g.setColor(new Color(0, 0, 0, 90));
g.fillRect(0, 0, Component.width, Component.height);
if (isInMenu) {
g.setColor(Color.LIGHT_GRAY);
if (saving) {
g.drawString("Saving", Component.width / 2 / Component.pixelSize - (int) (Component.width / 25), 35);
}
if (loading) {
g.drawString("Loading", Component.width / 2 / Component.pixelSize - (int) (Component.width / 25), 35);
}
for (int i = 0; i < string.length; i++) {
if (selected == i) {
g.setColor(Color.RED);
} else {
g.setColor(Color.WHITE);
}
g.drawString(string[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));
}
} else if (isInOptions) {
for (int i = 0; i < optionStrings.length; i++) {
if (selected == i) {
g.setColor(Color.RED);
} else {
g.setColor(Color.WHITE);
}
g.drawString(optionStrings[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (isInMenu) {
if (key == KeyEvent.VK_UP) {
selected--;
if (selected < 0) {
selected = string.length - 1;
}
}
if (key == KeyEvent.VK_DOWN) {
selected++;
if (selected > string.length - 1) {
selected = 0;
}
}
if (key == KeyEvent.VK_ENTER) {
if (selected == 0) {
Component.isInMenu = false;
} else if (selected == 1) {
isInMenu = false;
isInOptions = true;
selected = 0;
} else if (selected == 2) {
saving = true;
SaveLoad.save();
saving = false;
} else if (selected == 3) {
loading = true;
SaveLoad.load();
loading = false;
} else if (selected == 4) {
System.exit(0);
}
}
} else if (isInOptions) {
if (key == KeyEvent.VK_UP) {
selected--;
if (selected < 0) {
selected = optionStrings.length - 1;
}
}
if (key == KeyEvent.VK_DOWN) {
selected++;
if (selected > optionStrings.length - 1) {
selected = 0;
}
}
if (key == KeyEvent.VK_ENTER) {
if (selected == 0) {
System.out.println("HELP");
} else if (selected == 1) {
isInOptions = false;
isInMenu = true;
}
}
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
You can implement MouseListener too.
You can add these methods from MouseListener:
public void mousePressed(MouseEvent e) {
if(e.getSource() == button1)
{
isInMenu = false;
isInOptions = true;
selected = 0;
}
if(e.getSource() == button2)
{
saving = true;
SaveLoad.save();
saving = false;
}
if(e.getSource() == button3)
{
loading = true;
SaveLoad.load();
loading = false;
}
if(e.getSource() == button4)
{
System.exit(0);
}
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
First, you must get the bounds (x, y, width and height) of the text.
You already have the x and y:
g.drawString(string[i], Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5), Component.height / 8 + (i * space));
// x = Component.width / 2 / Component.pixelSize - (int) (Component.width / 17.5)
// y = Component.height / 8 + (i * space)
You can determine the width and height via Font#getStringBounds(String, FontRenderContext):
FontRenderContext renderContext = new FontRenderContext(null, true, true);
Font font = new Font("Arial", Font.PLAIN, 14);
String labelText = "Start";
Rectangle2D labelBounds = font.getStringBounds(labelText, renderContext);
int labelWidth = (int) labelBounds.getWidth();
int labelHeight = (int) labelBounds.getHeight();
The bounds is needed to determine if the mouse is hovering over the text when the click occurs.
Next, you must maintain the bounds for each menu item.
Right now, you're only maintaining the names in string and optionStrings. You'll need to maintain the x, y, width and height for every menu item.
Since every menu item each has their own name, size and position, it would be easier to create a new type composed of these properties:
public class Label {
private String name;
private Font font;
private int x, y;
private int width, height;
public Label(String name, Font font, int x, int y, int width, int height) {
this.name = name;
this.font = font;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
Instead of a String[], you could have a Label[]. Although it's preferrable to use List for it's higher-level functionality:
public class InGameMenu implements MouseListener {
private List<Label> labels;
public void mousePressed(MouseEvent event) {
int x = event.getX();
int y = event.getY();
labels.forEach(label -> {
// if (mouse hovering over label)
// ...
});
}
}
Then, you must determine if the mouse position is within the label's position.
The formula is pretty simple:
// checks if mouse intersects with label on X axis
intersectsHorizontally := mouseX > labelX && mouseX < labelX + labelWidth;
// checks if mouse intersects with label on Y axis
intersectsVertically := mouseY > labelY && mouseY < labelY + labelHeight;
// if both conditions above are true, mouse is hovering over label
The easiest way to implement this would be to give your Label objects a containsPoint(int x, int y) behavior:
public class Label {
private int x, y;
private int width, height;
//...
public boolean containsPoint(int pointX, int pointY) {
boolean containsHorizontally = pointX > x && pointX < x + width;
boolean containsVertically = pointY > y && pointY < y + height;
return containsHorizontally && containsVertically;
}
}
Now you can easily determine whether the mouse is hovering over a specific label:
public void mousePressed(MouseEvent event) {
int x = event.getX();
int y = event.getY();
labels.forEach(label -> {
if(label.containsPoint(x, y)) {
//...
}
});
}
Finally, you must determine which label was clicked
There are many ways to go about this. Instead of a List, you could maintain the labels independently and check each one:
public class InGameMenu implements MouseListener {
private Label startLabel;
private Label loadLabel;
public InGameMenu(Label startLabel, Label loadLabel) {
this.startLabel = startLabel;
this.loadLabel = loadLabel;
}
public void mousePressed(MouseEvent event) {
int x = event.getX();
int y = event.getY();
if(startLabel.containsPoint(x, y)) {
//start game
} else if(loadLabel.containsPoint(x, y)) {
//load game
}
}
}
But this isn't dynamic, as InGameMenu is forced to know about every label it has, and adding labels would be a pain.
A better approach is to create all the Label objects outside of InGameMenu, as the examples above have been doing:
FontRenderContext renderContext = ...;
Font font = ...;
// start label
String labelText = "Start";
Rectangle2D labelBounds = font.getStringBounds(labelText, renderContext);
int x = ...;
int y = ...;
int width = (int) labelBounds.getWidth();
int height = (int) labelBounds.getHeight();
Label label = new Label(labelText, font, labelX, labelY, labelWidth, labelHeight);
// list of all labels for menu
List<Label> labels = new ArrayList<>();
labels.add(label);
InGameMenu menu = new InGameMenu(labels);
Then have the label object tell us when it has been clicked. We can do this by giving Label a click() method for InGameMenu to trigger when the label has been clicked:
public class InGameMenu implements MouseListener {
private List<Label> labels;
public InGameMenu(List<Label> labels) {
this.labels = labels;
}
public void mousePressed(MouseEvent event) {
int x = event.getX();
int y = event.getY();
labels.forEach(label -> {
if(label.containsPoint(x, y))
label.click();
});
}
}
Then allowing Label to accept a callback function:
public class Label {
private String name;
private Font font;
private int x, y;
private int width, height;
private Runnable onClick;
public Label(String name, Font font, int x, int y, int width, int height, Runnable onClick) {
this.name = name;
this.font = font;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.onClick = onClick;
}
public void click() {
onClick.run();
}
//...
}
So when you create Label objects, you can give them actions that make use of outside data (maybe a GameStateManager or something):
Runnable onClick = () -> System.out.println("Start button was clicked!");
Label label = new Label("Start", ..., onClick);

My ellipse creating program is only creating lines

I have a program that makes an ellipse when you click somewhere on a JPanel. When I did a test run, it just made slanted lines to the right of where I clicked. Can anyone find the problem? Thanks, here is the code:
This is the code for the click:
final SpriteField mSpritePanel = new SpriteField();
mSpritePanel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
float tX = e.getX();
float tY = e.getY();
int tIntWidth;
int tIntHeight;
int tIntRotate = 0;
if(tTextWidth.getText() == null)
{
tTextWidth.setText("50");
}
try
{
tIntWidth = Integer.parseInt(tTextWidth.getText());
}
catch(NumberFormatException ex)
{
tIntWidth = 50;
}
if(tIntWidth == 0)
{
tIntWidth = 50;
}
if(tTextHeight.getText() == null)
{
tTextHeight.setText("50");
}
try
{
tIntHeight = Integer.parseInt(tTextHeight.getText());
}
catch(NumberFormatException ex)
{
tIntHeight = 50;
}
if(tIntHeight == 0)
{
tIntHeight = 50;
}
if(tTextRotation.getText() == null)
{
tTextRotation.setText("0");
}
try
{
tIntRotate = Integer.parseInt(tTextRotation.getText());
}
catch(NumberFormatException ex)
{
tIntRotate = 50;
}
mSpritePanel.CreateSpriteAt(tX, tY, tIntWidth, tIntHeight, tIntRotate);
mSpritePanel.repaint();
}
});
This is the code for my SpriteField class:
public class SpriteField extends JPanel
{
final List<RoundSprite> mSpriteList = new ArrayList<RoundSprite>();
public void CreateSpriteAt(float tX, float tY, int tWidth, int tHeight, int tRotation)
{
RoundSprite mSprite = new RoundSprite();
mSprite.SetPosition(tX, tY);
mSprite.SetSpriteWidth(tWidth);
mSprite.SetSpriteHeight(tHeight);
mSprite.SetSpriteRotation(tRotation);
mSpriteList.add(mSprite);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
AffineTransform originalTransform = g2.getTransform();
for (RoundSprite mSprite : mSpriteList)
{
mSprite.DrawSprite(g2);
g2.setTransform(originalTransform);
}
}
}
And this is the code for my RoundSprite class:
public class RoundSprite
{
private float mX;
private float mY;
int mWidth;
int mHeight;
int mRotate;
Color mColor;
void DrawSprite(Graphics2D g2)
{
AffineTransform tOldTransform = g2.getTransform();
g2.setColor(mColor);
g2.translate(mX, mY);
g2.rotate(mRotate);
g2.translate(mX - (mWidth / 2), mY - (mHeight / 2));
g2.draw(new Ellipse2D.Double(0, 0, mWidth, mHeight));
g2.setTransform(tOldTransform);
}
public void SetSpriteWidth(int tWidth)
{
mWidth = tWidth;
}
public void SetSpriteHeight(int tHeight)
{
mWidth = tHeight;
}
public void SetSpriteColor(Color tColor)
{
mColor = tColor;
}
public void SetPosition(float x, float y)
{
mX = x;
mY = y;
}
public void SetSpriteRotation(int tRotate)
{
mRotate = tRotate;
}
}
You've got a copy-paste error in your setters for RoundSprite:
public void SetSpriteWidth(int tWidth)
{
mWidth = tWidth; // set the width
}
public void SetSpriteHeight(int tHeight)
{
mWidth = tHeight; // set the width again, leaving mHeight forever 0...
}
This leaves all of your ellipses one-dimensional, so they render as a line.
Just make it mHeight = tHeight instead and your program will work.
Update to respond to the comment on ellipse location
In the RoundSprite#DrawSprite() method you are calling g2.translate() twice. g2.translate() is a relative, not absolute position change, so you don't want to give the mouse coordinates the second time you call it.
replace this:
g2.translate(mX - (mWidth / 2), mY - (mHeight / 2));
with this:
g2.translate(-mWidth/2, -mHeight/2);
to center the ellipse around the mouseclick location.

how to move and scale image by dragging it's edges?

I have post this question before also but this time I have added only required and necessary code only although the code is somewhat lengthy.
I want to load image in Jlabel and then after change image when user clicks next button. And when user want to move or scale image he can just easily do it by selecting image edges but it's not working.
All problem are solved except the scaling and moving image.
my code :
public class CopyOfPictureEditor extends JFrame
{
private static final long serialVersionUID = 6676383931562999417L;
String[] validpicturetypes = {"png", "jpg", "jpeg", "gif"};
Stack<File> pictures ;
JLabel label = new JLabel();
BufferedImage a = null;
JPanel panel = new JPanel();
public CopyOfPictureEditor()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e)
{
e.printStackTrace();
}
JMenuBar menubar = new JMenuBar();
JMenu toolsmenu = new JMenu(" File ");
final File dir = new File("");
final JFileChooser file;
file = new JFileChooser();
file.setCurrentDirectory(dir);
file.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
file.showOpenDialog(panel);
String path = file.getSelectedFile().getAbsolutePath();
System.out.println(path);
pictures= getFilesInFolder(path.toString());
JButton NEXT = new JButton("");
NEXT.setToolTipText("Next Image");
Image imgn = null;
try
{
imgn = ImageIO.read(getClass().getResource("/images/next12.png"));
}catch (IOException e) {
e.printStackTrace();
}
NEXT.setIcon(new ImageIcon(imgn));
JPanel buttonPane = new JPanel();
buttonPane.add(Box.createRigidArea(new Dimension(250,0)));
buttonPane.add(Box.createRigidArea(new Dimension(250,0)));
NEXT.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
nextImage();
}
});
buttonPane.add(NEXT);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
setJMenuBar(menubar);
menubar.add(toolsmenu);
panel.add(label,BorderLayout.CENTER);
add(panel);
setTitle("Aero Picture Editor");
setVisible(true);
setPreferredSize(getPreferredSize());
setLocation(0,0);
label.addMouseListenet(new MouseHandler());
label.addMouseMotionListenet(new MouseHandler());
}
public Stack<File> getFilesInFolder(String startPath){
File startFolder = new File(startPath);
Stack<File> picturestack = new Stack<File>();
String extension;
int dotindex;
for (File file : startFolder.listFiles()) {
extension = "";
dotindex = file.getName().lastIndexOf('.');
if (dotindex > 0) {
extension = file.getName().substring(dotindex + 1);
for (String filetype : validpicturetypes){
if (extension.equals(filetype)) {
picturestack.add(file);
}
}
}
}
return picturestack;
}
public void nextImage() {
String p;
File f;
try{
f= pictures.pop().getAbsoluteFile();
a=ImageIO.read(f);
p = f.getPath();
System.out.println(p);
} catch (IOException e1) {
e1.printStackTrace();
}
ImageIcon image = new ImageIcon(a);
label.setIcon(image);
repaint();
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - a.getWidth()) / 2;
int y = (getHeight() - a.getHeight()) / 2;
AffineTransform at = new AffineTransform();
at.translate(x, y);
g2d.setTransform(at);
g2d.drawImage(a, 0, 0, this);
g2d.dispose();
}
public enum MouseAction {
Move(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)),
ResizeSouth(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)),
ResizeNorth(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)),
ResizeEast(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)),
ResizeWest(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)),
ResizeNorthEast(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)),
ResizeNorthWest(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)),
ResizeSouthEast(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)),
ResizeSouthWest(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
private Cursor cursor;
private MouseAction(Cursor cursor) {
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
}
public class MouseHandler extends MouseAdapter
{
private MouseAction action;
private Point clickPoint;
private boolean ignoreMoves;
protected void updateAction(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int width = getWidth();
int height = getHeight();
if (x < 10 && y < 10) {
action = MouseAction.ResizeNorthWest;
} else if (x > width - 10 && y < 10) {
action = MouseAction.ResizeNorthWest;
} else if (y < 10) {
action = MouseAction.ResizeNorth;
} else if (x < 10 && y > height - 10) {
action = MouseAction.ResizeSouthWest;
} else if (x > width - 10 && y > height - 10) {
action = MouseAction.ResizeSouthEast;
} else if (y > height - 10) {
action = MouseAction.ResizeSouth;
} else if (x < 10) {
action = MouseAction.ResizeWest;
} else if (x > width - 10) {
action = MouseAction.ResizeEast;
} else {
action = MouseAction.Move;
} setCursor(action.getCursor());
}
#Override
public void mouseMoved(MouseEvent e) {
if (!ignoreMoves)
{
updateAction(e);
}
}
#Override
public void mousePressed(MouseEvent e) {
updateAction(e);
ignoreMoves = true;
clickPoint = e.getPoint();
repaint();
System.out.println(e.getX());
System.out.println(e.getY());*/
}
#Override
public void mouseReleased(MouseEvent e) {
clickPoint = null;
ignoreMoves = false;
}
#Override
public void mouseDragged(MouseEvent e) {
switch (action) {
case Move: {
Point p = e.getPoint();
p.x -= clickPoint.x;
p=SwingUtilities.convertPoint(label, p, null);
setLocation(p);
}
break;
case ResizeWest: {
Point p = e.getPoint();
int xDelta = p.x - clickPoint.x;
int width = getWidth() - xDelta;
int x = getX() + xDelta;
setSize(width, getHeight());
setLocation(x, getY());
revalidate();
}
break;
case ResizeEast: {
Point p = e.getPoint();
int xDelta = p.x - clickPoint.x;
int width = getWidth() + xDelta;
setSize(width, getHeight());
revalidate();
clickPoint = p;
}
break;
case ResizeNorth: {
Point p = e.getPoint();
int yDelta = p.y - clickPoint.y;
int height = getHeight() - yDelta;
int y = getY() + yDelta;
setSize(getWidth(), height);
setLocation(getX(), y);
revalidate();
}
break;
case ResizeSouth: {
Point p = e.getPoint();
int yDelta = p.y - clickPoint.y;
int height = getHeight() + yDelta;
setSize(getWidth(), height);
revalidate();
clickPoint = p;
}
break;
}
}
#Override
public void mouseExited(MouseEvent e)
{
}
}
}
Found this one:
label.addMouseListener(new MouseHandler());
label.addMouseMotionListener(new MouseHandler());
Since you set your clickPoint in mousePressed and want to have it in mouseDragged, it should be the same object. You should actually get some nullpointers in mouseDragged?
Hard to see without complete code, but for one, you're calling setSize and setLocation on the Window itself in your MouseDragged method. If you want to get the object the user clicked on you need to get it from e.getSource(), like:
public void mouseDragged(MouseEvent e){
JLabel l = (JLabel)e.getSource();
switch(action){
case ResizeWest:
Point p = e.getPoint();
int xDelta = p.x - clickPoint.x;
int width = getWidth() - xDelta;
int x = getX() + xDelta;
l.setSize(width, getHeight()); // call setSize on JLabel l
l.setLocation(x, getY());
l.revalidate();
break;
}
Incidentally, why are you using a JLabel for this? I would use a Java object that draws itself onto the JFrame using the JFrame's graphics context.

JLabels, that store ImageIcons, are returned back to original location when the mouse is clicked in the panel

I've added this listener to a JLabel, and I am able to drag the image around perfectly, However, as soon as I click on the panel(in an area where a JLabel is not present) the label returns back to it's original location. I can't figure out why that would happen. Please help me out, I've spent hours working on this. Thanks!
public class CardLabelListener extends MouseAdapter {
private MouseEvent initiateEvent = null;
#Override
public void mouseReleased(MouseEvent me) {
System.err.println("mouse release");
int dx = me.getX() - initiateEvent.getX();
int dy = me.getY() - initiateEvent.getY();
if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
Rectangle oldBound = me.getComponent().getBounds();
int newX = oldBound.x + dx;
int newY = oldBound.y + dy;
me.getComponent().setBounds(newX, newY, oldBound.width, oldBound.height);
}
initiateEvent = null;
}
public void mousePressed(MouseEvent me) {
GreetingCard.setBackground.findComponentAt(me.getX(), me.getY());
System.err.println("mouse pressed");
initiateEvent = me;
me.consume();
}
public void mouseDragged(MouseEvent me) {
System.err.println(me.getSource());
if (initiateEvent == null) return;
me.consume();
JComponent jc = (JComponent) me.getSource();
TransferHandler handler = jc.getTransferHandler();
handler.exportAsDrag(jc, me, TransferHandler.MOVE);
initiateEvent = null;
}
}
Firstly, you're not dragging the icon, your dragging the component itself.
Secondly, you're fighting against the layout manager which contains the label component. When ever the panel is invalidated, the labels are returned to their original layout positions.
Trying using something like a JLayeredPane to put your labels in
UPDATED with example based on feedback
public class MoveMe {
public static void main(String[] args) {
new MoveMe();
}
public MoveMe() {
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();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MoveMePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MoveMePane extends JLayeredPane {
public MoveMePane() {
int width = 400;
int height = 400;
for (int index = 0; index < 10; index++) {
String text = "Label " + index;
JLabel label = new JLabel(text);
label.setSize(label.getPreferredSize());
int x = (int) Math.round(Math.random() * width);
int y = (int) Math.round(Math.random() * height);
if (x + label.getWidth() > width) {
x = width - label.getWidth();
}
if (y + label.getHeight() > width) {
y = width - label.getHeight();
}
label.setLocation(x, y);
add(label);
}
MoveMeMouseHandler handler = new MoveMeMouseHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public class MoveMeMouseHandler extends MouseAdapter {
private int xOffset;
private int yOffset;
private JLabel draggy;
private String oldText;
#Override
public void mouseReleased(MouseEvent me) {
if (draggy != null) {
draggy.setText(oldText);
draggy.setSize(draggy.getPreferredSize());
draggy = null;
}
}
public void mousePressed(MouseEvent me) {
JComponent comp = (JComponent) me.getComponent();
Component child = comp.findComponentAt(me.getPoint());
if (child instanceof JLabel) {
xOffset = me.getX() - child.getX();
yOffset = me.getY() - child.getY();
draggy = (JLabel) child;
oldText = draggy.getText();
draggy.setText("What a drag");
draggy.setSize(draggy.getPreferredSize());
}
}
public void mouseDragged(MouseEvent me) {
if (draggy != null) {
draggy.setLocation(me.getX() - xOffset, me.getY() - yOffset);
}
}
}
}
For this to work you would need use a null layout on the container where the JLabel is located, otherwise the position will reset to that where the current layout manager positions the label.
A better approach would be to use DragLayout
DragLayout was designed to replace a null layout. It will respect the location of a component. By default it will use the preferred size of the component to determines its size. Finally, it will automatically calculate the preferred size of the Container.

Categories

Resources