I am trying to fill JFrame with a JPanel and colour that JPanel, but for some reason I get a border on the bottom right edges.
My code:
public class Main extends JFrame {
public MyPanel myPanel = new MyPanel();
public static void main(String args[])
{
Main main = new Main();
main.init();
}
public void init()
{
this.setSize(300,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(myPanel);
this.setVisible(true);
}
#Override
public void paint(Graphics g)
{
myPanel.paintComponents(g);
}
class MyPanel extends JPanel
{
#Override
public void paintComponents(Graphics g)
{
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
Shows:
You're short-circuiting the paint chain with this method
#Override
public void paint(Graphics g) {
myPanel.paintComponents(g);
}
This isnt really doing anything useful so you can remove it. Also you need to override paintComponent rather than paintComponents in MyPanel
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(0, 0, getWidth(), getHeight());
}
Aside:
You could have simply created a panel and called setBackground to get this functionality
Related
I try to use swing and I have a litle problem that I fail to solve. That I want to do is simple: I just want to had to JPanel in a JFrame using BorderLayout.
The problem is my center panel is always placed above my North Jpanel. In fact whatever the size I give my north panel just have like 10 pixel, after the center pannel beggin (like on this image).
Note: when I put my second panel south the first panel have enough place to be drawn but even if it has more place the second one also take just 10 pixel which is not enough (like on this image).
this is my Plateau constructor class which extends JFrame:
public Plateau(){
super("arkanoid");
this.setLayout(new BorderLayout());
setFocusable(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(affich,BorderLayout.NORTH);
this.getContentPane().add(jeu, BorderLayout.CENTER);
setVisible(true);
this.setResizable(false);
this.setMinimumSize(new Dimension(700,800));
this.setLocationRelativeTo(null);
}
here a part of my panel placed in center (the rest is dvariable modification and drawing functions):
public class Jeu extends JPanel {
public Jeu(int score, int plateauX, int balleX, int balleY, boolean perdu){
super();
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
this.setSize(new Dimension(Width,Heigth));
}
}
and here is all my class supposed to be on north:
public class Affich extends JPanel {
public Affich() {
super();
this.setSize(100,100);
}
public void paint(Graphics g){
this.setSize(100,100);
g.drawOval(0, 0, 50, 50);
}
}
I hope I was clear enough
NEVER call setSize(...) or anything like it within a painting method. These methods should be for painting and painting only, and if you try to change size state, you can end up with a vicious cycle of endless calls -- set size which calls repaint which sets size, which calls repaint.
Instead:
Override the JPanel's paintComponent not paint, since paint is responsible for more than painting the JPanel, and overriding it can have unintended consequences on the JPanel's borders and child components.
Call the super's paintComponent within the override
Again, do only painting within a painting method
Don't set size but instead set preferred size and from code that is called once, and not within a painting method.
For example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
public class MyDrawing {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int affichW = 100;
int affichH = 100;
Affich affich = new Affich(affichW , affichH );
Jeu jeu = new Jeu();
frame.add(affich, BorderLayout.PAGE_START);
frame.add(jeu, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class Jeu extends JPanel {
private static final int JEU_W = 600;
private static final int JEU_H = 450;
public Jeu(int score, int plateauX, int balleX, int balleY, boolean perdu) {
super();
setBorder(BorderFactory.createTitledBorder("Jeu"));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(JEU_W, JEU_H);
}
}
public Jeu() {
this(0, 0, 0, 0, false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw with g2 here
}
}
#SuppressWarnings("serial")
class Affich extends JPanel {
private int width = 0;
private int height = 0;
public Affich(int width, int height) {
super();
this.width = width;
this.height = height;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(width, height);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// draw smooth oval
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawOval(0, 0, 50, 50);
}
}
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();
}
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
My problem is that when i use
public void paint(Graphics g)
{}
Method to draw a String as
g.drawString("hello java",0,0);
My full code is
import javax.swing.*;
import java.awt.*;
class test
extends JFrame
{
public void testing()
{
setSize(500,500);
show();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{ super.paint(g);
g.drawString("HELLO JAVA");
}
public static void main(String arg[])
{
test t=new test();
t.testing();
} }
In JFrame i am getting a black screen without hello java being drawn
Please help me
Thanks in advance
To display the inherited frame correctly, the paint method in the inherited class should contain the call of super.paint():
class MyFrame extends JFrame {
public void paint(Graphics g) {
super.paint(g);
g.drawString("hello java", 50, 50);
}
}
EDIT (painting in the panel):
import java.awt.*;
import javax.swing.*;
public class CustomPaint {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("CustomPaint");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MyPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
class MyPanel extends JPanel {
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
String msg = "HELLO JAVA";
g2.setPaint(Color.BLUE);
int w = (getWidth() - g.getFontMetrics().stringWidth(msg)) / 2;
g2.drawString(msg, w, getHeight() / 2);
}
}
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.