0

I am developing Tetris for fun/to learn more about Java. I am having problems with the JFrame aspect of it. I have the actual game portion, which is a on the left side of the screen with the score, level, and high score to the right of this. Then, under the score, level, and high score I am trying to put in a button. Here is my code:

public class Tetris implements World {
    boolean pause = false; // for pausing the game
    boolean end = false; // for ending the game
    static int score = 0; // score.  Increments of 100
    static int level = 1; // indicates level.  Increments of 1.
    static int highScore = 1000; // indicates the overall high score
    static final int ROWS = 20; // Rows of the board
    static final int COLUMNS = 10; // Columns of the board

    Tetromino tetr, ghost, od1, od2, od3; // Tetr is the tetromino currently following.  Ghost is the shadow blocks.
    SetOfBlocks blocks; //SetOfBlocks on the ground

    Tetris(Tetromino tetr, SetOfBlocks blocks) {
        this.tetr = tetr;
        this.blocks = blocks;
    }

    //Main Method
    public static void main(String[] args) {
        BigBang game = new BigBang(500, new Tetris(Tetromino.pickRandom(), new SetOfBlocks()));
        JFrame frame = new JFrame("Tetris");

        //JButton
        JButton toggleGhost = new JButton("Toggle Ghost");
        toggleGhost.setFont(new Font("default", Font.PLAIN, 10));
        Dimension size = new Dimension(100, 25);
        toggleGhost.setPreferredSize(size);
        toggleGhost.setLocation(217, 60);

        //frame
        //frame.getContentPane().add( toggleGhost );
        frame.getContentPane().add(game);
        //frame.getContentPane().add( toggleGhost );
        frame.addKeyListener(game);
        frame.setVisible(true);
        frame.setSize(Tetris.COLUMNS * Block.SIZE + 150, Tetris.ROWS * Block.SIZE + 120); // Makes the board slightly wider than the rows
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        game.start();

BigBang is a class that extends JComponent and deals with the Timer primarily. If I uncomment the portion where I add the toggleGhost button to the frame, then it takes up the entire frame. I have tried many different alternatives with panels and containers but I can't seem to find the right combination where both the game and button display.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
JDeffo
  • 73
  • 1
  • 1
  • 4
  • As @ACV mentioned, you should use a [LayoutManager](https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html). The default one for a JFrame is the [BorderLayout](http://docs.oracle.com/javase/7/docs/api/java/awt/BorderLayout.html). Adding an item to the frame, like you're doing here would add it to the center of the BorderLayoutManager and take up the full frame. – Andy Stabler May 18 '15 at 14:27
  • `frame.setSize(Tetris.COLUMNS * Block.SIZE + 150, Tetris.ROWS * Block.SIZE + 120); // Makes the board slightly wider than the rows` This is guesswork. It is better to have the custom painted component return a preferred size, use layouts (+padding and borders) to position the components, then `pack()` the frame. 1) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example). 2) Provide ASCII art or a simple drawing of the layout of the GUI at minimum size, and if resizable, with more width and height. – Andrew Thompson May 18 '15 at 14:41
  • `new Font("default", Font.PLAIN, 10)` ?!? That `"default"` is more guesswork, perhaps even reaching the heights of 'coding by magic'.. – Andrew Thompson May 18 '15 at 14:44
  • Is [this image](http://i.stack.imgur.com/4T9rc.png) something like what this game requires? It centers the button above the red 'playing area' which in this case, is exactly 300x300 px in size. Resizing it would provide extra width and height to the red area, while the button remains centered above it. The way I've rewritten the code, it is a one line change to put the button to the bottom or to the left or right of the game area. – Andrew Thompson May 18 '15 at 15:06

2 Answers2

1

Because you should use LayoutManager . And setPreferredSize doesn't guarantee the size.

ACV
  • 9,964
  • 5
  • 76
  • 81
0

Like ACV said, you are adding objects to your JFrame without using a LayoutManager. You should use a LayoutManager when you want some control over how things will display (not when you're adding a single object to the frame). Consider BorderLayout or BoxLayout.

For instance, using BorderLayout you would have to add the following code:

frame.setLayout(new BorderLayout());
frame.add(game, BorderLayout.CENTER);
frame.add(toggleGhost, BorderLayout.SOUTH);

To understand the difference between setSize() and setPreferedSize(), see this question.
The best practice is to add a LayoutManager to whatever component you are using (JFrame, JPanel, ...) and use setPreferedSize(), setMinimumSize() or setMaximumSize().

Community
  • 1
  • 1
goncalotomas
  • 1,000
  • 1
  • 12
  • 29
  • 1
    *"you should use setSize() to get the desired component size"* No. The preferred size is more likely to be honored by the layout manager. See also [Should I **avoid** the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/q/7229226/418556) (Yes.) – Andrew Thompson May 18 '15 at 15:02
  • @AndrewThompson I had a feeling that `setSize()` worked on JFrames, @Sbodd also mentions it in his answer. I just tested it and you are correct. `setPreferredSize()` is the appropriate choice. I edited my answer accordingly. – goncalotomas May 18 '15 at 15:16
  • Oh, I forgot `JFrame` and other top level containers. But in their case, it is usually better to `pack()` as noted in my 1st comment on the question. – Andrew Thompson May 18 '15 at 15:23
  • I tried this layout manager and it now allows me to see both the button and the game itself. There's two issues I'm running in to now: setPreferredSize(), setMinimumSize(), and setMaximumSize() are only allowing me to change the width of the button. The button still takes up the entire length of the frame, no matter the size in those methods or the size of the frame. Also, my keyListeners for the game no longer work. – JDeffo May 18 '15 at 15:25
  • That is a property of the [BorderLayout](https://docs.oracle.com/javase/tutorial/uiswing/layout/border.html), not a bug. Try [BoxLayout](https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html)! Changing the LayoutManager shouldn't be the cause of your KeyListener not working, but If you'd like my help fixing it I would advise you to build an [MVCE](http://stackoverflow.com/help/mcve) as sugested by @AndrewThompson – goncalotomas May 18 '15 at 15:51
  • *"keyListeners for the game no longer work."* For Swing, we typically use [key bindings](https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html) rather than the lower level `KeyListener`. BTW - when I asked *"Is **this image** something like what this game requires?"* around an hour ago, it is because I wanted to check I had the right idea before posting the code that achieved that. But I **expect an answer** either way. – Andrew Thompson May 18 '15 at 16:30
  • @AndrewThompson my apologies, I'm still pretty new to StackOverflow. But yes, it is similar. The actual game is on the left, with the score, level, and high score to the right of that. And then the button is below the score, level, and high score area. And I'll check out key bindings, I've never seen them before. – JDeffo May 18 '15 at 16:39