This is my code:
JFrame frame = new JFrame();
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel1 = new JPanel(){
#Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
for (int i = 0; i < w; i+=100) {
g.drawLine(i, 0, i, h);
}
}
};
panel1.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseClicked(MouseEvent arg0) {
int x = arg0.getX();
int y = arg0.getY();
Graphics g = (Graphics) panel1.getGraphics();
g.setColor(Color.black);
g.fillOval(x, y, 100, 100);
}
});
frame.add(panel1);
frame.setVisible(true);
What it does is when i click on frame a circle is drawn. after drawing some circles when i maximize or minimize or resize my frame the circles gets disappeared. how can I solve it?
You should override paintComponent() method of the panel. The circles should be added in a list. In the paintComponent() call super and then iterate through the list painting each circle.
Related
I have a task in university to draw an ellipse and make it move step by step on the screen pressing the button only once. Here is my code:
public class Window extends JPanel {
private static Ellipse2D.Double Ellipse;
private JFrame frame;
public Window() {
super();
int width = 20;
int height = 30;
Ellipse = new Ellipse2D.Double(width, height, 100, 50);
}
public Dimension getPreferredSize()
{
return (new Dimension(frame.getWidth(), frame.getHeight()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D brush = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
g.clearRect(0, 0, width, height);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
brush.draw(Ellipse);
}
public class MoveCircle implements KeyListener, ActionListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Working on top!");
double newX = 0; double newY = 0;
if (e.getKeyCode() == Event.ENTER) {
for (int i = 0; i < 26; i ++)
{
System.out.println("Working on bottom!");
newX = Ellipse.x + 10;
Ellipse.x = newX;
newY = Ellipse.y + 10;
Ellipse.y = newY;
repaint();
}
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
private void createAndDisplayGUI(Window window)
{
frame = new JFrame();
Container container = frame.getContentPane();
container.add(window);
window.addKeyListener(new MoveCircle());
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
window.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Window window = new Window();
window.createAndDisplayGUI(window);
}
});
}
}
Although I call the function repaint() in cycle each time still the ellipse just moves radically from the original point to the point defined in the last iteration without drawing position of the ellipse in each iteration.
Is it possible to use a Swing Timer to make it repaint the ellipse in each iteration? I will be very glad to get help in this.
You have two problems: The first is that your loop is being run on the UI thread. The second is your misunderstanding in how repaint works. All repaint does is adds a request to the UI thread to do a repaining. It doesn't perform a repaint in and of itself. So if you are running operations on the UI thread, calling it multiple times will have no effect. As you suggested, you can fix this with a Swing Timer, as I've put together below
ActionListener al = new ActionListener() {
int iterations = 0;
public void actionPerformed(ActionEvent ae) {
if (iterations == 25) {
timer.stop();
}
interations++;
System.out.println("Working on bottom!");
newX = Ellipse.x + 10;
Ellipse.x = newX;
newY = Ellipse.y + 10;
Ellipse.y = newY;
repaint();
}
};
final timer = new javax.swing.Timer(delay, al);
timer.start();
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).
I found similar problems on the internet but the solutions provided didn't work.
I want to clear the JPanel. To do that I call repaint()(from the clear() method) with a flag set to false to avoid calling my drawing method (drawLines()). Drawn lines are still on the Panel.
I tried to repaint same lines again with the background color. This also didn't work.
public class WektPanel extends JPanel{
boolean check = false;
Color c = Color.BLUE;
boolean oval = false;
public WektPanel() {
setBackground(c);
setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(check)
drawLines(3, g);
}
void clear(){
check=false;
repaint();
}
void draw(){
check=true;
repaint();
}
void drawLines(int stroke, Graphics g){
g.drawLine(0,0,getWidth(),getHeight());
g.drawLine(0,getHeight(),getWidth(),0);
for(int i=1; i<stroke;i++){
g.drawLine(0+i,0,getWidth(),getHeight()-i);
g.drawLine(0,0+i,getWidth()-i,getHeight());
g.drawLine(0,getHeight()-i,getWidth()-i,0);
g.drawLine(0+i,getHeight(),getWidth(),0+i);
}
}
}
You're overriding paint(), but calling super.paintComponent(g). You should override paintComponent(g).
Edit: I couldn't follow your check logic. This worked for me.
public class Test {
private class WektPanel extends JPanel {
boolean clear;
public WektPanel() {
setBackground(Color.BLUE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawLines(3, g);
}
public void clear() {
clear = true;
repaint();
}
public void draw() {
clear = false;
repaint();
}
private void drawLines(int stroke, Graphics g) {
if (!clear) {
g.drawLine(0, 0, getWidth(), getHeight());
g.drawLine(0, getHeight(), getWidth(), 0);
for (int i = 1; i < stroke; i++) {
g.drawLine(0 + i, 0, getWidth(), getHeight() - i);
g.drawLine(0, 0 + i, getWidth() - i, getHeight());
g.drawLine(0, getHeight() - i, getWidth() - i, 0);
g.drawLine(0 + i, getHeight(), getWidth(), 0 + i);
}
}
}
}
private void showGUI() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WektPanel wektPanel = new WektPanel();
f.add(wektPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
wektPanel.clear();
}
}));
buttonPanel.add(new JButton(new AbstractAction("Draw") {
#Override
public void actionPerformed(ActionEvent e) {
wektPanel.draw();
}
}));
f.add(buttonPanel, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().showGUI();
}
});
}
}
The first line in the paint method should be something like:
g.clearRect(0, 0, getWidth(), getHeight());
This way you make sure that the previous paints will not be there when you start painting again.
I am trying to move a circle left with a keyEvent. So far, the circle is drawn on the window but it does not move left! I feel like the problem is where I add the Window() constructor to the container. The is no output on the console to tell me that it is working. So I dont think it even reaches the KeyEvent class. Here is my code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class Window extends JPanel {
private static Ellipse2D.Double circle;
public Window() {
super();
int width = 400;
int height = 400;
circle = new Ellipse2D.Double(0.5 * width, 0.9 * height,
0.1 * width, 0.05 * height);
addKeyListener(new MoveCircle());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D brush = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
g.clearRect(0, 0, width, height);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
brush.draw(circle);
}
public class MoveCircle implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Working on top!");
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Working on bottom!");
circle.x++;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public static void main(String[] args) {
Window window = new Window();
JFrame frame = new JFrame();
Container container = frame.getContentPane();
container.add(new Window());
frame.addKeyEvent(window.new MoveCircle());
frame.setSize(800, 700);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Actually what is happening is this, you are adding Window to the JFrame, but the focus lies with the JFrame, so when you type on your Keyboard that thing goes to the JFrame not the KeyListener attached to the Window class. So in order to get over it, you simply have to call requestFocusInWindow() on the Window class's Object. Try this code, I had done some modification regarding EDT and stuff.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class Window extends JPanel {
private static Ellipse2D.Double circle;
private JFrame frame;
public Window() {
super();
int width = 400;
int height = 400;
circle = new Ellipse2D.Double(0.5 * width, 0.9 * height,
0.1 * width, 0.05 * height);
}
public Dimension getPreferredSize()
{
return (new Dimension(frame.getWidth(), frame.getHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D brush = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
g.clearRect(0, 0, width, height);
brush.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
brush.draw(circle);
}
public class MoveCircle implements KeyListener {
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Working on top!");
if (e.getKeyCode() == Event.ENTER) {
System.out.println("Working on bottom!");
double newX = circle.x - 1;
circle.x = newX;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
private void createAndDisplayGUI(Window window)
{
frame = new JFrame();
Container container = frame.getContentPane();
container.add(window);
window.addKeyListener(new MoveCircle());
frame.setSize(800, 700);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
window.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Window window = new Window();
window.createAndDisplayGUI(window);
}
});
}
}
Only the focussed component will get key events. You need to call requestFocus() at some point.
A solution would be, to add the KeyListener to the JFrame. This way all the key strokes will throw an event, when the JFrame has the focus.
package test;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class test_bmp extends JPanel implements MouseListener,MouseMotionListener,ActionListener
{
static BufferedImage image;
Color color;
Point start=new Point();
Point end =new Point();
JButton elipse=new JButton("Elipse");
JButton rectangle=new JButton("Rectangle");
JButton line=new JButton("Line");
String selected;
public test_bmp()
{
color = Color.black;
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(this);
addMouseMotionListener(this);
}
public void paintComponent(Graphics g)
{
//super.paintComponent(g);
g.drawImage(image, 0, 0, this);
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(Color.black);
if(selected=="elipse")
{
g2.drawOval(start.x, start.y, (end.x-start.x),(end.y-start.y));
System.out.println("Start : "+start.x+","+start.y);
System.out.println("End : "+end.x+","+end.y);
}
if(selected=="line")
g2.drawLine(start.x,start.y,end.x,end.y);
}
//Draw on Buffered image
public void draw()
{
Graphics2D g2 = image.createGraphics();
g2.setPaint(color);
System.out.println("draw");
if(selected=="line")
g2.drawLine(start.x, start.y, end.x, end.y);
if(selected=="elipse")
{
g2.drawOval(start.x, start.y, (end.x-start.x),(end.y-start.y));
System.out.println("Start : "+start.x+","+start.y);
System.out.println("End : "+end.x+","+end.y);
}
repaint();
g2.dispose();
}
public JPanel addButtons()
{
JPanel buttonpanel=new JPanel();
buttonpanel.setBackground(color.lightGray);
buttonpanel.setLayout(new BoxLayout(buttonpanel,BoxLayout.Y_AXIS));
elipse.addActionListener(this);
rectangle.addActionListener(this);
line.addActionListener(this);
buttonpanel.add(elipse);
buttonpanel.add(Box.createRigidArea(new Dimension(15,15)));
buttonpanel.add(rectangle);
buttonpanel.add(Box.createRigidArea(new Dimension(15,15)));
buttonpanel.add(line);
return buttonpanel;
}
public static void main(String args[])
{
test_bmp application=new test_bmp();
//Main window
JFrame frame=new JFrame("Whiteboard");
frame.setLayout(new BorderLayout());
frame.add(application.addButtons(),BorderLayout.WEST);
frame.add(application);
//size of the window
frame.setSize(600,400);
frame.setLocation(0,0);
frame.setVisible(true);
int w = frame.getWidth();
int h = frame.getHeight();
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
g2.setPaint(Color.white);
g2.fillRect(0,0,w,h);
g2.dispose();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent event)
{
start = event.getPoint();
}
#Override
public void mouseReleased(MouseEvent event)
{
end = event.getPoint();
draw();
}
#Override
public void mouseDragged(MouseEvent e)
{
end=e.getPoint();
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==elipse)
selected="elipse";
if(e.getSource()==line)
selected="line";
draw();
}
}
I need to create a paint application. When I draw ellipse by dragging mouse from left to right it displays nothing. Why? Should I use any other function here?
Your program does draw an ellipse when you drag the mouse down and to the right. It's dragging up and/or left that does not work, because Graphics.drawOval does not work with a negative width or height.
Try adding a method like this:
private Shape createEllipse() {
Ellipse2D e = new Ellipse2D.Double();
e.setFrameFromDiagonal(start, end);
return e;
}
Then call it from draw and paintComponent like this:
if(selected=="elipse") {
g2.draw(createEllipse());
}
Also you probably do not need the call to draw() at the end of actionPerformed. If you switch between line and ellipse mode it will draw an ellipse with the same coordinates as the most recent line or vice-versa.
And one coding style issue: Using string literals for selected is confusing (although it does work.) I would define an enum instead.