I've had a look around for this problem but couldn't find an answer...
I currently have a JPanel in which I'm painting a load of unicode characters (music notes) using the Graphics2D g2.drawString() method.
I have an ArrayList of KeyPress objects, each of which contains one or more g2.drawString() calls.
So each KeyPress object is a music note and is painted on the JPanel.
How would I go about adding the functionality to enable the user to select and drag the objects?
Why not put your Strings in JLabels and simply drag them...
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class DragLabelEg {
private static final String[] LABEL_STRINGS = { "Do", "Re", "Me", "Fa",
"So", "La", "Ti" };
private static final int HEIGHT = 400;
private static final int WIDTH = 600;
private static final Dimension MAIN_PANEL_SIZE = new Dimension(WIDTH, HEIGHT);
private static final int LBL_WIDTH = 60;
private static final int LBL_HEIGHT = 40;
private static final Dimension LABEL_SIZE = new Dimension(LBL_WIDTH,
LBL_HEIGHT);
private JPanel mainPanel = new JPanel();
private Random random = new Random();
public DragLabelEg() {
mainPanel.setPreferredSize(MAIN_PANEL_SIZE);
mainPanel.setLayout(null);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
for (int i = 0; i < LABEL_STRINGS.length; i++) {
JLabel label = new JLabel(LABEL_STRINGS[i], SwingConstants.CENTER);
label.setSize(LABEL_SIZE);
label.setOpaque(true);
label.setLocation(random.nextInt(WIDTH - LBL_WIDTH),
random.nextInt(HEIGHT - LBL_HEIGHT));
label.setBackground(new Color(150 + random.nextInt(105), 150 + random
.nextInt(105), 150 + random.nextInt(105)));
label.addMouseListener(myMouseAdapter);
label.addMouseMotionListener(myMouseAdapter);
mainPanel.add(label);
}
}
public JComponent getMainPanel() {
return mainPanel;
}
private class MyMouseAdapter extends MouseAdapter {
private Point initLabelLocation = null;
private Point initMouseLocationOnScreen = null;
#Override
public void mousePressed(MouseEvent e) {
JLabel label = (JLabel) e.getSource();
// get label's initial location relative to its container
initLabelLocation = label.getLocation();
// get Mouse's initial location relative to the screen
initMouseLocationOnScreen = e.getLocationOnScreen();
}
#Override
public void mouseReleased(MouseEvent e) {
initLabelLocation = null;
initMouseLocationOnScreen = null;
}
#Override
public void mouseDragged(MouseEvent e) {
// if not dragging a JLabel
if (initLabelLocation == null || initMouseLocationOnScreen == null) {
return;
}
JLabel label = (JLabel) e.getSource();
// get mouse's new location relative to the screen
Point mouseLocation = e.getLocationOnScreen();
// and see how this differs from the initial location.
int deltaX = mouseLocation.x - initMouseLocationOnScreen.x;
int deltaY = mouseLocation.y - initMouseLocationOnScreen.y;
// change label's position by the same difference, the "delta" vector
int labelX = initLabelLocation.x + deltaX;
int labelY = initLabelLocation.y + deltaY;
label.setLocation(labelX, labelY);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGui();
}
});
}
private static void createGui() {
JFrame frame = new JFrame("App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DragLabelEg().getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
See the tutorial on supporting user interaction. It comes down to determining which (if any) objects were underneath the mouse when it was clicked and held. On a drag event, the selected object is moved and the canvas is repainted.
You can obtain the bounds of the string by using FontMetrics:
String text = "Hello world!";
Rectangle2D bounds = g2.getFontMetrics().getStringBounds(text, g2);
I assume the rectangle top-left will be (0, 0), so you need to add (x, y) to it (where x, y are the parameters you passed to drawString).
This example shows one way to select multiple objects, using keyboard or mouse, and drag
them as a group. It manipulates arbitrary nodes rather than glyphs, but you may find it instructive.
Related
I have a class , called boardGUI , it has a list of 64 labels (like a chess board). Every label coresponds to a specific tile on the board.
List<JLabel> labelList = new ArrayList<>();
In another class, I'm trying to set some of this labels opaque, with setOpaque(true) method , whenever I click on one of the labels (inside mouseClicked method).
JLabel l1 = boardGUI.labelList.get(1);
l1.setOpaque(true);
The problem is that although l1 refers the right label in labelList (I checked with the debugger) , it doesn`t make any visual change (on the GUI ).
But, if I'm trying to set opacity of the labels in the boardGUI class , it's working.
for (int i=0;i<64;i++)
labelList.get(i).setOpaque(true);
Where can the problem be?
here is the class where I'm trying to apply the changes :
public class Controller {
private Board board = new Board();
private BoardGUI boardGUI = new BoardGUI();
public Controller () {
boardGUI.setVisible(true);
boardGUI.addLabelListener(new LabelListener());
}
class LabelListener implements MouseListener{
#Override
public void mouseClicked(MouseEvent arg0) {
JLabel l1 = boardGUI.labelList.get(1);
l1.setOpaque(true);
}
BoardGUI class (there's more code , but it's not relevant) :
public class BoardGUI extends JFrame{
List<JLabel> labelList = new ArrayList<>();
public BoardGUI() {
createView();
}
public void createView() {
createLabels(mainPanel);
}
public void createLabels(JPanel mainPanel) {
int startX = 100;
int startY = 87;
int x = 100;
int y = 87;
int j = 0;
for (int i=0;i<64;i++) {
JLabel label = new JLabel();
label.setBounds(x , y , 62, 62);
labelList.add(label);
mainPanel.add(label);
if ( (i == 7*(j+1) +j )) {
x = startX;
y = startY + 62 *( i / 7);
j=j+1;
}
else {
x = x+62;
}
}
}
You need to set both background color and opaqueness; here's an example to show how these play together:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.GREEN);
JLabel label1 = new JLabel("label1");
label1.setBackground(Color.RED);
label1.setOpaque(false);
frame.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
label1.setOpaque(!label1.isOpaque());
label1.setBackground(label1.getBackground() == Color.RED ? Color.BLUE : Color.RED);
}
public void mouseReleased(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
});
frame.add(label1);
frame.pack();
frame.setVisible(true);
}
The label is initially transparanet, then changes to BLUE and opaque and back with every MouseClick. So basically, you would need to set the background color together with opaque (the RED color is just to demonstrate that it is never shown as the label is never both opaque and RED).
This program is asking the user to input the data of a circle. The following are included: the position of x, position of y, and the width and height of the circle.
So when I test this program, I enter the location and its size; and then I hit the draw button. The circle did not appear.
Here is my code!
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Draw extends JFrame
{
private JButton draw;
private JTextField posOfX;
private JTextField posOfY;
private JTextField Jwidth;
private JTextField Jheight;
private ActionListener listener;
private JLabel JLx;
private JPanel drawingPanel;
private JLabel JLy;
private JLabel JLwidth;
private JLabel JLheight;
private JComponent component;
public int x =100 ;
public int y =100 ;
public int width = 100;
public int height = 100 ;
private JPanel panel;
public Draw()
{
listener = new actionPerform();
component = new drawCircle();
panel = new JPanel();
draw = new JButton ("Draw");
draw.addActionListener(listener);
posOfX = new JTextField( 15);
posOfY = new JTextField(15);
Jwidth = new JTextField(15);
Jheight = new JTextField(15);
JLx = new JLabel("X");
JLy = new JLabel("Y");
JLwidth = new JLabel("Width");
JLheight = new JLabel("Height");
panel.add(JLx);
panel.add(posOfX);
panel.add(JLy);
panel.add(posOfY);
panel.add(JLwidth);
panel.add(Jwidth);
panel.add(JLheight);
panel.add(Jheight);
panel.add(draw);
panel.add(component);
add(drawingPanel,BorderLayout.SOUTH);
add(panel,BorderLayout.NORTH);
}
class drawCircle extends JComponent
{
public void paintComponent(Graphics g)
{
g.drawOval(x,y,width,height);
}
}
class actionPerform implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
try{
if(e.getSource() == draw)
{
width = width + Integer.parseInt(Jwidth.getText());
height = height + Integer.parseInt(Jheight.getText());
x = Integer.parseInt(posOfX.getText()) + width;
y = Integer.parseInt(posOfY.getText())+ height;
Jwidth.setText("");
Jheight.setText("");
posOfX.setText("");
posOfY.setText("");
}
}
catch (Exception except)
{
Jwidth.setText("");
Jheight.setText("");
posOfX.setText("");
posOfY.setText("");
JOptionPane.showMessageDialog(null,"You should enter numbers only","Error",JOptionPane.ERROR_MESSAGE);
}
}
}
}
import java.awt.*;
import javax.swing.*;
public class DrawViewer
{
public static void main(String []args)
{
Draw d = new Draw();
d.setVisible(true);
d.setTitle("Draw circle");
d.setSize(1000,1000);
d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
When creating a new JComponent object without a layout manager, the width of its preferred size is initially 0 and its height 0, so it's not at all visible. To fix this, your drawCircle class should override the getPreferredSize method so that the component you add it to knows what its size should be. For example:
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
It is strongly encouraged that you use a layout manager of some sort, however, so that you won't end up with various problems such as the size of components being wrong.
edit 2: I decided that it would be easier to understand if I just put the entire code up, so that you can test it.
edit: I realize that what I said was unclear, so I will explain this as best as I can. Basically, I am drawing rectangles on a Graphics page using the fillRect method. The problem is that when I change the size of one, they all change, as they are all being redrawn everytime a new one is drawn. To correct this, I added an array that stores all of the sizes which are input via the scrollwheel in another part of the problem. Anyways, I know that the problem is isolated to the loop that supposedly draws them all a certain size, so I added a loop that in theory should give me a temporary variable each time to use that redraws all of the rectangle's sizes starting at 0 each time the main loop is run. The problem is that this does not in fact redraw the rectangles to their individual sizes, and instead draws them to the current size. I have updated the code part as well.
I am having trouble with a project in Java. What it is supposed to do is change the size of each individual rectangle object by storing it in an array, and then recreating the rectangles based off the length from the array. I (at least I think) do this by creating a variable that should be equal to the SIZE that is changed in another part of the program, and then set that equal to the particular element in the array at i. Anyhow, when I do this, I change all of the lengths to whatever the current length is when I draw a rectangle. I know that the problem is by me using i in the size part, but what would I use? Thanks in advance for any help!
Here is the code:
public class Dots
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Array Rectangles");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DotsPanel dotsPanel = new DotsPanel();
frame.getContentPane().add(dotsPanel);
//buttons
JButton btnNewButton = new JButton("RED");
btnNewButton.setHorizontalAlignment(SwingConstants.LEFT);
btnNewButton.setVerticalAlignment(SwingConstants.BOTTOM);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnNewButton.setForeground(Color.RED);
dotsPanel.add(btnNewButton);
JButton btnNewButton_1 = new JButton("GREEN");
btnNewButton_1.setForeground(Color.GREEN);
btnNewButton_1.setVerticalAlignment(SwingConstants.BOTTOM);
dotsPanel.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("BLUE");
btnNewButton_2.setForeground(Color.BLUE);
dotsPanel.add(btnNewButton_2);
JButton btnNewButton_3 = new JButton("BLACK");
btnNewButton_3.setForeground(new Color(0, 0, 0));
dotsPanel.add(btnNewButton_3);
frame.pack();
frame.setVisible(true);
}
}
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class DotsPanel extends JPanel
{
// radius of each dot
private int SIZE = 25;
private int SIZEAccess;
private static final Random generator = new Random();
//used to count amount of dots
private ArrayList<Point> pointList;
int[] sizes = new int [10000];
//Sets up this std. sized panel to listen for mouse events.
public DotsPanel()
{
pointList = new ArrayList<Point>();
addMouseListener (new DotsListener());
addMouseMotionListener(new DotsListener());
addMouseWheelListener(new DotsListener());
setBackground(Color.white);
setPreferredSize(new Dimension(1024, 768));
}
//used to generate a random color
public static Color randomColor() {
return new Color(generator.nextInt(256), generator.nextInt(256), generator.nextInt(256));
}
// Draws all of the dots stored in the list.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
//draws a centered dot of random color
int i = 0;
for (Point spot : pointList)
{
sizes[i] = SIZE;
//SIZEAccess = SIZE;
//sizes[i] = SIZEAccess;
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
for (int temp = 0; temp <= i; temp++)
page.fillRect(spot.x-sizes[temp], spot.y-sizes[temp], sizes[temp]*2, sizes[temp]*2);
//page.fillRect(spot.x-SIZE, spot.y-SIZE, SIZE*2, SIZE*2);
//page.setColor(randomColor());
//page.setColor(c)
i++;
}
//displays the amount of rectangles drawn at the top left of screen
page.drawString("Count: " + pointList.size(), 5, 15);
page.drawString("To change the size of the squares, use mouse scroll wheel.", 350, 15);
page.drawString("Size: " + SIZE, 950, 15);
}
// Represents the listener for mouse events.
private class DotsListener implements MouseListener, MouseMotionListener, MouseWheelListener
{
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is pressed.
public void mousePressed(MouseEvent event)
{
pointList.add(event.getPoint());
repaint();
}
// Provide empty definitions for unused event methods.
public void mouseClicked(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseExited(MouseEvent event) {}
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is dragged.
public void mouseDragged(MouseEvent event) {
pointList.add(event.getPoint());
repaint();
}
public void mouseMoved(MouseEvent event) {
}
public void mouseWheelMoved(MouseWheelEvent event)
{
int notches = 0;
notches = event.getWheelRotation();
//int
if (notches > 0)
{
SIZE = SIZE + notches;
notches = 0;
}
else if (notches < 0)
{
int tempSIZE = SIZE;
tempSIZE = tempSIZE + notches;
//prevents the program from having dots that increase due to multiplying negatives by negatives
//by making anything less than 1 equal 1
if(tempSIZE < 1)
tempSIZE = 1;
SIZE = tempSIZE;
notches = 0;
}
}
}
//SIZE = SIZE + notches;
}
You appear to have ArrayList's interacting with arrays in a confusing mix that makes it hard for us to follow your logic. This suggests that your logic may be too complex for your own good and that your code might benefit from simplification. Why not instead create a List<Rectangle> such as an ArrayList<Rectangle>, and then simply loop through this list in your paintComponent method, and draw each Rectangle using the Graphics2D object's draw(...) or fill(...) method:
private List<Rectangle> rectangleList = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Rectangle rectangle : rectangleList) {
g2.fill(rectangle);
}
}
For example:
import java.awt.BasicStroke;
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.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color BACKGROUND = Color.black;
private static final Color FILL_COLOR = Color.pink;
private static final Color DRAW_COLOR = Color.red;
private static final Stroke STROKE = new BasicStroke(3);
private List<Rectangle> rectangleList = new ArrayList<>();
private Point pressPoint = null;
private Point dragPoint = null;
public Foo() {
setBackground(BACKGROUND);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#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);
Graphics2D g2 = (Graphics2D) g;
Stroke oldStroke = g2.getStroke();
g2.setStroke(STROKE);
for (Rectangle rectangle : rectangleList) {
g2.setColor(FILL_COLOR);
g2.fill(rectangle);
g2.setColor(DRAW_COLOR);
g2.draw(rectangle);
}
g2.setStroke(oldStroke);
if (pressPoint != null && dragPoint != null) {
g2.setColor(FILL_COLOR.darker());
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
g2.drawRect(x, y, width, height);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pressPoint = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
dragPoint = e.getPoint();
int x = Math.min(pressPoint.x, dragPoint.x);
int y = Math.min(pressPoint.y, dragPoint.y);
int width = Math.abs(pressPoint.x - dragPoint.x);
int height = Math.abs(pressPoint.y - dragPoint.y);
Rectangle rect = new Rectangle(x, y, width, height);
rectangleList.add(rect);
pressPoint = null;
dragPoint = null;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Sorry guys, I deleted my APPLES and CATS example :) Here's the updated version of my question!
I'm losing my sanity here. I need someone who can enlighten me. I've tried a couple of times explaining my problem here. Hopefully, this time, my question will be easier to understand.
Basically I have this frame, and there's an image displayed. There is a JList on the right, and there is another panel for JLabels at the bottom. Here's a screencap of my frame.
When I click on the image, a JOptionPane pops out, like so. And I enter my input. My JList is an ArrayList, so everything I input is added to the JList and the JPanel at the bottom.
Now, when I hover on the the part where I clicked, you noticed that the square disappeared). It only appears when I click the image, and when I hover the label at the bottom. My labels, as of now are LOLZ NOSE and INPUT HERE.
What I want to do is when I hover on the label, for example INPUT HERE, it shows the square again, featuring the part where I clicked. My problem now is when I click on NOSE, which is supposed to be showing a square on the nose part and a the name NOSE with black bg, IT IS NOT SHOWING. Also, only the last label's square is shown, disregarding the other labels' position clicked.
How do I get a label to remember the position of the click I make? People said I should use ArrayLists or HashCodes however I have no idea how to implement them. Thank you to anyone who can help.
Edit: I've already done the rectangle, btw. It's showing only for the last label inputted. Here are some of the code snippets requested!
How I'm setting the text on JLabel and updating the JList:
public void updateLabel(){
StringBuilder text = new StringBuilder(); //creates empty builder, capacity 16
for(Object s: tagModel.toArray()) //returns an array containing the elements of the tagModel
text.append(" " + s);
repaint();
hoverLabel.setText(text.toString()); //returns a String
hoverLabel.addMouseMotionListener(this);
hoverPanel.add(hoverLabel);
}
My mouseListener upon click:
#Override
public void mouseClicked(MouseEvent event) {
// TODO Auto-generated method stub
x = event.getX();
y = event.getY();
isRectPresent = true;
repaint();
input = JOptionPane.showInputDialog("Enter tag name:");
if((input != null) && !input.isEmpty()){
tagModel.addElement(input);
}
}
My mouseMotionListener upon hovering:
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
xpos = e.getX(); //gets where the mouse moved
ypos = e.getY();
//checks if the mouse is inside the bounds of the rectangle
if (xpos > x && xpos < x + 100 && ypos > y && ypos < y + 100)
isRectPresent = false;
if(e.getSource() == hoverLabel){
isRectPresent = true;
repaint();
}
repaint();
}
How I'm painting:
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0, 0, null);
if(image != null && isRectPresent){
Stroke stroke = g2.getStroke();
g2.setStroke(new BasicStroke(4));
g2.setColor(Color.WHITE);
g2.drawRect(x-50, y-50, 100, 100);
g2.setStroke(stroke);
}else{
if(xpos > x && xpos < x + 100 && ypos > y && ypos < y + 100){
g.setColor(Color.BLACK);
g.fillRect(x-50, y-50, 100, 25);
g.setColor(Color.WHITE);
g.setFont(new Font("Tahoma", Font.BOLD, 12));
g.drawString(input, x-30, y-30);
}
}
}
If you want me to add some more snippets, just tell me! :)
You should create a HashMap, say something like:
Map linkSet = new HashMap();
And whenever you click on the drawing and create a label, add the JLabel and the point on the image to the set using the put method with the JLabel as the key and the Point as the value. Then in the JLabel's MouseMotionListener, use your label as a key and obtain the corresponding point from the set using the map's get(...) method.
edit:
Corrected as per alicedimarco's comment. Again, thanks!
edit 2
I think you want again to use a Map. If you have a Map, you can have it retrieve the Point of interest from the JLabel's or the JList's String, and then pass this Point to the class that's drawing the image and let it use the Point to draw a rectangle. For instance you could give the image drawing class a Point field called displayPoint, and a method called setDisplayPoint(Point p). It can be as simple as this:
public void setDisplayPoint(Point p) {
this.displayPoint = p;
repaint();
}
and assuming that the object of interest is centered at that point, use the displayPoint in the paintComponent method:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// draw image
if (img != null) {
g.drawImage(img, X_SHIFT, Y_SHIFT, null);
}
// if displayPoint not null, draw the surrounding rectangle
if (displayPoint != null) {
g.setColor(RECT_COLOR);
int x = displayPoint.x - RECT_WIDTH / 2;
int y = displayPoint.y - RECT_WIDTH / 2;
int width = RECT_WIDTH;
int height = RECT_WIDTH;
g.drawRect(x, y, width, height);
}
}
edit 3:
To get mouse clicks, it's quite easy, simply add a MouseListener to the component that holds the image:
// !! added
imgRect.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
imgMousePressed(e);
}
});
And in your code that is called from this mouse listener, use a JOptionPane to get the user's choice of tag name, and add the resulting String to both the listDataModel so that it is seen in the JList and also in the stringPointMap together with the Point obtained from the MouseEvent so that you can map the String to the Point and be able to retrieve it:
// !! added
private void imgMousePressed(MouseEvent e) {
String result = JOptionPane.showInputDialog(this,
"Please enter name for this point on image:");
if (result != null) {
stringPointMap.put(result, e.getPoint());
listDataModel.addElement(result);
}
}
That's it.
Then putting it all together:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ImageRectMain extends JPanel {
private ImageRect imgRect;
private DefaultListModel listDataModel = new DefaultListModel();
private JList list = new JList(listDataModel);
private Map<String, Point> stringPointMap = new HashMap<String, Point>();
public ImageRectMain() {
String nose = "Nose";
String ear = "Ear";
String rightEye = "Right Eye";
String leftEye = "Left Eye";
listDataModel.addElement(ear);
listDataModel.addElement(nose);
listDataModel.addElement(rightEye);
listDataModel.addElement(leftEye);
stringPointMap.put(nose, new Point(480, 500));
stringPointMap.put(ear, new Point(270, 230));
stringPointMap.put(rightEye, new Point(380, 390));
stringPointMap.put(leftEye, new Point(662, 440));
MouseAdapter listMouseAdapter = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
listMouseMoved(e);
}
#Override
public void mouseExited(MouseEvent e) {
listMouseExited(e);
}
};
list.addMouseMotionListener(listMouseAdapter);
list.addMouseListener(listMouseAdapter);
try {
imgRect = new ImageRect();
// !! added
imgRect.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
imgMousePressed(e);
}
});
JPanel eastPanel = new JPanel();
eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.PAGE_AXIS));
eastPanel.add(new JLabel("You have tagged the following:"));
eastPanel.add(new JScrollPane(list));
eastPanel.add(Box.createVerticalGlue());
eastPanel.add(Box.createVerticalGlue());
eastPanel.add(Box.createVerticalGlue());
eastPanel.add(Box.createVerticalGlue());
setLayout(new BorderLayout());
add(imgRect, BorderLayout.CENTER);
add(eastPanel, BorderLayout.EAST);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// !! added
private void imgMousePressed(MouseEvent e) {
String result = JOptionPane.showInputDialog(this,
"Please enter name for this point on image:");
if (result != null) {
stringPointMap.put(result, e.getPoint());
listDataModel.addElement(result);
}
}
private void listMouseExited(MouseEvent e) {
imgRect.setDisplayPoint(null);
}
private void listMouseMoved(MouseEvent e) {
int index = list.locationToIndex(e.getPoint());
Object value = listDataModel.get(index);
if (value != null) {
Point point = stringPointMap.get(value.toString());
if (point != null) {
imgRect.setDisplayPoint(point);
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ImageRectMain");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ImageRectMain());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class ImageRect extends JPanel {
public static final String IMAGE_PATH = "http://i.stack.imgur.com/7oNzg.jpg";
private static final int DEFAULT_W = 687;
private static final int DEFAULT_H = 636;
private static final int X_SHIFT = -6;
private static final int Y_SHIFT = -26;
private static final Color RECT_COLOR = Color.pink;
private static final int RECT_WIDTH = 40;
private BufferedImage img;
private Point displayPoint = null;
public ImageRect() throws MalformedURLException, IOException {
img = ImageIO.read(new URL(IMAGE_PATH));
}
public void setDisplayPoint(Point p) {
this.displayPoint = p;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, X_SHIFT, Y_SHIFT, null);
}
if (displayPoint != null) {
g.setColor(RECT_COLOR);
int x = displayPoint.x - RECT_WIDTH / 2;
int y = displayPoint.y - RECT_WIDTH / 2;
int width = RECT_WIDTH;
int height = RECT_WIDTH;
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_W, DEFAULT_H);
}
}
One nice feature of a JList is that you can story any object in it. You're not limited to strings. When objects are stored in JLists, swing will call the object's toString() method, and display it in the list.
Knowing this, you can now write your own class that stores the name of your selection label and the coordinates of the box. This object's toString() method will return the name of the label, which will make the right thing appear in the JList.
Then, in the selection event handler for the JList, you can get your custom object out, and retrieve the box coordinates stored in it, and draw them on the screen. No need to fuss with other containers (although knowing how to use them is a good thing to).
Ok, Create a class like this...
public class MyLabel {
private int x;
private int y;
private String text;
public MyLabel (String text, int x, int y) {
this.text = text;
// assign x and y too...
}
#Override
public String toString() {
return label;
}
public int getX() {
return x;
}
// similar function to getY()
}
The class above overrides toString(), so when you put it in a JList, it will use the call to toString() to determine what to display, and since this toString implementation returns the label name you'll see that in the list.
And add those into your JList instead of Strings. Then at some point in your code you'll do something like this...
// this is pseudocode, method names may not be correct...
MyLabel ml = (MyLabel)jList.getSelectedItem();
int x = ml.getX();
int y = ml.getY();
// draw the box...
Hope that helps.
I want to allow users to be able to "draw" with their mouse (click and drag) to create and size a JTextArea. As well, I would like to have the text areas as resizeable.
Something like this:
comes to mind, but as a JTextArea instead of just a square.
Is there something in Java that would allow me to easily do this? I first thought to allow the user to draw a rectangle and just grab the co-ordinates and size to create the JTextArea. I am unsure on how to do the resizing though.
Edit: "Component Resizer / Reszing" was the term I was looking for and I'm adding it here in case someone else is looking for something similar!
You can found a solution here
I have already try it and the result is very well. In the tutorial there is a reference to another implementation here.
The resizing the JTextArea can be done easily enough via calling setBounds(...) on it -- or better on the JScrollPane that holds it, but you will need to use a null or similar (JLayeredPane) layout on the container that holds the JTextArea and will likely need to repaint the container after resizing the JScrollPane. You will also have to revalidate the scrollpane's viewport so it will re-layout the textarea that it holds.
e.g.,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ResizeableTextArea extends JPanel {
private static final int PREF_WIDTH = 700;
private static final int PREF_HEIGHT = 500;
private static final int ROWS = 60;
private static final int COLS = 80;
private static final Color RECT_COLOR = new Color(180, 180, 255);
private JTextArea textArea = new JTextArea(ROWS, COLS);
private JScrollPane scrollPane = new JScrollPane(textArea);
private int x, y, width, height;
private boolean drawRect = false;
public ResizeableTextArea() {
setLayout(null);
add(scrollPane);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawRect) {
g.setColor(RECT_COLOR);
g.drawRect(x, y, width, height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
private class MyMouseAdapter extends MouseAdapter {
private int innerX, innerY;
#Override
public void mousePressed(MouseEvent e) {
x = e.getX();
y = e.getY();
innerX = x;
innerY = y;
width = 0;
height = 0;
drawRect = true;
}
#Override
public void mouseDragged(MouseEvent e) {
calcBounds(e);
drawRect = true;
ResizeableTextArea.this.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
calcBounds(e);
drawRect = false;
scrollPane.setBounds(x, y, width, height);
scrollPane.getViewport().revalidate();
ResizeableTextArea.this.repaint();
}
private void calcBounds(MouseEvent e) {
width = Math.abs(innerX - e.getX());
height = Math.abs(innerY - e.getY());
x = Math.min(innerX, e.getX());
y = Math.min(innerY, e.getY());
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ResizeableTextArea");
frame.getContentPane().add(new ResizeableTextArea());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
You should be able to use the Component Resizer.
that not really good idea, sure is possible to put Image or ImageIcon as BackGround, better would be use for that JLabel with Icon, then you can painting selection easily