Multiple panels / canvas - java

I am looking for a way to dinamiclly switch between panels / between a panel or a canvas.
More specific: I am developing a game. In my code there is a class that extends canvas and implements
Runnable, and in the constructor of Game, it creates a new instance of a class called window. That is window class:
public class Window extends Canvas {
private static final long serialVersionUID = -299686449326748512L;
public static JFrame frame = new JFrame();
public Window(int width, int height, String title, Game game) {
// JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(width, height));
frame.setMaximumSize(new Dimension(width, height));
frame.setMinimumSize(new Dimension(width, height));
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(game);
frame.setVisible(true);
game.start();
}
}
I want to be able to remove game from the frame, activate another panel, and stop the execution of Game.
I have already tried:
game.stop();
Window.frame.remove(game);
but it makes the program to crash. Those are start() & stop() methods:
/**
* starts the game.
*/
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
/**
* tries to stop the game.
*/
public synchronized void stop() {
try {
thread.join();
running = false;
} catch (Exception e) {
e.printStackTrace();
}
}
My main goal is to be able to play a cutscene if some event happend and I am trying to use vlcj for that purpose. If anyone has an idea that will allow me to execute this goal that would be great too.

I've made an example, doing what I think you want without a card layout, and using a thread. I think this is a proof of concept, that what your asking is possible. Below, I will include a few things I would do to improve it.
import javax.swing.*;
import java.awt.*;
public class SwapCards{
Thread gameLoop;
volatile boolean running = false;
double x = 0;
double y = 0;
double theta = 0;
JFrame frame = new JFrame("swapped");
Canvas gamePanel = new Canvas(){
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLACK);
g.drawOval((int)x, (int)y, 25, 25);
}
};
Canvas nonGame = new Canvas(){
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);
g.fillRect(0,0,200, 200);
}
};
public void step(){
x = 100 + 50*Math.sin( theta );
y = 100 + 50*Math.cos( theta );
theta += 0.02;
if(theta > 6.28) theta = 0;
}
public void startGameLoop(){
frame.remove(nonGame);
frame.add(gamePanel, BorderLayout.CENTER);
frame.validate();
running = true;
gameLoop = new Thread(()->{
while(running){
step();
gamePanel.repaint();
try{
Thread.sleep(30);
}catch (Exception e){
running = false;
throw new RuntimeException(e);
}
}
});
gameLoop.start();
}
public void stopGameLoop(){
frame.remove(gamePanel);
frame.add(nonGame, BorderLayout.CENTER);
running = false;
try{
gameLoop.join();
} catch(Exception e){
throw new RuntimeException(e);
}
}
public void buildGui(){
JButton button = new JButton("action");
button.addActionListener( evt->{
if(!running){
startGameLoop();
} else{
stopGameLoop();
}
});
frame.add(nonGame, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
EventQueue.invokeLater( new SwapCards()::buildGui );
}
}
First off, Canvas is somewhat outdated, use a JPane and override paintComponent. That gives you more access to the power of swing.
In this example I am doing trivial work so the thread is absolutely overkill I could replace it with a javax.swing.Timer.
Timer timer = new Timer(30, evt->{
step();
gamePanel.repaint();
});
Then in the start and stop methods, I just call timer.start() or timer.stop() respectively.
Using a CardLayout makes it a bit clearer what you want to do, plus it has methods for navigating the cards. Eg. If you have a cut scene with a series of components you want to show, you can use cardLayout.next(parent).
When we create the layout:
cards = new CardLayout();
swap = new JPanel(cards);
swap.add(gamePanel, "game");
swap.add(nonGame, "nogame");
cards.last(swap);
frame.add(swap, BorderLayout.CENTER);
This will add the cards to swap and make it show "nogame". Then in the start/stop methods we just switch to the respective card.
cards.show(swap, "game");

Related

Background disappears when button is pressed [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last month.
Improve this question
I have set up a game in Java using Swing UI.
Expected
When firing a projectile across the screen and I want the background to be constantly there
Issue
When I run the code the background appears to be fine.
But when the button to fire the projectile is pressed then the background disappears.
Code
public class ProjectileShooterTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame() {
};
ImageIcon background=new ImageIcon("Background.png");
Image img=background.getImage();
Image temp=img.getScaledInstance(800,440,Image.SCALE_SMOOTH);
background=new ImageIcon(temp);
JLabel back=new JLabel(background);
back.setBounds(0,0,800,500);
f.getContentPane().setLayout(new BorderLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800,500);
final ProjectileShooter projectileShooter = new ProjectileShooter();
ProjectileShooterPanel projectileShooterPanel = new ProjectileShooterPanel(projectileShooter);
projectileShooter.setPaintingComponent(projectileShooterPanel);
JPanel controlPanel = new JPanel(new GridLayout(1,0));
controlPanel.add(new JLabel(" Post-Launch Angle"));
final JSlider angleSlider = new JSlider(70, 89, 85);
angleSlider.setLayout( new FlowLayout() );
controlPanel.add(angleSlider);
f.add(back);
controlPanel.add(new JLabel(" Thrust"));
final JSlider powerSlider = new JSlider(50, 80, 60);
powerSlider.setLayout( new FlowLayout() );
controlPanel.add(powerSlider);
JButton shootButton = new JButton("Launch");
shootButton.setLayout( new FlowLayout() );
shootButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int angleDeg = angleSlider.getValue();
int power = powerSlider.getValue();
projectileShooter.setAngle(Math.toRadians(angleDeg));
projectileShooter.setPower(power);
projectileShooter.shoot();
}
});
f.add(back);
controlPanel.add(shootButton);
f.getContentPane().add(controlPanel, BorderLayout.NORTH);
f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);
f.setVisible(true);
f.setLayout(new BorderLayout());
}
}
class ProjectileShooter
{
private double angleRad = Math.toRadians(45);
private double power = 50;
private Projectile projectile;
private JComponent paintingComponent;
void setPaintingComponent(JComponent paintingComponent)
{
this.paintingComponent = paintingComponent;
}
void setAngle(double angleRad)
{
this.angleRad = angleRad;
}
void setPower(double power)
{
this.power = power;
}
void shoot()
{
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
executeShot();
}
});
t.setDaemon(true);
t.start();
}
private void executeShot()
{
if (projectile != null)
{
return;
}
projectile = new Projectile();
Point2D velocity =
AffineTransform.getRotateInstance(angleRad).
transform(new Point2D.Double(1,0), null);
velocity.setLocation(
velocity.getX() * power * 0.5,
velocity.getY() * power * 0.5);
projectile.setVelocity(velocity);
//System.out.println("Initial "+velocity);
long prevTime = System.nanoTime();
while (projectile.getPosition().getY() >= 0)
{
long currentTime = System.nanoTime();
double dt = 3 * (currentTime - prevTime) / 1e8;
projectile.performTimeStep(dt);
prevTime = currentTime;
paintingComponent.repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
projectile = null;
paintingComponent.repaint();
}
Projectile getProjectile()
{
return projectile;
}
}
Question
How can I solve this?
f.add(back);
is equivalent to:
f.getContentPane().add(back, BorderLayout.CENTER);
Later in your code you do:
f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);
Which will cause problems because you can't add two components to the CENTER.
A Swing GUI is parent/child design so you need something like:
f.getContentPane().add(back, BorderLayout.CENTER);
back.setLayout(new BorderLayout());
back.add(projectileShooterPanel, BorderLayout.CENTER);
I'll let you figure out the logic order and placement of the above statements.
Also why do you have:
f.setLayout(new BorderLayout());
at the end of the constructor? This replaces all the constraint information of your original layout.
Finally, your projectile shooter panel needs to be transparent, otherwise it will paint over top of the background. So you also need:
projectileShooterPanel.setOpaque( false );
Note: instead of using the JLabel as the background it would be easier to paint the background in your projectile shooter panel. Then you won't have issues with trying to add multiple panels to one another and the shooter panel won't need to be transparent.
Edit:
You need a parent/child relationship between your components like:
- frame
- content pane
- background image
- projectile panel
- projectile
My first suggestion was to make the background a component and add the projectile panel to it:
set the layout of the background component
add the projectile panel to the background
make the projectile panel transparent so you can see the image
This is not the best solution
The second solution was to paint the background as part of the projectile panel:
paint the background image in the projectile panel
paint the projectile
This is the preferred solution.

Graphics loop glitches, how to fix?

I've been trying to make this work so that there are 20 boxes each with 3 different sizes and 3 different colours that chosen at random, but i cant make them come out at different times and they just glitch into eachother and the colours are glitching together and stuff like that, anyone know how to fix it? Heres what i got so far:
import java.awt.*;
import javax.swing.*;
public class testwork extends JPanel { //JPanel is a class
int l = 0;
private int x = 10;
private int y = 500;
private void move()
{
x++;
}
boolean red = false;
boolean blue = false;
boolean green = false;
#Override
public void paint(Graphics g) { //JPanel is a class defined in
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color rectColor = new Color(0, 66, 89);
g2d.setColor(rectColor);
//belt
g2d.setColor(Color.lightGray);
g2d.fillRect(0,450,1500,200);
g2d.fillRect(700,0,200,1000);
g2d.setColor(Color.orange);
for (int i = -10000; i<10000; i=i+50) {
int m= i++;
g2d.fillRect(m, 450, 25, 200);
}
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(700, 450, 200, 200);
//boxes
while (l<=20) {
if (Math.random() < 0.5)
{g2d.setColor(Color.RED);;}
else if (Math.random() < 0.5) {g2d.setColor(Color.GREEN);}
else {g2d.setColor(Color.BLUE);}
if (Math.random() < 0.5)
{g2d.fillRect(x,y,50,50);}
else if (Math.random() < 0.5) {g2d.fillRect(x,y,50,100);}
else {g2d.fillRect(x,y,100,50);}
l++;
}
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Frame"); //Add our JPanel to the frame
frame.add(new attempt());//instantiate a new object
frame.setSize(1500, 1000);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
testwork p = new testwork();
frame.add(p);
while (true)
{
p.move(); //Updates the coordinates
p.repaint();
Thread.sleep(10); //Pauses for a moment
}}
}
Unfortunately, you are doing a number of things incorrectly.
Override paintComponent and not paint.
Don't use Thread.sleep. Use a Swing timer and an ActionListener
You are doing too much in the painting method. All event handling including calls to repaint() is done on the Event Dispatch Thread(EDT). So all your updating are done inside of paintComponent so only the last painted objects will be shown when you exit. Update your coordinates, data structure and anything else that needs to be painted outside of your paint method.
Put your boiler plate code inside your Testwork class constructor. Here is an example.
public Testwork() {
setPreferredSize(new Dimension(1000, 700));
Timer timer = new Timer(0, this);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
// sizes the frame and jpanel and organizes the components.
frame.pack();
// centers the window in the screen
frame.setLocationRelativeTo(null);
// sets the delay in milliseconds
timer.setDelay(100);
// starts the timer
timer.start();
}
Here would be your actionListener code.
public void actionPerformed(ActionEvent ae) {
// update any variables that need to be used int he
// paint routine here. That means if you want to move something
// update the coordinates here and then use them in the paint method.
}
when you start up, your app, do it like this
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Testwork());
}
There is much more to painting. I recommend checking out Custom Painting in the Java tutorials. Here is another example on this (SO) site.

JFrame too small and pack() doesn't seem to work

For some reason, the JFrame is too small when run, and using pack(); doesn't seem to fix the problem. Any ideas?
public class Window {
public Window(String title, Game game) {
// Creates new JFrame
JFrame frame = new JFrame(title);
// Adds Game to window
frame.add(game);
frame.pack();
// Settings of Window
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
The cyan background is supposed to be a 64 x 64 border in the bottom and right sides. The boxes drawn are correct, which I checked by resizing the window. However the window is too small and does not fit the canvas.
Game Class:
public class Game extends Canvas implements Runnable {
private Handler handler;
public Game() {
// Create new window
Window window = new Window("Horses Aren't Real", this);
handler = new Handler();
this.addKeyListener(new KeyInput(handler));
handler.addObject(new Daanish(100, 100, ID.Player, handler));
}
public static void main (String args[]) {
// Creates new game
new Game();
}
public void draw() {
// Creates a new BufferStrategy
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
// This allows the game to preload 3 frames in order to prevent choppy framrate
this.createBufferStrategy(3);
return;
}
// Create Graphics
Graphics g = bs.getDrawGraphics();
g.setColor(Color.cyan);
g.fillRect(0, 0, 1024, 640);
g.setColor(Color.black);
g.fillRect(0, 0, 960, 576);
handler.draw(g);
// Remove frame from queue
g.dispose();
bs.show();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1024, 640);
}
}
So you're running into a number of issues. The first been, the size of the window must also account for the frame decorations, this means that the available space for the content is the size of the window MINUS the size of the frame decorations.
Setting the size of the window directly is ill-advised.
pack asks the content of the frame for it's preferred size and uses that to wrap the window around it. So, instead of window size - decorations = content size, you have content size + decorations = window size
From the JavaDocs
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents. The resulting width and height of the window are automatically enlarged if either of dimensions is less than the minimum size as specified by the previous call to the setMinimumSize method.
So, instead, override preferredSize of the Game class and return the amount of space you want, may be something like...
public class Game extends JPanel {
//...
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
//...
}
Your next problem is, Window extends from JFrame, but in the constructor, you're creating ANOTHER Frame ... so which one is actually doing what?
Remove the confusion. Avoid extending from top level containers like JFrame, you're not adding any new functionality to it
public class Window {
public Window(String title, Game game) {
// Creates new JFrame
JFrame frame = new JFrame(title);
// Adds Game to window
frame.add(game);
frame.pack();
// Settings of Window
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Updated...
So, I took your "updated" code, modified it so it would run, ran and didn't have any issues...
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Game game = new Game();
Window window = new Window("Help", game);
game.start();
}
});
}
public class Window {
public Window(String title, Game game) {
// Creates new JFrame
JFrame frame = new JFrame(title);
// Adds Game to window
frame.add(game);
frame.setResizable(false);
frame.pack();
// Settings of Window
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
public class Game extends Canvas { //implements Runnable {
// private Handler handler;
public Game() {
//
// handler = new Handler();
// this.addKeyListener(new KeyInput(handler));
//
// handler.addObject(new Daanish(100, 100, ID.Player, handler));
}
public void start() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
draw();
try {
Thread.sleep(40);
} catch (InterruptedException ex) {
}
}
}
});
thread.start();
}
public void draw() {
// Creates a new BufferStrategy
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
// This allows the game to preload 3 frames in order to prevent choppy framrate
this.createBufferStrategy(3);
return;
}
// Create Graphics
Graphics g = bs.getDrawGraphics();
g.setColor(Color.cyan);
g.fillRect(0, 0, 1024, 640);
g.setColor(Color.black);
g.fillRect(0, 0, 960, 576);
// handler.draw(g);
// Remove frame from queue
g.dispose();
bs.show();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1024, 640);
}
}
}
However, I'm running on MacOS. There is a little known issue with setResizable I've run across on Windows, where the window decorations change size when setResizable is called.
The "basic" solution is to call setResziable BEFORE calling pack, so that the frame decorations are modified before the the API makes decisions about how to update the size of the window.
I had thought this was fixed in later (8+) versions of Java, but since I don't run Windows, it's impossible for me to test
See My JFrame always becomes a few pixels too big. for some more details.
public class Window extends JFrame {
public Window(final int width, final int height, String title, Game game) {
super(title);
// Set dimensions
Dimension d = new Dimension(width, height);
game.setPreferredSize(d);
// Adds Game to window
add(game);
// Settings of Window
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
setVisible(true);
}
}
When you use pack, the frame generaly resize to content size

draw control inside another using its graphics

I'm basically trying to draw a JComponent inside another by calling the second component's paint passing it the first component's Graphics.
I'm trying to create a GUI editor, (reinventing the wheel, I know, it's just a proof of concept)
So I have a class that extends JPanel where I want to draw components from a VectorControls.
So far I got this method in my extended JPanel:
#SuppressWarnings("serial")
public class Sketch extends JPanel {
private Vector<JComponent> controls = new Vector<JComponent>();
public Sketch() {
super();
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
public void addControl(JComponent c) {
Dimension d = new Dimension(100,50);
c.setPreferredSize(d);
c.setMinimumSize(d);
c.setMaximumSize(d);
controls.add(c);
this.repaint();
this.revalidate();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int i=controls.size()-1; i>=0; i--) {
JComponent c = controls.get(i);
c.paint(g);
}
}
}
I'm building/attaching the Sketch panel like this:
public GUIEditor() {
mainFrame = new JFrame("GUI EDITOR");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Sketch mainPanel = new Sketch();
mainPanel.setPreferredSize(new Dimension(640,480));
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
mainFrame.setLayout(gbl);
JPanel toolsPanel = new JPanel();
toolsPanel.setPreferredSize(new Dimension(160,480));
toolsPanel.setLayout(new GridLayout(0,1));
for(Control c : toolBoxItems ) {
AbstractAction action = new ToolBoxButtonAction(mainPanel, c.type);
JButton b = new JButton(action);
b.setText(c.title);
toolsPanel.add(b);
}
gbc.gridx = 0;
gbc.gridy = 0;
gbl.setConstraints(mainPanel, gbc);
mainFrame.add(mainPanel);
gbc.gridx = 1;
gbc.gridy = 0;
gbl.setConstraints(toolsPanel, gbc);
mainFrame.add(toolsPanel);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
Inside ToolBoxButtonAction, basically I'm doing this:
public void actionPerformed(ActionEvent e) {
try {
sketch.addControl(control.newInstance());
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
but I'm writing this because it doesn't work.
Any ideas on how to achieve this?
I'm basically trying to draw a JComponent inside another by calling the second component's paint passing it the first component's Graphics.
Components can only be painted when the component has non-zero size. Normally the size of a component is determined by the layout manager.
Your basic code looks reasonable, but unless you have code to size and locate the components you won't see anything. If you just set the size then all components will paint on top of one another.
Or the problem may be that your parent panel doesn't have a size so it is not even painted. The default FlowLayout uses the preferred size of the child components to determine the panels size. Since you don't add components directly to the panel there are no child components so the preferred size will be 0. When you reinvent the wheel you need to reinvent everything.
Without a SSCCE the context of how you use this code is unknown to all we can do is guess.
Edit:
Create a SSCCE when you have a problem and get it working with hard coded values before trying to get it to work dynamically. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class Sketch extends JComponent
{
private Vector<JComponent> controls = new Vector<JComponent>();
public void addControl(JComponent c)
{
c.setSize(100, 50);
int location = controls.size() * 50;
c.setLocation(location, location);
controls.add(c);
repaint();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=controls.size()-1; i>=0; i--)
{
JComponent c = controls.get(i);
Point location = c.getLocation();
g.translate(location.x, location.y);
c.paint(g);
g.translate(-location.x, -location.y);
}
}
private static void createAndShowUI()
{
Sketch sketch = new Sketch();
sketch.addControl( new JButton("button") );
sketch.addControl( new JTextField(10) );
sketch.addControl( new JCheckBox("Checkbox") );
JFrame frame = new JFrame("Sketch");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( sketch );
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Some time ago, I've written a framework for such tasks. Maybe you find it useful (the library is Open Source):
Tutorial:
http://softsmithy.sourceforge.net/lib/current/docs/tutorial/swing/customizer/index.html
Javadoc:
http://softsmithy.sourceforge.net/lib/current/docs/api/softsmithy-lib-swing-customizer/index.html
Info about the latest release:
http://puces-blog.blogspot.ch/2012/11/news-from-software-smithy-version-03.html

Java: Image won't show until I resize the window

I am programming in java and I'm getting into GUIs and Graphics. In my program I paint an image onto a JPanel and add the JPanel to the main window. The Problem I'm having is when I run the program the image doesn't show until I manually resize the window. Here is the relevant code:
Where the image is drawn:
public class painting extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
g.drawImage(Toolkit.getDefaultToolkit().getImage("image.png"), 0, 0, null);
}
}
Where JPanel is added to JFrame (c is GridBagConstraints):
public class GUI extends JFrame{
public GUI(){
painting Pnt = new painting();
c.gridx = 1; c.gridy = 0;
c.ipadx = 540; c.ipady = 395;
add(Pnt, c);
}
}
Where The Window is set up:
public class MainC{
public static void main (String args[]){
GUI gui = new GUI();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.pack();
gui.setVisible(true);
gui.setTitle("Title");
}
}
Thanks,
Bennett
EDIT: I noiced that it sometimes displays the image correctly but then if I close the program and try again and it doesn't work until I resize it.
EDIT2: Here are the files GUI class, MainC class
Toolkit.getImage() works asynchronously. Either use ImageIO.read() or add a MediaTracker.
In GUI constructor you should call super() before anything else.
Also move:
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.pack();
gui.setVisible(true);
gui.setTitle("Title");
in GUI constructor.
Your problem must be somewhere else in your code. I copied and pasted your three classes into my IDE. The only thing I changed was in GUI.java I added setLayout(new GridBagLayout()); and GridBagConstraints c = new GridBagConstraints(); and I changed the location of the image to one of my own. The window works as expected with the image displayed right away.
I assume you have additional code not displayed here, such as the initialization of c that I added. Check your other code to make sure you are not redrawing over your image initially. Also, if you post the other code I could help you identify the problem
does
Toolkit.getDefaultToolkit().getImage("image.png")
brings you the picture?
I tried it with:
public class Gui extends JFrame{
public Gui() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.setBounds(100, 100, 300, 300);
JPanel pnl = new JPanel(){
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
try {
g.drawImage(new Robot().createScreenCapture(new Rectangle(90, 90)), 0, 0, null);
} catch (AWTException e) {
e.printStackTrace();
}
}
};
getContentPane().add(pnl, BorderLayout.CENTER);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
}
});
}
and it works.

Categories

Resources