i have a rendering problem with a JLabel in Java:
i use the pattern oberver observable and when my Model notify to my View that JLabel has changed the content of JLabel or specifically the content that is showed in my JLabel area is random. Sometimes it renders a part of a button that is in another panel or sometimes it renders colors that i set in other components of my view!
But if i minimize and then maximize my frame, all is correctly rendered.
Sorry for my bad english.
This is the correct rendering of numbers on the right and on the left
This is the rendering when I click some button and then executing some OnUpdate()
EDIT
this is the class of my JPanel that contains the JLabels:
class InformationPanel extends JPanel {
private static final int DEFAULT_INFO_WIDTH = Configuration.DEFAULT_INFO_PANEL_WIDTH;
private static final int DEFAULT_INFO_HEIGHT = Configuration.DEFAULT_INFO_PANEL_HEIGHT;
private String playerId;
private int numNaviVive;
private int numNaviAffondate;
private JLabel JLabelNumNaviAffondate;
private JLabel JLabelNumNaviVive;
public InformationPanel(String playerId) {
this.playerId = playerId;
numNaviVive = 0;
numNaviAffondate = 0;
JButton JButtonPlayerId = new JButton(playerId);
JLabelNumNaviAffondate = new JLabel(String.valueOf(numNaviAffondate));
JLabelNumNaviVive = new JLabel(String.valueOf(numNaviVive));
JLabel JlblNumNaviVive = new JLabel("Navi disponibili:");
JLabel JlblNumNaviAffondate = new JLabel("Navi affondate: ");
JButtonPlayerId.setBackground(new Color(0, 0, 0, 0));
JButtonPlayerId.setFont(new Font("Serif", Font.BOLD, 16));
JButtonPlayerId.setForeground(Color.YELLOW);
JButtonPlayerId.setFocusable(false);
JButtonPlayerId.setEnabled(false);
JlblNumNaviVive.setBackground(new Color(0, 0, 0, 0));
JlblNumNaviVive.setFont(new Font("Serif", Font.BOLD, 16));
JlblNumNaviVive.setForeground(Color.YELLOW);
JlblNumNaviVive.setDoubleBuffered(true);
JlblNumNaviAffondate.setBackground(new Color(0, 0, 0, 0));
JlblNumNaviAffondate.setFont(new Font("Serif", Font.BOLD, 16));
JlblNumNaviAffondate.setForeground(Color.YELLOW);
JlblNumNaviAffondate.setDoubleBuffered(true);
JLabelNumNaviAffondate.setBackground(new Color(0, 0, 0, 0));
JLabelNumNaviAffondate.setFont(new Font("Serif", Font.BOLD, 16));
JLabelNumNaviAffondate.setForeground(Color.YELLOW);
JLabelNumNaviAffondate.setFocusable(false);
JLabelNumNaviAffondate.setEnabled(false);
JLabelNumNaviVive.setBackground(new Color(0, 0, 0, 0));
JLabelNumNaviVive.setFont(new Font("Serif", Font.BOLD, 16));
JLabelNumNaviVive.setForeground(Color.YELLOW);
JLabelNumNaviVive.setFocusable(false);
JLabelNumNaviVive.setEnabled(false);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
setPreferredSize(new Dimension(DEFAULT_INFO_WIDTH, DEFAULT_INFO_HEIGHT));
//setBackground(new Color(0, 0, 0, 0));
setBackground(new Color(0,0,0,40));
add(JButtonPlayerId);
add(JlblNumNaviAffondate);
add(JLabelNumNaviAffondate);
add(JlblNumNaviVive);
add(JLabelNumNaviVive);
setVisible(true);
}
public String getId() {
return playerId;
}
public int getNumNaviAffondate() {
return numNaviAffondate;
}
public int getNumNaviVive() {
return numNaviVive;
}
public void setNumNaviVive(int numNaviVive) {
this.numNaviVive = numNaviVive;
this.JLabelNumNaviVive.setText(String.valueOf(numNaviVive));
this.validate();
}
public void setNumNaviAffondate(int numNaviAffondate) {
this.numNaviAffondate = numNaviAffondate;
this.JLabelNumNaviAffondate.setText(String.valueOf(numNaviAffondate));
this.validate();
}
}
Frist of all variable names should NOT start with an upper case character. You code is hard to read because the forum thinks all your variables are class names and highlights them as such. Follow Java conventions and don't make up your own.
JLabelNumNaviAffondate.setBackground(new Color(0, 0, 0, 0));
Variable are transparent by default so you can't set a background Color to them. The fact that you are trying to set a transparent color may or may not be your problem.
setBackground(new Color(0,0,0,40));
This may be the problem. You can't just set transparency on a Swing components as this breaks the painting chain. That is an opaque component guarantees to paint the background of itself, but when you use transparency the background is not completely painted so you get painting artifacts.
So basically you need to manage painting of the background yourself. So you actuallyl need to make your component non-opaque to the parent component is first painted, then you can paint your transparent background.
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false);
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);
See Background With Transparency for more information and a simpler solution so that you don't need to do custom painting on all your components.
Related
I am solving an activity with the following statement: Create an application to display in a JDialog window eight JPanel components. Each panel should be colored in one of the eight colors in figure 1.
Figure 1
On each panel should be written the word that translates the meaning of the color. Use font size 18. Each panel should be colored using a color from Table 1, specifying the amount of each RGB (Red, Green, Blue) component that corresponds to the meaning of the color. Use the java.awt.Color class. Should be implementing just a single paintComponent method to paint the 8 panels and write the meaning of each color.
Table 1
The problem is that my JPanel does not appear in JDialog. And I have no idea how to make it appear.
Follows the code:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SigCoresGUI extends JDialog {
private static final long serialVersionUID = 1L;
private Color[] cores = { new Color(255, 255, 255), new Color(249, 206, 137), new Color(255, 128, 0),
new Color(255, 0, 0), new Color(244, 102, 174), new Color(5, 120, 203), new Color(116, 186, 160),
new Color(0, 0, 0) };
private String[] sig = { "Paz", "Energia", "Criatividade", "Paixão", "Ternura", "Tranquilidade", "Harmonia",
"Elegância" };
private Font font = new Font("Arial", Font.BOLD, 18);
public SigCoresGUI() {
super();
Desenha desenha = new Desenha();
add(desenha);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
setLayout(new GridLayout(8, 8));
setSize(400, 500);
setVisible(true);
}
public class Desenha extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
for (int i = 0; i < 8; i++) {
JPanel panel = new JPanel();
panel.setBackground(cores[i]);
panel.setFont(font);
JLabel label = new JLabel(sig[i]);
label.setFont(font);
if (i > 0)
label.setForeground(Color.WHITE);
panel.add(label);
add(panel);
}
}
}
}
Never add or remove components from a container (here your JPanel) within a painting method. Painting methods should be for painting and painting only, not for changing the component structure of a container. Understand that you do not have direct control over when or even if a painting method is called, and it can be called many times -- adding many unnecessary components to the container -- and you also never want to slow painting down.
You are overriding paintComponents, a method that (per the API)
Paints each of the components in this container
and since the JPanel has no components to begin with, the method is likely never called.
Instead, add your components in the SigCoresGUI constructor.
Also:
Avoid using setSize(...)
Instead pack() the JDialog before displaying it to let the components and containers size themselves using their preferred sizes.
So this will work although I don't know what layout you're looking for:
import java.awt.*;
import javax.swing.*;
public class SigCoresGUI extends JDialog {
private static final long serialVersionUID = 1L;
private Color[] cores = { new Color(255, 255, 255), new Color(249, 206, 137), new Color(255, 128, 0),
new Color(255, 0, 0), new Color(244, 102, 174), new Color(5, 120, 203), new Color(116, 186, 160),
new Color(0, 0, 0) };
private String[] sig = { "Paz", "Energia", "Criatividade", "Paixão", "Ternura", "Tranquilidade", "Harmonia",
"Elegância" };
private Font font = new Font("Arial", Font.BOLD, 18);
public SigCoresGUI() {
super();
Desenha desenha = new Desenha();
add(desenha);
pack();
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
// setLayout(new GridLayout(8, 8));
// setSize(400, 500);
setVisible(true);
}
public class Desenha extends JPanel {
private static final long serialVersionUID = 1L;
public Desenha() {
setLayout(new GridLayout(0, 1));
for (int i = 0; i < 8; i++) {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(cores[i]);
panel.setFont(font);
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JLabel label = new JLabel(sig[i]);
label.setFont(font);
if (i > 0)
label.setForeground(Color.WHITE);
panel.add(label);
add(panel);
}
}
//#Override
//public void paintComponents(Graphics g) {
// super.paintComponents(g);
//}
}
public static void main(String[] args) {
new SigCoresGUI();
}
}
This question already has answers here:
Black square showing when adding a .GIF on JPanel
(2 answers)
Closed 7 years ago.
Here are my codes for adding the new component:
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if (!todoListInput.getText().equals("")) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel.setBackground(new Color(213, 134, 145, 55));
JCheckBox checkBox = new JCheckBox("");
checkBox.setOpaque(false);
checkBox.setForeground(Color.WHITE);
//checkBox.setBorder(line);
panel.add(checkBox);
Border border = new LineBorder(Color.GRAY, 1, true);
Border margin = new EmptyBorder(10,10,10,10);
panel.setBorder(new CompoundBorder(margin, border));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainList.add(panel, gbc, 0);
validate();
repaint();
todoListInput.setText("");
}
}
});
My problem is that when I do an "onmouseover" action to the checkbox, part of the the whole jFrame will be appeared behind the checkbox
I found that this only appear when I do checkBox.setOpaque(false) or checkBox.setBackground(new Color(122,122,122,55)).
May I know what is the problem of my code?
panel.setBackground(new Color(213, 134, 145, 55));
The problem is your panel is using a transparent background and you are breaking the painting contract between a component. An opaque component needs to repaint the entire background (with an opaque color), however because of the transparency you are getting painting artifacts.
Check out Background With Transparency for more information and a couple of solutions.
The basic solution is:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false);
panel.setBackground( new Color(255, 0, 0, 20) );
frame.add(panel);
However, the link also provides a reusable solution so you don't need to use custom painting on every component that has a transparent background.
I understand that the following sets the background colour of the contentPane. How do I set a picture as its background instead?
I've tried these:
Setting background images in JFrame
JAVA: Ways to fill a Frame. add(), setContentPane(), getContentPane()
http://www.dreamincode.net/forums/topic/131439-setting-background-color-content-pane/
But none of them have worked.
JLabel lblbackground = new JLabel();
lblbackground.setBounds(20, 20, 160, 160);
lblbackground.setBorder(new LineBorder(new Color(0, 0, 0), 2));
lblbackground.setIcon (new ImageIcon (this.getClass().getResource("/boundary/background.jpg")));
lblbackground.setHorizontalAlignment (SwingConstants.CENTER);
BufferedImage img = new BufferedImage(lblbackground.getIcon().getIconWidth(), lblbackground.getIcon().getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = img.createGraphics();
lblbackground.getIcon().paintIcon(null, g, 0, 0);
g.dispose();
Image newing = img.getScaledInstance(150, 150, java.awt.Image.SCALE_SMOOTH);
lblbackground.setIcon(new ImageIcon(newing));
//getContentPane().setLayout(new GridBagLayout());
contentPane = new JPanel();
//contentPane.setBackground(Color.LIGHT_GRAY);
contentPane.setBorder(null);
contentPane.setLayout(null);
contentPane.add(lblbackground);
setContentPane (contentPane);
(...)
// 1) Create your image;
final ImageIcon image = new ImageIcon("../folder/myImage.gif");
//2) Create a JPanel with a background image;
JPanel myPanel = new JPanel(){
#Override
public void paintComponent(Graphics g)
{
g.drawImage(image.getImage(), 0, 0, null);
}
};
//3) Add panel
getContentPane().add(myPanel);
(...)
I'm pretty new to Java, but have been using JPanels, JButtons, JLabels and JTextFields successfully in other parts of my program, but I'm running into trouble when trying to have a JPanel with a couple JButtons, JLabels, and JTextFields inside of it overtop of a painted background.
Here is all of the relevant code for this portion of the program. Currently, when the program runs the only thing that will display is the p1_fireButton, player1PowerField, and player1AngleField overtop of the background (Even though I have the components created for player 2, I purposely commented out adding the p2_Panel so that I could concentrate on p1_Panel.
The weird thing is that those JComponents will only display if I hit the TAB key after the program is running for whatever reason, which I'm also hoping someone could help me fix. My goal will be to have the p1_panel occupy the left orange box and the p2_panel occupy the right orange box. Help would be greatly appreciated!
public class GameFrame extends JFrame
{ //start class GameFrame
ImageIcon background = new ImageIcon("background.jpg");
ImageIcon terrain1 = new ImageIcon("terrain1.png");
//ImageIcon tank_red = new ImageIcon("tank_red.png");
//ImageIcon tank_red = new ImageIcon(player1Tank);
private int x_rectangle = 50;
private int y_rectangle = 50;
private JButton p1_fireButton;
private JButton p2_fireButton;
private JPanel p1_Panel;
private JPanel p2_Panel;
private JLabel player1PowerLabel;
private static JTextField player1PowerField;
private JLabel player1AngleLabel;
private static JTextField player1AngleField;
private JLabel player2PowerLabel;
private static JTextField player2PowerField;
private JLabel player2AngleLabel;
private static JTextField player2AngleField;
String player1Name;
String player2Name;
final Timer gameTimer = new Timer(8, new timer());
Projectile projectile = new Projectile(200, 300);
public GameFrame(String title)
{ //start GameFrame constructor
super(title);
Dimension size = getPreferredSize();
size.width = 1000;
setPreferredSize(size);
setResizable(false);
setLayout(null);
Color trans = new Color(0, 0, 0, 0);
//player1 panel
p1_Panel = new JPanel();
p1_Panel.setLayout(null);
p1_Panel.setBounds(0, 0, 500, 300);
p1_Panel.setBackground(trans);
p2_Panel = new JPanel();
p2_Panel.setLayout(null);
p2_Panel.setBounds(500, 0, 500, 300);
p2_Panel.setBackground(trans);
//player2 panel
/*p2_fireButtonPanel = new JPanel();
p2_fireButtonPanel.setBounds(400, 85, 100, 100);
p2_fireButtonPanel.setBackground(trans);*/
//player1 angle/power fields
player1PowerLabel = new JLabel("Power");
player1PowerLabel.setLayout(null);
player1PowerLabel.setBounds(400, 20, 50, 50);
player1PowerField = new JTextField(3);
player1PowerField.setLayout(null);
player1PowerField.setBounds(400, 10, 50, 25);
player1AngleLabel = new JLabel("Angle");
player1AngleLabel.setLayout(null);
player1AngleLabel.setBounds(30, 10, 50, 50);
player1AngleField = new JTextField(3);
player1AngleField.setLayout(null);
player1AngleField.setBounds(300, 10, 50, 25);
//player2 angle/power fields
player2PowerLabel = new JLabel("Power");
player2PowerLabel.setLayout(null);
player2PowerLabel.setBounds(0, 0, 10, 10);
player2PowerField = new JTextField(3);
player2PowerField.setLayout(null);
player2PowerField.setBounds(10, 10, 10, 10);
player2AngleLabel = new JLabel("Angle");
player2AngleLabel.setLayout(null);
player2AngleLabel.setBounds(30, 10, 10, 10);
player2AngleField = new JTextField(3);
player2AngleField.setLayout(null);
player2AngleField.setBounds(60, 10, 10, 10);
//player1 fire button
p1_fireButton = new JButton("Fire!");
p1_fireButton.setLayout(null);
p1_fireButton.setBounds(430, 70, 50, 50);
ActionListener fireListener = new fireButtonListener();
p1_fireButton.addActionListener(fireListener);
//player2 fire button
p2_fireButton = new JButton("Fire AGAIN!");
p2_fireButton.setLayout(null);
p2_fireButton.setBounds(530, 70, 50, 50);
//add components to player1 panel
p1_Panel.add(p1_fireButton);
p1_Panel.add(player1PowerLabel);
p1_Panel.add(player1PowerField);
p1_Panel.add(player1AngleLabel);
p1_Panel.add(player1AngleField);
//add components to player2 panel
p2_Panel.add(p2_fireButton);
p2_Panel.add(player2PowerLabel);
p2_Panel.add(player2PowerField);
p2_Panel.add(player2AngleLabel);
p2_Panel.add(player2AngleField);
//add components to GameFrame
add(p1_Panel);
//add(p2_Panel);
projectile.fireProjectile(60, -60 * Math.PI / 180.0);
} //end GameFrame constructor
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Image bg = background.getImage();
Image t1 = terrain1.getImage();
Image p1tank = StartPanel.getPlayer1Tank();
Image p2tank = StartPanel.getPlayer2Tank();
//Image tank1 = tank_red.getImage();
g2.drawImage(bg, 0, 0, 1000, 800, this);
g2.drawImage(t1, 0, 420, 1000, 380, this);
g2.drawImage(p1tank, 50, 300, 66, 50, null);
g2.drawImage(p2tank, 500, 300, 66, 50, null);
player1Name = new String(StartPanel.getPlayer1Name());
player2Name = new String(StartPanel.getPlayer2Name());
g.drawString(player1Name, 50, 50);
g.drawString(player2Name, 525, 50);
g2.setColor(Color.green);
g2.fillOval((int)projectile.getXPosition(), (int)projectile.getYPosition(), 15, 15);
}
public class timer implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//TanksGUI.gameFrame.moveRectangle(1, 1);
projectile.advanceProjectile(0.05);
if (projectile.getYPosition() > 400)
{
gameTimer.stop();
}
repaint();
}
}
public class fireButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
gameTimer.start();
}
}
} //end class GameFrame
Check out BackgroundPanel to help you with this. The basic code would be:
JPanel north = new JPanel();
north.add( new JLabel(...) );
north.add( new JTextField(10) );
JPanel gamePanel = new GamePanel();
BackgroundPanel background = new BackgroundPanel(...);
background.add(north, BorderLayout.North);
background.add(gamePanel);
frame.add(background);
The GamePanel is the panel where you do all the custom painting for your game characters. As noted by MadProgrammer, this painting should never be done in the paint() method of the frame.
Don't extend from JFrame you're not adding any functionality to it that creating an instance couldn't achieve. It also makes you're project unportable.
Don't override paint of top level containers. If for no other reason they are not double buffered, which will cause you problems if you want to perform animation. The paint chain for a top level container is rather complex and you've just circumvent the whole process.
Instead, create a custom component (from something like JPanel) and use it as you primary canvas. Override it's paintComponent method and render your background to it, making sure you call super.paintComponent first.
Make sure that any containers you are placing on this "canvas" are transparent, otherwise your background won't show up.
Have a look at Performing Custom Painting and Painting in AWT and Swing for more information
I have a JInternalFrame that I am applying a custom UI to. The UI paints the component, but when I add a JPanel to the JInternalFrame it doesn't show up. I think the UI is paining over the whole component, but how do I paint the UI THEN paint the components?
But if anyone has a better way of doing this, please let me know! Thanks!
public class ClassInternalFrame extends JInternalFrame {
public static Color currentColor;
public static final Color CLASS_TYPE = new Color(148, 227, 251);
public ClassInternalFrame(String title, Color classType) {
super(title, true, true, false, true);
currentColor = classType;
super.setUI(new ClassFrameUI());
Container pane = super.getContentPane();
pane.setLayout(new BorderLayout());
JPanel titlePanel = new JPanel();
titlePanel.setPreferredSize(new Dimension(0, 20));
pane.add(titlePanel, BorderLayout.NORTH);
titlePanel.setBorder(new MatteBorder(1, 1, 1, 1, Color.yellow));
}
}
class ClassFrameUI extends InternalFrameUI {
private final static ClassFrameUI frmUI = new ClassFrameUI();
public static ComponentUI createUI(JComponent c) {
return frmUI;
}
#Override
public void paint(Graphics g, JComponent c)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(0, 0, c.getWidth(), c.getHeight());
g2d.setColor(ClassInternalFrame.currentColor);
g2d.fillRect(0, 0, c.getWidth(), 20);
g2d.setColor(Color.DARK_GRAY);
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 1, 0 }, 0));
g2d.drawRect(0, 0, c.getWidth()-1, c.getHeight()-1);
g2d.drawLine(0, 20, c.getWidth(), 20);
}
}
The problem is not that you're painting over anything, but that InternalFrameUI does absolutely nothing (if it did, you would also need to call super.paint(g, c);). Normally, painting of the components is done by a subclass such as BasicInternalFrameUI. It looks like you're trying to paint a custom title bar, a task that BasicInternalFrameUI delegates to BasicInternalFrameTitleBar.