I am trying to get my hands on GUI programming in java and wanted to draw a rectangle in Jpanel. Code does not give any error but I cannot get rectangle in the GUI. Can somebody please tell me what I am missing in the following code. I am sure it is pretty simple so please be gentle.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HelloWorldGUI2 {
private static class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private static class RectDraw extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
}
public static void main(String[] args) {
JPanel content = new JPanel();
RectDraw newrect= new RectDraw();
JButton okButton= new JButton("OK");
JButton clearButton= new JButton("Clear");
ButtonHandler listener= new ButtonHandler();
okButton.addActionListener(listener);
clearButton.addActionListener(listener);
content.add(okButton);
content.add(clearButton);
content.add(newrect);
JFrame window = new JFrame("GUI Test");
window.setContentPane(content);
window.setSize(250,100);
window.setLocation(100,100);
window.setVisible(true);
}
}
Your newrect RectDraw's size is likely going to be quite small, probably [0, 0], since it has been added to a FlowLayout using JPanel and doesn't have a preferredSize set. Consider overriding its getPreferredSize() method and returning a suitable Dimension so that its drawing can be seen.
private static class RectDraw extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(230,80,10,10);
g.setColor(Color.RED);
g.fillRect(230,80,10,10);
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H); // appropriate constants
}
}
Also,
The paintComponent method should be protected, not public
Don't forget to use #Override before your method overrides.
Aim for much less code in the main method and more code in the "instance" world, not the static world.
Take care with your code formatting. Poor code formatting, especially misleading indentations, leads to silly errors.
Related
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
All i have is a JPanel with a white background and the JSlider on the bottom, not displaying the square, i think i have made some mistake with the JPanel class but i can't figure it out. Just before i made another project with g.fillOval and it worked properly, i checked it out and every line of code seems the same, i am really confused.
public class Main00 {
public static void main(String[] args) {
Gui asd=new Gui();
asd.setVisible(true);
asd.setSize(500,400);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class Gui extends JFrame {
private JSlider slider;
private DrawSquare square;
public Gui() {
super("square modificator");
setDefaultCloseOperation(EXIT_ON_CLOSE);
square = new DrawSquare();
square.setBackground(Color.WHITE);
slider = new JSlider(SwingConstants.HORIZONTAL, 0, 300,
square.getSide());
slider.setMajorTickSpacing(20);
slider.setPaintTicks(true);
add(square);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
square.setSide(slider.getValue());
}
});
}
}
import java.awt.*;
import javax.swing.*;
public class DrawSquare extends JPanel {
private int side = 10;
public void paintComponents(Graphics g) {
super.paintComponents(g);
g.setColor(Color.RED);
g.fillRect(20, 20, side, side);
}
public void setSide(int side) {
this.side=(side>=0)?side:0;
repaint();
}
public Dimension getPrefferedSize(){
return new Dimension(200,200);
}
public Dimension getMinimumSize(){
return getPrefferedSize();
}
public int getSide(){
return side;
}
}
You're overriding paintComponents rather than the correct paintComponent. These two methods have drastically different effects, and the effect of the second is the one you want.
From the API:
paintComponents API entry: Paints each of the components in this container.
paintComponent API entry: Calls the UI delegate's paint method, if the UI delegate is non-null. We pass the delegate a copy of the Graphics object to protect the rest of the paint code from irrevocable changes
Again, you are interested in painting the component itself via its delegate and not in painting the components held by this component.
I'm trying to find what is wrong with this short code. I can't print the String TEXT in my JFrame using drawString() method. Please Help . Only a plain white screen will appear if you run the program .
Code:
import javax.swing.*;
import java.awt.*;
public class sample extends JFrame
{
private JPanel panel;
public sample()
{
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
panel =new JPanel();
Container mainP= getContentPane();
mainP.add(panel);
panel.setBounds(0,0,500,500);
panel.setBackground(Color.WHITE);
}
public void paintComponent(Graphics g)
{
Graphics2D eg = (Graphics2D)g;
eg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
eg.setColor(Color.BLACK);
eg.drawString("TEXT", 40, 120);
}
public static void main(String args[])
{
new sample();
}
}
JFrame has no paintComponent method. So you aren't override anything, and not painting will be done.
On that note JPanel does have a paintComponent method, and you should be painting on a JComponent or JPanel, which do have the method. You don't want to paint on top-level containers like JFrame. (if you really need to know though, the correct method to override is paint for JFrame).
That being said, you should also call super.paintComponent inside the paintComponent method so you don't break the paint chain and leave paint artifacts.
Side Notes
As good practice, make use of the #Override annotation, so you know you are correctly overriding a method. You would've seen that paintComponent doesn't override one of JFrames methods.
setVisible(true) after add your components.
panel.setBounds(0,0,500,500); will do absolutely nothing, since the JFrame has a default BorderLayout
Follow Java naming convention and use capital letters for class names.
Run Swing apps from the Event Dispatch Thread. See more at Initial Threads
FINAL
import javax.swing.*;
import java.awt.*;
public class Sample extends JFrame {
private JPanel panel;
public Sample() {
setSize(500, 500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D eg = (Graphics2D) g;
eg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
eg.setColor(Color.BLACK);
eg.drawString("TEXT", 40, 120);
}
};
Container mainP = getContentPane();
mainP.add(panel);
panel.setBackground(Color.WHITE);
setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sample();
}
});
}
}
I have a JFrame created with GUI builder of Netbeans, which contains a JPanel only. I have created a method getPanel for getting a reference to this JPanel:
public class ShowDrawings extends JFrame {
public ShowDrawings() {
initComponents();
}
public JPanel getPanel(){
return panel;
}
private JPanel panel;
}
In my main function I am doing:
public class Main {
public static void main(String[] args){
ShowDrawings sd = new ShowDrawings();
sd.setSize(800, 600);
Graphics g = sd.getPanel().getGraphics();
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
sd.getPanel().paint(g);
sd.repaint();
sd.setVisible(true);
}
}
But it does not draw anything. Please help me.
I have looked some related questions but they are all suggesting extending JPanel and overriding its paint method. But I did not want to do that way.
Thanks.
I have looked some related questions but they are all suggesting
extending JPanel and overriding its paint method. But I did not want
to do that way
You should not override JPanel paint() method, rather paintComponent(..). This is best practice and should be done if you want code that will not produce anomalies. Also doing it in your current approach (as you have seen) makes creating persistent drawings a lot harder as they are wiped away on repaint()
Rather extend JPanel and override paintComponent(Graphics g) not forgetting to call super.paintComponent(g) as first call in overridden paintComponent(..) method. Also dont forget to override getPreferredSize() of JPanel so that we can return correct dimensions and pack() may be called on JFrame (+1 to #mKorbels comment):
Here is some example code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel testPanel = new JPanel() {
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.GREEN);
//g2d.drawOval(10,10,100,100);//I like fill :P
g2d.fillOval(10,10,100,100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
};
frame.add(testPanel);
frame.pack();
frame.setVisible(true);
}
}
The first time you repaint() your ShowDrawings sd frame anything you've painted like this (sd.getPanel().getGraphics().drawOval(...)) would be erased by the original JPanel#paintComponent() method.
As Andrew Thompson has written:
Do not use Component.getGraphics(). Instead, subclass and override the paint() (AWT), or paintComponent() (Swing) method.
Component.getGraphics() simply can't work. Java uses a callback mechanism for drawing graphics. You are not supposed to "push" graphics information into a component using getGraphics(). Instead you are supposed to wait until Java calls your paint()/paintComponent() method. At that moment you are supposed to provide the Component with the drawings you would like to do.
If you're just checking/debugging something you could even do something like this:
class Test {
private JPanel panel = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.drawOval(400, 300, 50, 50);
}
};
}
I have a class called survival that contains the main method, an initializes the program. Instead of putting the code for graphics int this class, how can I move it into a new class which is separate from survival?
Here is Survival.java:
package survival;
import javax.swing.*;
public class Survival extends JFrame {
private static int applicationWidth = 1024;
private static int applicationHeight = 768;
public Survival() {
setTitle("Survival");
setResizable(false);
setSize(applicationWidth, applicationHeight);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new Survival();
}
}
Here is GraphicsDisplay.java:
package survival;
import java.awt.*;
import javax.swing.*;
public class GraphicsDisplay extends JPanel {
#Override public void paintComponent(Graphics g) {
g.fillOval(50, 50, 100, 100);
}
}
It seems like you can just add() an instance of GraphicsDisplay in the Survival constructor.
...
setResizable(false);
add(new GraphicsDisplay());
setSize(applicationWidth, applicationHeight);
...
In this case, GraphicsDisplay acts as a view of your implicit, circular model. You might look at how this example separates classes in the Model–View–Controller pattern.
Because GraphicsDisplay is a custom component that is rendered entirely by your program, consider overriding getPreferredSize() to define the panel's geometry. Then the enclosing frame can just use pack() without knowing anything about other display panels used in the game. This LissajousPanel is an example.
You have to extend the JPanel (JComponent) and override a paintComponent(Graphics g) method.
For instance,
public class MyPanel extends JPanel
{
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // suggestion of #kleopatra
}
}
In the Constructor add the component (JPanel) to the container (JFrame):
public Survival() {
setTitle("Survival");
setResizable(false);
setSize(applicationWidth, applicationHeight);
this.getContentPane().add( new GraphicsDisplay() );
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}