How do I use mouse event dragging to draw line? - java

Okay so I added the recommended changes, however it (draggedMouse) still doesn't seem to be be connecting with the canvas even though I thought I am doing it right. I suppose it is not attached to the canvas, however I do not know how to go about doing this. I apologize in advance for my incompetence! I also included my Line class
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.ArrayList;
public class WholePanel extends JPanel
{
private Color currentColor;
private CanvasPanel canvas;
private JPanel leftPanel;
private JButton undo,erase;
private ArrayList<Line> lineList;
private Point ptStart,ptEnd, ptDrag;
private JRadioButton black,red,blue,green,orange;
private ArrayList<Line> drag;
public WholePanel()
{
currentColor = Color.black;
lineList = new ArrayList();
drag = new ArrayList();
undo = new JButton ("Undo"); // undo button
erase = new JButton("Erase"); // Erase button
black = new JRadioButton("Black"); black.setSelected(true); // setting black to the default line color
red = new JRadioButton("Red");
blue = new JRadioButton("Blue");
green = new JRadioButton("Green");
orange = new JRadioButton("Orange");
ButtonGroup group = new ButtonGroup(); // added buttons to group so only one can be selected at a time
group.add(black);
group.add(red);
group.add(blue);
group.add(green);
group.add(orange);
leftPanel = new JPanel(); // creates new JPanel that I can use to set the grid layout in and add the radio buttons
leftPanel.setLayout(new GridLayout(7,1));
leftPanel.add(black);
leftPanel.add(red);
leftPanel.add(blue);
leftPanel.add(green);
leftPanel.add(orange);
leftPanel.add(undo); // adds the undo button to the left panel above the erase button
leftPanel.add(erase); // adds the erase button to the left panel at the bottom
canvas = new CanvasPanel(); // creates the canvas panel
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, canvas); // splits the applet layout into two panels
setLayout(new BorderLayout());
add(sp);
undo.addActionListener( new ButtonListener()); // adding listener action for undo and erase buttons
erase.addActionListener( new ButtonListener());
black.addActionListener( new ComboListener()); // adding listener actions for radio buttons
red.addActionListener( new ComboListener());
blue.addActionListener( new ComboListener());
green.addActionListener( new ComboListener());
orange.addActionListener( new ComboListener());
//canvas.addMouseListener(new PointListener());
//canvas.addMouseMotionListener(new PointListener());
PointListener pl = new PointListener(canvas.getGraphics());
canvas.addMouseListener(pl);
canvas.addMouseMotionListener(pl);
}
//CanvasPanel is the panel where shapes will be drawn
private class CanvasPanel extends JPanel
{
//this method draws all shapes specified by a user
public void paintComponent(Graphics page)
{
super.paintComponent(page);
setBackground(Color.WHITE);
for(int i = 0; i< lineList.size(); i++){
(lineList.get(i)).draw(page);
}
}
} //end of CanvasPanel class
//ButtonListener defined actions to take in case
//"Undo", or "Erase" is chosen.
private class ButtonListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
JButton source = (JButton)event.getSource();
String name = source.getText();
if (name.equals("Undo"))
{
if(lineList.size() > 0)
{
lineList.remove(lineList.size()-1);
}
}
else if (name.equals("Erase"))
{
lineList.clear();
}
repaint();
}
} // end of ButtonListener
// listener class to set the color chosen by a user using
// the color radio buttons
private class ComboListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
JRadioButton src = (JRadioButton)event.getSource();
String name = src.getText();
if(name.equals("Black"))
{
currentColor = Color.BLACK;
}
else if (name.equals("Red"))
{
currentColor = Color.RED;
}
else if (name.equals("Blue"))
{
currentColor = Color.BLUE;
}
else if (name.equals("Green"))
{
currentColor = Color.GREEN;
}
else if (name.equals("Orange"))
{
currentColor = Color.ORANGE;
}
}
}
// listener class that listens to the mouse
public class PointListener implements MouseListener, MouseMotionListener {
Graphics g;
public PointListener(Graphics g){
this.g = g;
}
//{
//in case that a user presses using a mouse,
//record the point where it was pressed.
public void mousePressed (MouseEvent event)
{
ptStart = event.getPoint();
}
//mouseReleased method takes the point where a mouse is released,
//using the point and the pressed point to create a line,
//add it to the ArrayList "lineList", and call paintComponent method.
public void mouseReleased (MouseEvent event)
{
ptEnd = event.getPoint();
Line line = new Line(ptStart.x,ptStart.y,ptEnd.x,ptEnd.y,currentColor);
lineList.add(line);
repaint();
}
public void mouseClicked (MouseEvent event) {}
public void mouseEntered (MouseEvent event) {}
public void mouseExited (MouseEvent event) {}
//mouseDragged method takes the point where a mouse is dragged
//and call paintComponent method
public void mouseDragged(MouseEvent event)
{
ptDrag = event.getPoint();
Line dragLine = new Line(ptStart.x,ptStart.y,ptDrag.x,ptDrag.y,currentColor);
dragLine.draw(g);
repaint();
}
public void mouseMoved(MouseEvent event) {}
} // end of PointListener
} // end of Whole Panel Class
And this is my Line class
import java.awt.*;
public class Line {
private int x1,x2,y1,y2;
private Color color;
public Line(int px1, int py1, int px2, int py2, Color pColor) // constructor that sets the color of the line as well as the coordinates
{
x1 = px1;
y1 = py1;
x2 = px2;
y2 = py2;
color = pColor;
}
public void draw(Graphics page)
{
page.setColor(color);// insert user color
page.drawLine(x1, y1, x2, y2);
}
}

You could add a Graphics variable and a constructor for PointListener such as
public class PointListener implements MouseListener, MouseMotionListener {
Graphics g;
//declare point variables
Point ptStart, ptEnd, ptDrag;
public PointListener(Graphics g){
this.g = g;
}
}
Edit: by declaring your Points this way, you make them (ptStart in particular) visible to mouseReleased and mouseDragged
This would enable you to draw your line in mouseDragged more easily because you can use
g.drawLine(ptStart.x, ptStart.y, ptDrag.x, ptDrag.y, currentColor);
Then when you add point listener, you just need to change the code to
//added PointListener object because you previously
//created new object for each statement
//meaning separate objects are listening for Mouse and MouseMotion
PointListener pl = new PointListener(canvas.getGraphics());
//this should work but one way or another
//you need to pass the Graphics object
canvas.addMouseListener(pl);
canvas.addMouseMotionListener(pl);

Related

Get mouse coordinates for moving a JLabel

I am working on a project, develop a game called
Don't get mad bro.
I have a JPanel with shapes (circles) draw on it and JLabel components that contains images.I need that whenever I click "Throw dice" (which in background return a number between 1 and 6) I should wait for current player to click on one of his pawns, and that pawn should move after n positions, where n is equal with number that dice returned.
My question is, should I create a new thread in which I wait for mouseClick event? And how to get coordinates of mouseClick?
Here is my class that inherits panel and draw circles and add labels.
public class ImagePanel extends JPanel{
private static final long serialVersionUID = 1L;
ImageMatrix imageMatrix;
BufferedImage[] images;
public static JLabel[][] labels;
DrawGameBoard board = new DrawGameBoard();
List<GameFigure> gameCircles;
List<FinishFigure> finishCircles;
int initialHeight = 528;
int initialWidth = 596;
ThreadForPawnsClick labelsClick;
public ImagePanel(){
labels = new JLabel[4][4];
images = new BufferedImage[4];
setBackground(new Color(255,255,153));
gameCircles = new ArrayList<GameFigure>();
finishCircles = new ArrayList<FinishFigure>();
imageMatrix = new ImageMatrix(initialWidth,initialHeight);
try {
images[0] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\red.png"));
images[1] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\green.png"));
images[2] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\blue.png"));
images[3] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\yellow.png"));
} catch (IOException e) {
e.printStackTrace();
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
labels[i][j] = new JLabel(new ImageIcon(images[i]));
}
setLayout(null);
board.DrawHomeBoard(imageMatrix, labels);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
int width = this.getWidth();
int height = this.getHeight();
imageMatrix.update(width, height);
setLayout(null);
gameCircles = board.DrawMainBoard(g, imageMatrix);
//labels = board.DrawHomeBoard(g, imageMatrix, labels);
//board.DrawHomeBoard(imageMatrix, labels);
finishCircles = board.DrawFinishBoard(g, imageMatrix);
/*for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
add(labels[i][j]);
*/
}
}
Also, why my imageMatrix doesn't extend on whole screen, even if I call update matrix in paintComponent()?
My question is, should I create a new thread in which I wait for mouseClick event?
No, absolutely not. You need instead to change the state of the GUI somehow to wait-for-mouse-click mode, and then alter the behavior of the GUI's response to mouse clicks depending on its state. Usually state is represented by instance fields of the class. So when you need to wait, you change one of these state fields, and on mouse click, you check the state of the field and vary what happens depending on that. For instance in a turn based game of chess, one state field could be private boolean blackTurn, and then base what mouse does based on its state.
And how to get coordinates of mouseClick?
In the MouseListener the MouseEvent parameter gives you the x and y position of the mouse relative to the listened to component and to the screen. If your MouseListener is attached to the JLabels, then you can get a reference to the clicked JLabel via the MouseEvent's getSource() method, and then can get the location of the JLabel relative to its container JPanel (if needed) by calling getLocation() on it.
Side note: in a Swing GUI where you're moving around sprites, it's usually better not to put the sprites into JLabels but rather to simply draw them directly in the paintComponent method of a drawing JPanel.
As an example of what I mean, here is a program that draws 4 colored circles, circles that are draggable, but only draggable when the corresponding JRadioButton has been selected with the JRadioButton setting the "state" of the GUI. Here the state is represented by an enum called ColorState that holds 4 colors and corresponding text. Here is this enum:
import java.awt.Color;
public enum ColorState {
RED("Red", Color.RED),
GREEN("Green", Color.GREEN),
BLUE("Blue", Color.BLUE),
ORANGE("Orange", Color.ORANGE);
private String text;
private Color color;
private ColorState(String text, Color color) {
this.text = text;
this.color = color;
}
public String getText() {
return text;
}
public Color getColor() {
return color;
}
}
Then we create a drawing JPanel, one that holds four Ellipse2D Shape objects in a Map,
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
Within a for loop, we create the JRadioButtons, give them ActionListeners that set the object's state, and populate the Map with Ellipse2D Shape objects
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
We draw the ellipses within paintComponent:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
Finally in a MouseAdapter (both MouseListener and MouseMotionListener), we listen for mouse presses and register success if the left mouse is clicked and if it is clicked within the appropriate Shape:
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
Note that the mouse dragging code is thanks to MadProgrammer's answer here. Please up-vote this answer.
The entire class looks like so:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class StateDependentMouseListener extends JPanel {
private static final int W = 800;
private static final int H = 650;
private static final double CIRCLE_WIDTH = 60.0;
private ButtonGroup buttonGroup = new ButtonGroup();
private ColorState colorState = null;
private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);
public StateDependentMouseListener() {
setPreferredSize(new Dimension(W, H));
for (final ColorState state : ColorState.values()) {
// create the JRadioButton
JRadioButton radioButton = new JRadioButton(state.getText());
add(radioButton); // add to GUI
buttonGroup.add(radioButton); // add to ButtonGroup
// give it an ActionListener that changes the object's state
radioButton.addActionListener(e -> {
colorState = state;
});
// create a randomly placed Ellipse2D and place into Map:
double x = Math.random() * (W - CIRCLE_WIDTH);
double y = Math.random() * (H - CIRCLE_WIDTH);
Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
colorStateMap.put(state, ellipse);
}
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// make for smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// iterate through the enum, extracting the ellipse and drawing it
for (ColorState state : ColorState.values()) {
Shape shape = colorStateMap.get(state);
if (shape != null) {
g2.setColor(state.getColor());
g2.fill(shape); // draw the ellipse
}
}
}
private class MyMouse extends MouseAdapter {
private Shape selectedShape = null;
private Point2D offset = null;
#Override
public void mousePressed(MouseEvent e) {
// check that correct button pressed
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
// has our colorState been set yet? If not, exit
if (colorState == null) {
return;
}
// is an appropriate Shape held by the Map? If so, get it
Shape shape = colorStateMap.get(colorState);
if (shape == null) {
return;
}
// does this shape contain the point where the mouse was pressed?
if (!shape.contains(e.getPoint())) {
return;
}
// Get the selected shape, get the mouse point location relative to this shape
selectedShape = shape;
double x = e.getX() - shape.getBounds2D().getX();
double y = e.getY() - shape.getBounds2D().getY();
offset = new Point2D.Double(x, y);
}
#Override
public void mouseDragged(MouseEvent e) {
// drag shape to new location
if (selectedShape != null) {
double x = e.getX() - offset.getX();
double y = e.getY() - offset.getY();
Rectangle2D bounds = selectedShape.getBounds2D();
bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));
((Ellipse2D) selectedShape).setFrame(bounds);
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
}
private static void createAndShowGui() {
StateDependentMouseListener mainPanel = new StateDependentMouseListener();
JFrame frame = new JFrame("StateDependentMouseListener");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

How To Make a Key Listener Work To Draw With Graphics

Everything about the code works except when I try to use the keys to move the circle. I put in a System.out.println("Working") to see if the listener was working when any key was pressed but it's not working at all. I did the same with the mouse listener and it worked fine. I'm very new to programming and I'm not really sure what I'm doing so any help would be great.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; // to use listener interfaces
import java.awt.geom.Ellipse2D;
public class WholePanel extends JPanel
{
private Color foregroundColor, backgroundColor;
private int currentDiameter, x1, y1;
private CanvasPanel canvas;
private JPanel buttonPanel;
private JRadioButton filledRadio, unfilledRadio;
private JRadioButton red, green, blue;
private JRadioButton cyan, yellow, pink;
private JLabel fill, foreColor, backColor;
private ButtonGroup circleColor, canvasColor, circleFill;
public boolean filled = false;
public WholePanel()
{
backgroundColor = Color.CYAN;
foregroundColor = Color.RED;
currentDiameter = 100;
x1 = 200; y1 = 100;
//INITIATING VARIABLES
unfilledRadio = new JRadioButton("Unfilled", true);
filledRadio = new JRadioButton("Filled");
red = new JRadioButton("Red", true);
green = new JRadioButton("Green");
blue = new JRadioButton("Blue");
cyan = new JRadioButton("Cyan", true);
yellow = new JRadioButton("Yellow");
pink = new JRadioButton("Pink");
fill = new JLabel("Circle Filling");
foreColor = new JLabel("Foreground Color");
backColor = new JLabel("Background Color");
//ORGANIZING THE BUTTONS AND LABELS ON THE BUTTON PANEL
buttonPanel = new JPanel(new GridLayout(3,4));
buttonPanel.add(foreColor);
buttonPanel.add(red);
buttonPanel.add(green);
buttonPanel.add(blue);
buttonPanel.add(backColor);
buttonPanel.add(cyan);
buttonPanel.add(yellow);
buttonPanel.add(pink);
buttonPanel.add(fill);
buttonPanel.add(unfilledRadio);
buttonPanel.add(filledRadio);
//BUTTON GROUPS ALLOW FOR ONE RADIO BUTTON SELECTION AT A TIME
circleColor = new ButtonGroup();
circleColor.add(red);
circleColor.add(green);
circleColor.add(blue);
canvasColor = new ButtonGroup();
canvasColor.add(cyan);
canvasColor.add(yellow);
canvasColor.add(pink);
circleFill = new ButtonGroup();
circleFill.add(unfilledRadio);
circleFill.add(filledRadio);
//MAKES LISTENER FOR ALL RADIO BUTTONS
FillListener listener1 = new FillListener();
unfilledRadio.addActionListener(listener1);
filledRadio.addActionListener(listener1);
ColorListener listener2 = new ColorListener();
red.addActionListener(listener2);
green.addActionListener(listener2);
blue.addActionListener(listener2);
cyan.addActionListener(listener2);
yellow.addActionListener(listener2);
pink.addActionListener(listener2);
canvas = new CanvasPanel();
JSplitPane sPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, buttonPanel, canvas);
setLayout(new BorderLayout());
add(sPane, BorderLayout.CENTER);
}
//Its description should be completed
private class ColorListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
//CHANGES COLOR BASED ON WHICH BUTTON IS SELECTED
if(event.getSource() == cyan)
{
backgroundColor = Color.CYAN;
}
else if(event.getSource() == yellow)
{
backgroundColor = Color.YELLOW;
}
else if(event.getSource() == pink)
{
backgroundColor = Color.PINK;
}
if(event.getSource() == red)
{
foregroundColor = Color.RED;
}
else if(event.getSource() == green)
{
foregroundColor = Color.GREEN;
}
else if(event.getSource() == blue)
{
foregroundColor = Color.BLUE;
}
//SETS THE COLORS
setBackground(backgroundColor);
setForeground(foregroundColor);
}
} // end of ColorListener
//Its description should be completed
private class FillListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
//CHECKS IF USER WANTS CIRCLE FILLED OR UNFILLED
if(event.getSource() == unfilledRadio)
{
filled = false;
}
if(event.getSource() == filledRadio)
{
filled = true;
}
}
}
//CanvasPanel is the panel where a circle is drawn
private class CanvasPanel extends JPanel
{
//Constructor to initialize the canvas panel
public CanvasPanel( )
{
// make this canvas panel listen to keys
addKeyListener(new DirectionListener());
// make this canvas panel listen to mouse
addMouseListener(new PointListener());
setBackground(backgroundColor);
setForeground(foregroundColor);
//This method needs to be called for this panel to listen to keys
//When panel listens to other things, and go back to listen
//to keys, this method needs to be called again.
requestFocus();
}
//this method draws all characters pressed by a user so far
public void paintComponent(Graphics page)
{
super.paintComponent(page);
//SETS THE COLORS BASED ON USERS CHOICE
setBackground(backgroundColor);
setForeground(foregroundColor);
//DRAWS THE CIRCLE
Graphics2D page2d = (Graphics2D)page;
//DRAWS IT FILLED OR UNFILLED BASED ON USER CHOICE
if(filled == true)
{
page.setColor(foregroundColor);
Ellipse2D.Double circle = new Ellipse2D.Double(x1,y1,currentDiameter,currentDiameter);
page2d.fill(circle);
canvas.repaint();
}
else if(filled == false)
{
page.setColor(foregroundColor);
Ellipse2D.Double circle = new Ellipse2D.Double(x1,y1,currentDiameter,currentDiameter);
page2d.draw(circle);
canvas.repaint();
}
}
/** This method is overridden to enable keyboard focus */
public boolean isFocusable()
{
return true;
}
// listener class to listen to keyboard keys
private class DirectionListener implements KeyListener
{
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
// in case that a key is pressed, the following will be executed.
public void keyPressed(KeyEvent e)
{
//FOCUSES THE LISTENER ON THE KEYBOARD
canvas.requestFocus();
//CHANGES THE SIZE/POSITION OF CIRCLE IF KEYS ARE PRESSED
if(e.getKeyChar() == KeyEvent.VK_UP)
{
y1 = y1+5;
canvas.repaint();
}
else if(e.getKeyChar() == KeyEvent.VK_DOWN)
{
y1 = y1-5;
canvas.repaint();
}
else if(e.getKeyChar() == KeyEvent.VK_RIGHT)
{
x1 = x1+5;
canvas.repaint();
}
else if(e.getKeyChar() == KeyEvent.VK_LEFT)
{
x1 = x1-5;
canvas.repaint();
}
else if(e.getKeyChar() == 's')
{
if(currentDiameter >= 16)
currentDiameter = currentDiameter - 6;
canvas.repaint();
}
else if(e.getKeyChar() == 'b')
{
currentDiameter = currentDiameter + 6;
canvas.repaint();
}
}
} // end of DirectionListener
// listener class that listens to the mouse
// This class is already completed. No adjustment is needed.
public class PointListener implements MouseListener
{
//in case that a user presses using a mouse,
//it gains the focus of the keyboard keys
public void mousePressed (MouseEvent event)
{
canvas.requestFocus();
}
public void mouseClicked (MouseEvent event) {}
public void mouseReleased (MouseEvent event) {}
public void mouseEntered (MouseEvent event) {}
public void mouseExited (MouseEvent event) {}
} // end of PointListener
} // end of Canvas Panel Class
} // end of Whole Panel Class
KeyEvents are only dispatched to the component with focus. A panel is not focusable by default.
You need to add:
setFocusable(true);
in the constructor of your class.
You can only request focus on a visible component, which means the requestFocust() statement in the constructor will do nothing. Also, the method to use is requestFocusInWindow() (again after the frame is visible).
Finally, you should be using Key Bindings to listen for key events on a component (so you don't need to worry about the component having focus). See Motion Using the Keyboard for more information and examples.

Why won't my shapes draw on the JFrame?

I'm trying to get a specific shape to draw based on what the user clicks. Every other method in the program is working fine.
Here is a picture of what shows up currently:
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.*;
public class Gui3 extends JFrame {
private JPanel mousepanel;
private JLabel statusbar;
private JList list;
private static String[] colornames = {"black","blue","red","white"};
private static Color[] colors = {Color.BLACK, Color.BLUE,Color.RED,Color.WHITE};
private JCheckBox cb;
private JCheckBox rect;
private JCheckBox oval;
private JCheckBox drawBox;
private boolean changeColor = true;
private boolean ableToDraw = true;
public Gui3(){
super("The title");
list = new JList(colornames);
list.setVisibleRowCount(4);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setFixedCellHeight(15);
list.setFixedCellWidth(100);
add(new JScrollPane(list), BorderLayout.WEST);
list.addListSelectionListener(
new ListSelectionListener(){
public void valueChanged(ListSelectionEvent event){
if(changeColor==true){
mousepanel.setBackground(colors[list.getSelectedIndex()]);
}
else{
}
}
}
);
rect= new JCheckBox("Draw a rectangle");
oval= new JCheckBox("Draw a oval");
cb = new JCheckBox("Not able to change the color");
drawBox = new JCheckBox("Not able to draw shapes");
mousepanel = new JPanel();
mousepanel.setBackground(Color.WHITE);
add(mousepanel, BorderLayout.CENTER);
add(drawBox, BorderLayout.EAST);
add(cb, BorderLayout.NORTH);
mousepanel.add(rect,BorderLayout.EAST);
mousepanel.add(oval,BorderLayout.WEST);
statusbar = new JLabel("Default");
add(statusbar, BorderLayout.SOUTH);
HandlerClass handler = new HandlerClass();
mousepanel.addMouseListener(handler);
mousepanel.addMouseMotionListener(handler);
cb.addItemListener(handler);
drawBox.addItemListener(handler);
}
private class HandlerClass implements MouseListener, MouseMotionListener,ItemListener
{
#Override
public void mouseClicked(MouseEvent event) {
statusbar.setText(String.format("Clicked at %d, %d", event.getX(),event.getY()));
This is where what is selected is used to decided what to draw. It works by passing parameters to a method is the drawShape class; shown down below.
if(ableToDraw==true){
if(rect.isSelected()&&oval.isSelected()){
DrawShapes shapes = new DrawShapes();
shapes.whatToDraw(false,false);
}
}
else if(rect.isSelected()){
DrawShapes shapes = new DrawShapes();
shapes.whatToDraw(true, false);
shapes.setPosition(event.getX(), event.getY());
add(shapes);
}
else if(oval.isSelected()){
DrawShapes shapes = new DrawShapes();
shapes.whatToDraw(false, true);
shapes.setPosition(event.getX(), event.getY());
add(shapes);
}
else{
DrawShapes shapes = new DrawShapes();
shapes.whatToDraw(false,false);
}
}
#Override
public void mousePressed(MouseEvent event){
statusbar.setText("You pressed down the mouse");
}
#Override
public void mouseReleased(MouseEvent event){
statusbar.setText("You released the button");
}
#Override
public void mouseEntered(MouseEvent event){
statusbar.setText("You entered the area");
}
#Override
public void mouseExited(MouseEvent event){
statusbar.setText("The mouse has left the window");
}
//These are mouse motion events
#Override
public void mouseDragged(MouseEvent event){
statusbar.setText("You are dragging the mouse");
}
#Override
public void mouseMoved(MouseEvent event){
statusbar.setText("You are moving the mouse");
}
#Override
public void itemStateChanged(ItemEvent event){
if(cb.isSelected()){
changeColor=false;
}
else{
changeColor=true;
}
if(drawBox.isSelected()){
ableToDraw=false;
}
else{
ableToDraw=true;
}
}
}
}
This is the drawShapes class
import java.awt.*;
import javax.swing.*;
public class DrawShapes extends JPanel {
private int x,y;
private boolean ovals,rects;
public void paintComponent(Graphics g){
super.paintComponent(g);
if(ovals==false&&rects==true){
g.setColor(Color.BLUE);
g.fillRect(x,y,15,15);}
else if(ovals==true&&rects==false){
g.setColor(Color.BLUE);
g.fillOval(x, y, 30, 15);
}
else{
}
}
public void setPosition(int newX, int newY) {
this.x = newX;
this.y = newY;
repaint();
}
public void whatToDraw(boolean newrects, boolean newovals){
this.ovals=newovals;
this.rects=newrects;
repaint();
}
}
I would guess the problem is that you don't override the getPreferredSize() method of your DrawShapes class so there is nothing to paint. So you need to override the getPreferredSize() to return the actual size of your shape which in your case would appear to be (x + 30, y + 15) for your ovals and (x + 15, y + 15) rectangles.
You really should have separate classes for rectangles and ovals. Using if/else statements is not a good design and is not very flexible if you decide to add a "triangle" shape as your logic gets much more complicated.
However even if you do that you won't get what you expect because I'm guessing you add the DrawShapes component to a panel which by default is using a FlowLayout. So your shapes will just be displayed in a row on the panel, not where you click on the panel.
If you want the component to appear where you click then you need to set the size of the oval component to (30, 15) and the location of the component to (x, y). The painting of the shape would then be done at (0, 0) so the painting is relative to the component, not the panel. Then you need to set the layout of panel to null, so you can manually position each shape based on its location.
The other option is to not use real components, but just draw the shape onto a panel. Check out Custom Painting Approaches for examples of the two common ways incremental painting. It shows two different ways to do this depending on your exact requirement.
The examples show how to add Rectangles and you click/drag the mouse. So you need to modify the code to support different types of Shapes.
First I had to create a single instance of the drawShapes class, as stated by another user. Then the other part was that I messed up the logic, you should be able to draw only when ableToDraw==false meaning the button saying "not able to draw" isn't selected. That was bad naming on my part. Once that is done the code works fine.

Custom painting in Java - drawing UI elements onto the JPanel

I am creating a drawing board program, basically a simplified version of MS Paint. It is working for the most part but when I draw on the board, the currently selected UI element shows up on the drawing area.
I tried paintComponent, which worked when I called super.paintComponent(g) (as one does) but it cleared the drawing area before I drew the next object. I overrode update and put a println statement in there and it is never being called.
The buttons at the top are red because I set the background to the bottom JPanel to red to see what the background of these buttons would be. So clearly they are part of the bottom JPanel. I am using a BorderLayout for the layout.
Here is my code (with some irrelevant bits removed):
public class JSPaint extends JFrame implements Serializable
{
private static final long serialVersionUID = -8787645153679803322L;
private JFrame mainFrame;
private JPanel bp;
private JButton ...
private DrawingArea da;
public JSPaint()
{
setTitle("JS Paint");
setSize(1024, 768);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Drawing area
da = new DrawingArea();
setLayout(new BorderLayout());
// add the buttons to the panel
buttonPanel();
// Add the drawing area
add(bp, BorderLayout.SOUTH);
bp.setBackground(Color.RED);
add(da, BorderLayout.CENTER);
da.setBackground(Color.BLUE);
setVisible(true);
}
// I put it here too just in case
#Override
public void update(Graphics g)
{
System.out.println("update in JSPaint called.");
paint(g);
}
/*
* Creates the panel for the buttons, creates the buttons and places them on
* the panel
*/
public void buttonPanel()
{
// Create the panel for the buttons to be placed in
bp = new JPanel();
saveButton = new JButton("Save");
loadButton = new JButton("Load");
//more buttons
bp.add(saveButton);
bp.add(loadButton);
//more buttons
// ActionListeners
colorButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
System.out.println("color");
da.color();
}
});
}
public class DrawingArea extends JPanel
{
private static final long serialVersionUID = -8299084743195098560L;
boolean dragged = false;
#Override
public void update(Graphics g)
{
System.out.println("Update in DrawingArea called");
paint(g);
}
/*
* Draws the selected shape onto the screen and saves it into a Stack.
*
*/
public void draw()
{
this.addMouseMotionListener(new MouseMotionListener()
{
public void mouseDragged(MouseEvent me)
{
dragged = true;
}
public void mouseMoved(MouseEvent me) {}
});
//more listeners...
});
}
/*
* Draws the selected String onto the screen when the mouse is held down.
*
*/
public void brush()
{
this.addMouseMotionListener(new MouseMotionListener()
{
public void mouseDragged(MouseEvent me)
{
// If we are in drawing mode, draw the String. Create a new
// Figure Object and push it onto the Stack
if(activeButton == "brush")
{
startPoint = me.getPoint();
Figure fig = new Figure("String", startPoint, null, currentColor);
// figures.push(calculate(fig));
toPaint.push(calculate(fig));
repaint();
}
}
public void mouseMoved(MouseEvent me) {}
});
}
// more of the same...
public void paint(Graphics g)
{
toSave.addAll(toPaint);
while(!toPaint.isEmpty())
{
Figure f = toPaint.pop();
String t = f.type;
if(f.color != null)
{
g.setColor(f.color);
}
switch(t)
{
case "Rectangle": g.drawRect(f.x1, f.y1, f.width, f.height);
break;
case "Oval": g.drawOval(f.x1, f.y1, f.width, f.height);
break;
case "Line": g.drawLine(f.x1, f.y1, f.x2, f.y2);
break;
case "Clear":
g.fillRect(0, 0, da.getWidth(), da.getHeight());
clearStack(toSave);
break;
case "String": g.drawString(f.toPrint, f.x1, f.y1);
break;
}
}
}
}
private class Figure implements Serializable
{
private static final long serialVersionUID = 4690475365105752994L;
String type, toPrint;
Color color;
Point start;
Point end;
int x1, y1, x2, y2, width, height;
public Figure(String figureType,
Point startPoint, Point endPoint, Color figureColor)
{
type = figureType;
color = figureColor;
start = startPoint;
end = endPoint;
}
// Rect, Oval
public Figure(String figureType, int figureX, int figureY,
int figureWidth, int figureHeight, Color figureColor)
{
type = figureType;
x1 = figureX;
y1 = figureY;
width = figureWidth;
height = figureHeight;
color = figureColor;
}
// more shapes
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new JSPaint();
}
});
}
}
If the currently selected UI element shows up on the drawing area, this can have only one reason: you are doing something wrong with the Graphics objects, possibly calling a translate on them, and not resetting the tranlation when you are done. (See this link for an example of translate used correctly).

How to use Canvas to draw multiple rectangles based on user input?

So basically I'm writing a program where the user clicks and drags the mouse to a size he/she wants, and lets go, filling in a rectangle based on the choice from the JComboBox.
What I have implemented is MouseListener and MouseMotionListener to track the location of the mouse, and draw a rectangle based on where the user first clicked, to where it was let go.
When the user clicks and drags (but does not let go), there is a drawRect() but not a fillRect() (as in, the rectangle does not fill - only when the user releases the mouse does the rectangle fill with the color).
This class creates a Rect object that has another part in the constructor, which is the color that is selected (which is determined in the ColorListener class below).
This is where I included my instance variables, and everything is instantiated in the constructor below:
private ArrayList<Rect> rectList;
private Color currentColor;
private Canvas canvas;
private JPanel controlPanel;
private JButton undo, erase;
private JComboBox comboBox;
private int xStart, yStart, xEnd, yEnd;
private Graphics page;
private Point pt = null;
private PointListener pointListener;
private ColorListener colorListener;
public WholePanel()
{
// here we use black to draw a rectangle
currentColor = Color.black;
pointListener = new PointListener();
addMouseListener(pointListener);
addMouseMotionListener(pointListener);
String[] listOfColors = {"black", "red", "blue", "green", "orange"};
comboBox = new JComboBox(listOfColors);
comboBox.setSelectedIndex(0);
rectList = new ArrayList<Rect>();
controlPanel = new JPanel(new GridLayout(1,3));
undo = new JButton("Undo");
erase = new JButton("Erase");
controlPanel.add(comboBox);
controlPanel.add(undo);
controlPanel.add(erase);
undo.addActionListener(new ButtonListener());
erase.addActionListener(new ButtonListener());
canvas = new Canvas();
JSplitPane sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, controlPanel, canvas);
setLayout(new BorderLayout());
add(sp);
}
The Rect class can create a Rect object used later.
public class Rect
{
private int x1, y1, width1, height1;
private Color color1;
public Rect(int x, int y, int width, int height, Color color)
{
x1 = x;
y1 = y;
width1 = width;
height1 = height;
color1 = color;
}
public void draw(Graphics page)
{
page.setColor(color1);
page.drawRect(x1,y1,width1,height1);
}
}
The Canvas class creates the space that allows for drawing of an object.
private class Canvas extends JPanel
{
public void paintComponent(Graphics page)
{
super.paintComponent(page);
setBackground(Color.white);
if (pt != null)
{
Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
rect.draw(page);
}
}
}
The PointListener class finds all the points that are there, as in where the user clicks, to where the user drags, and also to where the user releases.
private class PointListener implements MouseListener, MouseMotionListener
{
public void mousePressed(MouseEvent event)
{
pt = event.getPoint();
xStart = pt.x;
yStart = pt.y;
}
public void mouseReleased(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
}
}
public void mouseClicked(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mouseDragged(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
Rect rect = new Rect(xStart, yStart, xEnd-xStart, yEnd-yStart, currentColor);
rect.draw(page);
}
repaint();
}
public void mouseMoved(MouseEvent event) {}
}
ColorListener finds the type of object that is selected in the JComboBox determined in the main() method, and sets the currentColor to it (it is put back as the color in the Rect constructor above).
private class ColorListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource().equals("black"))
{
currentColor = Color.black;
comboBox.setSelectedIndex(0);
}
else if (event.getSource().equals("red"))
{
currentColor = Color.red;
comboBox.setSelectedIndex(1);
}
else if (event.getSource().equals("blue"))
{
currentColor = Color.blue;
comboBox.setSelectedIndex(2);
}
else if (event.getSource().equals("green"))
{
currentColor = Color.green;
comboBox.setSelectedIndex(3);
}
else if (event.getSource().equals("orange"))
{
currentColor = Color.orange;
comboBox.setSelectedIndex(4);
}
}
}
So what I am having trouble with is being able to draw it. I don't see any flaws in logic in the program so far above, and nothing is being able to be drawn onto the Canvas (don't worry about the JButtons Undo and Erase, as they are easy to work with with an ArrayList and remove() and clear() and things like that).
Your program should have no Graphics field that is a class field (your page class field). I'm surprised your not seeing a NullPointException with the way you're attempting to use it above in say your Mouse Listener class:
public void mouseReleased(MouseEvent event)
{
pt = event.getPoint();
if (pt != null)
{
xEnd = pt.x;
yEnd = pt.y;
// !!!! don't do this !!!!
page.fillRect(xStart, yStart, xEnd-xStart, yEnd-yStart);
}
}
Instead the Graphics object should only be obtained from the JVM, should only exist within the paintComponent method and should only be used within the same paintComponent method (exceptions being any methods called from with paintComponent that are passed this object and of course a Graphics object obtained from a BufferedImage). The MouseListener/MouseMotionListener should fill in your x-start, y-start, x-end, and y-end variables during mouseDragged, and then on mouseRelease these variables should be used to create a new Rect object that is placed in the rectList, and then repaint called.
Then paintComponent should iterate through rectList, filling each Rect object it finds there.

Categories

Resources