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
Related
My paint method doesnt seem to paint my 20x20 cells. I have a boolean array for the cells to control their state and that if true, call the cells paint method, a cell is painted however I have two problems;
Only one is painted at a time which is odd because i should have a 40x40 array of booleans meaning i have 40x40 cells
They dont actually paint exactly where I click. I do not know how this is the case as when I get the co-ordinates of my click I immediately place those co-ordinates as my x, and y values in my paint method.
Main
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
public class mainApplication extends JFrame implements Runnable, MouseListener {
private static final Dimension windowsize = new Dimension(80, 600);
private BufferStrategy strategy;
private Graphics offscreenGraphics;
private static boolean isGraphicsInitialised = false;
private static int rows = 40;
private static int columns = 40;
private static int height = windowsize.height;
private static int width = windowsize.width;
private static Cells cells = new Cells();
private int xArrayElement,yArrayElement, xPosition, yPosition;
private static boolean gameState[][] = new boolean[rows][columns];
public mainApplication() {
System.out.println(System.getProperty("user.dir"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width / 2 - windowsize.width / 2;
int y = screensize.height / 2 - windowsize.height / 2;
setBounds(x, y, screensize.width, screensize.height);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
offscreenGraphics = strategy.getDrawGraphics();
isGraphicsInitialised = true;
// MouseEvent mouseEvent = new MouseEvent();
addMouseListener(this);
// addMouseMotionListener(MouseEvent);
Thread t = new Thread(this);
t.start();
}
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 1){
xPosition = e.getX();
yPosition = e.getY();
cells.setPosition(xPosition,yPosition);
xArrayElement = (xPosition/20);
yArrayElement = (yPosition/20);
if(gameState[xArrayElement][yArrayElement]){
gameState[xArrayElement][yArrayElement] = false;
}
else if (!gameState[xArrayElement][yArrayElement]) {
gameState[xArrayElement][yArrayElement] = true;
}
else(gameState[xArrayElement][yArrayElement]) = true;
}
}
#Override
public void run() {
while (true) {
try { //threads entry point
Thread.sleep(20); //forces us to catch exception
}
catch (InterruptedException e) {
}
this.repaint();
}
}
public void paint(Graphics g) {
if (isGraphicsInitialised) {
g = strategy.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
if (gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.WHITE);
cells.paint(g);
System.out.println(xPosition);
}
else if (!gameState[xArrayElement][yArrayElement]) {
g.setColor(Color.BLACK);
g.fillRect(xPosition, yPosition, 20, 20);
}
strategy.show();
}
}
public static void main(String[]args){
mainApplication test = new mainApplication();
}
}
Cell Class
import java.awt.*;
public class Cells {
int x;
int y;
public Cells(){
}
public void setPosition(int xi, int xj){
x = xi;
y = xi;
}
public boolean cellState(boolean visible){
return visible;
}
public void paint(Graphics g){
g.drawRect(x, y, 20,20);
}
}
You are doing a number of things wrong. My first suggestion would be to forget about offscreen graphics and ensure you are doing what you want. You can always create an image latter. Here are some basic guidelines:
Don't extend JFrame. Use an instance.
Extend JPanel or create a class that extends JPanel and add to frame instance
Then override paintComponent(g) and use that graphics context to draw.
Here is an earlier answer that may help Can't add Graphics into JPanel in Java
More information may be found in the Java Tutorials on painting.
Updated. It took me a few minutes to find this.
public void setPosition(int xi, int xj){
x = xi;
y = xi; // <--- should be xj
}
Regarding (1) above. You must repaint every cell each time you enter paintComponent. This means you will need to iterate across the list and paint them in the correct spot. Right now you are only painting one upon each entry.
A couple more suggestions. Instead of messing with the thread and calling repaint every 20ms in a loop, why not just invoke repaint in the mouseClicked() method.
If you do eventually need to paint every 20ms. I suggest using a swing Timer as follows: (check JavaDoc to ensure I got the syntax correct!!)
Timer timer = new Timer(0, (ev)-> frame.repaint());
timer.setDelay(20);
timer.start();
And you can create your own mouseListener class and extending MouseAdapter. The purpose of these adapter classes is to keep the clutter down so you don't have to have empty methods to satisfy the interface requirements. Put the class inside your main class so it has access to the appropriate data structures. Then just add an instance of it to the mouse listener of the target Component.
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();
}
});
}
}
I have many planes(threads) that move in window, and I want switch the ImageIcon according to the direction of the plane.
For example: if a plane goes to the right, the imageIcon of the plane is right and then plane goes to the left, exchange the imageIcon for the plane is left.
How can I do that in method paintComponent?
Sorry for my bad english.
If you're talking about swapping the ImageIcon displayed by a JLabel, then you should not switch ImageIcons in paintComponent but rather should do this in the non-paintComponent region of code, perhaps in a Swing Timer. Even if you're not talking about a JLabel, the paintComponent method should not be used for changing the state of an object.
Your question however leaves too much unsaid to allow us to be able to answer it completely and well. Consider telling and showing more.
If you are looking for a logic thingy, then a small example is here, though you might have to modify it for your needs.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
public class FlyingAeroplane
{
private Animation animation;
private Timer timer;
private ActionListener timerAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
animation.setValues();
}
};
private void displayGUI()
{
JFrame frame = new JFrame("Aeroplane Flying");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
animation = new Animation();
frame.setContentPane(animation);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(100, timerAction);
timer.start();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new FlyingAeroplane().displayGUI();
}
});
}
}
class Animation extends JPanel
{
private final int HEIGHT = 150;
private final int WIDTH = 200;
private int x;
private int y;
private ImageIcon image;
private boolean flag;
private Random random;
public Animation()
{
x = 0;
y = 0;
image = new ImageIcon(getClass().getResource("/image/aeroplaneright.jpeg"));
flag = true;
random = new Random();
}
public void setValues()
{
x = getXOfImage();
y = random.nextInt(70);
repaint();
}
private int getXOfImage()
{
if (flag)
{
if ((x + image.getIconWidth()) == WIDTH)
{
flag = false;
x--;
return x;
}
x++;
image = new ImageIcon(getClass().getResource("/image/aeroplaneright.jpeg"));
}
else if (!flag)
{
if (x == 0)
{
flag = true;
x++;
return x;
}
x--;
image = new ImageIcon(getClass().getResource("/image/aeroplaneleft.jpeg"));
}
return x;
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(WIDTH, HEIGHT));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image.getImage(), x, y, this);
}
}
IMAGES USED :
On setting the direction you should set the image icon too, or have a getImageIcon(direction).
In the paintComponent no heavy logic should happen; it should be as fast as possible. You have no (total) control when and how often paintComponent is called.
I've been trying to get this rectangle to move that I've created using a for loop. All that's happening with this code is that there is an original rectangle and then a new one next to that rectangle. No animation happens, only those two rectangles show on the window. What are some methods to get this rectangle to animate?
import java.awt.*;
import javax.swing.*;
public class Gunman extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
public int x = 10;
public int y = 10;
public int width = 8;
public int height = 10;
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawRect (x, y, width, height);
g.fillRect (x, y, width, height);
for(int i = 0; i<=1024; i++){
g.setColor(Color.red);
g.drawRect(x++, y, width, height);
g.fillRect(x++, y, width, height);
}
}
}
Don't have program logic in a paint or paintComponent method, and by logic, I mean the for loop with "motion" as that just won't work. You want to
Almost never draw in a JComponent's paint method but rather in its paintComponent method.
Don't forget to call the super.paintComponent(g) method too, often as the first method call in the paintComponent(g) override.
Use a Swing Timer to step wise change the x and y values
call repaint() on the JComponent after the changes are made
For example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Gunman extends JComponent {
private static final long serialVersionUID = 1L;
private static final int PREF_W = 900;
private static final int PREF_H = 700;
private static final int TIMER_DELAY = 30;
public int rectX = 10;
public int rectY = 10;
public int width = 8;
public int height = 10;
public Gunman() {
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent actEvt) {
if (rectX < PREF_W && rectY < PREF_H) {
rectX++;
rectY++;
repaint();
} else {
((Timer)actEvt.getSource()).stop();
}
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(rectX, rectY, width, height);
g.fillRect(rectX, rectY, width, height);
}
public int getRectX() {
return rectX;
}
public void setRectX(int rectX) {
this.rectX = rectX;
}
public int getRectY() {
return rectY;
}
public void setRectY(int rectY) {
this.rectY = rectY;
}
private static void createAndShowGui() {
Gunman mainPanel = new Gunman();
JFrame frame = new JFrame("Gunman");
frame.setDefaultCloseOperation(JFrame.EXIT_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();
}
});
}
}
There are numerous ways to animate. Here is another example. Notice the location of repaint() inside a background thread. This paints directly on a JFrame. Use paintComponent() when painting on JPanels.
public static void main(String args[]) throws Exception {
new JFrame("Draw a red box") {
Point pointStart = new Point(50,50);
Point pointEnd = new Point(200,200);
public void paint(Graphics g) {
super.paint(g);
if (pointStart != null) {
g.setColor(Color.RED);
g.drawRect(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
}}{
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(300, 300);
setLocation(300, 300);
setVisible(true);
Thread t = new Thread(new Runnable() {
public void run() {
while (pointEnd.x > 0 && pointEnd.y > 0) {
pointEnd = new Point(--pointEnd.x, --pointEnd.y);
repaint();
try {
Thread.sleep(22);
} catch (InterruptedException e) {
e.printStackTrace();
}}
pointStart = null;
pointEnd = null;
}});
t.setDaemon(true);
t.start();
}};}
UPDATE: Ok previous answer was not so good from the old memory, here is the quickest, cheapest, most dirty way to get some animation quicksmart, you can copy and compile the code as is:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Test extends JFrame {
public Gunman g = new Gunman();
public static void main( String[] args ) {
Test t = new Test();
t.setSize( 800, 600 );
t.setVisible( true );
t.getContentPane().add( t.g );
while ( true ) {
t.g.x = t.g.x + 1;
t.g.y = t.g.y + 1;
t.repaint();
try {
Thread.sleep( 100 );
} catch ( InterruptedException e ) {
}
}
}
public void paintComponent( Graphics g ) {
g.clearRect( 0, 0, 800, 600 );
}
}
class Gunman extends JComponent {
private static final long serialVersionUID = 1L;
public int x = 10;
public int y = 10;
public int width = 8;
public int height = 10;
public void paintComponent( Graphics g ) {
g.setColor( Color.red );
g.fillRect( x, y, width, height );
}
}
There are ALOT of shortcuts in this, as Hovercraft of Eels has said, this is not an 'ideal' way to do it, but it has the basic structure. You have a canvas (I have used the JFrame, again not really recommended), and you add a component to it. You must override paintComponent (if you are using swing, which I do recommend you do), and this will draw your component.
You then need to alter your component's position in some way (recommend a proper method call on the object that does this), and ask the canvas to repaint itself.
I have included the wait so you can see what's happening, but if you are thinking of game programming, you should look into creating a game loop to manage this, I recommend Killer game programming in java, you can get a free ebook version with a quick google search.
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.