load contents of panel in java applet - java

I am trying to load a panel into a java applet, but the contents of the panel do not populate. As you can see from the code below, I set up a test to see where the code in the panel is failing to run, and the results of my test indicate that getRootPane().add(MyLabel) is the line of code that triggers the exception.
All of the code required to recreate this problem is included below. Can anyone show me how to alter the code below so that the contents of the panel get loaded into the applet?
Here is the code for TestApplet.java:
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class TestApplet extends JApplet {
public void init(){//Called when this applet is loaded into the browser.
//Execute a job on the event-dispatching thread; creating this applet's GUI.
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
}
}
private void createGUI(){
TestPanel myPanel = new TestPanel();
myPanel.setOpaque(true);
setContentPane(myPanel);
}
}
And here is the code for TestPanel.java:
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
getRootPane().add(myLabel);
System.out.println("Still running in constructor. ");
}
}
EDIT:
I edited my code as follows, based on the suggestions given so far. Using this.add does cause the JLabel to load, however, an inner class is still not loading, which I have added to the code below. Also, the changed code below is no longer triggering an exception; it just only loads the JLabel but does not load the inner class. Any suggestions as to how to load the inner class?
Here is the new TestApplet.java:
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class TestApplet extends JApplet {
public void init(){//Called when this applet is loaded into the browser.
//Execute a job on the event-dispatching thread; creating this applet's GUI.
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
System.err.println(e);
e.printStackTrace();
}
}
private void createGUI(){
TestPanel myPanel = new TestPanel();
myPanel.setOpaque(true);
setContentPane(myPanel);
}
}
And here is the new TestPanel.java:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestPanel extends JPanel{
DrawingLines myDrawingLines = new DrawingLines();
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
this.add(myLabel);
this.add(myDrawingLines);
myDrawingLines.repaint();
System.out.println("Still running in constructor. ");
}
//inner class to override paint method
class DrawingLines extends Canvas{
int width, height;
public void paint( Graphics g ) {
width = getSize().width;
height = getSize().height;
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
System.out.println("Running in paint method.");
}
}//end of inner class
}

Set the method as:
private void createGUI(){
TestPanel myPanel = new TestPanel();
getContentPane().add(myPanel);
}
and the class TestPanel as
public class TestPanel extends JPanel{
TestPanel(){
super();
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
add(myLabel);
System.out.println("Still running in constructor. ");
}
}

The rootpane is null because the Jpanel has not been added to any component yet. And adding stuff to panel rootpane like that is.. pretty dirty.

Let start at the beginning...
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
getRootPane().add(myLabel);
System.out.println("Still running in constructor. ");
}
}
Using getRootPane to add a component to it is the wrong thing to do. You should never need to add anything to a root pane. Instead you should be using the content pane, but that's not what you are trying to do (or should be doing from this context).
Instead, you simply be calling add
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
add(myLabel);
System.out.println("Still running in constructor. ");
}
}
This will then add the label to the TestPane
Lets take a look at the extension...
public class TestPanel extends JPanel{
DrawingLines myDrawingLines = new DrawingLines();
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
this.add(myLabel);
this.add(myDrawingLines);
myDrawingLines.repaint();
System.out.println("Still running in constructor. ");
}
//inner class to override paint method
class DrawingLines extends Canvas{
int width, height;
public void paint( Graphics g ) {
width = getSize().width;
height = getSize().height;
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
System.out.println("Running in paint method.");
}
}//end of inner class
}
First of, you should avoid mixing heavy and lightweight components (putting a Canvas on a JPanel), this is just not worth the frustration it will cause.
There is no need to call repaint in the constructor. At the time the constructor is called, the component can't be painted anyway.
Instead, simply override the panel's paintComponent method
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth;
int height = getHeight();
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
}
I strongly suggest you take a look at
Custom Painting
2D Graphics
Painting in AWT and Swing

Related

paintComponent isn't called [duplicate]

This question already has an answer here:
paintComponent is not being called in JPanel
(1 answer)
Closed 3 years ago.
Sorry for a probably already solved problem, but I've searched everywhere and cannot find a solution. I've just found that no matter what, paintComponent is not called no matter where I put repaint()
I have already tried putting it in several different methods and tried to call it from different areas but no matter what, it seems to never be called.
import java.awt.*;
import java.awt.event.*;
import java.awt.Component;
import javax.swing.*;
import javax.swing.BoxLayout;
import javax.swing.event.*;
import java.awt.event.KeyEvent;
import java.util.Scanner;
public class LevelOne extends JPanel implements KeyListener
{
int width = 0;
int height = 0;
int bx = 0;
int hx = 0;
int by = 0;
int hy = 0;
Image joe = new ImageIcon("upgrademan.png").getImage();
ImagePanel2 panel2 = new ImagePanel2(new ImageIcon("levelone.png").getImage());
JFrame frame = new JFrame ("Level One");
public LevelOne()
{
frame.getContentPane().add(panel2);
Game game1 = new Game();
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBackground(Color.WHITE);
frame.pack();
frame.setVisible(true);
levelOne();
requestFocus();
}
public void levelOne()
{
repaint(); // this doesn't call paintComponent below?
}
public void paintComponent(Graphics g)
{
super.paintComponent(g); //draw background color
System.out.println("this enters paintComponent");
g.drawImage(joe,100,100,200,200, null); // this doesn't seem to be drawing
requestFocus();
}
public void keyPressed(KeyEvent e) // all they keyListener methods
{
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
}
class ImagePanel2 extends JPanel { // this entire class simply exists to call in order to set a picture as a background
Image img;
public ImagePanel2(String img) { // just sets img in method to class img variable
this(new ImageIcon(img).getImage());
}
public ImagePanel2(Image img) { // sets size of picture
this.img = img;
Dimension dims = new Dimension(600,600);
setPreferredSize(dims);
setMinimumSize(dims);
setMaximumSize(dims);
setSize(dims);
setLayout(null);
}
public void paintComponent(Graphics g) { // draws image
g.drawImage(img, 0, 0, this);
}
}
I expected the ImagePanel class to print a background, which it did, but I also expected the image called joe to print, which it did not.
The only place you display "joe" is in the paintComponent() method of instances of LevelOne. But you never add a LevelOne instance to your frame, or to any panel in that frame.

Java: having trouble calling a method from one class into another

Still trying to grasp how classes and methods work in Java. To experiment, I tried to create a graphics class, with a void draw box method inside. Then, I try to call that method in the main method to try to draw those boxes. I'm getting "cannot be resolved to variable" errors which I believe means the main class can't see my other class for some reason?
Boxymain.java:
import java.awt.*;
import javax.swing.JFrame;
public class Boxymain extends Canvas {
public static void main(String[] args){
BoxyMethod c = new BoxyMethod();
c.drawBox(window, Color.RED, 200, 300);
JFrame win = new JFrame("Boxy Main");
win.setSize(800,600);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Boxymain canvas = new Boxymain();
win.add(canvas);
win.setVisible(true);
}
}
BoxyMethod.java:
import java.awt.*;
import javax.swing.JFrame;
public class BoxyMethod {
public void drawBox(Graphics window, Color c, int x, int y){
window.setColor(c);
window.fillRect(x, y, 100, 100);
window.setColor(Color.WHITE);
window.fillRect(x+10,y+10,80,80);
}
}
Error text: "window cannot be resolves to a variable."
The error message is telling you exactly what is wrong. You're passing in a window variable into the drawBox method, but you don't declare or initialize such a variable in the main method before doing so, and so this cannot be done in Java.
BoxyMethod c = new BoxyMethod();
// *** window variable below is used but never declared prior to use
c.drawBox(window, Color.RED, 200, 300);
More importantly though, you're not doing Swing drawing correctly.
Instead, you should create a class that extends JPanel, give it a paintComponent(Graphics g) method override, and draw in that method. Then place that JPanel in a JFrame and display the JFrame. Please check out the Performing Custom Painting Swing graphics tutorial for more detail on how to do Swing graphics.
As an aside, do not follow that tutorial that you've linked to as it is 30 years out of date.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class BoxyTest {
private static void createAndShowGui() {
JFrame frame = new JFrame("Boxy Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new BoxyPanel(200, 300));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class BoxyPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private int myX;
private int myY;
public BoxyPanel(int myX, int myY) {
this.myX = myX;
this.myY = myY;
}
#Override // so my JPanel will be big enough to see
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
// call super method so that the JPanel can do housekeeping painting
super.paintComponent(g);
g.fillRect(myX, myY, 100, 100);
g.setColor(Color.WHITE);
g.fillRect(myX + 10, myY + 10, 80, 80);
}
}

Java GUI stumped. Only one display in JFrame

I am trying to create Jframe that houses three JPanels. I have extended JPanel so that each time it may be passed a color and a diameter. The end result being a JFrame that has 1 red, 1 yellow and 1 green stoplightpanel. I plan on adding an ActionListener to these panels which is why it is designed this way. It is not working because currently, I only can see the yellow panel.
Fair warning this is for a class. So I have tried every configuration I can think of and I still only see one instance of my subclass present in my Jframe. If anyone can point out the obvious I would be appreciated. Oddly enough only my yellow light is displayed.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class TrafficLight3 extends JFrame {
public static void main ( String [] args ) {
TrafficLight3 tl = new TrafficLight3 ( );
}
// Constructor
public TrafficLight3( ) {
setTitle( "Traffic Light" );
setSize ( 200, 400 );
setLocation ( 200, 200 );
setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
StopLightPanel red = new StopLightPanel( 100, Color.RED );
// add stoplight panel's to JFrame's default border layout.
add( red, BorderLayout.NORTH );
StopLightPanel yellow = new StopLightPanel( 100, Color.YELLOW );
add( yellow, BorderLayout.CENTER );
StopLightPanel green = new StopLightPanel( 100, Color.GREEN );
add ( green, BorderLayout.SOUTH );
setVisible( true );
}
class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel ( int d, Color c) {
diameter = d;
color = c;
}
public void paintComponent ( Graphics g ) {
g.setColor ( color );
g.fillOval ( 50, 25, diameter, diameter );
}
}
}
1- Ensure that your code runs in EDT
2- #Flight2039 is correct, it seems that BorderLayout where location is not the CENTER uses preferredSize to determinate the size. So you could override getPreferredSize()
3- When you override paintComponent(..) you have to call super.paintComponent(..) to follow painting method chaining. More information here.
4- Add #Override annotation always this will check at compile time for example if you make some typo overriding the method.
See this runnable example, i used gridLayout with one column and three rows.
package test2;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TrafficLight3 {
private JPanel redPanel;
private JPanel yellowPanel;
private JPanel greenPanel;
// Constructor
public TrafficLight3() {
redPanel = new StopLightPanel(100, Color.RED);
yellowPanel = new StopLightPanel(100, Color.YELLOW);
greenPanel = new StopLightPanel(100, Color.GREEN);
}
private static class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel(int d, Color c) {
diameter = d;
color = c;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(50, 25, diameter, diameter);
}
#Override
public Dimension getPreferredSize(){
int x = diameter*2;
return new Dimension(x,x);
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("Traffic Light");
frame.setSize(200,500);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new GridLayout(3,1));
frame.setLocationByPlatform(Boolean.TRUE);
TrafficLight3 example = new TrafficLight3();
frame.add(example.redPanel);
frame.add(example.yellowPanel);
frame.add(example.greenPanel);
// Display the window.
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
And the output..
You need to override getPreferredSize() for your custom JPanels so that layout managers know how big to make them. The center position will size your panels to use all the available space, but the other positions will not. See this example which also removes your setSize() and setLocation() as well and replaces it with a call to pack().
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TrafficLight3 extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TrafficLight3 tl = new TrafficLight3();
}
});
}
// Constructor
public TrafficLight3() {
setTitle("Traffic Light");
// setSize(200, 400);
// setLocation(200, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StopLightPanel red = new StopLightPanel(100, Color.RED);
// add stoplight panel's to JFrame's default border layout.
add(red, BorderLayout.NORTH);
StopLightPanel yellow = new StopLightPanel(100, Color.YELLOW);
add(yellow, BorderLayout.CENTER);
StopLightPanel green = new StopLightPanel(100, Color.GREEN);
add(green, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
class StopLightPanel extends JPanel {
private int diameter;
private Color color;
public StopLightPanel(int d, Color c) {
diameter = d;
color = c;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(50, 25, diameter, diameter);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 133);
}
}
}

How to resize frame dynamically with Timer?

I'm trying to resize a window dynamically using a Timer object, but not succeeding... I set the preferred size of the panel in the constructor, which sets the size of the window nicely, though only once. The preferred size changes after the program is initialized, but the window size stays the same. Why? Because the constructor is initialized only once and therefore isn't affected by the size change? If so, how could I get around this to resize the window in real-time?
I know this won't solve the problem in the exercise given in the beginning comments, so please ignore that :-)
/*
* Exercise 18.15
*
* "(Enlarge and shrink an image) Write an applet that will display a sequence of
* image files in different sizes. Initially, the viewing area for this image has
* a width of 300 and a height of 300. Your program should continuously shrink the
* viewing area by 1 in width and 1 in height until it reaches a width of 50 and
* a height of 50. At that point, the viewing area should continuously enlarge by
* 1 in width and 1 in height until it reaches a width of 300 and a height of 300.
* The viewing area should shrink and enlarge (alternately) to create animation
* for the single image."
*
* Created: 2014.01.07
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Ex_18_15 extends JApplet {
// Main method
public static void main(String[] args) {
JFrame frame = new JFrame();
Ex_18_15 applet = new Ex_18_15();
applet.isStandalone = true;
frame.add(applet);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// Data fields
private boolean isStandalone = false;
private Image image = new ImageIcon("greenguy.png").getImage();
private int xCoordinate = 360;
private int yCoordinate = 300;
private Timer timer = new Timer(20, new TimerListener());
private DrawPanel panel = new DrawPanel();
// Constructor
public Ex_18_15() {
panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
add(panel);
timer.start();
}
class DrawPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(yCoordinate <= 50) {
yCoordinate++;
xCoordinate++;
}
else if(yCoordinate >= 300) {
yCoordinate--;
xCoordinate--;
}
panel.setPreferredSize(new Dimension(xCoordinate, yCoordinate));
repaint();
}
}
}
You need to re-pack your JFrame to resize it. For instance at the end of your ActionListener:
Window win = SwingUtilities.getWindowAncestor(panel);
win.pack();
A question for you though: Why in heaven's name is your class extending JApplet and not JPanel? Or if it needs to be an applet, why are you stuffing it into a JFrame?
Edit
Regarding your comment:
Wouldn't it usually be extending JFrame not JPanel? I'm stuffing it into a JFrame to allow it to run as an application as well as an applet. That's how 'Introduction to Java Programming' tells me how to do it :p Adding your code at the end of the actionPerformed method didn't do anything for me ;o
Most of your GUI code should be geared towards creating JPanels, not JFrames or JApplets. You can then place your JPanels where needed and desired without difficulty. Your book has serious issues and should not be trusted if it is telling you this.
Edit 2
Works for me:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShrinkingGui extends JPanel {
private static final int INIT_W = 400;
private static final int INIT_H = INIT_W;
private static final int TIMER_DELAY = 20;
private int prefW = INIT_W;
private int prefH = INIT_H;
public ShrinkingGui() {
new Timer(TIMER_DELAY, new TimerListener()).start();;
}
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (prefW > 0 && prefH > 0) {
prefW--;
prefH--;
Window win = SwingUtilities.getWindowAncestor(ShrinkingGui.this);
win.pack();
} else {
((Timer)e.getSource()).stop();
}
}
}
private static void createAndShowGUI() {
ShrinkingGui paintEg = new ShrinkingGui();
JFrame frame = new JFrame("Shrinking Gui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Make text appear briefly in a JPanel

I am trying to make text appear briefly before it disappears. It would be along the lines of
1) Set color to black
2) wait x amount of seconds
3) set color to background color
The method I call is repaint(), which then calls paintComponent(Graphics painter). repaint() is called only if I press the space-bar.
I thought of trying repaint();Thread.sleep(1000);repaint(); (I do catch the Interrupt exception, just not shown), but it only calls paintComponent once per space-bar .
Is there an easy way to do this or is this something that is a bit challenging?
I would use a Swing Timer to schedule the repainting of the text.
Also, I would just use a JLabel to display the text. Then you just use the setText(...) method to change the text as you wish and the component will repaint itself.
You need to override the paint method in your panel and make it implement Runnable so that you can turn off the text after a few seconds. Here is some sample code:
import java.awt.Color;
import java.awt.Graphics;
import java.io.Exception;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
class MyPanel extends JPanel implements Runnable{
private final static String TEXT = "HELLO WORLD";
private boolean on = true;
#Override
public void paint(Graphics g) {
super.paint(g);
if(on){
g.drawString(TEXT, 20, 20);
}
}
#Override
public void run() {
for(int i = 0 ; i< 2 ; i++){
paintImmediately(0, 0, getWidth(), getHeight());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
on = false;
}
}
}
public class App {
public static void main(String[] args) throws Exception {
JFrame f = new JFrame();
final MyPanel p = new MyPanel();
f.add(p);
f.setSize(100,100);
f.setVisible(true);
Thread t = new Thread(p);
t.start();
}
}

Categories

Resources