0

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

enter image description here 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);

    }

}
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Memphys
  • 13
  • 5

2 Answers2

1

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.

DSquare
  • 2,458
  • 17
  • 19
  • Thanks for the answer DSquare! was really helpful, i'll take a look at the layout managers and learn more about that, thank you! – Memphys Apr 12 '14 at 19:19
  • @Memphys Glad I could help. Remember to upvote any useful answer and accept the best one, whenever you get a question solved here at StackOverflow. There are other minor problems in your code, for example you do not call `invokeLater` in your main, look at [Swing's Hello World](http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/start/HelloWorldSwingProject/src/start/HelloWorldSwing.java). Why do you need to do that is a matter of [threading](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html). – DSquare Apr 12 '14 at 20:07
  • Hummmmmmm, ok i'll check, i can't upvote cuz i don't have enough reputation, but i put as best answer, thank you!! – Memphys Apr 12 '14 at 20:09
-1

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 :)

Rustom
  • 11
  • 5
  • Downvoted for recommending using null layout. [Never use null layout](http://stackoverflow.com/questions/6592468/why-is-it-frowned-upon-to-use-a-null-layout-in-swing). The first line of the [official tutorial](http://docs.oracle.com/javase/tutorial/uiswing/layout/none.html) for null layouts is: "Although it is possible to do without a layout manager, you should use a layout manager if at all possible." It only exists because the technology is capable of it (and needs it to implement the LayoutManagers), but it should not be used. – DSquare Apr 12 '14 at 20:15
  • I did say that the way I provided was probably (and most likely) not the best way, but it is a "way" in the sense that it works. I've tried other solutions for this problems such as a JLayeredPane, but there is just too much flicker or it does not render properly. – Rustom Apr 12 '14 at 20:29
  • His problem was a mere missunderstanding of how to use LayoutManagers, nothing complex. For the kind of GUI he is trying to do a couple of very simple LayoutMangers work perfectly well. `JLayeredPane` is not relevant at all. Furthermore `paint` should never be called from the application (as specified in the paint method at [the documentation](http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html)), If you need it (and a well designed code doesn't) you can call `repaint()`. – DSquare Apr 12 '14 at 20:36
  • Thank you for your comments, I think I did get a bit off track from the question being asked which is why I brought up JLayeredPane. – Rustom Apr 12 '14 at 21:00
  • Sure no problem, I am glad to discuss all of this and share knowledge. I am just trying to avoid @Memphys form getting confused or get bad habits since this is his thread. – DSquare Apr 12 '14 at 21:03
  • Thanks for all the help guys, i'm just deeping in layout manager now to learn more about all this stuff, ^^ – Memphys Apr 12 '14 at 21:12