Sliding drawer animation using java swing - java

I am new to swing and designing an interface using java swing. I want a drawer to pull out with sliding animation on a button click. Firstly, is it possible to do so and if yes, how do I do it. Thank you. I will appreciate a response in terms of some specific method information.

There are a number of possible ways you might achieve depending on what you want to achieve.
The basic method would be simply draw the graphics and a Swing Timer
This would allow you to simply update a variable which would act as the bases for the size of the draw, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawerPaneTest {
public static void main(String[] args) {
new DrawerPaneTest();
}
public DrawerPaneTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawerPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawerPane extends JPanel {
private boolean drawIn = false;
private Timer timer;
private int drawWidth = 0;
private int drawDelta = 4;
public DrawerPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
timer.stop();
drawIn = !drawIn;
drawDelta = drawIn ? 4 : -4;
timer.start();
}
});
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
drawWidth += drawDelta;
if (drawWidth >= getWidth() / 2) {
drawWidth = getWidth() / 2;
timer.stop();
} else if (drawWidth < 0) {
drawWidth = 0;
timer.stop();
}
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, drawWidth, getHeight());
g2d.dispose();
}
}
}
This is really basic and doesn't take into account things like slow out/slow in concepts. For those, you'd better look at a dedicated animation framework, like
Timing Framework
Trident
Universal Tween Engine
Which you might use depends on what it is you want to achieve, I personally like the Timing Framework, mostly because it gives me a lot of freedom, where as something like Trident has being (mostly) designed to provide the ability to change properties on a object, such as the size or position, for example. While the Timing Framework can do this do, it would require more work to get it that point.
I've not used the Universal Tween Engine, but have seen some real nice examples, such as the Sliding-Layout, which might actually meeet your needs...

First of all, I think that you shouldn't use Canvas, since, IMO, you shouldn't mix Swing's Components with AWT if it's not necessary (I'm talking in terms of the actual components you place in the GUI - I know Swing is built on top of AWT).
You might instead want to use a JPanel and perform custom painting using its paintComponent method. There are many tutorials about this (e.g. Lesson: Performing Custom Painting).
Once you figured out how to draw your drawer inside your JPanel (simply using Graphics2D drawing), you'll want to animate it: basically, you'll just need to update some of its properties, most likely some position...
Would you like to have some nice easing effects and everything being easily handled and packaged, I would recommend you to have a look to the Universal Tween Engine. I've already used it and could help you with that as well.
Once you have your Universal Tween Engine library linked to your project, simply use some call as following:
Tween
.to(drawerProperties, Type.POSITION, 10.0f) // animate the POSITION property of your drawerProperties on 10.0 units of time
.target(100) // set the number of frames of that animation to
.ease(Quad.OUT) // set a nice quadratic effect on the animation
.start(tweenManager); // launch the animation
Then, elsewhere, you just need to have a Thread running that constantly updates your TweenManager using TweenManager#update.
Once again, it looks like a lot of work but it actually is very easy to use and the Universal Tween Engine's getting started section is extremely good. Moreover, if you want to really add animation to your project, this could definitely be a great tool to use :)
One last point: you might need to update your properties in the Swing's Event Dispatch Thread, depending on how exactly will your solution be implemented. If you don't know so much about that, you could read Lesson: Concurrency in Swing - or just search StackOverflow if you've specific questions :)

Related

Graphics 2D not drawing images in Java

I'm following a Java course, and the current idea is to draw an image using Java Graphics2D. I'm following the steps one by one, but it seems not to be drawing anything. The panel is shown within the frame and everything is correct, but the image is not drawn. I'm using Java 15 and the course is Java 13.
JPanel class code:
public class MyPanel extends JPanel implements ActionListener {
Image ball;
int x = 0;
int y = 0;
MyPanel(){
this.setPreferredSize(new Dimension(PANEL_WIDTH,PANEL_HEIGHT));
this.setBackground(Color.BLACK);
ball = new ImageIcon("ball.png").getImage();
}
public void paint(Graphics g){
Graphics2D G2D = (Graphics2D) g;
G2D.drawImage(ball,x,y,null);}
JFrame class code:
public class MyFrame extends JFrame{
MyPanel panel;
MyFrame(){
panel = new MyPanel();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
Main class code:
new MyFrame();
I picked out most of the relevant code.
First, I recommend reading through Performing Custom Painting and Painting in AWT and Swing to get a better idea of how painting in Swing should work.
I then suggest reading through Reading/Loading an Image
The "problem" with ImageIcon is that
It doesn't report any errors if the load fails
It loads the image in a second thread, which means you don't know (easily) when it's available
ImageIO on the hand will throw an error if the image can't be loaded, which is much easier to diagnose, and will only return AFTER the image is fully loaded and available.
One concept which can be hard to grasp when your starting is the concept of "embedded" resources. Java allows you to package "resources" along with your code. These resources live within the context of your programs class path and make it MUCH easier to load when compared to having to deal with external files.
Have a look Packaging and accessing run-time resources in a runnable Jar for some basics.
Depending on the IDE you're using, it's usually pretty easy to "copy" these resources into your project/src and allow the IDE to package itself.
The problem with a question like this is it's very, very hard for anyone to truely diagnose, as there are so many reasons why the image might not have loaded and the solution is usual one of trial and error.
Me, I'd start by just drawing some lines/rectangles and make sure that paint is been called. I'd then look at things like the image's size, to make sure it's not something like 0x0.
Runnable example
This is a simple runnable example based on comments I made above. I'm using NetBeans and the image was stored in the "Source Package" (so, along with the other source code) under the /images package
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage beachBall;
public TestPane() {
try {
beachBall = ImageIO.read(getClass().getResource("/images/BeachBall.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (beachBall == null) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - beachBall.getWidth()) / 2;
int y = (getHeight() - beachBall.getHeight()) / 2;
g2d.drawImage(beachBall, x, y, this);
g2d.dispose();
}
}
}
It really looks like your image is not loaded.
As #MadProgrammer just told, new ImageIcon("ball.png") does not raise any error, and getImage() will always return something (not null), even if the file is not properly loaded.
To make sure your image is available, you can try ball.getWidth(null), and
if it returns -1, then something went wrong.
You can check the root path used by the JVM ("execution" location) with System.getProperty("user.dir"), the image file has to be exactly in this folder.
I tried your code with java 1.8 and it works well.

How to get keyEvent to work in Java?

I'm completely new at programming Java. I can't get my keyEvents to wont work. I need this for a little game I'm making. Here is my code:
package markusrytter.pingpong;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class main extends JPanel implements KeyListener {
static int ballX;
static int ballY;
static int ballR = 15;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(ballX - ballR, ballY - ballR, ballR * 2, ballR * 2);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Sample Frame");
main game = new main();
frame.add(game);
frame.setSize(1400, 800);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
ballX = frame.getContentPane().getSize().width / 2;
ballY = frame.getContentPane().getSize().height / 2;
while (true) {
game.repaint();
Thread.sleep(10);
}
}
public void keyPressed(KeyEvent e) {
System.out.println("A key is Pressed: " + e.getKeyCode());
if(e.getKeyCode() == KeyEvent.VK_SPACE){
System.out.println("Spacebutton pressed");
}
}
}
I do hope someone can help, I have tried to watch videos but again, I'm new at java.
Your code won't compile since you didn't implement KeyListener (completely)
You didn't add the key listener to the panel in its constructor.
KeyEvents are only dispatched to components with focus. Your panel is not focusable so it will never receive events. You use the method setFocusable(true).
Don't override paint(). Instead you should be overriding paintComponent(...).
You shouldn't even be using a KeyListener. Instead when using Swing you should be using Key Bindings.
Don't use static variables for the properties of your class.
Your GUI is not created on the Event Dispatch Thread (EDT).
i have read articles, i have watched videos, and done everything exactly like them,
Obviously not or it would work.
For a proper tutorial start with the Swing Tutorial. There are sections on:
How to Write a KeyListener
Custom Painting
Key Bindings.
Concurrency
Most importantly: change the name of your class. It's called main and that's a bad idea. Also it's much more advisable to override paintComponent() instead of paint.
You didn't add the keylistener to the JFrame. You should call this in your main after creating game:
frame.addKeyListener(game);
You also need to add the remaining KeyListener methods.
and that should do it.

Why isn't my JFrame repainting like I told it to?

When instantiating my modified JPanel class, I pass in a file through the constructor. The file (XML) gets read and the data gets used by me later in the paint method. However, right after I parse the data, I call both repaint() and revalidate(), but my GUI looks exactly the same. I call these methods both in my main class which extends JFrame and my panel class which extends JPanel.
When I choose an xml file from my JFileChooser, the drawPanel class gets instantiated with its other constructor, taking in the file and parsing it, then calling repaint and revalidate. I omitted most of the code to save your time.
Here's the main class' code:
public class myCode extends JFrame {
public myCode() {
super("Roadway Simulator");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
drawie = new drawPanel();
drawie.setSize(new Dimension(width - 200, height));
drawie.setMinimumSize(new Dimension(width - 200, height));
drawie.setMaximumSize(new Dimension(width - 200, height));
drawie.setLocation(0, 0);
add(drawie);
setVisible(true);
try{Thread.sleep(500);revalidate();repaint();}catch(InterruptedException eeee){}
}
public static void main(String[] args){new myCode();}
}
Here's my drawPanel class:
class drawPanel extends JPanel {
boolean drawRoad = false;
public drawPanel() {
super();
}
public drawPanel(Document doc){
super();
//the change in my paint method
drawRoad = true;
revalidate();
repaint();
}
public paint(Graphics g){
super.paint(g);
if(drawRoad){
g.setColor(Color.BLACK);
g.fillRect(0,0,600,600);
}
}
}
My code is the same as above, just with a lot more detail. Why isn't my JFrame repainting?
Here:
try{Thread.sleep(500);revalidate();repaint();}catch(InterruptedException eeee){}
Understand what Thread.sleep(...) does to a Swing GUI when called on the Swing event thread -- it puts the current thread which happens to be the Swing event thread, the one responsible for all drawing and user interaction, to sleep. In other words, you put your entire application completely to sleep.
Solution -- don't call this ever on the event thread.
As an aside, there's no cost to putting each method call on its own line, and no reason for that long line that you've posted as it serves no purpose other than to confuse.
try{Thread.sleep(500);revalidate();repaint();}catch(InterruptedException eeee){} is most likely blocking the Event Dispatching Thread, preventing from processing the Event Queue and making it look like your program has hung.
See Concurrency in Swing for more details...
It is also not recommended to override paint of Swing components and instead use paintComponent, see Performing Custom Painting for more details
In your case, I would recommend using a javax.swing.Timer instead of Thread.sleep, see How to use Swing Timers for more details
Updated
I don't see any where in your code that would change drawRoad from false to true, so your paint method is painting...nothing...so I guess you frame is painting exactly the way you told it to...
You may also like to take a look at Initial Threads and you might like to have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others
Updated
Given that you example is incomplete and won't compile, when I rebuild it, this will work...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.w3c.dom.Document;
public class TestDraw extends JFrame {
public TestDraw() {
super("Roadway Simulator");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawPanel drawie = new DrawPanel(null);
add(drawie);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new TestDraw();
}
});
}
class DrawPanel extends JPanel {
boolean drawRoad = false;
public DrawPanel() {
super();
}
public DrawPanel(Document doc) {
super();
drawRoad = true;
revalidate();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawRoad) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
}
If I change DrawPanel drawie = new DrawPanel(null); to DrawPanel drawie = new DrawPanel(); it still paints, but doesn't perform your custom painting.
The other problem is, as has already been highlighted, is the use of null layouts
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify.
Have a look at Why is it frowned upon to use a null layout in SWING? for more details...
Now, having said that, when you add drawie, you never give it a size, Swing is smart enough not to paint 0x0 sized components...

Java animation freeze

I am trying to write a simple 2d animation engine in Java for visualizing later programming projects. However, I am having problems with the window refresh. On running, the frame will sometimes display a blank panel instead of the desired image. This begins with a few frames at a time at apparently random intervals, worsening as the program continues to run until the actual image only occasionally blinks into view. The code for processing each frame is run, but nothing in the frame is actually displayed. I believe the problem may come from my computer more than my code (certainly not from bad specs though), but am not sure. Help much appreciated.
Three classes. Code here:
package animator;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.AudioClip;
public class APanel extends JPanel
{
public APanel(int l, int h){
setPreferredSize(new Dimension(l,h));
setLocation(80, 80);
setVisible(true);
setFocusable(true);
}
public Graphics renderFrame(Graphics g){
return g;
}
public void paintComponent(Graphics g) {
requestFocusInWindow();
renderFrame(g);
}
}
package animator;
import java.awt.*;
public class Animator extends APanel
//extending the APanel class allows you to code for different animations
//while leaving the basic functional animator untouched
{
public static final int SCREEN_X = 700;
public static final int SCREEN_Y = 700;
int frameNum;
public Animator() {
super(SCREEN_X, SCREEN_Y);
frameNum = 0;
}
public Graphics renderFrame(Graphics g) {
frameNum++;
g.drawString(""+frameNum,5,12);
return g;
}
}
package animator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Runner {
int framerate = 30;
Animator a = new Animator();
JFrame j = new JFrame();
public Runner(){
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.add(a);
start();
j.setSize(a.getPreferredSize());
j.setVisible(true);
}
public void start() {
Timer t = new Timer(1000/framerate, new ActionListener() {
public void actionPerformed(ActionEvent e){
j.getComponent(0).paint(j.getComponent(0).getGraphics());
//The following line of code keeps the window locked to a preferred size
// j.setSize(j.getComponent(0).getPreferredSize());
}
});
t.start();
}
public static void main(String[] args){
Runner r = new Runner();
}
}
There are some serious mistakes in your code which could be the cause or a factor of your problem...
j.setSize(a.getPreferredSize()); is irrelevant, simply use JFrame#pack, you get better results as it takes into account the frame decorations
j.setSize(j.getComponent(0).getPreferredSize()); use JFrame#setResizable and pass it false instead...
NEVER do j.getComponent(0).paint(j.getComponent(0).getGraphics()); this! You are not responsible for the painting of components within Swing, that's the decision of the RepaintManager. Just call j.repaint()
super(SCREEN_X, SCREEN_Y);...just override the getPreferredSize method and return the size you want.
setLocation(80, 80); irrelevant, as the component is under the control of a layout manager
setVisible(true); (inside APanel)...Swing components are already visible by default, with the exception of windows and JInternalFrames
And finally...
public void paintComponent(Graphics g) {
requestFocusInWindow();
renderFrame(g);
}
There is never any need for this method to be made public, you NEVER want someone to be able to call it, this will break the paint chain and could have serious ramifications in the ability for the component to paint itself properly.
You MUST call super.paintComponent before performing any custom painting, otherwise you could end up with all sorts of wonderful paint artifacts and issues
Never modify the state of a component from within a paint method...while it "might" not be an immediate issue calling requestFocusInWindow(); within your paintComponent could have side effects you don't know about...
Instead, it should look more like...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
renderFrame(g);
}

JButtons "extending" out of my JFrame

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

Categories

Resources