I'm new at working with JFrames. So I dont really know how to draw/paint/display everything in a JFrame. Im working on a memory game. Currently im working at the first form, this form must display a background image, a welcome text, a dropdown list with the amount of cards for the memory game and a button which should start the game. I succesfully displayed the background image and the welcome text. After adding the JButton and combobox my form got messed up (I only see a blue background). I have no idea what im doing wrong, also I dont know how I can place the button and dropdown on the right x and y position. I want to place the dropdown box under the welcome text and the button to the right of the dropdownbox.
This is my code:
Main:
package Memory;
public class Main {
public static Memory memory;
public static void main(String[] args) {
memory = new Memory();
}
}
Renderer:
package Memory;
import javax.swing.*;
import java.awt.*;
public class Renderer extends JPanel {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Memory.backImage = new ImageIcon("Memory/memoryGame.jpg");
Main.memory.repaint(g);
}
}
Memory:
package Memory;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.*;
import javax.imageio.*;
import java.awt.FlowLayout;
public class Memory implements ActionListener {
public String[] amountOfCards = {"8","16","32"};
private JButton startButton;
public Renderer renderer;
public static ImageIcon backImage;
public boolean screen1;
public static final int WORLD_WIDTH=1250, WORLD_HEIGHT=800;
public Memory() {
JComboBox comboBox = new JComboBox(amountOfCards);
comboBox.setSelectedIndex(1);
startButton = new JButton("Start game");
JFrame jframe = new JFrame();
Timer timer = new Timer(20,this);
renderer = new Renderer();
jframe.add(renderer);
jframe.setTitle("Memory game");
jframe.setSize(WORLD_WIDTH,WORLD_HEIGHT);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);jframe.add(startButton);
jframe.add(comboBox);
jframe.setVisible(true);
screen1=true;
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
renderer.repaint();
}
public void repaint(Graphics g) {
//welcome screen
if(screen1) {
BufferedImage scaledImage = getScaledImage();
g.drawImage(scaledImage, 0, 0, null);
g.setColor(new Color(150, 196, 100));
g.setFont(new Font("TimesRoman", Font.PLAIN, 75));
g.drawString("MEMORY GAME", WORLD_WIDTH / 2 - 275, 100);
g.setFont(new Font("TimesRoman", Font.PLAIN, 25));
g.drawString("Please select the amount of cards u want to play with and start the game!", WORLD_WIDTH / 2 -400, 200);
}
}
public BufferedImage getScaledImage() {
BufferedImage image = new BufferedImage(WORLD_WIDTH,WORLD_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(backImage.getImage(), 0, 0,WORLD_WIDTH,WORLD_HEIGHT, null);
return image;
}
}
Alright, multiple errors in a first view of your code
public static Memory memory; : That line, having static and being a public member of class will harm you a lot! Why? Because your memory variable is the same for all the instances you create, because it's a "Class variable" not an "instance variable", and being public is going against the convention and security reasons. For reference see: What does the 'static' keyword do in a class? and Why use getters and setters?
From the above point, static is not a "magic cross method / class" word that allows you to use variables through classes or with main and other methods... and thus this line public static ImageIcon backImage; and this one: Memory.backImage = new ImageIcon("Memory/memoryGame.jpg"); shouldn't exist. And the same for this one: Main.memory.repaint(g);
That being said, you should NEVER NEVER NEVER EVER!!! override repaint() method, all of that code should be into the paintComponent(...) mehtod!
Also it is wise to treat images as embedded resources, because, once you export your program as a JAR file, they will become embedded resources, it's better to treat them like if they already were, here you can find information about how to change your program accordingly.
Try and set your ImageIcon BackImage from public static, to public. Also, try and write the jframe.setVisible(true); command after timer.start()
note that setting your JFrame to visible, before completing every initialisation, might lead to unwanted behaviour of your program.
To set the position of your button on the screen, after adding your JButton to your JFrame, you can use: startButton.setLocation(x,y);
After you play a little bit with the coordinates of your window, you'll get the spot you want for your JButton. Keep in mind that (0,0) is usually the upper left corner of your JFrame.
Be careful when using static variables in your program. There seems to be no reason in setting your Memory class, your width and height variables as static.
For more information regarding this, check out this post: Why are static variables considered evil?
Related
I'm making a small game using Java Swing. A class Game extends JPanel and implements ActionListener, a Timer in it calls repaint() to update the screen, then create a JFrame and add Game to it.
Then I noticed when I make the window full screen, the screen is updated once when paint() is called twice. This is weird! Any help would be appreciated.
Here is an SSCCE, the example creates a variable count, and paint count then count+=1; in repaint(). When not full screen, it shows 0 1 2 3 4... When full screen, it shows 4 6 8 10...
Example code here:
package test.swing.FullScreenDropFrameRate;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
class Game extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private int count = 0;
public Game() {
new Timer(1000, this).start();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
#Override
public void paint(Graphics g) {
// bg
g.setColor(Color.black);
g.fillRect(0, 0, getSize().width, getSize().height);
// info string
g.setColor(Color.white);
g.setFont(new Font("serif", Font.BOLD, 30));
g.drawString(""+count, 0, 30);
count += 1;
g.dispose();
}
}
public class TestFullScreenFrameRate {
public static void main(String[] args) {
JFrame jf = new JFrame("Snake");
jf.setBounds(100, 35, 800, 600); // x, y, width, height
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(new Game());
jf.setVisible(true);
}
}
OK, so the problem is that I shouldn't put anything which updates the game state in paint(). Java calls it when needed. Thanks to #Andrew Thompson.
Some other mistakes, improvements and documentation:
1)Documentation - JComponent - paint(): Invoked by Swing to draw components. ... A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.
2)Documentation - Font - SERIF: A String constant for the canonical family name of the logical font "Serif". It is useful in Font construction to provide compile-time verification of the name.
3)Oracle - about Painting
4)Documentation - Graphics - dispose(): For efficiency, programmers should call dispose when finished using a Graphics object only if it was created directly from a component or another Graphics object.
5)A Java Game Tutorial on Youtube: Bad example! DO NOT use paint() and g.dispose() here!!!
package Main;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
I'm using Java's JFrame. So this isn't recognising the paint method and cant figure out why. I've been looking on YouTube videos and having a look to see if anyone has had similar problems, however everything I've found doesn't seem to help the problem.
when i set the background colour in the main part, it works, bit in paint, it doesn't seem to do anything and leaves it blank.
Its a white line over a black background, so i should easily be able to see it.
Admittedly, I don't know much about Swing (I prefer JavaFX). However, it's clear that your Main class is a JFrame, so you should not make a new one within it. All of those methods you call on display are built in your current class. Basically, within your JFrame you made a new JFrame. However, your paint method was being called on the parent JFrame, which you never made visible. This solves your problem (you may have to fullscreen the window):
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
new Main();
}
public Main() {
int width = 800;
int height = 600;
String title = "Test";
setTitle(title);
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.WHITE);
g.drawLine(100, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
You are creating an instance of JFrame with
JFrame display = new JFrame();
But the JFrame class has no logic to draw a white line on a black background. That logic is in your custom class Main. So instead, you should create an instance of Main:
JFrame display = new Main();
However, that change along still won't fix the problem because you are setting the background color of the "content pane" but trying to draw directly on the JFrame itself. The preferred solution here is to extend JPanel instead of JFrame and override its paintComponent() method. Then create an instance of your new class to use as the content pain:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainPanel extends JPanel{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setContentPane(new MainPanel());
}
public MainPanel() {
setBackground(Color.black);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
}
}
Notes:
I call setBackground() in the constructor because it does not rely on the Graphics instance passed to paintComponent(). This also avoids the overhead of another function call for each render.
In paintComponent(), I call super.panitComponent(). This allows JPanel to clear the area to be painted and any other necessary initialization.
I am learning java abstract window toolkit and i am stuck in this code.When i interchange the commented line, the output changes.Any Explanation for both the cases will be appreciated.
import java.awt.*;
public class guibutton
{
public guibutton()
{
Frame f = new Frame("Panel Example");
Panel panel = new Panel();
panel.setBounds(40,80,200,200);
panel.setBackground(Color.gray);
f.add(panel);
f.setVisible(true); ////////////////this line
f.setLayout(null); /////////////////this line
f.setResizable(true);
f.setSize(400,400);
}
public static void main(String args[])
{
new guibutton();
}
}
This line:
f.setVisible(true);
renders your GUI in its current state, one where the JFrame's default BorderLayout is in force. Note that BorderLayout ignores the setBounds(...) method.
This line:
f.setLayout(null);
removes the JFrame contentPane's BorderLayout, and so your GUI is rendered without the layout, changing the positioning of the added JPanel -- the setBounds(...) method call here is respected.
If you call this after the GUI has been rendered, it won't have an effect, unless you do something that triggers the layout managers to re-layout the components, such as re-size the GUI.
Myself, I wouldn't use AWT but would use Swing, I'd draw the rectangle within the paintComponent method of a JPanel, using a Rectangle object. This way, I could monitor the mouse in relation to the rectangle, and change its state. For instance, try out this program, and see what happens to the rectangle when the mouse hovers over it:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class GuiButton2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int RECT_X = 40;
private static final int RECT_Y = 80;
private static final int RECT_W = 200;
private static final Color DEFAULT_RECT_COLOR = Color.GRAY;
private static final Color HOVER_RECT_COLOR = Color.PINK;
private Rectangle rectangle = new Rectangle(RECT_X, RECT_Y, RECT_W, RECT_W);
private boolean hover = false;
public GuiButton2() {
setPreferredSize(new Dimension(PREF_W, PREF_H));
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
// hover true if mouse is hovering over the rectangle
hover = rectangle.contains(e.getPoint());
repaint();
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// if hover true -- use hover color, otherwise use default color
Color c = hover ? HOVER_RECT_COLOR : DEFAULT_RECT_COLOR;
g2.setColor(c);
g2.fill(rectangle); // draw rectangle
}
private static void createAndShowGui() {
GuiButton2 mainPanel = new GuiButton2();
JFrame frame = new JFrame("GUI Button");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Side note 1:
While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Side note 2:
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
Sorry about my English, and my ignorance in programming, its because I'm new at this , and I'm having problem with Buttons and JFrame, please help me ;)
I'll post the print of the problem, and the codes of my the two classes I have so far, Game and Menu, hope you guys can solve it, I want the buttons to paint inside the gray panel.
Thanks.
Print of my Problem
Print
(GAME CLASS)
package br.com.lexo.dagame;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import br.com.lexo.dagame.menu.Menu;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private static int width = 300;
private static int height = width / 16 * 9;
private static int scale = 3;
private static String title = "Da Game";
private Thread thread;
public JFrame janela;
private Menu menu;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
janela = new JFrame();
menu = new Menu(janela, this);
}
private synchronized void start() {
if (running) return;
running = true;
thread = new Thread(this, "Thread_01");
thread.start();
}
private synchronized void stop() {
if (!running) return;
running = false;
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public void update() {
}
public void run() {
while (running){
render();
update();
}
stop();
}
public static void main(String[] args) {
Game game = new Game();
game.janela.add(game);
game.janela.setTitle(title);
game.janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.janela.pack();
game.janela.setLocationRelativeTo(null);
game.janela.setResizable(false);
game.janela.setVisible(true);
game.start();
}
}
(MENU CLASS)
package br.com.lexo.dagame.menu;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import br.com.lexo.dagame.Game;
public class Menu extends Canvas {
private static final long serialVersionUID = 1L;
public boolean inMenu = false;
JButton startGame = new JButton("Começar Jogo");
JButton exitGame = new JButton("Sair do Jogo");
JButton howToPlay = new JButton("Como Jogar");
private Game game;
public Menu(JFrame janela, Game game){
this.inMenu = true;
this.game = game;
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
howToPlay.setEnabled(false);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
}
I don't know what are you trying to accomplish but you are not adding the components correctly:
Look at:
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
This is incorrect, the add method has two arguments, like this: container.add(component, constraints); your error is not specifying the constraints. The constraints contains all the details to know where in the panel you want to add that component.
For each LayoutManager the Object constraints is diferent. For the GridBagLayout the constraints is a GridBagConstraints object.
However GridBagLayout is a the most difficult layout to use and you don't really need it. I recommend you to look at this visual guide pick a layout and learn it properly. The tutorial for each LayoutManager explains what do you need to put in the constraints parameter.
The call container.add(component) exists because sometimes the LayoutManager does not need extra information (like the BoxLayout), in the other cases it just uses the "default" constraints for the LayoutManager in use, which may not be what you need.
For example the line in your main:
game.janela.add(game);
Is correct, but what it actually does is calling game.janela.add(game, defaultConstraints); where defaultConstraints is the default constraints value for the LayoutManager of the JFrame janela. Because you didn't explicitely specify a layout for the frame it is using the default layout for JFrames: BorderLayout, and the default constraints for the BorderLayout is the constant BorderLayout.CENTER.
So what that line actually does is:
game.janela.add(game, BorderLayout.CENTER);
Which incidentally is what you wanted to do.
To summarize:
Most calls to add must have two parameters: the component and the constraints. Each LayoutManager uses different constraints. You must be aware of what means to not specify the constraints for your LayoutManager. Do not start learning about how to properly use LayoutMangers with the GridBagLayout it's much more complex.
A quick way to somehow paint components to a graphics object is calling the paint method of component class. So in your render method:
g.fillRect(0, 0, getWidth(), getHeight());
menu.startGame.paint(g);
...
But as you'll soon see that everything is painted on the top left as components are laid out as said in the other answer and to get everything working to how you want them to work is a bit more complicated.
Now the following advice is based on my limited knowledge and was quickly put together so there are probably better ways.
About the menu class:
You are extending java.awt.Canvas when I think it would be best to extend a container like javax.swing.JPanel as you want it (I assume) to hold those 3 buttons.
Next would be to set the appropriate layout for this application, which would be null. So instead of:
game.janela.setLayout(new GridBagLayout());
it would now be:
setLayout(null);
This is because you want components (which are those buttons) to be paint on top of another component which is the Game class that extends Canvas and null allows you to do that.
Because the layout is now null, you must specify the bounds of the components which are the x and y coordinates alone with the width and the height otherwise everything will just be 0, 0, 0, 0 and nothing would show up.
So in the Game's constructor
setBounds(0, 0, width * scale, height * scale);
and janela.setPreferredSize(size); instead of setPreferredSize(size);
Back in the Menu class you will have to set the bounds of the buttons like so:
Dimensions sgSize = startGame.getPreferredSize();
startGame.setBounds(50, 50, sgSize.width, sgSize.height);
I am using preferred size to get the optimal width and height of the button that was set in the buttons UI (I think).
and add them to the Menu which is now a JPanel instead of adding them to the JFrame(janela). (add(startGame);) Also, don't forget to add the game to the menu panel.
and it should work like so:
(http://i.imgur.com/7cAopvC.png) (image)
Alternatively you could make your own widget toolkit or custom layout, but I wouldn't recommend that. I had this same problem last year but ended up moving to OpenGL but anyway, I hope this has helped :)
I want my program to display the canvas that is repainted once at the start and then whenever a change is made afterwards. I thought I had everything coded correctly, but for some reason nothing that is painted onto the canvas actually shows (I know it's repainting, I tested that).
Here are the code segments:
public TileMapCreator()
{
currentView = new BufferedImage(640, 640, BufferedImage.TYPE_INT_ARGB);
currentView.getGraphics().setFont(new Font("Arial", Font.BOLD, 100));
currentView.getGraphics().drawString("No Map Yet Open", currentView.getWidth()/2, currentView.getHeight()/2);
this.setJMenuBar(createMenuBar());
this.setContentPane(createMapPanel());
}
private JPanel createMapPanel()
{
JPanel p = new JPanel();
p.add(setUpCanvas());
p.setVisible(true);
return p;
}
private Canvas setUpCanvas()
{
mapCanvas = new Canvas(){
private static final long serialVersionUID = 1L;
public void repaint()
{
mapCanvas.getGraphics().drawImage(currentView, 0, 0, this);
}
};
mapCanvas.setIgnoreRepaint(true);
Dimension size = new Dimension(currentView.getWidth(), currentView.getHeight());
mapCanvas.setSize(size);
mapCanvas.setPreferredSize(size);
mapCanvas.setMaximumSize(size);
mapCanvas.setMinimumSize(size);
mapCanvas.setFocusable(true);
mapCanvas.addMouseListener(this);
mapCanvas.addMouseMotionListener(this);
mapCanvas.setVisible(true);
return mapCanvas;
}
Currently the area where the canvas should be painting is just the regular grey color of the Java GUI. Thanks for your help!
You appear to be mixing Swing with AWT components, and drawing in a very strange way, one that I've honestly never seen before (and I've seen a lot). Why not simply do your drawings in the paintComponent(Graphics g) method of a JPanel using the Graphics object given by the JVM, like you'll find in the Swing graphics tutorials and 98% of the Swing graphics answers on this site? Also for my money, I'd avoid using Canvas or trying to mix heavy and light weight components together. Stick with Swing all the way, and things should go more smoothly.
I'd be happy to give you more specific advice and perhaps some if you could create and post a minimal example program. Please have a look at the link and let us know if you need more information.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class TestImagePanel extends JPanel {
private static final int BI_WIDTH = 640;
BufferedImage currentView = new BufferedImage(BI_WIDTH, BI_WIDTH, BufferedImage.TYPE_INT_ARGB);
public TestImagePanel() {
Graphics g = currentView.getGraphics();
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.black);
g.setFont(new Font("Arial", Font.BOLD, 60));
g.drawString("No Map Yet Open", 20, currentView.getHeight()/2);
g.dispose();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (currentView != null) {
g.drawImage(currentView, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (currentView != null) {
return new Dimension(BI_WIDTH, BI_WIDTH);
}
return super.getPreferredSize();
}
private static void createAndShowGui() {
TestImagePanel mainPanel = new TestImagePanel();
JFrame frame = new JFrame("TestImagePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I've found the Swing tutorials to be a great asset, and bet you would too. Please have a look at them.
Edit
You ask:
Hmm, so apparently getting the graphics object of my buffered image twice did not result in anything actually being painted... I had to get the graphics object, assign it to a variable, and then paint.
I wouldn't say that. I'd say that your way of getting the Graphics object should work the same as mine, but yours is not safe since the Graphics objects obtained in this way cannot be disposed of, and you risk running out of resources. I think that your image didn't show up due to your very convoluted and unusual way of trying to display your image. You override repaint(), put some weird code inside of it, tell the JVM to ignore repaint calls, never call the repaint super method inside of your override, so that repaint does in fact nothing. I have to wonder -- where did you get this code? Was it from a tutorial? If so, please share the link here. And never get advice from that site again.