I am trying to make an applet run as a JFrame. The code I have below is simple but should work. It will run as an JApplet but when I go to RUN AS --> nothing appears.
import java.awt.*;
import java.applet.Applet;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LifeCycle extends Applet
{
private static final long serialVersionUID = 1L;
String output = "test";
String event;
public void init()
{
gui(); //I am not certain if this needs to be there.
event = "\nInitializing...";
printOutput();
}
public void start()
{
event = "\nStarting...";
printOutput();
}
public void stop()
{
event = "\nStopping...";
printOutput();
}
public void destroy()
{
event = "\nDestroying...";
printOutput();
}
private void printOutput()
{
System.out.println(event);
output += event;
repaint();
}
private void gui() {
JFrame f = new JFrame("Not resizable");
JPanel d = new JPanel();
// LifeCycle a = new LifeCycle();
// a.init();//not working
d.setLayout(new BorderLayout());
d.add(new JButton("a"));
d.add(new JButton("b"));
d.setBackground(Color.RED);
//f.add(new LifeCycle());
f.add(d);
f.setSize(545,340);
f.setResizable(false);
f.setLocationRelativeTo(null);
f.setTitle("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//a.destroy();
}
public void paint(Graphics g)
{
System.out.println("Graphics Paint Method!");
g.drawString(output, 100, 100);
}
public static void main(String[] args) {
LifeCycle l = new LifeCycle();
l.gui();
}
}
I would like to see the code that should be changed, but I cannot seem to find why this will not work. I have added to buttons to the panel to be displayed.
Don't mix AWT (Applet) with Swing components. Stick with just Swing.
Gear your class towards creating JPanels. Then you can place it in a JApplet if you want an applet or a JFrame if you want a JFrame.
Read up on use of BorderLayout -- you're adding multiple components to the default BorderLayout.CENTER position, and only one component, the last one added, will show.
For example ...
LifeCycle2.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
class LifeCycle2 {
private static final int GAP = 5;
private static final int PREF_W = 545;
private static final int PREF_H = 340;
private JPanel mainPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return LifeCycle2.this.getPreferredSize();
}
};
public LifeCycle2() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
buttonPanel.add(new JButton("A"));
buttonPanel.add(new JButton("B"));
buttonPanel.setOpaque(false);
JPanel flowLayoutPanel = new JPanel();
flowLayoutPanel.setOpaque(false);
flowLayoutPanel.add(buttonPanel);
mainPanel.setLayout(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setBackground(Color.red);
mainPanel.add(flowLayoutPanel, BorderLayout.NORTH);
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public JComponent getMainPanel() {
return mainPanel;
}
}
Show as a JFrame,
LifeCycleFrame.java
import javax.swing.*;
public class LifeCycleFrame {
private static void createAndShowGui() {
LifeCycle2 lifeCycle2 = new LifeCycle2();
JFrame frame = new JFrame("LifeCycleTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(lifeCycle2.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Show as an applet,
LifeCycleApplet.java
import java.lang.reflect.InvocationTargetException;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class LifeCycleApplet extends JApplet {
#Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
LifeCycle2 lifeCycle2 = new LifeCycle2();
getContentPane().add(lifeCycle2.getMainPanel());
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
}
Add f.setVisible(true); to the end of the gui() method. Without this call your frame won't be shown.
Please read the "How to Make Frames" Tutorial
Related
basically I'm trying to understand Threads in Java.So I thought I'd create a main JFrame class containing two JPanels from external classes and then do something in one and control it with messages from the second panel.So far I have only created the first external panel and there the probleme starts! It does not show correctly although it appears to be "loaded".(see system.out lines)
So here is the Main Class
package com.maybee.gui;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class Maybee extends JFrame implements Runnable
{
public JFrame maynFrame = null;
public JPanel contentPanel = null;
public SimPanel simPanel = null;
public int screenWidth = 0;
public int screenHeight = 0;
public Maybee()
{
}
private void init()
{
System.out.println("In Inint");
maynFrame = new JFrame("Maybee");
maynFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
screenWidth = gd.getDisplayMode().getWidth();
screenHeight = gd.getDisplayMode().getHeight();
maynFrame.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
maynFrame.setContentPane(getContentPanel());
maynFrame.setVisible(true);
maynFrame.pack();
}
public JPanel getContentPanel()
{
if (contentPanel == null)
{
contentPanel = new JPanel();
contentPanel.setPreferredSize(new Dimension(screenWidth,screenHeight - 100));
contentPanel.setBorder(new LineBorder(Color.BLUE));
contentPanel.setBackground(Color.RED);
contentPanel.setLayout(new BorderLayout());
contentPanel.add(getSimPanel(),BorderLayout.CENTER);
}
return contentPanel;
}
public SimPanel getSimPanel()
{
if(simPanel == null)
{
simPanel = new SimPanel(this);
}
return simPanel;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
System.out.println("Start");
Maybee maybee = new Maybee();
maybee.run();
}
});
}
public void run()
{
init();
}
}
and now the first external JPanel class
package com.maybee.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class SimPanel extends JPanel
{
public Maybee localMaybee = null;
public JPanel simPanel = null;
private JButton btn;
public SimPanel(Maybee interMaybee)
{
localMaybee = interMaybee;
init();
}
public void init()
{
simPanel = new JPanel();
simPanel.setLayout(new BorderLayout());
simPanel.setPreferredSize(new Dimension(localMaybee.screenWidth/4,localMaybee.screenHeight - 100));
simPanel.setBackground(Color.GREEN);
simPanel.add(getBtn(),BorderLayout.CENTER);
simPanel.setVisible(true);
System.out.println("IN SIM" + localMaybee.screenWidth);
}
public JButton getBtn()
{
if(btn == null)
{
btn = new JButton("ENDE");
btn.setSize(70, 20);
btn.setForeground(Color.YELLOW);
btn.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
}
});
}
return btn;
}
}
So what am I missing?
Many thanks!
The immediate issue is the second instance of JPanel created in SimPanel.init(). SimPanel is already a JPanel, there is no need to maintain public JPanel simPanel member.
The same problem is in the Maybee class which extends JFrame, but maintains public JFrame maynFrame member.
Also, as already mentioned in comments above (thanks #Frakcool!) :
Make sure to call pack() before setVisible();
Don't call setPreferredSize(), do override getPreferredSize() intead;
No need to extend JFrame;
No need to call setVisible on JPanel;
Don't call btn.setSize(), it is a job for a layout manager;
No need for setContentPane(), JFrame by default has a JPanel as content pane with BorderLayout. Calling add() is enough in this case.
Here is a slightly modified version of the original code (simplified for clarity):
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Maybee2 {
static class SimPanel extends JPanel {
public SimPanel() {
setLayout(new BorderLayout());
JButton btn = new JButton("ENDE");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//TODO
}
});
add(btn, BorderLayout.CENTER);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
}
private static void createAndShowGUI() {
final JFrame frame = new JFrame("Maybee");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SimPanel simPanel = new SimPanel();
frame.add(simPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
EDIT:
The application may consist of many panels. The high level container such as JFrame is not aware of all the underlying layout complexities and cannot enforce a certain size. The panel itself knows its internal layout and its content. So the panel reports its preferred size to the layout manager which eventually packs the content. See Laying Out Components Within a Container for more information.
setBackground has its effect although the button occupies the center of the BorderLayout which takes all the space of the panel. Change the layout of the panel and see the effect. Or move the button into another area, ie - add(btn, BorderLayout.NORTH); Read more in A Visual Guide to Layout Managers.
I've a main frame on which there is a side panel with some buttons, and central panel used to display the tables and data generated from buttons on the side panel and its sub-panels
On the start my central panel is blank and I want it to always return to its initial state( blank ) after each click on a button before generating any data
I've use some sort of observer pattern (I'm not so experienced) but my problem is that the central panel must display data after clicks on some buttons that are on panels that also need a click on the side panel before to be generated
I've tried to make an executable example on the following classes, my real application displays some tables on the central panel and i send the models via the update method of the observers
hope its clear for you and I hope if you can really help me
1 - the main frame:
package tests;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MainFrame extends JFrame implements MyObserver{
private SidePanel sidePanel;
private JPanel centralPanel;
private JFrame frame;
private JLabel title;
public MainFrame(){
frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
sidePanel = new SidePanel();
sidePanel.addObserver(this);
centralPanel = new JPanel();
title = new JLabel();
initialise(0);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
private void initialise(int i) {
if( i == 0){
centralPanel.setPreferredSize(new Dimension(400,300));
centralPanel.setBackground(Color.green);
title.setText("GREEN");
centralPanel.add(title, BorderLayout.CENTER);
frame.add(sidePanel, BorderLayout.WEST);
frame.add(centralPanel, BorderLayout.CENTER);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MainFrame();
}
});
}
#Override
public void update(int color) {
if(color == 0){
centralPanel.setBackground(Color.yellow);
title.setText("YELLOW");
}else{
centralPanel.setBackground(Color.pink);
title.setText("PINK");
}
}
}
2 - The side Panel
package tests;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
public class SidePanel extends JPanel implements MyObserver,MyObservable{
private JPanel panel;
private JButton test;
private MyObserver observer;
private ButtonPanel buttonPanel;
public SidePanel(){
panel = new JPanel();
panel.setPreferredSize(new Dimension(140, 300));
panel.setBackground(Color.blue);
panel.setLayout(new BoxLayout(panel, 0));
test = new JButton("Lunch buttons");
test.setPreferredSize(new Dimension(80,30));
buttonPanel = new ButtonPanel();
buttonPanel.addObserver(this);
test.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
buttonPanel.setVisible(true);
}
});
panel.add(Box.createVerticalGlue());
panel.add(test);
panel.add(Box.createVerticalGlue());
panel.setVisible(true);
this.add(panel, BorderLayout.CENTER);
}
#Override
public void addObserver(MyObserver obs) {
this.observer = obs;
}
#Override
public void updateObserver(MyObserver obs, int color) {
obs.update(color);
}
#Override
public void update(int color) {
updateObserver(observer, color);
}
}
3 - the buttons panel, generally the source of any data to be displayed on the central panel
package tests;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
public class ButtonPanel extends JDialog implements MyObservable{
private JButton yellow;
private JButton orange;
private JPanel panel;
private MyObserver observer;
public ButtonPanel(){
panel = new JPanel();
panel.setPreferredSize(new Dimension(300, 40));
panel.setLayout(new FlowLayout());
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.setContentPane(panel);
yellow = new JButton("YELLOW");
yellow.setPreferredSize(new Dimension(100,30));
yellow.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
updateObserver(observer, 0);
}
});
orange = new JButton("ORANGE");
orange.setPreferredSize(new Dimension(100,30));
orange.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateObserver(observer, 1);
}
});
panel.add(yellow);
panel.add(orange);
pack();
setLocationRelativeTo(null);
}
#Override
public void addObserver(MyObserver obs) {
this.observer = obs;
}
#Override
public void updateObserver(MyObserver obs, int color) {
obs.update(color);
}
}
Finally, the customized observer and observable interfaces, note in the real app i use a table model not just an int - I'm not sure it's a good way -
package tests;
public interface MyObservable {
public void addObserver(MyObserver obs);
public void updateObserver(MyObserver obs, int color);
}
package tests;
public interface MyObserver {
public void update(int color);
}
CHANGED ANSWER:
In SidePanel.java add:
private MainFrame frame;
Then make your constructor take a MyFrame object as parameter. Do this:
public SidePanel(MainFrame frame){
this.frame = frame;
//rest not changed
//
}
Change the actionPerformed() of test button to:
test.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
buttonPanel.setVisible(true);
frame.initialise(0); // this line is added
}
});
In MainFrame.java:
Change sidePanel = new SidePanel(); to sidePanel = new SidePanel(this);
AND
Change private void initialise(int i) to public void initialise(int i)
This does what you are trying to achieve.
I've made a Jpanel with a background image and a Jbutton also with its background. The problem is that background sometimes is loaded sometimes no.
public class Window extends JFrame {
public static JFrame createwindow() {//fare singleton
JFrame frame = new JFrame("Battaglia navale");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(740, 740);
frame.setVisible(true);
frame.setResizable( false );
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(((int)dim.getWidth()-(int)frame.getWidth())/2, ((int)dim.getHeight()-(int)frame.getHeight())/2);
return frame;
}
}
public class StartWindow {
JFrame frame;
private JButton button;
private JButton button2;
final String button_start = "img/start.png";
ImageIcon start = new ImageIcon(button_start);
public void CreateStartWindow() {
frame = Window.createwindow();
Container container = frame.getContentPane();
JpanelStart panel = new JpanelStart();
container.add(panel);
this.button = new JButton(start);
button.setActionCommand("start");
button.setHideActionText(true);
button.setOpaque(false);
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setContentAreaFilled(false);
this.button2 = new JButton("Classifica");
panel.add(button);
panel.add(button2);
frame.setVisible(true);
}
public void addActionListener(ActionListener al) {
this.button.addActionListener(al);
this.button2.addActionListener(al);
}
public void chiudi() {
frame.dispose();
}
}
class JpanelStart extends JPanel {
private Image img;
private String path_img = "img/sfondo.jpg";
public JpanelStart() {
img = Toolkit.getDefaultToolkit().createImage(path_img);
loadImage(img);
}
private void loadImage(Image img) {
try {
MediaTracker track = new MediaTracker(this);
track.addImage(img, 0);
track.waitForID(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
setOpaque(false);
g.drawImage(img, 0, 0, this);
super.paintComponent(g);
}
}
super.paintComponet should go right after the method signature.
you set the button opacity to false, so it won't be seen.
Run your program from the Event Dispatch Thread.
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new StartWindow().CreateStartWindow();
}
});
}
In your method, you're making the frame visible before adding anything. Leave that out in the method
Don't set the size of the frame. Instead override the getPrefereedSize() of the JPanel and call pack() on the frame.
IMO, I see no use at all for this so-called helper method. I would toss it out the window
You should load your image as an embedded resource, and not from the file system.
img = ImageIO.read(StartWindow.class.getResource(path_img));
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class StartWindow {
JFrame frame;
private JButton button;
private JButton button2;
final String button_start = "img/start.png";
ImageIcon start = new ImageIcon(button_start);
public void CreateStartWindow() throws IOException {
frame = Window.createwindow();
Container container = frame.getContentPane();
JpanelStart panel = new JpanelStart();
container.add(panel);
this.button = new JButton(start);
button.setActionCommand("start");
button.setHideActionText(true);
button.setOpaque(false);
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setContentAreaFilled(false);
this.button2 = new JButton("Classifica");
panel.add(button);
panel.add(button2);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
try {
new StartWindow().CreateStartWindow();
} catch (IOException ex) {
Logger.getLogger(StartWindow.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public void addActionListener(ActionListener al) {
this.button.addActionListener(al);
this.button2.addActionListener(al);
}
public void chiudi() {
frame.dispose();
}
}
class Window {
public static JFrame createwindow() {//fare singleton
JFrame frame = new JFrame("Battaglia navale");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
return frame;
}
}
class JpanelStart extends JPanel {
private static final int D_W = 700;
private static final int D_H = 700;
private Image img;
private String path_img = "/images/logo.gif";
public JpanelStart() throws IOException {
img = ImageIO.read(StartWindow.class.getResource(path_img));
loadImage(img);
}
private void loadImage(Image img) {
try {
MediaTracker track = new MediaTracker(this);
track.addImage(img, 0);
track.waitForID(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, D_W, D_W, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(D_W, D_H);
}
}
**Shows Up Every time **
draw the image after super.paintComponent(g) (which draws the component that you want to draw on top of)
call repaint() in loadImage() after the image is set (so that it redraws it)
loadImage() doesn't seem to be setting the img variable does it need to?
(not essential but recommended) you should also move UI changes into the EDT (Event Dispatch Thread).
Example of running a UI task on EDT
This puts UI operations on a queue so that all UI changes are made from the same thread and avoid interference.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
//UI Operations
}
} );
i am trying to add 2 different panels in a Frame. one panel adds few buttons in the frame. others frame will add a chess board into the frame. i am confused, how to draw this board on a panel. my Frame will have a board on the top and buttons at the bottom. Moreover, let me know if i am somewhere wrong in the given code can anybody help me? my Code is
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
private JFrame main;
private JPanel board;
private JPanel buttons;
private JButton add;
private JButton delete;
public Test()
{
main=new JFrame();
board=new JPanel();
buttons=new JPanel();
add=new JButton("Add");
delete=new JButton("Delete");
init();
addButtons();
}
public void init()
{
main.setSize(700,700);
main.setVisible(true);
main.setDefaultCloseOperation(main.EXIT_ON_CLOSE);
}
public void addButtons()
{
buttons.setSize(700,40);
buttons.setLayout(new FlowLayout());
buttons.add(add);
buttons.add(delete);
main.add(buttons,BorderLayout.SOUTH);
}
public void addBoxes()
{
// what should be my code here...??
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new Test();
}
}
You need a component to paint on, like a JPanel.
You need to #Override its paintComponent method
You can use a loop to paint using Graphics context
Use a flag to alternate between colors.
Take a look at some Painting Graphics tutorials
In the mean time, give this a whirl
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 Board extends JPanel {
private static final int DIM_WIDTH = 640;
private static final int DIM_HEIGHT = 640;
private static final int SQ_SIZE = 80;
boolean black = true;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < DIM_HEIGHT; i += SQ_SIZE) {
if (black) {
black = false;
} else {
black = true;
}
for (int j = 0; j < DIM_WIDTH; j += SQ_SIZE) {
if (black) {
g.setColor(Color.WHITE);
g.fillRect(j, i, SQ_SIZE, SQ_SIZE);
black = false;
} else {
g.setColor(Color.BLACK);
g.fillRect(j, i, SQ_SIZE, SQ_SIZE);
black = true;
}
}
}
}
public static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new Board());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(DIM_WIDTH, DIM_HEIGHT);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I've made a custom subclass of JLabel. I have a single instance of this, inside a single JPanel, inside a single JFrame. I do not override the paintComponent() method; all the class does is change the background color when the cursor hovers over it.
The JFrame loads immediately, but for several seconds the JPanel is left undrawn. I verified that this is because of my custom class by overriding paintComponent() and adding some debug println() statements.
public void paintComponent(Graphics context)
{
System.out.println("Painting...");
super.paintComponent(context);
System.out.println("Painted.");
}
The strange thing is, it's drawn instantly when I use Panel instead of JPanel or Label instead of JLabel.
Where is this lag coming from?
EDIT: Some example code. Nothing is actually drawn; look at the console message delay.
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.GridLayout;
import javax.swing.JPanel;
public class Example extends JLabel implements MouseListener
{
private static final long serialVersionUID = 0;
public Example()
{
super();
System.out.println("Constructed.");
}
public void paintComponent(java.awt.Graphics g)
{
System.out.println("Painting component...");
super.paintComponent(g);
System.out.println("Painted.");
}
public void mouseEntered(MouseEvent event) { }
public void mouseExited(MouseEvent event) { }
public void mouseReleased(MouseEvent event) { }
public void mousePressed(MouseEvent event) { }
public void mouseClicked(MouseEvent event) { }
public static void main(final String[] arguments)
{
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1));
panel.add(new Example());
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
System.out.println("Set visible.");
}
}
My code doesn't lag:
My SSCCE:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class LabelTest extends JPanel {
public LabelTest() {
add(new MyLabel("Fubar!"));
}
private static void createAndShowGui() {
LabelTest mainPanel = new LabelTest();
JFrame frame = new JFrame("LabelTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyLabel extends JLabel {
private static final Color BACKGROUND_DEFAULT = new Color(200, 200, 255);
private static final Color BACKGROUND_MOUSEOVER = new Color(255, 200, 200);
private static final int PREF_W = 200;
private static final int PREF_H = 100;
public MyLabel(String text) {
super(text, SwingConstants.CENTER);
setOpaque(true);
setBackground(BACKGROUND_DEFAULT);
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent arg0) {
setBackground(BACKGROUND_MOUSEOVER);
}
#Override
public void mouseExited(MouseEvent e) {
setBackground(BACKGROUND_DEFAULT);
}
});
}
#Override
public Dimension getPreferredSize() {
int width = Math.max(super.getPreferredSize().width, PREF_W);
int height = Math.max(super.getPreferredSize().height, PREF_H);
return new Dimension(width, height);
}
}
This suggests to me that the problem isn't in the concept of a JLabel whose background changes via a MouseListener, but rather you've got a bug somewhere in your code. Where? Who knows until you post compilable runnable code, an SSCCE, like the one I've posted above.