so I'm trying to draw a rectangle when the mouse is clicked by creating an object an adding it to the JFrame. But it won't show up once the command is run. Any ideas why?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Gui3 extends JFrame {
private JPanel mousepanel;
private JLabel statusbar;
public Gui3(){
super("The title");
mousepanel = new JPanel();
mousepanel.setBackground(Color.WHITE);
add(mousepanel, BorderLayout.CENTER);
statusbar = new JLabel("Default");
add(statusbar, BorderLayout.SOUTH);
HandlerClass handler = new HandlerClass();
mousepanel.addMouseListener(handler);
mousepanel.addMouseMotionListener(handler);
}
private class HandlerClass implements MouseListener, MouseMotionListener
{
This is where the problem is arising. The program and all its methods work, it's just drawing the rectangle that is the problem. The Object that draws the shape is below.
public void mouseClicked(MouseEvent event) {
statusbar.setText(String.format("Clicked at %d,%d",event.getX(),event.getY()));
DrawShapes shapes = new DrawShapes();
add(shapes);
}
public void mousePressed(MouseEvent event){
statusbar.setText("You pressed down the mouse");
}
public void mouseReleased(MouseEvent event){
statusbar.setText("You released the button");
}
public void mouseEntered(MouseEvent event){
statusbar.setText("You entered the area");
mousepanel.setBackground(Color.RED);
}
public void mouseExited(MouseEvent event){
statusbar.setText("The mouse has left the window");
mousepanel.setBackground(Color.WHITE);
}
//These are mouse motion events
public void mouseDragged(MouseEvent event){
statusbar.setText("You are dragging the mouse");
}
public void mouseMoved(MouseEvent event){
statusbar.setText("You are moving the mouse");
}
}
}
Here is the object that draws the rectangle
import java.awt.*;
import javax.swing.*;
public class DrawShapes extends JPanel {
public void PaintComponent(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(0,0,30,30);
}
}
regarding
public void PaintComponent(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(0,0,30,30);
}
Understand that
PaintComponent != paintComponent
Be sure to use the #Override annotation to let you know when you are or aren't overriding methods that you think you are.
The correct method would look something like:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // don't forget this!
g.setColor(Color.BLUE);
g.fillRect(0, 0, 30, 30);
}
Also, if you want to replace the original JPanel, then use a CardLayout to help you easily do this. Otherwise you must be sure to call revalidate() and repaint() yourself after swapping components in a container.
e.g.,
#Override
public void mouseClicked(MouseEvent event) {
statusbar.setText(String.format("Clicked at %d,%d", event.getX(), event.getY()));
remove(mousepanel);
DrawShapes shapes = new DrawShapes();
getContentPane().add(shapes, BorderLayout.CENTER);
getContentPane().revalidate();
getContentPane().repaint();
}
Related
I am trying to add the MouseHandler to my DrawPanel class to eventually have a status label that updates the mouse location, but while using print statements, it seems like it is not registering any mouse input at all.
private class DrawPanel extends JPanel {
public DrawPanel() {
JPanel mousePanel = new JPanel();
this.add(mousePanel);
MouseHandler handler = new MouseHandler();
mousePanel.addMouseListener(handler);
mousePanel.addMouseMotionListener(handler);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
}
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
#Override
public void mousePressed(MouseEvent event) {
System.out.print("Pressed");
}
#Override
public void mouseReleased(MouseEvent event) {
System.out.print("Released");
}
#Override
public void mouseDragged(MouseEvent event) {
System.out.print("Dragged");
//lblStatus.setText(String.format("(%d,%d)",event.getX(),event.getY()));
}
#Override
public void mouseMoved(MouseEvent event) {
System.out.print("Moved");
//System.out.print("("+event.getX()+","+event.getY()+")");
//lblStatus.setText(String.format("(%d,%d)",event.getX(),event.getY()));
}
}
}
You're creating and adding another JPanel, the mousePanel, and adding it to the DrawPanel JPanel, a container that uses the default FlowLayout. This makes the mousePanel's size its preferred size which is [0, 0] meaning that the mousePanel component is being added but it is too small to be seen or to do anything significant. But why do you even have or need this extra JPanel?
Solution: get rid of the mousePanel, there is no need for it. Instead add your mouse handler to this.
Side issue, no need to implement MouseMotionListener. A MouseAdapter already implements this interface.
For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FooSwing02 extends JPanel {
private JLabel statusLabel = new JLabel("");
public FooSwing02() {
setPreferredSize(new Dimension(800, 650));
add(new JLabel("Mouse Location:"));
add(statusLabel);
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
private class MyMouse extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent event) {
Point p = event.getPoint();
String text = String.format("[%03d, %03d]", p.x, p.y);
statusLabel.setText(text);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.add(new FooSwing02());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
I'm doing my final project for my college. And I don't have much Java knowledge to debug the code. The bug is in question. I am to drop 3 classes Java code here, Drawing Panel, the Jframe and main() one.
main() code:
package test;
public class main {
public static void main(String[] agrs) {
Aaa a = new Aaa();
}
}
Aaa code (IDK what to name):
package test;
import java.awt.*;
import javax.swing.*;
public class Aaa extends JFrame{
JPanel panel = new JPanel();
JLabel text = new JLabel("please try click on the button first, then drawing, then click and draw again.");
JButton button = new JButton("bug here");
DrawingPanel drawingPanel = new DrawingPanel();
public Aaa() {
this.add(panel, BorderLayout.NORTH);
panel.setBackground(Color.WHITE);
panel.add(text);
panel.add(button);
this.add(drawingPanel, BorderLayout.CENTER);
this.setSize(700,500);
this.setTitle("Submit to StackOverFlow");
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
DrawingPanel() Class (Personally suspect this is where the bug is. I have been using this in different projects and it got the same bug too):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawingPanel extends JPanel implements MouseListener, MouseMotionListener{
boolean mouse = false;
private int x1,y1,x2,y2;
protected int resetCount = 0;
public DrawingPanel() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
protected void paintComponent(Graphics g) {
if (mouse) {
if (resetCount == 0 ) {
super.paintComponent(g);
resetCount++;
}
g.setColor(Color.black);
g.drawLine(x1, y1, x2, y2);
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {
mouse = false;
}
public void mousePressed(MouseEvent e) {
mouse= true;
x2 = (int) e.getPoint().getX();
y2 = (int) e.getPoint().getY();
}
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
x1 = x2;
y1 = y2;
x2 = (int) e.getPoint().getX();
y2 = (int) e.getPoint().getY();
repaint();
}
}
With these 3 codes run together, DrawingPanel drawingPanel will copy JButton button onto the top left of its panel. If there's 2 or more button it will copy the lasted one. the 1st clicked button will not be duplicate onto its panel. Sometimes this bug applies to JTextField too. Also, we can paint over the panel! This is the picture of
this
If anyone knows how to debug this I'm all ears to fix them, Thank you so much!
I am trying to make a drawOval moving by using the two buttons that I set to be North and East so the ball will move between the JButtons, at the center.
Why does not appear at the panel?
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
I do not figure out what can I do.
So this is the code I made:
public class Main extends JFrame implements ActionListener {
JButton left;
JButton right;
JPanel p;
Main(){
JButton left = new JButton("left");
left.addActionListener(this);
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
//The first way I think is better to make it move.
}
});
JButton right = new JButton("right");
right.addActionListener(this);
Panel p = new Panel();
p.setLayout(new BorderLayout());
p.add("West",left);// to the left
p.add("East",right);//to the right
Container c = getContentPane();
c.add(p);
}
public static void main(String[] args) {
Main f=new Main();
f.setTitle("Heracles");
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true); //this is the window
}
public void paintComponent (Graphics g) {
super.paintComponents(g);
Graphics2D g1=(Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
To understand why it's not working, you need to understand how the paint system actually works
Just by looking at this snippet it should be obvious something is wrong.
public class Main extends JFrame implements ActionListener {
//...
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
You've declare a method called paintComponent but are calling the super method paintComponents (note the s at the end).
Further, when ever you "think" you're overriding a method, you should make use of the #Override attribute, this will cause a compiler error when you've done something wrong
public class Main extends JFrame implements ActionListener {
//...
#Overrride
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
The above code will now fail to compile, as JFrame doesn't declare a paintComponent method.
As a general rule, you should avoid extending directly from JFrame (or other top level containers), they are compound components and have a complex hierarchy and functionality.
A better place to start might be with a JPanel
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
public TestPane() {
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
paintPane = new PaintPane();
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
g1.drawOval(3, 5, 45, 46); // The ball
g1.fillOval(20, 30, 40, 40);
}
}
}
You should take the time to have a look at Painting in Swing and Performing Custom Painting for more details.
Some other concepts you might like to take the time to learn:
Single Responsibility Principle - a class should do one thing and do it well
Observer Pattern - This typically represent in Swing as the listener API
Model-View-Controller - this encompasses the above and defines different layers of responsibility for different parts of the program, it will helper you understand the basic structure of Swing as well
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
Ok, so this is where the "model" part of the MVC will play it's part.
So lets start by defining the basic properties we expect the model to support...
public interface ShapeModel {
public Point getPoint();
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
}
Here is supports a Point to act as the location and a ChangeListener to act as the observer pattern, which will notify interested parties that the state of the model has changed.
Why start with a interface? As a general concept, you should always prefer to code to interface instead of implementation. In this case, one aspect of the interface which hasn't been defined is, how does the Point get updated? That's of little interest to most parties who want to work with the model, they just want to know when it changes, the mutation of the model can be expressed either directly via the implementation or a "mutable" interface which extends from the this interface
Next, we define a default implementation...
public class DefaultShapeModel implements ShapeModel {
private Point point = new Point(40, 40);
private List<ChangeListener> listeners = new ArrayList<>(25);
#Override
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
fireStateChanged();
}
protected void fireStateChanged() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
}
This does define how the paint is to be updated.
Finally, we update the TestPane and PaintPane to support the model...
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
private DefaultShapeModel model;
public TestPane() {
model = new DefaultShapeModel();
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Point p = model.getPoint();
p.x--;
if (p.x > 0) {
p.x = 0;
}
model.setPoint(p);
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point p = model.getPoint();
p.x++;
if (p.x + 40 > paintPane.getWidth()) {
p.x = paintPane.getWidth() - 40;
}
model.setPoint(p);
}
});
paintPane = new PaintPane(model);
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
private ShapeModel model;
public PaintPane(ShapeModel model) {
this.model = model;
this.model.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
public ShapeModel getModel() {
return model;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
Point p = getModel().getPoint();
g1.fillOval(p.x, p.y, 40, 40);
g1.setColor(Color.WHITE);
g1.drawOval(p.x, p.y, 40, 40);
}
}
Why does not appear at the panel?
To display graphic you created, use follow these steps,
Remove paintComponent method and replace it with below code..
public JComponent createOvel() {
return new JComponent() {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
};
}
Then call it in Main() constructor,
p.add("Center", createOvel());
This will display the graphic you created.
I'm trying to make a simple application for painting. I have a main method that sets up a JFrame, and then adds a JPanel and a JLabel using flowlayout. The JLabel is for counting clicks.
The panel class implements a mouselistener and mousemotionlistener.
The problem is when I paint something or click on the panel, it adds the label to the JPanel aswell, and depending on where I click, it can add it twice to the panel, it's making me mad. I just can't understand why it's added to the JPanel.
Also, the JPanel is surrounded by a border, and when I click or paint something it adds a new vertical borderline somewhere on the panel, it's random every time.
Code for the two classes:
public class mainepanel extends JPanel implements MouseMotionListener, MouseListener{
Graphics globalGraphics;
int clickCount = 0;
public mainepanel(){
setBorder(BorderFactory.createLineBorder(Color.black));
setPreferredSize(new DimensionUIResource(200,200));
addMouseMotionListener(this);
addMouseListener(this);
validate();
setFocusable(true);
}
public void paintComponent(Graphics g){
globalGraphics = g.create();
}
#Override
public void mouseDragged(MouseEvent e) {
globalGraphics.fillOval(e.getX(), e.getY(), 10,10);
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
clickCount ++;
maine.setLabel(clickCount);
globalGraphics.fillOval(e.getX(), e.getY(), 10,10);
repaint();
}
maine
public class maine extends JFrame{
static JLabel label;
public maine(){
setSize(600,400);
setDefaultCloseOperation(3);
setResizable(false);
label = new JLabel("Clicks:");
setLayout(new FlowLayout());
add(label);
add(new mainepanel());
setVisible(true);
}
public static void setLabel(int clicks){
label.setText("Clicks: " + clicks);
}
public static void main(String[]args){
new maine();
}
}
Perform all the drawing within paintComponent (and be sure to call super.paintComponent) - the MouseListener/MouseMotionListener should only need to change the data model (and if necessary call repaint so the UI reflects the change).
A simple example below with a single circle created with a Mouse click, and moved with a mouse dragged:
Point center = null;
...
#Override
public void mouseClicked(MouseEvent e){
center = e.getPoint();
repaint();
}
#Override
public void mouseDragged(MouseEvent e){
center = e.getPoint();
repaint();
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
if ( center != null ){
g.fillOval(center.getX(), center.getY(), 10, 10);
}
}
I don't know why, but I can't call the method paint(Graphics g) from code. I have MouseListeners:
#Override
public void mouseReleased(MouseEvent e) {
pointstart = null;
}
#Override
public void mousePressed(MouseEvent e) {
pointstart = e.getPoint();
}
and MouseMotionListeners:
#Override
public void mouseMoved(MouseEvent e) {
pointend = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent arg0) {
pointend = arg0.getPoint();
// ==========================================================================
// call repaint:
repaint();
// ==========================================================================
}
and my paint method:
public void paint(Graphics g){
super.paint(g); //here I have my breakpoint in debugger
g.translate(currentx, currenty);
if(pointstart!=null){
g.setClip(chartPanel.getBounds());
g.setColor(Color.BLACK);
g.drawLine(pointstart.x, pointstart.y, pointend.x, pointend.y);
}
}
in the initialize method:
currentx = chartPanel.getLocationOnScreen().x;
currenty = Math.abs(chartPanel.getLocationOnScreen().y - frame.getLocationOnScreen().y);
All in class, which is my work frame, it extends JFrame.
Problem is, that program doesn't call paint method. I checked that in debugger.
I tried do this by paintComponent , without super.paint(g).
And the best is that, that code I copied from my other project, where it works fine.
UPDATE:
This is code which I want to draw line on panel (no matter - panel/chartpanel/etc). And it doesn't paint. I tried do this by paint(Graphics g){super.paint(g) ..... } and it doesn't too. Painting should be aneble after clicking button "line".
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.JScrollPane;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class Window extends JFrame {
private JFrame frame;
public JPanel panelbuttons;
public JPanel panelscrollpane;
public JButton btnLine;
public JToolBar toolBar;
public JScrollPane scrollPane;
public JPanel panel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Window window = new Window();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Window() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 644, 430);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panelbuttons = new JPanel();
frame.getContentPane().add(panelbuttons, BorderLayout.WEST);
panelbuttons.setLayout(new BorderLayout(0, 0));
toolBar = new JToolBar();
toolBar.setOrientation(SwingConstants.VERTICAL);
panelbuttons.add(toolBar, BorderLayout.WEST);
btnLine = new JButton("line");
btnLine.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
panel.addMouseListener(mouselistenerLine);
panel.addMouseMotionListener(mousemotionlistenerLine);
}
});
toolBar.add(btnLine);
panelscrollpane = new JPanel();
frame.getContentPane().add(panelscrollpane, BorderLayout.CENTER);
panelscrollpane.setLayout(new BorderLayout(0, 0));
scrollPane = new JScrollPane(panel);
panel.setLayout(new BorderLayout(0, 0));
scrollPane.setViewportBorder(null);
panelscrollpane.add(scrollPane);
panelscrollpane.revalidate();
}
Point pointstart = null;
Point pointend = null;
private MouseListener mouselistenerLine = new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("I'm in first listener. - mouse Released");
pointstart = null;
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("I'm in first listener. - mousePressed");
pointstart = e.getPoint();
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
};
private MouseMotionListener mousemotionlistenerLine = new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("I'm in second listener. - mouseMoved");
pointend = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent arg0) {
System.out.println("I'm in second listener. - mouseDragged");
pointend = arg0.getPoint();
repaint();
}
};
public void paintComponent(Graphics g){
System.out.println("I'm in paintComponent method.");
if(pointstart!=null){
System.out.println("I'm drawing.");
g.setClip(scrollPane.getBounds());
g.setColor(Color.BLACK);
g.drawLine(pointstart.x, pointstart.y, pointend.x, pointend.y);
}
}
}
You are creating two separate instances of JFrame and showing only one.
One instance is created because Window class extends JFrame, and the second is created inside initialize method.
To fix this without a lot of changes in code do this:
private void initialize() {
frame = this;
frame.setBounds(100, 100, 644, 430);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BTW. change paintComponent(Graphic g) to paint(Graphic g) because JFrame is not a JComponent.
In a ChartPanel context, consider one of the org.jfree.chart.annotations such as XYLineAnnotation, illustrated here and here.
Calling repaint() will trigger your paint(Graphics g) method to be called. So, you don't have to explicitly call paint().