Clicking a button within a JFrame passes an data to a JPanel - java

I have a Jframe with two buttons: '1' and '2'. Clicking the button '1' should display the capital letter A in the JPanel.
Code fore my JFrame:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawFrame extends JFrame{
private final int WIDTH = 500;
private final int HEIGHT = 300;
private JButton number1;
private JButton number2;
private JPanel numberPanel;
private DrawPanel graphicsPanel;
public DrawFrame()
{
createSelectionPanel();
createGraphicsPanel();
this.setSize(WIDTH, HEIGHT);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
private void createSelectionPanel()
{
numberPanel = new JPanel();
number1 = new JButton("1");
number2 = new JButton("2");
numberPanel.setLayout(new GridLayout(2,2));
numberPanel.add(number1);
numberPanel.add(number2);
this.add(numberPanel, BorderLayout.WEST);
}
private void createGraphicsPanel()
{
//instantiate drawing panel
graphicsPanel = new DrawPanel();
//add drawing panel to right
add(graphicsPanel);
}
private class Number1ButtonListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
Number number = new Number();
number.setNumber('A');
}
}
//creates a drawing frame
public static void main(String[] args)
{
DrawFrame draw = new DrawFrame();
}
}
Code for my JPanel
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class DrawPanel extends JPanel{
public Coordinates current;
public DrawPanel(){
//nothing drawn initially
current = null;
//set white background for drawing panel
setBackground(Color.WHITE);
//add mouse listeners
MouseHandler mouseHandler = new MouseHandler();
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
public void paint(Graphics g){
super.paint(g);
if(current!=null){
I want to replace "A" with number.getNumber()
g.drawString("A", current.getX(), current.getY());
}
}
//class to handle all mouse events
private class MouseHandler extends MouseAdapter implements MouseMotionListener
{
public void mousePressed(MouseEvent event)
{
current = new Coordinates(event.getX(), event.getY());
}
public void mouseReleased(MouseEvent event)
{
repaint();
}
}
}
I'm not sure if this is possible. So sorry if I am mistaken in my logic. Please provide an alternate way for me to approach this problem. Appreciate any guidance.
Thanks!

The Coordinates and Number classes weren't included, so I had to modify the code somewhat.
Here's the GUI I created.
The first thing I did was create a model class for the GUI. By creating a model class, I could make the display string and the drawing coordinate available to the view and the controller classes. This is a simple example of the model / view / controller pattern.
package com.ggl.drawing;
import java.awt.Point;
public class GUIModel {
private String displayString;
private Point coordinate;
public GUIModel(String displayString) {
this.displayString = displayString;
}
public Point getCoordinate() {
return coordinate;
}
public void setCoordinate(int x, int y) {
this.coordinate = new Point(x, y);
}
public void setCoordinate(Point coordinate) {
this.coordinate = coordinate;
}
public void setDisplayString(String displayString) {
this.displayString = displayString;
}
public String getDisplayString() {
return displayString;
}
}
Now that we have a model, lets look at the DrawFrame class.
package com.ggl.drawing;
import java.awt.BorderLayout;
import java.awt.GridLayout;
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 DrawFrame implements Runnable {
private final int WIDTH = 500;
private final int HEIGHT = 300;
private JFrame frame;
private GUIModel model;
public DrawFrame() {
this.model = new GUIModel("A");
}
#Override
public void run() {
frame = new JFrame("Draw Letters");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createSelectionPanel(), BorderLayout.WEST);
frame.add(new DrawPanel(WIDTH, HEIGHT, model), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private JPanel createSelectionPanel() {
JPanel numberPanel = new JPanel();
ButtonListener listener = new ButtonListener();
JButton number1 = new JButton("A");
number1.addActionListener(listener);
JButton number2 = new JButton("B");
number2.addActionListener(listener);
numberPanel.setLayout(new GridLayout(0, 2));
numberPanel.add(number1);
numberPanel.add(number2);
return numberPanel;
}
private class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
model.setDisplayString(event.getActionCommand());
}
}
// creates a drawing frame
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawFrame());
}
}
I started the Java Swing application on the Event Dispatch thread with the call to the SwingUtilities invokeLater method.
I separated the JFrame construction from the 2 JPanels construction. I used a JFrame, rather than extend a JFrame. The only time you should extend any Java class is if you want to override one or more of the class methods.
I used the same ButtonListener for both JButtons. I'm guessing what you want, but I drew either an "A" or a "B", depending on which button you left clicked.
Let's look at the DrawPanel class.
package com.ggl.drawing;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
private static final long serialVersionUID = 3443814601865936618L;
private GUIModel model;
public DrawPanel(int width, int height, GUIModel model) {
this.setPreferredSize(new Dimension(width, height));
this.model = model;
// add mouse listeners
MouseHandler mouseHandler = new MouseHandler();
this.addMouseListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (model.getCoordinate() != null) {
Point p = model.getCoordinate();
Font font = g.getFont().deriveFont(48F);
g.setFont(font);
g.drawString(model.getDisplayString(), p.x, p.y);
}
}
// class to handle all mouse events
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent event) {
model.setCoordinate(event.getPoint());
}
#Override
public void mouseReleased(MouseEvent event) {
DrawPanel.this.repaint();
}
}
}
The major change I made in this class was to use the paintComponent method, rather than the paint method. The paintComponent method is the correct method to override.
I set the size of the drawing panel in the DrawPanel constructor. It's much better to let Swing figure out the size of the JFrame. That's what the pack method in the DrawFrame run method does.
I increased the font size so you can see the drawn letter better.
I removed the mouse motion listener code, as it wasn't needed.
I hope this was helpful to you.

OK, all I know so far is that you want the text displayed in a JPanel to change if a button is pressed. If so, then your code looks to be way too complex for the job. Suggestions include:
Give the DrawingPanel a setter method, say, setText(String text), that allows outside classes to change the text that it displays.
Within that method, set a field of DrawingPanel, say called text, and call repaint().
Override DrawingPanel's paintComponent not its paint method, and call the super's method within your override.
Within the paintComponent method, call drawString to draw the String held by the text field, if the field is not null.
Give your buttons ActionListeners or AbstractActions that call the DrawingPanel's setText(...) method, setting the text to be displayed.
For example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class DrawAorB extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public DrawAorB() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
btnPanel.add(new JButton(new ButtonAction("A")));
btnPanel.add(new JButton(new ButtonAction("B")));
setLayout(new BorderLayout());
add(drawingPanel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.PAGE_END);
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
String text = e.getActionCommand();
drawingPanel.setText(text);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawAorB");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawAorB());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class DrawingPanel extends JPanel {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private String text = null;
public void setText(String text) {
this.text = text; // set the JPanel's text
repaint(); // and draw it
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (text != null) {
int x = getWidth() / 2;
int y = getHeight() / 2;
// use FontMetrics if you want to center text better
g.drawString(text, x, y);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
Even simpler, easier, and probably better would be to display the text within a JLabel as it's much easier to center this text.

Related

How to make the JFrame contentPane transparent but the JFrame visible?

I wanted to know how to make the JFrame's contentPane transparent but the JFrame visible. I saw many pages but all showed on how to make the JFrame border visible but the contentPane visible.
I tried using setOpacity() but that requires the JFrame to be undecorated.
Are there any methods that I can achieve this?
Swing was not designed to paint with transparent backgrounds. You cannot create a transparent contentPane. However, you can fake a transparent background.
Here's a screenshot showing a fake transparent background. I cropped and reduced the image by 50% to get it to display in this answer.
So, how did I do this?
I took a snapshot of the background and painted the background on the JPanel.
This only works if you do not change the background while you're displaying your JFrame. If you change the background by opening or closing any other applications, this fake will not work.
You can move the JFrame around. Do not move the JFrame close to the edge of the screen, or you'll ruin the illusion.
Iconifying and deiconifying the JFrame works, but the illusion becomes obvious.
You can resize, maximize, and restore the JFrame.
It requires a lot of code to make this fake work properly.
Here's the complete runnable code. I made all the additional classes inner classes so I could post this code as one block.
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TransparentJPanelView implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TransparentJPanelView());
}
private DrawingPanel drawingPanel;
private JFrame frame;
private TransparentJPanelModel model;
public TransparentJPanelView() {
this.model = new TransparentJPanelModel();
this.drawingPanel = new DrawingPanel(model);
}
#Override
public void run() {
this.frame = new JFrame("Fake Transparent JPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addComponentListener(new FrameComponentListener(this, model));
FrameListener listener = new FrameListener(this, model);
frame.addWindowListener(listener);
frame.addWindowFocusListener(listener);
frame.addWindowStateListener(listener);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public void repaint() {
drawingPanel.repaint();
}
public JFrame getFrame() {
return frame;
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private TransparentJPanelModel model;
public DrawingPanel(TransparentJPanelModel model) {
this.model = model;
this.setLayout(new FlowLayout());
this.setPreferredSize(new Dimension(600, 300));
JButton button = new JButton("Click me");
this.add(button);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Point point = new Point(this.getLocation());
SwingUtilities.convertPointToScreen(point, this);
Image image = model.getSubImage(point.x, point.y, getWidth(), getHeight());
g.drawImage(image, 0, 0, this);
}
}
public class FrameComponentListener extends ComponentAdapter {
private final TransparentJPanelView view;
private final TransparentJPanelModel model;
public FrameComponentListener(TransparentJPanelView view,
TransparentJPanelModel model) {
this.view = view;
this.model = model;
}
#Override
public void componentResized(ComponentEvent event) {
view.repaint();
}
#Override
public void componentMoved(ComponentEvent event) {
view.repaint();
}
}
public class FrameListener extends WindowAdapter {
private final TransparentJPanelView view;
private final TransparentJPanelModel model;
public FrameListener(TransparentJPanelView view,
TransparentJPanelModel model) {
this.view = view;
this.model = model;
}
#Override
public void windowDeiconified(WindowEvent event) {
model.setBackground();
view.repaint();
}
}
public class TransparentJPanelModel {
private BufferedImage background;
private final Rectangle screenRect;
private final Robot robot;
public TransparentJPanelModel() {
this.robot = createRobot();
this.screenRect = new Rectangle(
Toolkit.getDefaultToolkit().getScreenSize());
setBackground();
}
private Robot createRobot() {
Robot robot = null;
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
return robot;
}
public void setBackground() {
this.background = robot.createScreenCapture(screenRect);
}
public Image getSubImage(int x, int y, int width, int height) {
if (x < 0) {
x = 0;
width = Math.min(width, screenRect.width);
}
if (y < 0) {
y = 0;
height = Math.min(height, screenRect.height);
}
if (x + width > screenRect.width) {
width = screenRect.width - x;
}
if (y + height > screenRect.height) {
height = screenRect.height - y;
}
return background.getSubimage(x, y, width, height);
}
}
}
You can use setVisible(false) method for each element that is inside that JFrame. You use this in the intialize() method. Once you want them to be shown (for example after some button is clicked) than you will use the same method setVisible(true).

How can I pass an argument to paintComponent in order to call it in a different class?

In my main class I have the following code to load an image from my machine and display it on the frame to draw things on it:
public class ShowMap extends JPanel {
private static final int WIDTH = 1340;
private static final int HEIGHT = 613;
public void main(String args[]) {
JFrame frame = new JFrame("MAP");
frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
frame.setMinimumSize(new Dimension(WIDTH, HEIGHT));
frame.setMaximumSize(new Dimension(WIDTH, HEIGHT));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = (JPanel)frame.getContentPane();
JLabel label = new JLabel();
label.setIcon(new ImageIcon("map.png"));
panel.add(label);
}
}
The image I am loading is a map where I would like to indicate the position of some objects by drawing points in the right coordinates. So it is important here to dictate to the DrawPoint class (below) what coordinates should get the point.
Also, I would greatly appreciate an explanation of how to erase a point that has been drawn.
My search led me to the following, but as soon as I add int coordx, int coordy to the arguments of the method, it is no more highlighted, and I don't know how to call this method in ShowMap while passing the coordinates as arguments.
public class DrawPoint extends JPanel {
private int coordx;
private int coordy;
public void paintComponent(Graphics g, int coordx, int coordy){
g.setColor(Color.BLACK);
g.fillOval(coordx,coordy,8,8);
}
}
Here is a demonstration of what MadProgrammer wrote in his comment : "should be changing a state variable of the component and then calling repaint" :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SwingTest extends JFrame {
private static final int SIZE = 300;
private DrawPoint drawPoint;
public SwingTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
drawPoint = new DrawPoint();
drawPoint.setPreferredSize(new Dimension(SIZE, SIZE));
add(drawPoint);
pack();
setVisible(true);
}
//demonstrate change in DrawPoint state
private void reDraw() {
Random rnd = new Random();
Timer timer = new Timer(1000, e -> { //periodically change coordinates and repaint
drawPoint.setCoordx(rnd.nextInt(SIZE));
drawPoint.setCoordy(rnd.nextInt(SIZE));
drawPoint.repaint();
});
timer.start();
}
public static void main(String[] args){
SwingUtilities.invokeLater(() -> new SwingTest().reDraw());
}
}
class DrawPoint extends JPanel {
private int coordx, coordy;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(coordx,coordy,8,8);
}
//use setters to change the state
void setCoordy(int coordy) { this.coordy = coordy; }
void setCoordx(int coordx) {this.coordx = coordx;}
}

External JPanel classs does not show correctly in Main JFrame class

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.

Component won't display unless window is resized - Java

I have problem with image visibility after click the button. I have the main class with frame:
package superworld;
import java.awt.*;
import javax.swing.*;
public class SuperWorld {
public static void main(String[] args) {
JFrame frame= new JFrame();
frame.setSize(1050,650);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SuperPanel());
frame.setVisible(true);
// frame.setResizable(false);
}
}
Then I have class with Panel with all components:
package superworld;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import javax.swing.Timer;
public class SuperPanel extends JPanel implements ActionListener{
Timer mainTimer;
public static final int HEIGHT = 550;
public static final int WIDTH = 1050;
int i;
int w=-100;
int h=-50;
ArrayList<SuperMiasto> miasta = new ArrayList<SuperMiasto>();
private JButton heroButton;
private JButton cywilButton;
public SuperPanel() {
mainTimer = new Timer(10,this);
heroButton = new HeroButton(this);
cywilButton = new CywilButton(this);
setLayout(null);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.GREEN);
for(i=0;i<10;i++)
{
miasta.add( new SuperMiasto() );
miasta.get(i).x=w;
miasta.get(i).y=h;
miasta.get(i).imagelabel = new JLabel(miasta.get(i).image);
miasta.get(i).imagelabel.setBounds(miasta.get(i).x,miasta.get(i).y,miasta.get(i).image.getIconWidth(),miasta.get(i).image.getIconHeight());
add(miasta.get(i).imagelabel);
w=w+200;
if (w > WIDTH-200)
{
h=h+200;
w=-100;
}
}
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
add(heroButton);
add(cywilButton);
}
public void actionPerformed(ActionEvent e) {
repaint();
}
}
And Class with button with add new object with image:
package superworld;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class HeroButton extends JButton implements ActionListener {
private JPanel buttonPanel;
HeroButton(JPanel buttonPanel) {
super("Dodaj hero");
this.buttonPanel = buttonPanel;
setBounds(0,500,150,50);
addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
SuperLudzie batman = new SuperLudzie();
batman.imagelabel = new JLabel(batman.image);
batman.imagelabel.setBounds(50,50,batman.image.getIconWidth(),batman.image.getIconHeight());
buttonPanel.add(batman.imagelabel);
}
}
And class of this SuperLudzie:
package superworld;
import java.awt.*;
import javax.swing.*;
public class SuperLudzie {
private String imie;
private int zycie;
private int inteligencja;
private int wytrzymalosc;
private int sila;
private int umiejetnosci_walki;
private int x,y;
ImageIcon image = new ImageIcon("C:/Users/Zuzanna Sawala/Moje dokumenty/NetBeansProjects/SuperWorld/mysz.jpg");
JLabel imagelabel;
}
Everything work great. I have only problem with this object and image created by button it's not visible just after clicking but after i resize a window. I know that it have something to do with setVisibility(true); but i'm not sure where to use it.
Use SwingUtilities.invokeLater() or EventQueue.invokeLater() to make sure that EDT is initialized properly.
Use overridden paintComponent() method instead of paint()
class SuperPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(..., ...);
}
}
Read more points...
Try to avoid null layout and use proper layout that suits as per our need.
Please have a look at How to Use Various Layout Managers that has sole responsibilities for positioning and sizing of the components.

Why does my custom Swing label take so long to initialize?

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.

Categories