I want to write a code to draw a filled oval where ever the mouse is clicked inside a panel. I used to develop some codes but unfortunately when I tried to do the next click the whole panel blanked and new point appeared. I want to keep the previous points and add some new ones by the next user’s click on the panel. How do I implement the paint component of MyPanel? Here is my code; it does not work properly, because it produces some small points instead of rectangle.
class MyPanel extends JPanel {
Point pointClicked;
public MyPanel() {
this.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
pointClicked = e.getPoint();
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(pointClicked.x, pointClicked.y, 1, 1);
}
}
I want to keep the previous points and add some new ones by the next user’s click on the panel.
You need to keep track of each oval painted and repaint all ovals each time the paintComponent() method is called.
Check out Custom Painting Approaches for two different ways to do this
Related
I have a JSlider in a JPanel that return me a value of R-G-B .
I create it, in the Costructor of JPanel. I draw in same Panel (using paintComponent) a little circle, and I change his color using the Slider. I want that the color change in contemporany of slider shift.
So, i use the method repaint.. Next to Panel there is another Panel, with two button.. If I use method repaint in first panel , the buttons of second panel duplicated in the topLeft of First Panel. Why? Thank's you.
First Panel:
public class OptionsPanel extends JPanel {
static JSlider RBG = new JSlider(0,255);
OptionsPanel(){
this.setVisible(false);
this.setSize(350,1000);
this.setLayout(null);
this.setBackground(new Color(200,200,0));
Main.f1.add(this);
RBG.setVisible(true);
RBG.setSize(255,50);
RBG.setLocation(30,240);
this.add(RBG);
LotL lotl = new LotL();
Button save = new Button("Save");
save.setVisible(true);
save.setSize(100,40);
save.setLayout(null);
save.setLocation(60,300);
save.addActionListener(lotl);
save.setBackground(Color.yellow);
save.identificatore=3;
this.add(save);
}
boolean draw=false;
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
}
Second Panel:
public class FirstPanel extends JPanel{
FirstPanel(){
this.setVisible(true);
this.setSize(1000,1000);
this.setLayout(null);
this.setBackground(new Color(255,200,180));
Main.f1.add(this);
Button start = new Button("Start Game!");
Button options = new Button("Options");
LotL LotL = new LotL();
start.setVisible(true);
start.setSize(200,80);
start.setLayout(null);
start.setLocation(400,450);
start.addActionListener(LotL);
start.setBackground(Color.green);
start.identificatore=1;
this.add(start);
options.setVisible(true);
options.setSize(200,70);
options.setLayout(null);
options.setLocation(400,550);
options.addActionListener(LotL);
options.setBackground(Color.green);
options.identificatore=2;
this.add(options);
}
}
You've broken the paint chain...
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
Graphics is a shared resource, which gets passed to ALL the components that are painted during a given paint cycle.
One of the jobs of paintComponent is to prepare the Graphics context for painting, but filling with the components background color.
You MUST call super.paintComponent before performing any custom painting.
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
}
Also, there is never any need for paintComponent to be public, no one should ever be calling directly and NEVER modify the state of a component from within any paint method which may trigger a repaint, you will get yourself into a infinite loop which will eventually consume your CPU and make you computer unusable.
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details
You should also avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
I'm trying to learn how to do custom GUI stuff in Java for a group project I'm working on. I've done user form type GUIs in the past so I know the gist of what I'm doing here, but the custom drawing stuff still confuses me.
I copied this code from online and I've been trying to figure out how it works, but I don't get why I can't loop the drawing method. As a simple test I'm trying to make the program draw an oval on my cursor. It draws the oval on the cursor, but only once on runtime and then does nothing.
How can I make this loop so I can continue to draw things? Or is there a different way I need to call/use the methods?
public class BombermanGUI extends JFrame {
public static final int CANVAS_WIDTH = 640;
public static final int CANVAS_HEIGHT = 480;
private DrawCanvas canvas;
public BombermanGUI() {
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
Container cp = getContentPane();
cp.add(canvas);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setTitle("......");
this.setVisible(true);
}
private class DrawCanvas extends JPanel{
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
setBackground(Color.BLACK);
int x, y;
x = MouseInfo.getPointerInfo().getLocation().x - this.getLocationOnScreen().x;
y = MouseInfo.getPointerInfo().getLocation().y - this.getLocationOnScreen().y;
g.setColor(Color.YELLOW);
g.drawOval(x, y, 10, 10);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BombermanGUI();
}
});
}
}
Painting a complex series of callbacks and responses to changes within the system. The first thing to remember is that you don't control the painting process, but rather make suggestions to the system so that it can make decisions about what and when it should repaint...
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details.
Painting is a destructive process. It is assumed that when a repaint occurs, that you will repaint the entire state of the current component. This means that you will need some kind of model which maintains all the content that needs to be painted...
Have a look at 2D Graphics, in particular, have a look at the section on Shape
MouseInfo is a seriously crappy way to detect the location of the mouse for this purpose, instead, you should be using a MouseListener and/or MouseMotionListener to detect mouse events.
Basically, when the user presses a mouse button, you would record the location of the mouse press. When the mouse is moved, you would calculate the width and height of the movement relative to the mouse press and update the "current" shape. You would call repaint to request that the UI be updated and paint this shape via the paintComponent method (painting all the previous shapes first).
When the mouse button is released, you would commit the "current" shape to the model, so it will be painted every time paintComponent is called.
THIS IS tobais_k ANSWER IM ANSWERING TO CLOSE THE QUESTION!
Either add an event listener and have it call the repaint method, e.g. a mouse motion listener for tracking your mouse cursos, or have some thread run your game and trigger repaint in regular intervals.
I'm working on a assignment for school but I got a problem :P.
I got this code:
public void mouseEntered(MouseEvent e) {
MyPanel b = (MyPanel)e.getSource();
System.out.println("ID: "+b.getId()+"");
b.setColor(Color.blue);
}
In the MyPanel object I got:
public void setColor(Color kleur) {
if(this.getBackground()==Color.white) {
this.setBackground(kleur);
repaint();
}
}
When I enter the panel with my mouse the color flashes that I entered. But I want it to stay the color so I can draw a trail in a Jform with 500 Jpanels(I've added them to a ArrayList but this part works just fine)
What am I doing wrong?
Based on #ErickRobertson's comment on the question, I guess the problem is the following:
Your MyPanel replaces the JPanel#paintComponents() method. Is that possible? If so, you could do the following. In your MyPanel#setColor(Color) method, you don't set the background, but a field containing your new background color:
private Color backgroundColor = Color.white;
public void setColor(Color kleur) {
backgroundColor = kleur;
repaint();
}
Then, in your MyPanel#paintComponents(Graphics):
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// draw background
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
// draw your stuff here
}
Make sure that only one JPanel is visible at a time.
When you add the JPanels to their parent, are they all going on top of each other? If so, then when you call repaint() on one of them, it's being repainted immediately and you can see it as blue. But as soon as the whole window repaints again, the JPanels are painted in the order they have been added and the last one is ultimately painted on top. This panel still has a white background, so that's what you're seeing.
Make sure only one of these panels are visible at a time, or that you have some plan in place to manage these panels so that only one of them are visible. Otherwise, make sure they are laid out in a grid or some other way so they don't appear on top of each other.
Where is your MouseListener implemented, since you are getting the panel from the MouseEvent. It's easier to have the panels implement the MouseListener and let them decide when to change color for themselves.
class Panel extends JPanel implements MouseListener {
public Panel() {
// Make sure the listener listens
addMouseListener(this);
}
#Override
public void mouseEntered(MouseEvent e) {
setColor(Color.blue);
}
// ... other mouselisteners can be ignored or implemented as needed
}
You can still keep a reference to some other class if you need it to be notified of a mouseenter. Just create a private member and set the reference in the constructor.
public void setColor(Color kleur) {
if(this.getBackground()==Color.white) {
this.setBackground(kleur);
repaint();
}
}
dont use == repalce with equals and try invalidate(. Your code is basically saying only replace background if background is white ???
I'd like to begin by saying this is an assignment. I do not want the answer spoon fed to me but I would like to know what is causing my problems.
I am currently implementing Conway's Game of Life. Clicking the cell should change the color, as to represent that cell being switched to an alive state. if clicked again, it should return to the default color.
When I click anywhere in the window, the program throws a Null Pointer Exception at line 56. Have been stuck on this for the last day or so, so any help is appreciated. Thanks!
Heres the code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class VisibleGrid extends JPanel implements MouseListener, KeyListener{
CellGrid cellGrid;
Graphics rect;
public VisibleGrid(){
addMouseListener(this);
cellGrid = new CellGrid();
}
//Draw the grid of cells, 7px wide, 75 times to create 75x75 grid
public void paint(Graphics g){
for(int i=0; i<525;i=i+7){
for(int j = 0; j<525; j=j+7){
g.drawRect(i ,j,7,7);
}
}
}
//auxillary method called to fill in rectangles
public void paint(Graphics g, int x, int y){
g.fillRect(x, y, 7, 7);
repaint();
}
//main method, adds this JPanel to a JFrame and sets up the GUI
public static void main(String[] args){
JFrame j = new JFrame("Conway's Game of Life");
j.setLayout(new BorderLayout());
j.add(new VisibleGrid(), BorderLayout.CENTER);
JTextArea info = new JTextArea("Press S to Start, E to End");
info.setEditable(false);
j.add(info, BorderLayout.SOUTH);
j.setSize(530,565);
j.setVisible(true);
}
//these methods are to satisfy the compiler/interface
//Begin Mouse Events
public void mouseExited(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseClicked(MouseEvent e){
//fill the selected rectangle
rect.fillRect(e.getX(), e.getY(), 7,7);
repaint();
//set the corresponding cell in the grid to alive
int row = e.getY() /7;
int column = e.getX() /7;
cellGrid.getCell(row, column).setAlive(true);
}
//End Mouse Events
//These methods are to satisfy the compiler/interface
//Begin KeyEvents
public void keyReleased(KeyEvent e){}
public void keyPressed(KeyEvent e){}
public void keyTyped(KeyEvent e){}
}
The problem here is that your rect field is never set to anything so it stays as null. Calling rect.drawRect will cause the NullPointerException you're seeing.
If I remember correctly, Swing Graphics objects don't really like you painting on them when they're not expecting you to be doing any painting. I would therefore recommend against stashing the Graphics object you get during a call to paint() in a field such as rect. If you want to repaint part of the window, it's better to tell Swing what part of the window needs repainting and then let it call your paint() method.
Within your mouseClicked() method, I removed the call to rect.fillRect() and moved the call to repaint() to the end of the method. I also modified the paint() method to draw a filled rectangle if the cell was alive and an unfilled one otherwise. After doing this, your code appeared to work, in that I could click on some cells and they would turn black.
I have a few suggestions for improvements to your code. I'll leave the last two as exercises for you:
I'd recommend adding the line j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); to main(). This line makes the application quit properly when you close the window.
At the moment, your code is repainting the entire 75 × 75 grid every time a single cell changes. It should be possible to change your code so that it repaints only the changed cell. You can pass a Rectangle to the repaint() method, which tells Swing 'only this part of my component needs to be repainted'. In the paint method, you can get hold of this rectangle using the getClipBounds() method of the Graphics class and use it to determine which cell or cells to repaint.
drawRect only draws the outline of a rectangle. If a cell dies, your paint method won't clear the existing black rectangle from the grid. You could fix this by drawing dead cells as a white filled rectangle with a black outline rectangle on top.
Are you sure the CellGrid objects has been filled with cells? I'm no Java expert but I don't see in your code this initialization...
I insert an image to a JPanel. I write this code.
public void paint(Graphics g)
{
img1=getToolkit().getImage("/Users/Boaz/Desktop/Piece.png");
g.drawImage(img1, 200, 200,null);
}
I want to add an action listener to that picture, but it does not have an addActionListener() method. How can I do that without putting the image in a button or label?
There are a few options.
Use a MouseListener directly in the JPanel
A simple but dirty way would be to add an MouseListener directly to the JPanel in which you overrode the paintComponent method, and implement a mouseClicked method which checks if the region where the image exists has been clicked.
An example would be something along the line of:
class ImageShowingPanel extends JPanel {
// The image to display
private Image img;
// The MouseListener that handles the click, etc.
private MouseListener listener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// Do what should be done when the image is clicked.
// You'll need to implement some checks to see that the region where
// the click occurred is within the bounds of the `img`
}
}
// Instantiate the panel and perform initialization
ImageShowingPanel() {
addMouseListener(listener);
img = ... // Load the image.
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
Note: An ActionListener can't be added to a JPanel, as a JPanel itself does not lend itself to create what is considered to be "actions".
Create a JComponent to display the image, and add a MouseListener
A better way would be to make a new subclass of JComponent whose sole purpose is to display the image. The JComponent should size itself to the size of the image, so that a click to any part of the JComponent could be considered a click on the image. Again, create a MouseListener in the JComponent in order to capture the click.
class ImageShowingComponent extends JComponent {
// The image to display
private Image img;
// The MouseListener that handles the click, etc.
private MouseListener listener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// Do what should be done when the image is clicked.
}
}
// Instantiate the panel and perform initialization
ImageShowingComponent() {
addMouseListener(listener);
img = ... // Load the image.
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
// This method override will tell the LayoutManager how large this component
// should be. We'll want to make this component the same size as the `img`.
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
}
The easiest way is to put the image into a JLabel. When you use the program, it appears to just be the image, you can't tell its in a JLabel. Then just add a MouseListener to the JLabel.