I am practicing to draw a ball in the Panel and show the ball's coordinate when the ball is dragged.
This is my first time to practice a drawing exercise(?)
This is my code.
import java.awt.*;
import java.awt.event.*;
public class MovingBall extends Frame {
Panel ballPanel = new Panel();
Label ballLabel = new Label();
Panel coordinatePanel = new Panel();
Label coordinateLabel = new Label();
int x0=0,y0 =0, x=20,y=30;
int nowX, nowY;
Label nowXcoordinateLabel = new Label("Now X :"+nowX);
Label nowYcoordinateLabel = new Label("Now Y :"+nowY);
MovingBall(){
setLayout(new GridLayout(1,1));
ballPanel.add(ballLabel); coordinatePanel.add(coordinateLabel);
add(ballPanel);
add(coordinatePanel);
ballPanel.setBackground(Color.white);
coordinatePanel.setBackground(Color.LIGHT_GRAY);
nowXcoordinateLabel.setBackground(Color.WHITE);
nowYcoordinateLabel.setBackground(Color.WHITE);
coordinatePanel.add(nowXcoordinateLabel);
coordinatePanel.add(nowYcoordinateLabel);
setVisible(true);
setSize(400,400);
MouseMotionListener ml = new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
Point p = new Point();
nowX = (int) p.getX();
nowY = (int) p.getY();
}
};
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
dispose();
}
}
);
}
public void paintComponent(Graphics2D gg){
// super.paintComponents(gg);
ballPanel.paintComponents(gg);
gg.setColor(Color.BLUE);
gg.fillOval(x0, y0, 10, 10);
}
public static void main(String[]arg){
MovingBall mb = new MovingBall();
}
}
I have two problems
I used fillOval and paintComponent to draw and display a ball but I don't see that on the screen. Why?
Any idea how to move the ball if I want to move that using mouseDragged? Do I need some thread?
Let's start with
Frame doesn't have a paintComponent method, so nothing is ever going to call it.
Even if it did, position 0x0 would paint the circle under the frame's borders, so you wouldn't see it
You should be getting the Point from the MouseEvent, not from the new Point object you've created
It's not the responsibility of the frame to manage the mouse dragged or painting, the frame is responsible for providing the initial container onto which everything else added
From that, you should move the functionality of the painting and mouse dragged management to it's own class. This provides you with two things, first, a surface onto which you can paint, and which will contained within the frame borders and the mouse events will automatically be converted to the panels context (0x0 will be the top left corner of the panel)
This raises the question about how to update the labels. Well, you could take a leaf from the AWT API and use a simple observer pattern to generate events when the coordinates are changed, for example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;
public class MovingBall extends Frame {
BallPane ballPanel = new BallPane();
Label ballLabel = new Label();
int x0 = 0, y0 = 0, x = 20, y = 30;
int nowX, nowY;
Label nowXcoordinateLabel = new Label("Now X :" + nowX);
Label nowYcoordinateLabel = new Label("Now Y :" + nowY);
MovingBall() {
setLayout(new BorderLayout());
ballPanel.add(ballLabel);
add(ballPanel);
ballPanel.setBackground(Color.white);
nowXcoordinateLabel.setBackground(Color.WHITE);
nowYcoordinateLabel.setBackground(Color.WHITE);
setVisible(true);
setSize(400, 400);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
dispose();
}
});
Panel coordinates = new Panel(new FlowLayout());
coordinates.add(nowXcoordinateLabel);
coordinates.add(nowYcoordinateLabel);
coordinates.setBackground(Color.LIGHT_GRAY);
add(coordinates, BorderLayout.SOUTH);
ballPanel.addCoordinateListene(new CoordinateListener() {
#Override
public void coordinatesChanged(CoordinateEvent evt) {
nowXcoordinateLabel.setText("Now X: " + evt.getCoordinate().getX());
nowYcoordinateLabel.setText("Now X: " + evt.getCoordinate().getY());
revalidate();
repaint();
}
});
}
public static void main(String[] arg) {
MovingBall mb = new MovingBall();
}
public class CoordinateEvent extends EventObject {
private final Point p;
public CoordinateEvent(Object source, Point p) {
super(source);
this.p = p;
}
public Point getCoordinate() {
return p;
}
}
public interface CoordinateListener {
public void coordinatesChanged(CoordinateEvent evt);
}
public class BallPane extends Panel {
int x0 = 0, y0 = 0, x = 20, y = 30;
private List<CoordinateListener> coordinateListeners;
public BallPane() {
MouseMotionListener ml = new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
x0 = (int) e.getX();
y0 = (int) e.getY();
fireCoordinateChange(new Point(e.getPoint()));
repaint();
}
};
addMouseMotionListener(ml);
coordinateListeners = new ArrayList<>(5);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLUE);
g.fillOval(x0, y0, 10, 10);
}
public void addCoordinateListene(CoordinateListener listener) {
coordinateListeners.add(listener);
}
public void removeCoordinateListene(CoordinateListener listener) {
coordinateListeners.remove(listener);
}
protected void fireCoordinateChange(Point p) {
CoordinateEvent evt = new CoordinateEvent(this, p);
for (CoordinateListener listener : coordinateListeners) {
listener.coordinatesChanged(evt);
}
}
}
}
Make your class extending Panel and make it ready to drawing with overriding paint method and add the MouseMotionListener to listining your panel.Get X and Y coordinates for using in paint method, at last add your drawing panel to Frame.
Simple code : UPDATED
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class TestClass extends Panel {
/**
*
*/
private static final long serialVersionUID = 1L;
Panel ballPanel = new Panel();
Label ballLabel = new Label();
Panel coordinatePanel = new Panel();
Label coordinateLabel = new Label();
int nowX, nowY;
Label nowXcoordinateLabel = new Label("Now X :");
Label nowYcoordinateLabel = new Label("Now Y :");
TestClass() {
coordinatePanel.add(coordinateLabel);
nowXcoordinateLabel.setBackground(Color.WHITE);
nowYcoordinateLabel.setBackground(Color.WHITE);
nowXcoordinateLabel.setPreferredSize(new Dimension(100, 25));
nowYcoordinateLabel.setPreferredSize(new Dimension(100, 25));
coordinatePanel.setPreferredSize(new Dimension(400, 30));
coordinatePanel.setBackground(Color.LIGHT_GRAY);
coordinatePanel.add(nowXcoordinateLabel);
coordinatePanel.add(nowYcoordinateLabel);
MouseAdapter ml = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
nowXcoordinateLabel.setText("Now X :" + e.getX());
nowYcoordinateLabel.setText("Now Y :" + e.getY());
nowX = e.getX();
nowY = e.getY();
repaint();
super.mouseMoved(e);
}
};
setLayout(new GridLayout(1, 1));
setBackground(Color.WHITE);
addMouseMotionListener(ml);
setVisible(true);
setSize(400, 400);
}
#Override
public void paint(Graphics g) {
Graphics2D gg = (Graphics2D) g;
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gg.setColor(Color.BLUE);
gg.fillOval(nowX, nowY, 20, 20);
}
public static void main(String[] arg) {
TestClass mb = new TestClass();
Frame frame = new Frame("Test drawing");
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
frame.dispose();
super.windowClosing(e);
}
});
frame.setLayout(new GridLayout(1, 1));
frame.add(mb);
frame.add(mb.coordinatePanel);
frame.setSize(800, 600);
frame.setVisible(true);
}
}
To get the position of the mouse instead of:
nowX = (int) p.getX();
Write this:
nowX = (int) e.getX();
You also need to redraw the oval every time the user triggers a Mouse Drag event
Related
I want to have a text field to input an integer, then select 1) Grow or 2) Shrink, and then click the button so that the circle gets redrawn on the screen based on the selected options.
I don't know why it isn't repaining. (Don't worry about the layout, just want to get it to work first)
My Frame:
public class Main {
public static void main(String[] args) {
var frame = new JFrame();
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
var circleComp = new circleComponent();
var panel1 = new JPanel();
var multiplierLabel = new JLabel("Grow Multiplier");
var multiplierField = new JTextField(20);
var radio1 = new JRadioButton("Grow Circle");
var radio2 = new JRadioButton("Shrink Circle");
var bg = new ButtonGroup();
bg.add(radio1);
bg.add(radio2);
JButton button = new JButton("Rivizato");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(radio1.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())*rrComp.getWidth(), Integer.parseInt(multiplierField.getText())*rrComp.getHeight());
}
else if(radio2.isSelected()){
rrComp.repaint(0,0,Integer.parseInt(multiplierField.getText())/rrComp.getWidth(), Integer.parseInt(multiplierField.getText())/rrComp.getHeight());
}
}
}
);
panel1.add(multiplierLabel);
panel1.add(multiplierField);
panel1.add(button);
panel1.add(radio1);
panel1.add(radio2);
frame.add(panel1);
frame.add(circleComp);
}
}
My CircleComponent class:
public class CircleComponent extends JComponent {
public void paintComponent(Graphics g){
super.paintComponent(g);
var g2 = (Graphics2D) g;
var circle = new Ellipse2D.Double(0,0,100,100);
g2.draw(circle);
}
}
var circle = new Ellipse2D.Double(0,0,100,100); means that your circle will never change size.
You should also be careful with repaint(x, y, width, height) as it could leave regions of your component "dirty". Better to just use repaint.
As a conceptual example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private CirclePane circlePane;
public MainPane() {
setLayout(new BorderLayout());
JPanel actionsPane = new JPanel(new GridBagLayout());
JButton growButton = new JButton("Grow");
growButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.grow();
}
});
JButton shrinkButton = new JButton("Shrink");
shrinkButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
circlePane.shrink();
}
});
actionsPane.add(growButton);
actionsPane.add(shrinkButton);
circlePane = new CirclePane();
add(circlePane);
add(actionsPane, BorderLayout.SOUTH);
}
}
public class CirclePane extends JPanel {
private Ellipse2D circle;
public CirclePane() {
circle = new Ellipse2D.Double(0, 0, 100, 100);
}
public void grow() {
double width = circle.getWidth() + 10;
double height = circle.getHeight() + 10;
circle.setFrame(0, 0, width, height);
repaint();
}
public void shrink() {
double width = Math.max(0, circle.getWidth() - 10);
double height = Math.max(0, circle.getHeight() - 10);
circle.setFrame(0, 0, width, height);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double x = (getWidth() - circle.getWidth()) / 2d;
double y = (getHeight() - circle.getHeight()) / 2d;
g2d.translate(x, y);
g2d.draw(circle);
g2d.dispose();
}
}
}
nb: I know I've not used JTextField to specify the size of the circle, that's on purpose. You will need to adapt your requirements to work in a similar way - can you see where you might pass parameters to the CirclePane?
I'm trying to animate a rectangle based on a coordinate determined by for-loop, inside a button. Here is my JComponent Class:
public class Rect extends JComponent {
public int x;
public int y;
public int w;
public int h;
public Rect (int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
repaint();
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g);
g2.setColor(Color.green);
g2.drawRect(x+15, y+15, w, h);
}
}
and here is my button and button inside JFrame class:
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
}
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
validate();
repaint();
}
}
});
}
But when I run the code and click the button, nothing happens. What's wrong?
EDIT: I run the frame inside my main class like this:
public class OrImage {
public static void main(String[] args) throws Exception
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
});
}
}
I changed the code of class MainFrame such that when you press the animate button, something happens, but I don't know if that is what you want to happen.
I did not change class Rect and I added main() method to MainFrame just to keep everything in one class.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int k = 0; k < 500; k+=50) {
R = new Rect(k, k, 50, 50);
lm.add(R);
}
lm.revalidate();
lm.repaint();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
The main change is in method actionPerformed(). You need to add R to the JPanel. You need to call revalidate() on the JPanel because you have changed the number of components that it contains. And after calling revalidate() you should call repaint() (again, on the JPanel) to make it redraw itself.
This is how it looks before pressing animate.
And this is how it looks after pressing animate
EDIT
As requested – with animation.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
import javax.swing.Timer;
public class MainFrame extends JFrame {
Rect R = new Rect(15, 15, 50, 50);
JPanel lm = new JPanel();
LayoutManager lay = new OverlayLayout(lm);
JButton animate = new JButton("animate");
private int x;
private int y;
private Timer timer;
public MainFrame () {
setSize(1200, 700);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lm.setLayout(lay);
lm.add(R);
timer = new Timer(500, event -> {
if (x < 500) {
lm.remove(R);
x += 50;
y += 50;
R = new Rect(x, y, 50, 50);
lm.add(R);
lm.revalidate();
lm.repaint();
}
else {
timer.stop();
}
});
timer.setInitialDelay(0);
animate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
add(lm, BorderLayout.CENTER);
add(animate, BorderLayout.PAGE_END);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainFrame());
}
}
I'm making a basic bubble shooter game to practice my coding and I am trying to make the pointer so that it will aim where I want it to shoot, I have the line movement to follow my mouse but it extends one it gets further away from the center. I want to turn almost like there is a pivot point.
public static void pointer(Graphics g) {
g = panel.getGraphics();
g.drawLine(325, 530, x, 450);
g.fillRect(325, 530, x, 450);
}
public static void UI() {
frame = new JFrame("Bubble shooter");
panel = new JPanel();
panel.setBackground(Color.white);
panel.setLayout(null);
frame.setSize(650,550);
frame.setResizable(false);
frame.setVisible(true);
//frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
mouseMoving = true;
x = e.getX();
System.out.println("X: " + e.getX());
System.out.println("Y: " + e.getY());
}
});
I am trying to make the line follow my mouse without growing or shrinking onto a pivot point. Instead, the line doesn't pass the set y coordinate but extends to follow the mouse.
You have some errors in your code:
You need to add panel to frame.
You need to call your drawing method.
You need to set color while drawing.
You should calculate first point by current size of your panel instead of constant point.
Here is a working code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MouseTest {
int x = -1;
int y = -1;
public void pointer(Graphics g) {
if (x < 0) {
return;
}
g.setColor(Color.BLUE);
Rectangle bounds = g.getClipBounds();
int startX = (int) (bounds.getWidth() / 2);
int startY = (int) bounds.getHeight();
g.drawLine(startX, startY, x, y);
}
public void UI() {
JFrame frame = new JFrame("Bubble shooter");
JPanel panel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
pointer(g);
}
};
panel.setBackground(Color.white);
panel.setLayout(null);
frame.setSize(650,550);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(panel);
frame.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
panel.repaint();
}
});
}
public static void main(String[] args) {
MouseTest mouseTest = new MouseTest();
mouseTest.UI();
}
}
I want to be able to click on a JTextArea and drag it around my JPanel. I'm not sure the method on doing so. What I'm trying to do is change the x,y coordinates of the JTextArea as it is dragged, I'm not dragging a JTextArea above or below another. Just around on the screen, similar to moving Text Boxes in a program like Microsoft PowerPoint
The only method I can think of is using a MouseListener but I'm wondering if there is an easier way to implement it other than detecting a hover/press/drag on the JTextArea. Any ideas on how I can start?
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class UMLEditor {
public static void main(String[] args) {
JFrame frame = new UMLWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class UMLWindow extends JFrame {
Canvas canvas = new Canvas();
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
}
public void addMenus() {
getContentPane().add(canvas);
JMenuBar menubar = new JMenuBar();
JMenuItem newTextBox = new JMenuItem("New Text Box");
newTextBox.setMnemonic(KeyEvent.VK_E);
newTextBox.setToolTipText("Exit application");
newTextBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
canvas.addTextBox();
}
});
menubar.add(newTextBox);
setJMenuBar(menubar);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
class Canvas extends JPanel {
JTextArea commentTextArea = new JTextArea(10, 10);
public Canvas() {
this.setOpaque(true);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void addTextBox() {
commentTextArea.setLineWrap(true);
commentTextArea.setWrapStyleWord(true);
commentTextArea.setVisible(true);
commentTextArea.setLocation(0, 0);
this.add(commentTextArea);
commentTextArea.setBounds(0, 0, 100, 100);
revalidate();
repaint();
}
class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
}
You don't really want to try and "drag" on JTextComponents, they already have functionality enabled which allows the user to click and drag to highlight text, you really don't want to be competing within this.
Instead, you want to define a "hot zone" area around the component which would allow you "highlight" the component in some and allow the user to drag the component via it.
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class DragMe {
public static void main(String[] args) {
new DragMe();
}
public DragMe() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JTextArea ta = new JTextArea(10, 20);
ta.setText("Bananas in pajamas");
JScrollPane sp = new JScrollPane(ta);
DragProxyPane proxy = new DragProxyPane(sp);
proxy.setSize(proxy.getPreferredSize());
proxy.setLocation(100 - proxy.getWidth() / 2, 100 - proxy.getHeight()/ 2);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
frame.add(proxy);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class DragProxyPane extends JPanel {
public static final int BUFFER_ZONE = 10;
private boolean mouseInHouse;
private JComponent component;
private List<HotZone> hotZones;
public DragProxyPane(JComponent comp) {
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
mouseInHouse = true;
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
mouseInHouse = false;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
Cursor cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
for (HotZone hz : hotZones) {
if (hz.getBounds(getSize()).contains(e.getPoint())) {
cursor = hz.getCursor();
break;
}
}
setCursor(cursor);
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
setOpaque(false);
setLayout(new BorderLayout());
add(comp);
setBorder(new EmptyBorder(BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE, BUFFER_ZONE));
hotZones = new ArrayList<>(8);
// Top left, middle, right
hotZones.add(new HotZone(0f, 0f, Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 0f, Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0f, Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR)));
// Left, right
hotZones.add(new HotZone(0f, 0.5f, Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 0.5f, Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)));
// Bottom left, middle, right
hotZones.add(new HotZone(0f, 1f, Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)));
hotZones.add(new HotZone(0.5f, 1f, Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)));
hotZones.add(new HotZone(1f, 1f, Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (mouseInHouse) {
g2d.setColor(Color.BLACK);
for (HotZone hotZone : hotZones) {
g2d.draw(hotZone.getBounds(getSize()));
}
}
g2d.dispose();
}
public class HotZone {
private float x, y;
private Cursor cursor;
public HotZone(float x, float y, Cursor cursor) {
this.x = x;
this.y = y;
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
public Rectangle getBounds(Dimension size) {
return getBounds(size.width - 1, size.height - 1);
}
public Rectangle getBounds(int width, int height) {
int halfBuffer = BUFFER_ZONE / 2;
float xPos = (width * x) - halfBuffer;
float yPos = (height * y) - halfBuffer;
xPos = Math.min(Math.max(0, xPos), width - BUFFER_ZONE);
yPos = Math.min(Math.max(0, yPos), height - BUFFER_ZONE);
return new Rectangle(Math.round(xPos), Math.round(yPos), BUFFER_ZONE, BUFFER_ZONE);
}
}
}
}
This sets up a simple proxy component which acts as the hot zone manager, detecting the mouse coming into or out of it and updating the cursor based on its location within in it, but it does not disrupt the normal operations of the component.
Now, this example doesn't drag, sorry, you have plenty of other examples which should be able to get you over the line, but, you could simply add a MouseListener/MouseMoitionListener to the proxy to detect when the user drags, but you will need to add some more functionality to it to determine what that drag actually means (resize or move) ;)
So I am trying to create a simple paint program and I have been having a problem. The program has a window, on the left of the window is a bar with pen size control, and the rest of the window is the drawing pane. However, whenever I draw on the pane, the side bar is basically copied onto the pane, but it can be drawn over.
Here is my CHPaint class (main):
package paint;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CHPaint{
JFrame frame;
JLabel penSizeLabel;
PaintPanel panel;
JButton upButton;
JButton downButton;
JPanel left;
JPanel main;
int penSize = 1;
public static void main(String[] args){
CHPaint gui = new CHPaint();
System.out.println("gui built");
gui.go();
}
public void go() {
frame = new JFrame("Caleb's Paint");
panel = new PaintPanel();
upButton = new JButton("Up");
downButton = new JButton("Down");
penSizeLabel = new JLabel("Size: " + penSize);
left = new JPanel();
main = new JPanel();
panel.addMouseListener(new Painting());
panel.addMouseMotionListener(new Painting());
upButton.addActionListener(new UpButton());
downButton.addActionListener(new DownButton());
left.setLayout(new BoxLayout(left, BoxLayout.Y_AXIS));
main.setLayout(new BorderLayout());
left.add(upButton);
left.add(penSizeLabel);
left.add(downButton);
left.setBackground(Color.gray);
penSizeLabel.setBackground(Color.gray);
frame.getContentPane().add(BorderLayout.CENTER, main);
main.add(BorderLayout.WEST, left);
main.add(BorderLayout.CENTER, panel);
frame.setSize(600, 600);
frame.setVisible(true);
}
class UpButton implements ActionListener{
public void actionPerformed(ActionEvent e){
panel.changePenSize(1);
penSize++;
penSizeLabel.setText("Size: " + penSize);
}
}
class DownButton implements ActionListener{
public void actionPerformed(ActionEvent e){
panel.changePenSize(-1);
if (penSize > 1){
penSize--;
}
penSizeLabel.setText("Size: " + penSize);
}
}
class Painting implements MouseListener, MouseMotionListener{
public void mousePressed(MouseEvent e) {
panel.draw(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e) {
panel.draw(e.getX(), e.getY());
}
public void mouseReleased(MouseEvent e) {
panel.mouseUp();
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
}
}
Here is the class for the drawing panel:
package paint;
import java.awt.*;
import javax.swing.*;
public class PaintPanel extends JPanel {
int drawX = -10;
int drawY = -10;
int oldX = -10;
int oldY = -10;
int penSize = 1;
public void draw(int x, int y){
oldX = drawX;
oldY = drawY;
drawX = x;
drawY = y;
this.repaint();
}
public void mouseUp(){
oldX = -10;
oldY = -10;
drawX= -10;
drawY= -10;
}
public void changePenSize(int p){
if (penSize > 0){
penSize = penSize+p;
}
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if (oldX != -10 && (oldY) != -10){ // If you didn't just start or lift the pen
g2.setStroke(new BasicStroke(penSize, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.setColor(Color.red);
g.drawLine(oldX, oldY, drawX, drawY);
} else {
g.setColor(Color.red);
g.fillOval(drawX-(penSize/2), drawY-(penSize/2), penSize, penSize);
}
}
}
EDIT:
Sorry, I didn't know the rules here for posting, please forgive me D:. Also, I didn't know what part of the code messed it up so I didn't know what I should cut out. Thanks for your help.
This won't solve your problem but the following is not used anymore:
main.add(BorderLayout.CENTER, panel); // read the API for more info
You should be using:
main.add(panel, BorderLayout.CENTER);
You need to call super.paintComponent() in your paintComponent() method. Among other things, this will clear the JPanel for you.