0

So, I've been learning Java and I'm still pretty new, so bear with me. My latest goal is graphical programs, and this one is a test on keyboard control. For some reason, this program won't display a rectangle. Normally paint() runs on its own, but for some reason it isn't. I've looked at other programs that I made that work, and others on the web, and I still can't figure it out.

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;

public class App extends JFrame{

    public static int keyVal = 0;
    public static void main(String[] args) {
        new App();   
        while(true){
            System.out.println(keyVal);
            Wait.ms(50);
        }
    }

    public App(){
        JFrame f = new JFrame();

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setTitle("Pong");
        f.setSize(300,400);

        f.setLocationRelativeTo(null);

        f.addKeyListener(new KeyListener(){
            public void keyPressed(KeyEvent e){
                keyVal = e.getKeyCode();
            }

            public void keyReleased(KeyEvent e){
                keyVal = 0;
            }

            public void keyTyped(KeyEvent e){}
        });

        f.setVisible(true);
    }

    public void paint(Graphics g){
        g.setColor(Color.orange);
        while(true){
            g.drawRect(20, 20, 100, 60);
        }
    }

}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • 1
    step 1 - never put a `while(true)` in your `paint` function - it'll never finish, and your UI will lock up. – Krease Jan 24 '14 at 06:23
  • Thanks for the tip! Although sadly it still doesn't work. :/ – Matt Coffey Jan 24 '14 at 06:28
  • Sorry, haven't had time to look into this further - I scanned through it and noticed the glaring issue, and figured I could be at least a little helpful, even if I didn't solve the problem. – Krease Jan 24 '14 at 06:29
  • [This tutorial](http://docs.oracle.com/javase/tutorial/uiswing/painting/step1.html) will step you through creating an example Swing app - you should be able to take the lessons learned and apply it to your app. Some other differences I've noticed - override `paintComponent` instead of `paint`, and don't use `Wait` in your `main` function. If someone else wants to pattern your app after the code samples there and post it as an answer, be my guest... – Krease Jan 24 '14 at 06:35

1 Answers1

2
  1. One don't paint on top-level containers like JFrame as they already carry the load of painting components and aren't double buffered.
  2. Instead use a custom JPanel to paint and override its paintComponent method and call super.paintCompoent. Then add that panel to the frame.

    public class MyPanel extends JPanel {
        @Override 
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    }
    
  3. Also notice in the code above, I overrode the getPreferredSize() method. This is what you want to do when painting on a JPanel. The reason is that there is no set preferred size, so you'll want to set it. Also this should be used so you don't have to set a size the frame that holds it. Instead just call frame.pack() and the preferred size of the JPanel will be respected.

  4. Don't use KeyListener with Swing apps. Instead use Key Bindings, and you may face focus issues, among others, using KeyListener. You can see an example Here on how to use a simple key bind.
  5. Also you should run your Swing apps from the Event Dispatch Thread like this

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                new MyApp();
            }
        });
    }
    
  6. Don't use while in your paintComponent methods. You will run into problems. If you want something to be drawing repeatedly, like animation, you will want to look into using a javax.swing.Timer. You can see an example here or an any number of SO post you can find just doing a simple search of how to use a Swing Timer.

  7. Also, Your App class is already a JFrame sublcass. There's no need to create another JFrame in the constructor. Just add the components to it, something like this

    public App() {
        add(new MyPanel(), BorderLayout.CENTER);
        add(new JButton("Button"), BorderLayout.SOUTH);
    }
    
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720