It won't paint at all, any ideas?
Nothing is displayed on the back panel, how do I get to paint with the mouseDragged event?
I can't even display a single line with that... Here's the source code.. I added the Jbutton just to see if the Panel was actually being displayed
public class pinta extends JFrame {
HandlerClass handler=new HandlerClass();
JPanel back=new JPanel();
public pinta(){
setSize(500,500);
setResizable(true);
getContentPane().setLayout(new BorderLayout());
back.setBackground(Color.white);
back.setSize(500,500);
this.add(back);
back.add(new JButton("test"));
back.addMouseMotionListener(handler);
back.setOpaque(true);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.black);
Graphics2D g2d = (Graphics2D)g;
g2d.fillOval(100, 100, 20, 10);
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
}
public class HandlerClass implements MouseMotionListener{
int x, y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void mouseDragged(MouseEvent e) {
x=e.getX();
y=e.getY();
}
public void mouseEntered(MouseEvent e){
}
public void mouseMoved(MouseEvent e) {
}
}
}
JFrame does not have a method call paintComponent. If you used the #Override annotation, the compiler would have failed.
Also note, you are calling super.paintComponents - Notice the "s" at the end, this should have being an interactor of problems
JComponent (or JPanel which extends JComponent) is what you're after.
Take a look at Performing Custom Painting for more details
I should also mention that back.setSize(500,500) is irrelevant, as the layout manager will decide what size it wants to make the component
Related
I'm trying to make the game snake and have run into an issue. What I have is a class called Segment which is used to create the objects that hold the x- and y-positions and also the direction of the snake. The class extends JPanel and overrides the method paintComponent(). I then add an object of type Segment to a JFrame in a different class. The methods I have for moving/changing directions of the snake (actually just a square at the moment) work perfectly but my problem is this:
When the square gets to about half of the width of the frame or half of the height of the frame it stops being drawn. I have made the background of the JPanel light grey so I know that the square hasn't reached the end of the JPanel when it stops. Below is my simple paintComponent() method and the section in the class that extends JFrame where I add the object.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.LIGHT_GRAY);
g.setColor(Color.black);
g.fillRect(xpos, ypos, width, height);
}
public Snake() {
setLayout(new BorderLayout());
addKeyListener(l);
segment = new Segment(100, 100, Segment.Dir.RIGHT);
segment.setPreferredSize(new Dimension(500,500));
add(segment, BorderLayout.CENTER);
timer.start();
setVisible(true);
pack();
setTitle("Snake");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
I also know that the objects position doesn't stop being updated so it's just the drawing of the square in the entire panel/frame that's the issue. Appreciate any help!
Here's an MCVE:
import java.awt.*;
import javax.swing.*;
public class Segment extends JPanel {
private int width = 10;
private int height = 10;
private int xpos, ypos;
private Dir dir;
public enum Dir {
LEFT, RIGHT, UP, DOWN;
}
public Segment() {
xpos = 0;
ypos = 0;
dir = Dir.RIGHT;
}
public Segment(int x, int y, Dir d) {
xpos = x;
ypos = y;
dir = d;
}
public Dir getDir() {
return dir;
}
public void setDir(Dir d) {
dir = d;
}
public void setX(int x) {
xpos = x;
repaint();
}
public void setY(int y) {
ypos = y;
repaint();
}
public int getX() {
return xpos;
}
public int getY() {
return ypos;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.LIGHT_GRAY);
g.setColor(Color.black);
g.fillRect(xpos, ypos, width, height);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Snake extends JFrame implements ActionListener {
Segment segment;
Timer timer = new Timer(50, this);
public Snake() {
setLayout(new BorderLayout());
setSize(500,500);
segment = new Segment(100, 100, Segment.Dir.RIGHT);
segment.setPreferredSize(new Dimension(getWidth(),getHeight()));
add(segment, BorderLayout.CENTER);
timer.start();
setVisible(true);
setTitle("Snake");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == timer) {
segment.setX((segment.getX() + 4 + getWidth())%getWidth());
}
}
public static void main(String[] arg) {
new Snake();
}
}
Don't override getX() and getY() of the Segment class.
Those are methods of all Swing components. They get the current location of the component within the parent container.
Use different method names to control the location of the painting of your snake. Since your variable names are xPos and yPos maybe use getXPos() and getYPos().
So what happens is that the snake is drawn at xPos/yPos relative to the Segment panel and the Segment panel is also drawn at xPos/yPos relative to its parent container.
I got my code running so far, except for the recursive part. I get a StackOverflow error and I really don't get why, or how to fix it. When I work through the code it seems logically fine.
public class SierpinskiTriangle {
public static int SIZE = 1000;
JFrame frame;
JPanel panel;
#SuppressWarnings("serial")
public void display() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paint(Graphics g) {
super.paint(g);
paintSierpinskiTriangle(20, 20, 360, (Graphics2D)g);
}
};
panel.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
panel.repaint();
}
});
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setSize(SIZE, SIZE);
frame.setVisible(true);
}
public static void main(String[] args) {
SierpinskiTriangle triangle = new SierpinskiTriangle();
triangle.display();
}
public static void paintSierpinskiTriangle(int x, int y, int s, Graphics2D g) {
g.drawLine(x, y, x+s, y);
g.drawLine(x, y, x, y+s);
g.drawLine(x+s, y, x, y+s);
paintSierpinskiTriangle(x, y, s/2, g);
paintSierpinskiTriangle(x+s/2, y, s/2, g);
paintSierpinskiTriangle(x, y+s/2, s/2, g);
}
}
You need to add some conditions to return from the paintSierpinskiTrianglemethod.
Without any conditions, it will keep calling itself infinitely, even if s = 0, which is what causes the Error.
I have a panel which contains custom components that have been added to it. It paints correctly except when the components (which have their own mouselisteners) are being dragged it starts to paint weirdly.
Interestingly if I slightly re-size the parent panel it will now paint as intended. I know that the parent panel is being repainted through
super.paintComponent(g);
and a print statement inside the panels
paintComponent(Graphics g):
method. I tried revalidating when the component is dragged around (as the component is having its bounds re-set) it becomes invalidated. Still I am having no success and was wondering if anyone could help.
Is there some place where i am not repainting correctly that might be causing this behavior?
Also as an addendum I have a mouse listener on both the panel and its components, is there a way so that when a component is clicked the panel mouse listener also responds (beyond going back up to the parent class from the component)
Here is a working example of the issue I am having
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.*;
public class testHome {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testHome window = new testHome();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public testHome() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new myPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
}
}
class myPanel extends JPanel {
MyComponent comp;
public myPanel() {
super(null);
comp = new MyComponent(5, 5);
this.add(comp);
revalidate();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Line2D.Double line = new Line2D.Double(10, 10, comp.getX(), comp.getY());
System.out.println(comp.getX() + " " + comp.getY());
g2d.draw(line);
}
}
class MyComponent extends JComponent implements MouseListener, MouseMotionListener {
int x;
int y;
int mx;
int my;
public MyComponent(int x, int y) {
this.setVisible(true);
this.setBounds(x, y, 15, 15);
this.x = x;
this.y = y;
addMouseMotionListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.black);
g2d.fillRect(this.x, this.y, 15, 15);
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("dragging");
int dx = e.getX() - mx;
int dy = e.getY() - my;
this.setBounds(this.getX() + dx, this.getY() + dy, 15, 15);
}
#Override
public void mousePressed(MouseEvent e) {
mx = e.getX();
my = e.getY();
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
}
The parent panel does not actually get automatically repainted completely. paintComponent() is called, but if you check the clipping, for example by:
System.out.println(g.getClipBounds());
you'll see that only the area below the smaller component is painted. (The component is not opaque, so the parent component needs to paint the area below it). You need to call repaint() explicitly for the parent panel:
getParent().repaint();
(Or using the repaint() variants that specify the region, if the parent component is expensive to draw and can optimize partial draws).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a combobox in which I can choose to draw either a rectangle, a circle or by freehand.
If I choose to draw a circle it draws it perfectly. If I then switch to draw a rectangle it draws a circle inside the rectangle. The same happens if I first choose to draw a rectangle and then a circle. (See Picture below)
My questions are:
How can I switch between drawing a circle and a rectangle without the circle appearing inside the rectangle?
How can I get the rectangle/circle to show while I'm dragging the mouse. What I mean is how can the lines show until I release the mouse click?
Why doesn't it work drawing by free hand?
This is my testclass:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class Lab6 extends JFrame implements ActionListener {
int startX, startY, endX, endY, w, h;
ArrayList<Shape> shapeList = new ArrayList<Shape>();
Container cp = getContentPane();
private JPanel topPanel;
private JComboBox comboBox;
private final String[] boxOptions = new String[] {"Rektangel", "Cirkel", "Frihand"};
public Lab6(String title) {
super(title);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(840, 500);
this.initComponents();
this.setVisible(true);
}
private void initComponents() {
topPanel = new JPanel(new GridLayout(1,2));
topPanel.setPreferredSize(new Dimension(0,40));
comboBox = new JComboBox(boxOptions);
comboBox.setSelectedIndex(0);
comboBox.addActionListener(this);
topPanel.add(comboBox);
this.add(topPanel, BorderLayout.PAGE_START);
}
#Override
public void paint(Graphics g) {
for (Shape s : shapeList) {
s.draw(g);
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(comboBox)) {
JComboBox cb = (JComboBox)e.getSource();
if (cb.getSelectedItem().equals("Rektangel")) {
cp.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Rectangle r = new Rectangle(startX, startY, w, h);
shapeList.add(r);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Cirkel")) {
cp.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
int width = startX - endX;
int height = startY - endY;
w = Math.abs(width);
h = Math.abs(height);
Circle c = new Circle(startX, startY, w, h);
shapeList.add(c);
repaint();
}
});
}
else if (cb.getSelectedItem().equals("Frihand")) { //I need help with this part
cp.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
}
#Override
public void mouseDragged(MouseEvent e) {
FreeHand fh = new FreeHand(startX, startY, e.getX(), e.getY());
shapeList.add(fh);
repaint();
}
});
}
}
}
public static void main(String args[]) {
new Lab6("Drawing Program");
}
}
In class Rectangle (class Circle looks the same):
import java.awt.*;
public class Rectangle extends Shape {
public Rectangle(int x, int y, int width, int height) {
super(x, y, width, height);
}
public Rectangle() {
super();
}
#Override
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(4));
g.drawRect(getX(), getY(), getWidth(), getHeight());
}
}
In class FreeHand (I need help with this part):
import java.awt.*;
public class FreeHand extends Shape {
public FreeHand(int x, int y, int width, int height) {
super(x, y, width, height);
}
public FreeHand() {
super();
}
#Override
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.setStroke(new BasicStroke(4));
g2.drawLine(getX(), getY(), getWidth(), getHeight());
}
}
In class shape:
import java.awt.Graphics;
import javax.swing.JPanel;
public abstract class Shape extends JPanel {
private int startX, startY, width, height;
public Shape() {
this(0, 0, 1, 1);
}
public Shape(int startX, int startY, int width, int height) {
this.startX = startX;
this.startY = startY;
this.width = width;
this.height = height;
}
public abstract void draw(Graphics g);
#Override
public int getX() {
return startX;
}
#Override
public int getY() {
return startY;
}
#Override
public int getWidth() {
return width;
}
#Override
public int getHeight() {
return height;
}
}
There are a multitude of things going on...
Overriding paint of JFrame
Not calling super.paint before performing custom painting.
Adding a new MosueListener EVERY time you change the shape
Instead, create a custom component, extending from something like JPanel and override it's paintComponent method. Use this component has your basic drawing surface (your controls should contained in another component).
Make sure you call super.paintComponent before performing any custom painting so you don't break the paint chain
See Performing Custom Painting and Painting in AWT and Swing for more details
Create a SINGLE MouseListener and register it to the panel. When the use selects a different shape, change a state variable within the panel (via a setter) which tells the MouseListener what it should do when the user starts drawing.
Updated...
Create a custom class that extends from JPanel...
public static class ShapePane extends JPanel {
}
Override the classes paintComponent method...
public static class ShapePane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Custom Painting here...
}
}
Provide some sizing hints for the layout manager...
public static class ShapePane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Custom Painting here...
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
Provide a means by which the type of shape can be changed...so you know what to paint...
public static class ShapePane extends JPanel {
public enum ShapeType {
CIRCLE,
RECTANGLE
}
private ShapeType currentShapeType;
public void setCurrentShapeType(ShapeType currentShapeType) {
this.currentShapeType = currentShapeType;
}
public ShapeType getCurrentShapeType() {
return currentShapeType;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Custom Painting here...
}
}
Add a SINGLE MouseListener to the custom class to create the required type of shapes...
public static class ShapePane extends JPanel {
public enum ShapeType {
CIRCLE,
RECTANGLE
}
private ShapeType currentShapeType;
public ShapePane() {
addMouseListener(new MouseAdapter() {
private Point clickPoint;
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
}
#Override
public void mouseReleased(MouseEvent e) {
Point releasePoint = e.getPoint();
int x = Math.min(releasePoint.x, clickPoint.x);
int y = Math.min(releasePoint.y, clickPoint.y);
int width = Math.abs(clickPoint.x - releasePoint.x);
int height = Math.abs(clickPoint.y - releasePoint.y);
switch (getCurrentShapeType()) {
case CIRCLE:
// Make a circle
break;
case RECTANGLE:
// Make a rectangle...
break;
}
repaint();
}
});
}
public void setCurrentShapeType(ShapeType currentShapeType) {
this.currentShapeType = currentShapeType;
}
public ShapeType getCurrentShapeType() {
return currentShapeType;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Custom Painting here...
}
}
Fill in the blanks...
Create another JPanel (you can simply create an instance this time), add your controls to it
Create an instance of a JFrame, add the custom class to it and the controls panel (make sure they are laid out correctly so they don't override each other - see Laying Out Components Within a Container for more details)
Use appropriate listeners to the controls to determine the type of shape the user wants to draw and set the currentShapeType property accordingly...
I have a problem, when i call repaint() on JDialog, I see nothing on the screen, but when i move the JDialog by my self, I see what i wanted to paint.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class dude extends JFrame {
private static int cnt = 0;
public dude() {
super("ff");
makeFrame();
}
public void makeFrame() {
new Dialog(this);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setSize(400, 400);
setVisible(true);
}
private class Dialog extends JDialog {
public Dialog(JFrame frame) {
super(frame, "ff", true);
makeFrame();
}
public void makeFrame() {
getContentPane().addMouseListener(new M(this));
setDefaultCloseOperation(HIDE_ON_CLOSE);
pack();
setLocation(200, 200);
setSize(400, 400);
setVisible(true);
}
private class M extends MouseAdapter {
private JDialog dialog;
public M(JDialog dialog) {
this.dialog = dialog;
}
public void mouseClicked(MouseEvent e) {
P p = new P(e.getX(), e.getY());
p.repaint();
dialog.add(p);
}
private class P extends JPanel {
private int x, y;
public P(int x, int y) {
this.x = x;
this.y = y;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawOval(x, y, 10, 10);
}
/*public void paint(Graphics g)
{
g.setColor(Color.black);
g.drawOval(x,y,10,10);
}*/
}
}
}
}
That's weirdest piece of code I've seen for a while, but. You're immeditate problem is with you mouseClicked event...
Replace your p.repaint call with a call to the dialogs revalidate method.
P p = new P(e.getX(), e.getY());
dialog.add(p);
dialog.revalidate();
Your repaint method would have done nothing any way, it was being called before you panel was realized (connected to the screen)
Seems like you need to look into the coding style you adhering to. Though, leave that for latter part, simply add this method to your M Class
public void setValues(int x, int y)
{
this.x = x;
this.y = y;
repaint();
}
And make p an Instance Variable of your Dialog Class. And inside your mouseClicked() method, simply call this method. And remove the constructor part, since you initializing a new JPanel for each drawing which I guess is not good in any sense. When you simply can draw the new thingy on the same JPanel