How can I add a JButton to a JPanel from other class? - java

So I have 2 classes. One that creates a JPanel and a JFrame, and one that creates Buttons. Now I want to add those Buttons to my JPanel.
Where my JPanel and JFrame are created:
public class Surface extends JPanel implements KeyListener, ActionListener
{
private static final long serialVersionUID = 1L;
static JFrame jframe = new JFrame("TitleComingSoon");
Snake mySnake = new Snake(true);
int width;
int height;
#SuppressWarnings("deprecation")
public Surface(int width, int height)
{
this.width = width;
this.height = height;
// Create the JPanel
setLayout(null);
setBounds(0, 0, 400, 400);
setBackground(Color.DARK_GRAY);
// Create the JFrame
jframe.setSize(width, height);
jframe.setResizable(false);
jframe.setLayout(null);
jframe.add(this); // Add the JPanel to the JFrame
jframe.setVisible(true);
// Add the KeyListener
addKeyListener(this);
setFocusTraversalKeysEnabled(true);
setFocusable(true);
requestFocusInWindow();
show();
}
#Override
public void paintComponent(Graphics diamond)
{
super.paintComponent(diamond);
diamond.drawRect(60, 60, 100, 50);
diamond.setColor(Color.RED);
repaint();
}
}
And in my other class I'm doing this:
Surface.jframe.add(myButton);
My problem is, that the buttons is under the JPanel. So if I remove the JPanel, I can see the button.

Several things jump out...
Use of null layouts. While it might seem like you gain control, you increase your work load and lose flexibility between platforms.
Creating a frame from with another component, but more importantly, from within its constructor. The panel shouldn't be concerned with how it will be displayed and should be focused on doing the job it was designed for.
Use of KeyListener. KeyListener is fussy and troublesome, better to use the Key Bindings API
Use of static for cross object communication. Static is not how you provide access to fields across classes, there are plenty of other techniques which provide better support. The main problem is, if you create another instance of your pane, you'll create a new frame and change the reference to the static field...now which frame are you actually addressing?
So, what's the solution?
From your "main" entry class, create an instance of a JFrame, your Surface panel and button. Set the Surface panel as the content panel of the frame, then add the button to the frame.
Make use of appropriate layout managers
Use the key bindings API instead of KeyListener

You could create an instance of your ButtonHolderClass in Surface and retrieve the button by way of a public getter method:
public Surface(int width, int height)
{
...
ButtonHolderClass buttonHolder = new ButtonHolderClass();
JButton myButton = buttonHolder.getMyButton();
add(myButton); // Add myButton
jframe.add(this); // Add the JPanel to the JFrame
}

Surface.jframe.add(myButton);
You are adding the button to the JFrame. You said you wanted to add it to the JPanel.
Simply make it
Surface.add(myButton);
Surface.jframe.add(Surface);
That will add the JButton to the JPanel, then it will add the JPanel to the JFrame.

There is a slight problem in ordering things here. You are adding your Surface instance to the frame before the Surface constructor is done constructing it.
package test;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Surface extends JPanel {
static JFrame jframe;
static Surface surfaceInstance = new Surface();
public static Surface getInstance() {
return surfaceInstance;
}
public static void main(String argv[]) {
/* You need this to be a good friend of the Swing */
Runnable initiator = new Runnable() {
public void run() {
jframe = new JFrame("Whatever title you want");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // this will kill the application when you close the frame
jframe.setContentPane(Surface.getInstance());
jframe.pack();
jframe.setVisible(true);
}
};
/** You let the Swing run your initiator when Swing wishes to do so */
SwingUtilities.invokeLater(initiator);
Surface.getInstance().setPreferredSize(new Dimension(400,400));
/** then you can add other stuff to it **/
for (String buttonTitle: new String[] {"button1", "button2", "button3"}) {
Surface.getInstance().add(new JButton(buttonTitle));
}
}
}

Related

how to put my background image at the bottom

I want to put my background image at the very bottom in this frame, and the button on top. However the code I wrote below doesn't work. Can anyone see where the problems are?
Another thing is that even though I set the location for my button, it keep showing at the top center on the frame.
Please ignore the comment lines. (I was just guessing, and hoping them will work, but they don't apparently.)
public class Menu extends JFrame{
private JLayeredPane pane;
private JLayeredPane pane2;
public Menu(){
final JFrame f = new JFrame("Chinese Chess");
JButton play = new JButton("Play vs. AI");
f.setLayout(new FlowLayout());
f.setLocationRelativeTo(null);
f.setSize(800, 800);
f.setVisible(true);
f.setResizable(false);
//f.pack();
pane = new JLayeredPane();
pane2 = new JLayeredPane();
f.add(pane);
f.add(pane2);
//background image
JLabel background = new JLabel(new ImageIcon("res/img/background.png"));
background.setLocation(0, 0);
background.setSize(800, 800);
pane.add(background, JLayeredPane.FRAME_CONTENT_LAYER);
pane2.add(play, JLayeredPane.DEFAULT_LAYER);
//pane.moveToBack();
//button PlayAI
play.setLocation(500,500);
play.setPreferredSize(new Dimension(100,50));
//f.setLayout(new FlowLayout());
//frame menu
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//f.getContentPane().add(play);
play.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
new PlayAI();
}
});
}
public static void main(String[] args){
new Menu();
}
Problems/Solutions:
setLocation(...) and setBounds(...) types of calls are ignored by most layout managers. The only way to use them is to set the layout of the container to null via .setLayout(null);
But having said that, while null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
So in sum -- don't do this, don't use null layouts or setBounds, but rather nest JPanels, each using its own layout manager, and thereby create easy to maintain and decent GUI's.
If you want an image to be in the background, then draw it in a JPanel that you use as a container for your GUI components by drawing it in the JPanel's paintComponent(Graphics g) method as has been demonstrated in many many similar questions on this site -- I'll find you some of mine in a second.
If you add any JPanels on top of this image drawing JPanel, be sure that you can see through them by calling setOpaque(false) on these overlying JPanels. Otherwise you'll cover up the image.
Your code has two JFrames when only one is needed. Get rid of the one you don't use.
You call setVisible(true) too early on the JFrame, before components have been added to the GUI -- don't. Call it only after adding everything to the GUI so all display OK.
You're creating two JLayedPanes, and completely covering one by the other by adding them to the JFrame without understanding how the JFrame's BorderLayout handles added components.
I suggest that you not even use one JLayeredPane but instead draw in the JPanel as noted above, and use that as your container.
Your code looks to be opening a completely new GUI window when the play button is pressed, and if so, this can get annoying to the user fast. Consider swapping views instead with a CardLayout.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
// extend JPanel so you can draw to its background
#SuppressWarnings("serial")
public class Menu2 extends JPanel {
private BufferedImage bgImage = null; // our background image
private JButton playButton = new JButton(new PlayVsAiAction("Play Vs. AI", KeyEvent.VK_P));
public Menu2(BufferedImage bgImage) {
this.bgImage = bgImage;
setLayout(new GridBagLayout()); // center our button
add(playButton);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bgImage != null) {
g.drawImage(bgImage, 0, 0, this);
}
}
// to size our GUI to match a constant or the image.
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
// if you want to size it based on the image
if (bgImage != null) {
int width = bgImage.getWidth();
int height = bgImage.getHeight();
return new Dimension(width, height);
} else {
return super.getPreferredSize();
}
// if you want to size the GUI with constants:
// return new Dimension(PREF_W, PREF_H);
}
private class PlayVsAiAction extends AbstractAction {
public PlayVsAiAction(String name, int mnemonic) {
super(name); // have our button display this name
putValue(MNEMONIC_KEY, mnemonic); // alt-key to press button
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO code to start program
}
}
private static void createAndShowGui() {
BufferedImage img = null;
String imagePath = "res/img/background.png";
try {
// TODO: fix this -- use class resources to get image, not File
img = ImageIO.read(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
Menu2 mainPanel = new Menu2(img);
JFrame frame = new JFrame("Chinese Chess");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
Apart from the solution above... you should create and launch your swing application this way:
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();
}
});
}
private static void createAndShowGUI() {
// Instantiate your JFrame and show it
}

How to Get JPanel to Fit Snug With Its Components?

I have 2 issues.
First issue: I have to set the JFrame as non resizable, however, an error is thrown up when I enter in frame.setResizable(false);
Second issue: I have ran into the problem of the JFrame not fitting the component within it perfectly. I have set the dimensions for the JFrame to 600x720 and the board component as being 600x600. However, when I extend the JFrame I can see that there is more of the component to be revealed. How would I change this to accommodate the component to fit snugly but also leave space for another component of size 100x120? My understanding of this is that JFrame sets the size with the borders included, however, I want the space within the JFrame to be exactly 600x720 pixels without including the border.
The code is set out below.
Game Class
package snake;
//This class is used to run the game.
public class Game {
/**
* #author HyperBlue
*/
//Declaring a static variable of type Board. This can be accessed from anywhere in the program. The fact that it is static means that it cannot be edited.
public static Board board;
public static void main(String[] args) {
// TODO Auto-generated method stub
//Creates an object board from the Board() construct
board = new Board();
}
}
Board Class
package snake;
//Importing allows us to use pre-defined classes in Java, this contains its methods. We can also import entire packages which contain a number of classes in that package.
//This class allows us to assign/capture the width and height of an object.
import java.awt.Dimension;
//The Toolkit is an abstract class containing abstract and (possibly) non-abstract methods. Abstract classes cannot be instantiated (i.e. we cannot make an object from them). Abstract methods have no body (no code), for example we declare it as "public abstract boolean isChanged() ;", the semi colon shows it has no body (i.e. no {}).
import java.awt.Toolkit;
//ActionEvent gets information about an event (input) and its source. You can create an object from this.
import java.awt.event.ActionEvent;
//The ActionListener defines what should be done when a certain action is performed by the user.
import java.awt.event.ActionListener;
//This imports the JFrame class from the swing package.
import javax.swing.JFrame;
import javax.swing.Timer;
//This class is used to create the game board.
//The ActionListener is implemented because it is implementing an interface. What ActionListener does is it handles events; the ActionListener defines what should be done when a certain action is performed by the user.
public class Board implements ActionListener {
//The JFrame is the window in which everything will be placed into, this will provide the framed window (what is visible to us) in which the game will run in. We are creating a variable frame of type JFrame.
public JFrame frame;
//Creating a variable drawBoard of type DrawBoard. This allows us to add the component of drawBoard to the Board.
public DrawBoard drawBoard;
//Defining a new Timer called ticker. This is using the form new Timer(int delay in milliseconds, ActionListener listener). What the timer does is it allows threads to schedule the execution of instructions. In this case to constantly refresh the drawBoard component at regular intervals. This will give the appearance of motion. What "this" does is it is in reference to the current instance,
public Timer ticker = new Timer(20, this);
//This is a constructor for the class Board. This will allow us to create an object.
public Board() {
//Making an instance of dimension dim and assigning it to the size of the screen.
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
//Declaring instance of the JFrame 'frame'. This JFrame is called to declare a title for this frame - "Snake".
frame = new JFrame("Snake");
//JFrame is initially set to invisible, so we use the setVisible method (setting it to true) to make the JFrame 'frame' visible.
frame.setVisible(true);
frame.setPreferredSize(new Dimension(600, 720));
frame.getContentPane().add(drawBoard = new DrawBoard());
frame.pack();
//What this does is it places the JFrame 'frame' into the middle of the user's screen, this diminishes the issue of not all screens being the same resolution and size. This is done by setting the (x, y) position of the JPanel. For example, the x position is gained by dividing the size of the monitor by 2 and negating the size of the JPanel by 2 from that value, this places it in the middle of the screen's x axis. This is true for the y-axis too.
frame.setLocation((dim.width / 2) - (frame.getWidth() / 2), (dim.height / 2) - (frame.getHeight() / 2));
//Sets the operation which will happen when the user closes the JFrame 'frame', the EXIT_ON_CLOSE exits the application using the System exit method. This means that when the JFrame is closed, the application will be exited (closed).
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Starts the timer, this starts is sending action events to its listeners.
ticker.start();
}
//Overriding the actionPerformed method from the ActionListener class.
#Override
//This is the actionPerformed method. We parse it the ActionEvent e, what this is is an object which gives information about the event and its source. This allows us to perform an action based upon a specific event (e.g. a keyboard key pressed).
public void actionPerformed(ActionEvent e) {
//This repaints this component for every tick
//drawBoard.repaint();
}
}
DrawBoard Class
package snake;
//Allows use of default sRGB colours.
import java.awt.Color;
//Graphics is an abstract class that allows us to draw onto components.
import java.awt.Graphics;
import javax.swing.JPanel;
//Warnings will not be thrown (are suppressed).
#SuppressWarnings("serial")
//This class is used to create the board component in which the snake can move on.
//What extending does is it allows us to inherit the methods and attributes (properties) of another class. In this case, the DrawBoard class (subclass - inherits state and behaviour from all of its ancestors) inherits properties from the JPanel class (superclass - gives properties to its subclasses).
public class DrawBoard extends JPanel{
//Declaring the colour 'yellow' as the hex colour code (turned to decimal using a hex calculator so Java can use it) which was chosen in the design stage.
public static Color yellow = new Color(13816442);
//We are overriding the protected method in order to define our own body (and properties) for the paintComponent method. Overriding this allows us to define how we will paint the component DrawBoard. Protected means that it can only be accessed by things within the same package.
#Override
//A component is an object which has a graphical representation that can interact with the user (e.g. buttons).
//What this does is it paints the component using the graphics class, defined as instance g.
protected void paintComponent(Graphics g) {
//'Super.' refers to the method calling its super class, which in this case is JPanel. Doing this allows me to use in built 'drawings' such as rectangle and oval, which can be drawn by calling their methods.
super.paintComponent(g);
//Setting the colour in which graphics objects are made to the colour defined in the colour 'yellow'
g.setColor(yellow);
//Filling in a rectangle which starts at the point (0, 120) - [this is from the top left of the screen, with (0, 120) referring to 120 pixels down] and has a width and height of (600, 600), in other words provides a background of colour 'yellow' defined.
g.fillRect(0, 120, 600, 600);
}
}
Regarding:
How to Get JPanel to Fit Snugly With It's Components?
Let the layout managers do this work for you.
Suggestions:
Don't set sizes or preferred sizes.
Instead let the component's preferred size and your layout managers do the sizing for you.
If you do need to actively have a hand in setting some sizes, override getPreferredSize() and return an appropriate dimension, but do so taking care not to upset the preferred size of the constituent components. This must be done with care.
Re " I have set the dimensions for the JFrame to 600x720 and the board component as being 600x600. However, when I extend the JFrame I can see that there is more of the component to be revealed." -- You're forgetting the size of the top bar of the JFrame, something that may change size depending on the look and feel. Again, don't set the JFrame's size, and this will be a moot point.
To center a JFrame, simply call frame.setLocationRelativeTo(null); after it has been packed.
Avoid over-use of comments as these make your code nearly unreadable.
If you have problems and need help with an error such as you mention here: "I have to set the JFrame as non resizable, however, an error is thrown up when I enter in frame.setResizable(false);", then show the offending code and the error message.
Don't call frame.setVisible(true); until all components have been added and the JFrame has been packed.
For example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class Game {
public static Board board;
public static void main(String[] args) {
board = new Board();
}
}
class Board implements ActionListener {
public JFrame frame;
public DrawBoard drawBoard;
public Timer ticker = new Timer(20, this);
public Board() {
frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setPreferredSize(new Dimension(600, 720));
frame.getContentPane().add(drawBoard = new DrawBoard(), BorderLayout.CENTER);
frame.getContentPane().add(new BottomComponent(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
ticker.start();
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
class DrawBoard extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
public static Color yellow = new Color(13816442);
public DrawBoard() {
setBorder(BorderFactory.createTitledBorder("Draw Board"));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(yellow);
g.fillRect(0, 120, 600, 600);
}
}
class BottomComponent extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = 120;
public BottomComponent() {
setBorder(BorderFactory.createTitledBorder("Bottom Component"));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}

JButton isn't visible until I Scroll over it

I am just starting to make a simple mp3 player, I am creating the play, forward, back, etc... Button but for some reason only the first button appears and to make the second button appear I have to go and scroll over it. If you could help me fix that, that would be great. And I am using a two images one named play.jpg and another named next.png.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Graphic extends JPanel{
JFrame f = new JFrame();
JPanel p = new JPanel(new GridBagLayout());
public Graphic(){
gui();
}
public void gui(){
f.setVisible(true);
f.setSize(1600,900);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(p);
ppr(75,26,25,25,"pics/play.jpg");
//above is the play button
ppr(40,26,25,25,"pics/next.png");
// above is the button that wont appear until it is scrolled over (it is just to the left of the button above
}
public void ppr(int x, int y, int width, int height, String file){
p.setLayout(null);
Toolkit tool = Toolkit.getDefaultToolkit();
Image player = tool.getImage(file);
ImageIcon playbutton = new ImageIcon(player);
JButton play = new JButton(playbutton);
play.setBounds(x, y, width, height);
p.add(play);
// ********************** above is the the method that makes a button
}
public static void main(String args[]) {
new Graphic();
}
}
Don't use setBounds. Use GridBagLayout
you specified while initialising the panel and specify GridBagConstraints
The setVisible(true) method should be invoked AFTER all the components have been added to the GUI.
I also agree with the other suggestions for better GUI design.
Run the GUI in a different thread, not the main thread.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
All UI code should be run in the event dispatch thread for Swing.

Pass a JPanel class to the main class in JAVA

I need to pass a JPanel extending class to the main class.
Here is what I have so far:
Main class
import java.awt.Color;
import javax.swing.*;
public class main {
private gamePanel gamepanel = new gamePanel();
public JPanel createContentPane(){
// We create a bottom JPanel to place everything on.
JPanel totalGUI = new JPanel();
//We set the Layout Manager to null so we can manually place
// the Panels.
totalGUI.setLayout(null);
//Now we create a new panel and add it to the bottom JPanel.
totalGUI.add(gamepanel);
totalGUI.setOpaque(true);
return totalGUI;
}
private static void createAndShowGUI(){
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] There's a JPanel in here! [=]");
//Create and set up the content pane.
main demo = new main();
frame.setContentPane(demo.createContentPane());
//The other bits and pieces that make your program a bit more stable.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,500);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a jog for the event-dispatching thread:
//creating and showing this application's GUI.
System.out.println(gamepanel);
SwingUtilities.invokeLater(new Runnable() {
public void run(){
createAndShowGUI();
}
});
}
}
The gamePanel class
public class gamePanel extends JPanel implements Commons {
private Dimension d;
private ArrayList snowmens;
private coreFunctions functions = new coreFunctions();
private int snowmenX = 150;
private int snowmenY = 5;
private final String snowmenpix = "snowman.png";
private JPanel background;
public gamePanel() {
add(new JLabel("TEST"));
setFocusable(true);
setDoubleBuffered(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 700, 700);
}
}
I can't figure out why the blue background and the label is not being shown...
EDIT:
Here are more details:
Ok so I am trying to make a little 2D game. For that I need to create some snowmen on the gamePanel class and display it via the main class. To start it off, the createContentPane creates a background panel, the root panel if you want. The createandshowgui creates a JFrame.
The gamepanel class is in fact a JPanel which has 1 panel as of now, which is the background panel. For now, I only want it to have a blue background.
I tried putting it like this because I saw some examples and they were pretty similar to what I have, but for some reason, I can't get it to work....
Thank you,
Ara
You should use LayoutManager instead of setLayout(null); and if only one component is being added no need for it either (that component will stretch to fill unless others are added)
see here for tutorial on LayoutManagers:
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
If all you are trying to do is have a blue background (on which you can add components) then simply override paintComponent() of your gamePanel and paint the background blue:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
then you can add your JLabel as if it was a normal Panel as the background is now being painted blue and not set by/as a component.
If you have an image look into g.drawImage(Image image,int x,int y,ImageObserver iO)
EDIT
DROP THE CALL TO:
setLayout(null);
and it will work

I can't see my JPanel and its components in the JApplet

I want to put a JPanel in a JApplet, the problem is that I can't see it :( I've overridden the paintComponent of my JPanel in order to have a background image, but I can't see anything. When I remove the paintComponenet method that I had overriden, and set a color to the background of this panel, it seems that JPanel fills the JApplet and still no component is visible :-S I've tried different layouts. I also put my panel in the center of another panel which fills my JApplet but nothing changed, and still no component and no background image is visible :(
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Main extends JApplet implements Runnable{
private JTextArea display;
private Thread outputThread;
JPanel boardPanel;
private ClientViewManager view;
#Override
public void init() {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't successfully complete");
}
}
private void createGUI() {
display = new JTextArea(4, 30);
display.setEditable(false);
getContentPane().add(new JScrollPane(display), BorderLayout.SOUTH);
setFocusable(true);
setVisible(true);
setName("CE Tanks");
setSize(600, 600);
setLocation(100, 100);
boardPanel = new JPanel();
boardPanel.setLayout(null);
boardPanel.setBackground(new java.awt.Color(128, 255, 255));
getContentPane().add(boardPanel, BorderLayout.CENTER);
}
public void start() {
outputThread = new Thread(this);
outputThread.start();
}
public void run() {
view = new ClientViewManager();
boardPanel.add(view);
boardPanel.repaint();
repaint();
}
}
class ClientViewManager extends JPanel {
private int rows=8;
private int columns=8;
public ClientViewManager() {
super(null);
JLabel lb= new JLabel("lb.jpg");
lb.setLocation(10, 10);
lb.setSize(50, 50);
lb.setOpaque(false);
lb.setVisible(true);
this.add(lb);
}
public void paintComponent(Graphics g) {
g.drawImage(new ImageIcon("ground.jpg").getImage(), 0, 0, columns * 50,
rows * 50, this);
}
}
The code above can be compiled. I cant even add Keylistener to neither my JPanel nor to my JApplet. I used java.awt.KeyEventDispatcher and in dispatchKeyEvent(KeyEvent e) I printed something in console but, it was printed 3 times. :(
I've overridden the paintComponent of my JPanel inorder to have a background image,
But you didn't add the custom component to your applet:
//boardPanel = new JPanel();
boardPanel = new ClientViewManager();
Also:
get rid of setVisible(). This is not required for any of the controls in your program. By default all components except top level Container (Jframe, JDialog etc) are already visible. In the case of JApplet, you don't need to make it visible as this is part of the process of displaying an applet.
get rid of setSize() and setLocation() you can't control the position of the applet this way.
Don't read the image file in the paintComponent() method. This is not efficient as this method is invoked whenever Swing determines the component needs to be repainted.
JLabels are opaque by default so there is not need to invoke the setOpaque method.
When doing custom painting you should also override the getPreferredSize() method of the component to return the proper size of the custom painting so layout managers can use this information. It works in this case because you added the panel to the CENTER of the BorderLayout. Try adding the panel to the NORTH to see what happens.
Edit:
Now I see where you are adding the ClientViewManager. I'm not sure why you are trying to do this with a Thread but once again there are several problems.
When you add/remove components from a visble GUI then the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
However this still won't work because you are using a null layout and the size of the panel is 0. Use a proper layout manager and implement the getPreferredSize() method as suggest above and the component will be displayed properly.
I recommend you to use the GUI Builder of Netbeans to build a GUI like that, and then compare the generated code to your code. Netbeans results really useful to help you create swing code.

Categories