How do I draw on a JFrame, or any JComponent? - java

I am trying to draw something using paint() on my JFrame. I can't get it to show though. Why?
claass DrawOn extends JFrame{
public static void main(String args[]){
new DrawOn();
}
public DrawOn(){
setVisible(true);
pack();
}
paint(Graphics g){
g.drawOval(10,10,100,100);
}
}

You should draw in a JPanel:
JPanel panel = new JPanel()
{
#Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
g.drawOval(10, 10, 100, 100);
}
};
Don't forget to add the JPanel to the JFrame:
add(panel);
Code:
public DrawOn()
{
JPanel panel = new JPanel()
{
#Override
protected void paintComponent(Graphics g)
{
// TODO Auto-generated method stub
super.paintComponent(g);
g.drawOval(10, 10, 100, 100);
}
};
add(panel);
setPreferredSize(new Dimension(200, 200));
setVisible(true);
pack();
}
Note: You could make a class that extends JPanel instead of using an anonymous class so your code is clearer.

Related

Failing to call a call paintcomponent method :(

What I am trying to achieve is that the program would draw a line in the middle of the frame as soon as the user has clicked draw. But sadly nothing is happening other than "frame 3" is disappearing. Any ideas about how I could fix the problem?
Here is the method:
Windowj is my frame. Frame3 is the previous frame please don't worry about it.
public static void graf() {
frame3.setVisible(false);
windowj.setSize(400, 500);
windowj.setLocationRelativeTo(null);
windowj.setResizable(false);
windowj.setLayout(null);
windowj.setVisible(true);
windowj.setTitle("Graphs");
windowj.setDefaultCloseOperation(EXIT_ON_CLOSE);
xinwindow.setBounds(30,40, 90, 40);
yinwindow.setBounds(100,100,90,40);
thefunction.setBounds(200,300,90,40);
draw.setBounds(300,200,90,40 );
windowj.add(xinwindow);
windowj.add(yinwindow);
windowj.add(thefunction);
windowj.add(draw);
c.setPreferredSize(new Dimension(300,200));
draw.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
windowj.add(c);
c.revalidate();
c.repaint();
}
And here is the paintcomponent method:
private static Component c = new JComponent() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(50, 0, 70 , 100);
}
};
Any help would be appreciated, and please try to keep it simple, I am a beginner. :)
I will assume you use windowj as your JFrame and that what will happen when you click draw button your use windowj.setVisible(false) and that will make your window disappear
so remove it
2nd thing is you need to put your Component in windowj as windowj.add(c); in your draw ActionListener at actionPerformed before c.revalidate();
and here a little code that I wrote to understand what I mean:
public class DrawLine {
private JFrame windowj = new JFrame();
private JButton draw = new JButton();
private static int width = 640, height = 480;
private static JComponent c = new JComponent() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine((width/2) - 1, 0, (width/2) +1 , height);
}
};
public DrawLine() {
windowj.setDefaultCloseOperation(windowj.EXIT_ON_CLOSE);
windowj.setSize(width, height);
windowj.setLayout(new FlowLayout());
windowj.setResizable(false);
windowj.setLocationRelativeTo(null);
windowj.setVisible(true);
draw = new JButton("Draw");
draw.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//i don't know why you set windowj(windowj) false but that will close your window
//windowj.setVisible(false);
//add component to windowj(windowj)
windowj.add(c);
c.revalidate();
c.repaint();
}
});
c.setPreferredSize(new Dimension(width, height-100));
windowj.add(draw);
}
public static void main(String[] args) {
new DrawLine();
}
}
Here is the modified code:
private JFrame frame3, windowj;
private JPanel xinwindow, yinwindow,thefunction;
private JButton draw;
private static Component c = new JComponent() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.drawLine(50, 0, 70 , 100);
}
};
public DrawLine() {
xinwindow = new JPanel();
yinwindow = new JPanel();
thefunction = new JPanel();
draw = new JButton("Draw");
//i ignored frame3 as you said so just ignore my implementation here
frame3 = new JFrame();
frame3.setVisible(false);
windowj = new JFrame();
windowj.setSize(400, 500);
windowj.setLocationRelativeTo(null);
windowj.setResizable(false);
windowj.setLayout(null);
windowj.setVisible(true);
windowj.setTitle("Graphs");
windowj.setDefaultCloseOperation(EXIT_ON_CLOSE);
/*i used setBackground(Color.anycolor); to make it easier for me to know where
your window is in your frame*/
xinwindow.setBackground(Color.RED);
xinwindow.setBounds(30,40, 90, 40);
yinwindow.setBackground(Color.yellow);
yinwindow.setBounds(100,100,90,40);
thefunction.setBounds(200,300,90,40);
thefunction.setBackground(Color.green);
draw.setBounds(300,200,90,40 );
windowj.add(xinwindow);
windowj.add(yinwindow);
windowj.add(thefunction);
windowj.add(draw);
//here use setBonds instead of setPreferredSize
c.setBounds(100, 200, 200, 200);
draw.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
windowj.add(c);
c.revalidate();
c.repaint();
}
});
}
public static void main(String[] args) {
new DrawLine();
}
hope that solve your problem.

Java pass JPanel down to child class

i am exercising some OOP with java.
I just want to write a game with some graphic objects but i want to structure it with some classes.
The overall layout should look like this:
MainClass -> new MainPanel(extends JPanel)->new StartWindow(extends abstract GameWindow which contains the gameloop)
This way i should be able to create StartWindow, Level1Window, Level2Window and so on.
My StartWindow should now Draw the Layout for the first level.
The StartWindow will create other objects(Player, Enemy and so on) which will later be responsible for drawing themself.
So i want to create something like "every object is responsible to draw itself"
I hope i could make clear how this should work.
Problem is, i cant figure out how to delegate down this task.
My Code looks like this at the moment:
public class MainClass extends JFrame implements ActionListener {
//..... other stuff
public MainClass () {
MainPanel mainPanel = new MainPanel();
}
//.... other stuff
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel () {
currentWindow = new StartWindow(this);
}
public void paintComponent(Graphics g) {
g.drawRect (10, 10, 200, 200); // <-- can see on the window
}
}
abstract class GameWindow {
// contains game loop and update functions and so on
}
public class StartWindow extends GameWindow {
GamePanel _parentWindow;
public StartWindow(GamePanel parentWindow) {
super();
_parentWindow = parentWindow;
}
public void paintComponent(Graphics g) {
//Does not work
g.drawRect (20, 20, 100, 100);
}
}
the "_parentWindow" contains the MainPanel, so i should have all the information that is needed to draw on its Panel, i just cant figure out how to do it.
Edit:
Minimum example thats working:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainClass extends JFrame implements ActionListener {
public static void main(String[] args)
{
System.out.println("Program Window1");
MainClass glt = new MainClass();
glt.setVisible(true);
}
//..... other stuff
public MainClass () {
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
System.out.println("Program Window2");
MainPanel gamePanel= new MainPanel();
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
}
//.... other stuff
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel () {
currentWindow = new StartWindow(this);
}
public void paintComponent(Graphics g) {
g.drawRect (0, 0, 200, 200); // <-- can see on the window
}
}
abstract class GameWindow {
// contains game loop and update functions and so on
}
class StartWindow extends GameWindow {
MainPanel _parentWindow;
public StartWindow(MainPanel parentWindow) {
super();
_parentWindow = parentWindow;
}
public void paintComponent(Graphics g) {
//Does not work
g.drawRect (20, 20, 100, 100);
}
}
I would draw the sprites in your main drawing JComponent, e.g.,
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainClass extends JFrame implements ActionListener {
public static void main(String[] args) {
System.out.println("Program Window1");
MainClass glt = new MainClass();
glt.setVisible(true);
}
// ..... other stuff
public MainClass() {
super("Fixed Timestep Game Loop Test");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1, 2));
System.out.println("Program Window2");
MainPanel gamePanel = new MainPanel();
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
}
// .... other stuff
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel() {
currentWindow = new StartWindow(this);
}
// public void paintComponent(Graphics g) {
// g.drawRect(0, 0, 200, 200); // <-- can see on the window
// }
// this should be protected, not public and should call super method
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, 200, 200); // <-- can see on the window
currentWindow.draw(g);
}
}
interface Drawable {
void draw(Graphics g);
}
abstract class GameWindow implements Drawable {
// contains game loop and update functions and so on
}
class StartWindow extends GameWindow {
MainPanel _parentWindow;
public StartWindow(MainPanel parentWindow) {
super();
_parentWindow = parentWindow;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.red);
g.drawRect(20, 20, 100, 100);
}
}
but again, I reiterate that the game loop should not be inherited but rather its reference should be passed. Extension via composition rather than inheritance.
Or perhaps even better, have your model classes implement an interface, something like:
public interface Tickable {
void tick(int deltaTime);
}
Then a collection such as a List<Tickable> is held by the main model, and every time the game loop ticks, it iterates through the list calling tick(...) on each item in the List.
Try something like this inside the paintComponent method of your MainPanel class.
public void paintComponent(Graphics g) {
g.drawRect (10, 10, 200, 200); // <-- can see on the window
Graphics2D g2d = (Graphics2D) g.create();
((StartWindow) currentWindow).paintComponent(g2d);
g2d.dispose();
}

repaint() is not working

I want to draw circle and align it to center, but when I am calling repaint() nothing happens. I tried almost everything, I have changed layouts, alignments, but always the same. This is my code:
public class Frame extends JFrame {
JButton button,dugme;
JLabel lab;
public Frame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(480,320);
setResizable(false);
setLocationRelativeTo(null);
setLayout(new FlowLayout());
setVisible(true);
button = new JButton("Klikni me");
button.setSize(75,75);
add(button);
button.setHorizontalAlignment(SwingConstants.RIGHT);
dugme= new JButton("Klikni opet");
dugme.setSize(75,75);
add(dugme);
dugme.setHorizontalAlignment(SwingConstants.LEFT);
lab = new JLabel("Ovde je tekst koji se menja");
add(lab);
lab.setHorizontalAlignment(SwingConstants.CENTER);
Handler handler = new Handler();
Handler1 handler1= new Handler1();
repaint();
button.addActionListener(handler);
dugme.addActionListener(handler1);
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.fillOval(30, 30, 60, 75);
}
public class Handler implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
lab.setText("New text");
}
}
public class Handler1 implements ActionListener{
public void actionPerformed(ActionEvent e){
lab.setText("Same text again ");
repaint();
}
}
}
public void paintComponent(Graphics g){
super.paintComponents(g);
Breaks the paint chain, it should be:
public void paintComponent(Graphics g){
super.paintComponent(g); // no S in method name..

Paint new things on JPanel

Ok, so I have a JPanel with the paintComponent method overrided.
it's simple, looks like this:
public class Panel1 extends JPanel {
public void paintComponent (Graphics g) {
super.paintComponent (g);
g.fillOval (0, 0, getWidth (), getHeight ());
}
}
Now, I add this JPanel as an attribute to another JPanel class, like:
public class Panel2 extends JPanel {
Panel1 panel;
public Panel2 (Panel1 panel) {
this.panel = panel;
}
protected void paintComponent (Graphics g) {
super.paintComponent (g);
panel.paint (g); //This isn't working.
// panel.paintComponent (g); //Tried this too
g.drawOval (100, 100, getWidth () - 200, getHeight () - 200);
}
}
What I want is Panel2 to be painted exactly the same as Panel1 (without hard-coding it) and maybe add other stuff (like a triangle or sth, I don't know).
Is this even possible? I looked into it but didn't find any way to do it. Thanks in advance for your help!!
The MAIN in case it helps:
public class Main {
public static void main (String[] args) {
JFrame frame = new JFrame ();
frame.setSize (500, 500);
frame.add (new Panel2 (new Panel1 ()));
frame.setVisible (true);
}
}
EDIT: just in case, I don't want to do it with inheritance; that's why I add it as an attribute, but if there is other way just let me now.
You could try to make paintComponent of Panel1 public and then call it in paintComponent of Panel2:
protected void paintComponent (Graphics g) {
panel1.paintComponent(g);
}
You could also create a method inside your Panel1 class that handles the painting for you
public void yourPainting(Graphics g){
//whatever you want to paint
}
and then call this method in the paintComponent methods of both your Panel1 and your Panel2
The reason it does not work the way seen in the question is that Panel1 has a size of 0x0. To get a sensible size, return a size from getPreferredSize(), then set the panel size to the preferred size.
import java.awt.*;
import javax.swing.*;
public class PaintUnrealized {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
JFrame f = new JFrame("Paint Unrealized Component");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(new Panel2(new Panel1()));
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
class Panel1 extends JPanel {
public Panel1() {
setBackground(Color.RED);
setSize(getPreferredSize());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
class Panel2 extends JPanel {
Panel1 panel;
public Panel2(Panel1 panel) {
this.panel = panel;
setBackground(Color.YELLOW);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
panel.paintComponent(g); // This works
int pad = 25;
g.drawOval(pad, pad, getWidth()-(2*pad), getHeight()-(2*pad));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
}
public class Panel2 extends JPanel {
private Panel1 panel1;
public Panel2 (Panel1 panel) {
this.panel1 = panel;
}
protected void paintComponent (Graphics g) {
panel1.paint(g);
}
}
I believe that should work

Graphics not working in Java

I am trying to mess around with some graphics in java, however i can't get it to work. The JFrame comes up with the button i created, but the JFrame is just gray with no red line that i want it to draw.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Shapes extends JFrame implements ActionListener{
JButton button = new JButton("click");
public Shapes() {
setVisible(true);
setSize(500, 500);
button.addActionListener(this);
button.setSize(20, 20);
setLayout(new FlowLayout());
add(button);
repaint();
}
public static void main(String[] args){
Shapes s = new Shapes();
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawLine(5, 10, 10, 20);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button){
repaint();
}
}
}
Two things:
1). You don't really want to do custom painting on a top-level container such as a JFrame. Instead you want to use a JPanel
class Panel extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawLine(5, 10, 10, 20);
}
}
And add it to your JFrame: add(new Panel()); (Or create an object if you want).
2). setVisible(true); should be the very last thing that you do while setting up your window. So change your constructor:
public Shapes() {
setSize(500, 500);
button.addActionListener(this);
button.setSize(20, 20);
setLayout(new FlowLayout());
add(button);
add(new Panel()) // added from part 1
repaint();
setVisible(true);
}
For more information go through the "performing custom painting tutorials."

Categories