Drawing images in Jpanel, JFrame and game loop

Guys, my first post, here.
I’m learning to program a game. I just want to create a Runnable thread, putting inside the run method a static image.
I just want to understand the little steps that I’m thinking about. I’ll deal with fps,doublebuffering and keylistener later.
The problem is that now when I run the program, nothing is displayed.
I have another class, which is just a jframe calling this other class and putting everything inside with setContentPane.
I’ve also tried with paintcomponent but nothing changes.

public class myPanel extends JPanel implements Runnable{

//FIELDS
public static int WIDTH = 1024;
public static int HEIGHT = WIDTH / 16 * 9;
private BufferedImage bg;
private BufferedImage charac;
private boolean running;
private Thread t1;
private int startposX = WIDTH / 2;
private int startposY = HEIGHT / 2;
private int cordX = startposX;
private int cordY = startposY;
int speed = 50;


//METHODS   
public synchronized void start (){
    running = true;
    t1 = new Thread (this);
    t1.start();
}

public synchronized void stop (){
    running  = false;
    try {
        t1.join();
        System.out.println("The game stopped");
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
              }
 }

 //INIT
 public myPanel(){

   setPreferredSize(new Dimension(WIDTH, HEIGHT));
   setFocusable(true);
   requestFocus();
    }

 //MAIN RUN METHOD

 public void run(){
           while (running){
           load();
           System.out.println("The game runs");
           repaint();
          }
 }


  //PAINT WITH GRAPHICS METHOD
  public void paint (Graphics g){
    super.paint(g);
    g.drawImage(bg, 0, 0, this);
    g.drawImage(charac, 110, 280, this);

}

//LOAD IMAGES IN MEMORY
public void load (){
            try {
        String path1 = "res/bg.png";
        bg = ImageIO.read(new File (path1));
        String path2 = "res/charac.png";
        charac = ImageIO.read(new File (path2));
    } catch (IOException e) {

        e.printStackTrace();
    }

}

Took your code and tweaked it so that a frame displays with a rectangle displayed in the top left.

If your JFrame is not even appearing make sure you call setVisible(true);

public class Example extends JFrame implements Runnable {

    // FIELDS
    public static int WIDTH = 800;
    public static int HEIGHT = 600;

    private boolean running;
    private Thread t1;

    // METHODS
    public synchronized void start() {
        running = true;
        t1 = new Thread(this);
        t1.start();
    }

    public synchronized void stop() {
        running = false;
        try {
            t1.join();
            System.out.println("The game stopped");
        }
        catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // INIT
    public Example() {
        setSize(new Dimension(WIDTH, HEIGHT));
        setFocusable(true);
        requestFocus();
        
        setVisible(true);
    }

    // MAIN RUN METHOD

    public void run() {
        while (running) {
            //load();
            System.out.println("The game runs");
            repaint();
        }
    }

    // PAINT WITH GRAPHICS METHOD
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.BLACK);
        g.drawRect(0, 0, 100, 100);

    }

    // LOAD IMAGES IN MEMORY
//    public void load() {
//        try {
//            String path1 = "res/bg.png";
//            bg = ImageIO.read(new File(path1));
//            String path2 = "res/charac.png";
//            charac = ImageIO.read(new File(path2));
//        }
//        catch (IOException e) {
//
//            e.printStackTrace();
//        }
//
//    }
    
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        Example example = new Example();
    }    
}

Did you make sure that you are adding the Jpanel to your JFrame?

Thanks Andy and Longarmx.
I did a stupid error in the other class. And more, now I’ve used paintComponent.
Let me ask you another thing. I don’t see flickering in the movement.
Does that mean that I don’t need to manually setup double buffering?

JPanel is already double buffered :point:

You should declare “running” with the “volatile” keyword. It’s the only variable used by both threads, so having done that you can remove “synchronized” from “start” and “stop”. The alternative would be to synchronize the check on “running” in the “run” method, which would be doable but a bit awkward; you don’t want to synchronize the whole method or the “stop” method will be unable to execute.

In my experience, leaving out the “volatile” usually works okay. But sometimes it takes a few tenths of a second before the watching thread notices the change, and your game can get annyoingly sluggish. Much less often, the thread never sees the change at all and you’re wondering why the stupid button won’t work all of a sudden. (Without “volatile” or without all references “synchronized”, the JVM is under no obligations to do or not do anything, nor is it under any obligations to be fast or slow about it.