Nothing happens on pressing the Button, what I am doing wrong?? I want the Rectangle to be drawn on pressing the button. What's wrong with the code??
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
class rectangle{
public static void main(String args[]){
EventQueue.invokeLater(new Runnable(){
public void run(){
final JFrame frame=new JFrame("RECTANGLE");
final JPanel panel=new JPanel();
JButton button=new JButton("DRAW");
panel.add(button);
frame.add(panel);
frame.setSize(400,400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
panel.add(new drawrectangle());
}
});
}
});
}
}
class drawrectangle extends JComponent{
public void paintComponent(Graphics g){
Graphics2D g2=(Graphics2D) g;
g2.setPaint(Color.PINK);
Rectangle2D rect=new Rectangle2D.Double(50,50,200,200);
g2.draw(rect);
g2.fill(rect);
}
}
You need to call repaint() on your JFrame.
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
drawrectangle rec= new drawrectangle();
panel.add(rec);
rec.paintComponent();
frame.repaint();
}
});
Simply write :
frame.validate();
frame.repaint();
Your component has no size. You need to either override getPreferredSize() and return the size of your rectangle, or else you need to set its size in its constructor by calling setSize(). The reason your rectangle doesn't appear is because it is drawing outside of its area, and the Java 2D graphics are clipping the portion you are drawing outside the component (that is, all of it).
It is not the case that you need to either call repaint() or validate() because when you add the rectangle to the panel, it will automatically lay itself out again and mark itself as needing a repaint.
However, be aware that you are adding a new rectangle every time the event fires. Is that what you want? Also, rectangle and drawrectangle should begin with capital letters to conform to the normal Java naming conventions, although there is also a java.awt.Rectangle class, so Rectangle might not be the best name to use.
Just add window.visibility to true.
Related
I'm practising to draw a shape on a JPanel by clicking on a Jbutton, but I cannot. It's been five hours that I'm surfing the web, but I cannot find the way to do it.
This is what I want to do: if I click on "Rectangle" button a rectangle appears under the buttons and if I click on "Circle" button a circle appears.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Shape extends JFrame {
JButton rec, circle;
static String botSelected;
Shape (){
frameSet ();
}
void frameSet(){
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600,300);
rec = new JButton ("Rectangle");
circle = new JButton("Circle");
JPanel panel = new JPanel();
frame.add(panel);
panel.add(rec);
panel.add(circle);
Click clk = new Click();
rec.addActionListener(clk);
circle.addActionListener(clk);
}
public void paint (Graphics g){
super.paint(g);
if (botSelected.equals("Rectangle"))
g.fillRect(50,50,50,50);
else if (botSelected.equals("Circle"))
g.fillOval(50,50,50,50);
}
public static void main (String [] arg){
Shape s = new Shape();
}
}
class Click implements ActionListener{
public void actionPerformed (ActionEvent e){
Shape.botSelected = e.getActionCommand();
}
}
The first thing I would do is have a read through Painting in Swing and Performing custom painting to better understand how the painting process works.
Next you need to understand that JFrame is a bad choice for painting to. Why? Because it's multilayered.
A JFrame contains a JRootPane, which contains a JLayeredPane the contentPane, glassPane and the JMenuBar and in your example, it also contains a JPanel.
With the (default) exception of the glassPane, all these components are opaque.
While it's possible to have something drawn in the paint method show it, if any of the other components paint themselves, it will be wiped clean - this is because Swing components can actually be painted independently of each other, with having to have the parent paint itself first.
A better solution is to start by extending from JPanel and override its paintComponent method.
For simplicity, I'd also encourage you to implement the ActionListener against this class as well, it will allow the actionPerformed method to access the properties of the component and, in your case, call repaint to trigger a paint cycle when you want to update the UI.
Here is a derived example from your code.
As #MadProgrammer said, don't extend JFrame.
In the following example, here are the major changes :
give a non-null value to botSelected, or the first calls to paintComponent will give you a NullPointerException
the class now extends JPanel, and overrides paintComponent for custom painting
the ActionListener is an anonymous class, because you don't need a separate class, and it has direct access to the fields from Shape
botSelected is no longer static (see above point)
.
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Shape extends JPanel {
JButton rec, circle;
String botSelected = "";// don't let it be null, it would make paintComponent crash on startup
Shape() {
frameSet();
}
void frameSet() {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setSize(600, 300);
rec = new JButton("Rectangle");
circle = new JButton("Circle");
frame.add(this);
this.add(rec);
this.add(circle);
// anonymous class, has access to fields from the outer class Shape
ActionListener clk = new ActionListener() {
public void actionPerformed(final ActionEvent e) {
botSelected = e.getActionCommand();
repaint();
}
};
rec.addActionListener(clk);
circle.addActionListener(clk);
}
//custom painting of the JPanel
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if (botSelected.equals("Rectangle")) {
g.fillRect(50, 50, 50, 50);
} else if (botSelected.equals("Circle")) {
g.fillOval(50, 50, 50, 50);
}
}
public static void main(final String[] arg) {
Shape s = new Shape();
}
}
I have a program where I have a JFrame with a JButton in it. When the user clicks the JButton, all Components of the JFrame are removed, and a JPanel with red background is added to it.
When I click the JButton, that red JPanel does not become visible unless I resize the JFrame (I am using Windows 7). Is there a way to achieve what I want without having to manually resize the JFrame?
Here is a part of the code I am using:
public class Demo implements ActionListener{
public static void main(String args[]){
...............
button.addActionListener(this); //'button' is an object of Jbutton class.
frame.setVisible(true); //'frame' is an object of JFrame class.
............
}
public void actionPerformed(ActionEvent ae){
frame.removeAllComponents();
frame.add(panel1); //panel1 is an object of Jpanel class with red background.
/* Here is where my problem lies.
panel1 is not visible to me unless I manually resize the JFrame. */
}
}
For removing (and then, for example, add new JComponents) JComponents from JPanel or from top-level containers you have to call, only once and on the end of the action:
revalidate();
repaint();
And if you only resize or change JComponents:
validate();
repaint();
For me, this was a bit of an oddity. As it turned out, invoking remove(Component comp), adding the new JPanel, and then invoking pack() worked for me.
public class Demo{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
createAndShowGUI();
}
});
}
private static void createAndShowGUI(){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
final JButton button = new JButton("Press Me");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
frame.remove(panel);
final JPanel redPanel = new JPanel(){
#Override
public Dimension getPreferredSize(){
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g){
Graphics g2 = g.create();
g2.setColor(Color.RED);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.dispose();
}
};
frame.add(redPanel);
frame.pack();
}
});
panel.add(button);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
BEFORE PRESSING THE BUTTON
AFTER PRESSING THE BUTTON
ODDITIES
Invoking removeAll() actually caused the GUI to freeze. It seems that this event has occurred before. This occurred even after I attempted to remove the action listener prior to removal of all components.
I did not need to invoke any of the validate methods, or even repaint the GUI.
you have to force a repaint() in the frame so the frame have to repaint itself.
I'm new here. Been reading questions and answers for aeons. Recently I found time to start studying Java, and I'm seriously enjoying the process. Until I started to write some code. The getting stuck is killing me. So I've come to seek advice on something extremely simple but I cannot crack it.
The code below attempts to create a frame, maximize it, and place elements inside. I was just fooling around. First the button1, I tried to change its size (so I got it into a FlowLayout). Then a button in the mainPanel, just to... try. Then an oval. I tried for 2 hours to get the oval to display but it is Impossible. When I found about "drawOval" I thought that was it but it made no difference. And to think that I was planning for the button1 to create Moving Balls. I'm so, So far away from that.
Please, why does the silly Oval refuse to display itself. Help.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainClass {
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel southPanel = new JPanel();
JButton button1 = new JButton("Button1");
JButton button2 = new JButton("Button2");
Oval oval = new Oval();
public static void main(String[] args) {
MainClass program = new MainClass();
program.go();
}
public void go() {
buildGUI();
}
public void buildGUI() {
button1.setBorder(BorderFactory.createMatteBorder(2,2,2,2, Color.BLACK));
button1.addActionListener(new Button1Listener());
frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
button1.setPreferredSize(new Dimension(200, 50));
frame.getContentPane().add(BorderLayout.SOUTH, southPanel);
southPanel.add(button1);
mainPanel.add(button2);
mainPanel.add(oval);
frame.setSize(400, 400);
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
class Button1Listener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
//What the button will do.
}
}
}
And the Oval part
import java.awt.*;
import javax.swing.*;
public class Oval extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.orange);
g.fillOval(20, 50, 100, 100);
}
}
JPanel uses a FlowLayout by default. Since you Oval class doesn't provide any sizing hints, then it's set to a default size of 0x0.
Start by updating your class to something more like...
public class Oval extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 150);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.orange);
g.fillOval(20, 50, 100, 100);
}
}
to create Moving Balls.
Ok, you might want to have a look at:
java bounceBall mouse escape
paintComponent not working
In a program I'm building for my class I have the same class extending a Swing JPanel and implementing MouseListener, for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel.
But when I click in the window, repaint() the MouseClicked method in the mouse listener fails to call the first object's paintComponent() method. For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestPanel extends JPanel implements MouseListener{
static boolean black;
static TestPanel test = new TestPanel();
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseClicked(MouseEvent e){ //Expected behavior: the square turns black immediately
System.out.println("CLICK!");
black = true;
test.repaint(); //this fails
try{
Thread.sleep(3000);
}catch(Exception ex){}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
System.out.println("Painting...");
g2d.setColor(Color.white);
if(black){
g2d.setColor(Color.black);
}
g2d.fillRect(0, 0, 200, 200);
}
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.addMouseListener(new TestPanel());
test.setPreferredSize(new Dimension(200, 200));
frame.add(test);
frame.pack();
frame.setVisible(true);
while (true){
black = false;
test.repaint();
Thread.sleep(100);
}
}
}
If you watch what happens on a click, the screen stays white for the 3 seconds after the click is registered, until the loop starts up again, i.e., the repaint() call in the mouse listener didn't work. Why does this happen?
I'm guessing it would work if I made different classes for the objects, but I'm mostly curious as to why it doesn't work this way.
for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel.
There is no need to do that. All you need is a single instance of the TestPanel class.
In the constructor of your TestPanel class you just add:
addMouseListener( this);
The get rid of the static variable for the TestPanel class.
Then the code in your main method should look something like:
//test.addMouseListener(new TestPanel());
//test.setPreferredSize(new Dimension(200, 200));
//frame.add(test);
frame.add( new TestPanel() );
Also, the TestPanel class should override the getPreferredSize() method to return the Dimension of your panel.
Read the section from the Swing tutorial on Custom Painting for a working example with a MouseListener.
The AWT thread is responsible for calling MouseListener and for repaint.
Inside the repaint(); method, the AWT thread is told to call the paint();
Just call it using a different thread. In general, it is a bad idea to do anything intensive with the AWT thread. It already does a lot, taking too much of its time will mess your GUI up.
Depending on your needs, this might work:
new Thread(()->{repaint();}).start();
I wrote a paint class, and added the jpanel to the frame, but it's getting called twice for some reason, as I put a print statement inside the graphics method, and it printed it twice. The codes below are all the codes I have in my package.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Paint extends JPanel {
static Paint paint = new Paint();
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Hello");
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(paint);
frame.pack();
frame.setLocation(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I tried your code and paintComponent it's not called twice every time. I don't think you have the control on when the JFrame is calling pack() when you call setVisible. It may depends on how your OS manage the windows.