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.
Related
I have a problem. I am trying to create "alert" component that I can display in a JFrame. This alert has a semi-transparent background (70% opacity, white) with any trivial amount of JButtons on it. The background itself has rounded corners, and thus I made a custom component.
When rendering this alert, artifacts appear: no alert-background is rendered on the button that is initially selected. When moving my mouse across the buttons, it looks like the text of the buttons is being drawn in two places for no reason.
Screenshots of the artifacts (top = initial render, bottom = moving mouse around):
Code that causes these problems:
public class Test {
public static void main(String[] args) {
MyRoundedTransparentBackground background = new MyRoundedTransparentBackground();
background.setSize(200, 200);
background.setLocation(100, 100);
background.setLayout(new GridBagLayout());
JPanel spacer = new JPanel();
spacer.setBackground(new Color(0, 0, 0, 0));
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = 1;
c.gridheight = 1;
c.weighty = 1;
background.add(spacer, c);
JButton button1 = new JButton("Hi there");
JButton button2 = new JButton("Bye ...");
button1.setBackground(new Color(0, 0, 0, 0));
button1.setFocusPainted(false);
button1.setBorderPainted(false);
button2.setBackground(new Color(0, 0, 0, 0));
button2.setFocusPainted(false);
button2.setBorderPainted(false);
c.weighty = 0;
c.gridy = 1;
background.add(button1, c);
c.gridx = 1;
background.add(button2, c);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocation(2000, 100);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.red);
frame.add(background);
frame.setVisible(true);
}
private static class MyRoundedTransparentBackground extends JComponent {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(1f, 1f, 1f, 0.7f));
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 15, 15);
}
}
Can someone help me find out what the issue is, and give a potential solution to achieve the desired behavior?
I already looked up this problem and found several threads. Tried all the solutions and none of them helped. I am trying to show a cross where my mouse is placed, the x and the y coordinate of my current mouse position is supposed to be shown in the top left and top right corner. In order to achieve this, I used two JLabels.
Maybe I am overlooking something?
I played around with the standard Text I set in the Labels, positioning, different Layouts for my frame and panel - nothing helps.
The following code should be good enough to get an understanding, I dont think it would be helpful if I left out something.
Fensterkreuz(){
jl1 = new JLabel("0");
jl2 = new JLabel("0");
jl1.setSize(new Dimension(100,100));
jl2.setSize(new Dimension(100,100));
jl1.setFont(new Font ("Arial", Font.PLAIN, 15));
jl2.setFont(new Font ("Arial", Font.PLAIN, 15));
cP = new Point();
this.add(jl1);
this.add(jl2);
addMouseMotionListener(this);
}
public void mouseDragged (MouseEvent e){
}
public void mouseMoved (MouseEvent e) {
cP = e.getPoint();
repaint();
}
public void paint (Graphics g){
g.drawLine((cP.x),(cP.y-15), (cP.x),(cP.y+15));
g.drawLine((cP.x-15),(cP.y), (cP.x+15),(cP.y));
jl1.setText(String.valueOf(cP.x));
jl2.setText(String.valueOf(cP.y));
}
public static void main (String [] args) {
JFrame f = new JFrame();
JComponent test = new Fensterkreuz();
test.setOpaque(false);
f.setVisible(true);
f.setSize(1500,1000);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(test);
}
Put repaint() at the bottom of your main method. Repaint calls the Paint method you have but I think you also have to add your own overriding repaint method to stop “flickering”.
You are overriding the paint() method. So, you need add super.paint(g); as the first line in your overridden paint() method.
To show the 2 labels properly, you need to add this.setLayout(new FlowLayout(FlowLayout.LEFT)); line.
I'm adding the full code with above changes here, so that you can run it and see the results yourself.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Fensterkreuz extends JComponent implements MouseMotionListener {
private JLabel jl1;
private JLabel jl2;
private Point cP;
Fensterkreuz(){
jl1 = new JLabel("0");
jl2 = new JLabel("0");
jl1.setSize(new Dimension(100,100));
jl2.setSize(new Dimension(100,100));
jl1.setFont(new Font ("Arial", Font.PLAIN, 15));
jl2.setFont(new Font ("Arial", Font.PLAIN, 15));
cP = new Point();
//this.setLayout(new FlowLayout(FlowLayout.LEFT));
//this.add(jl1);
//this.add(jl2);
this.setLayout(new GridBagLayout());
this.add(jl1, new GridBagConstraints(0, 0, 1, 1, 0.0, 1.0, GridBagConstraints.NORTHWEST,
GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
this.add(jl2, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHEAST,
GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
addMouseMotionListener(this);
}
public void mouseDragged (MouseEvent e){
}
public void mouseMoved (MouseEvent e) {
cP = e.getPoint();
repaint();
}
public void paint (Graphics g){
super.paint(g);
g.drawLine((cP.x),(cP.y-15), (cP.x),(cP.y+15));
g.drawLine((cP.x-15),(cP.y), (cP.x+15),(cP.y));
jl1.setText(String.valueOf(cP.x));
jl2.setText(String.valueOf(cP.y));
}
public static void main (String [] args) {
JFrame f = new JFrame();
JComponent test = new Fensterkreuz();
test.setOpaque(false);
f.setVisible(true);
f.setSize(1500,1000);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(test);
}
}
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.
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 JPanel(a) with box layout, and all the components are stacked on it vertically.
Among them, I have a JPanel(b) with horizontal box layout. To that JPanel(b) I have added rigid area, JPanel and JTextArea.
What I want is that JPanel(b) increases its height every time JTextArea expands due to word wrap. However, since my JPanel in beginning has the height of a single row. JTextArea doesn't expand because all space is filled.
Is there a way to fix this, an alternative?
It doesn't have to be JPanel and JTextArea, just something that can contain components and a JTextComponent that suporrts multi line.
class Question extends JPanel
{
public JPanel questionArea;
public JTextArea number, question;
public Question(Page page)
{
setSize(new Dimension(556, 100));
setBackground(Color.PINK);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
Border in = BorderFactory.createDashedBorder(Color.BLACK);
Border out = BorderFactory.createMatteBorder(0, 0, 10, 0, Color.WHITE);
setBorder(BorderFactory.createCompoundBorder(out, in));
questionArea = new JPanel();
questionArea.setPreferredSize(new Dimension(556, 32));
questionArea.setBackground(Color.YELLOW);
questionArea.setLayout(new BoxLayout(questionArea, BoxLayout.LINE_AXIS));
out = BorderFactory.createMatteBorder(0, 0, 8, 0, Color.WHITE);
setBorder(BorderFactory.createCompoundBorder(out, in));
number = new JTextArea();
number.setPreferredSize(new Dimension(25, 32));
number.setBackground(Color.GREEN);
number.setFont(new Font("Arial", Font.BOLD, 15));
number.setText("10.");
number.setEditable(false);
question = new JTextArea();
question.setPreferredSize(new Dimension(494, 32));
question.setBackground(Color.PINK);
question.setFont(new Font("Arial", Font.BOLD, 15));
question.setText("What is the first question?");
questionArea.add(Box.createRigidArea(new Dimension(35, 32)));
questionArea.add(number);
questionArea.add(question);
add(questionArea);
page.editArea.add(this, page.content);
}
}
break
class Page extends JPanel
{
public JPanel editArea;
public Box.Filler blank;
public Page(JPanel panel)
{
setLayout(null);
setBounds(92, panel.getPreferredSize().height+40, 794, 1123);
setBackground(Color.WHITE);
editArea = new JPanel();
editArea.setLayout(new BoxLayout(editArea, BoxLayout.PAGE_AXIS));
editArea.setBounds(119, 96, 556, 931);
editArea.setBackground(Color.LIGHT_GRAY);
blank = new Box.Filler(new Dimension(556, -1), new Dimension(556, 931), new Dimension(556, 931));
editArea.add(blank);
add(editArea);
}
}
Page class is itself on a JPanel with null layout, no need for code, right?
I think horizontal BoxLayout is doing you in.
It will display components at their preferred size (using getPreferredSize() upon instantiation) and I don't believe it will readily resize it for you. You might want to change Panel(b) to a BorderLayout, and add the components to the EAST, WEST, and the JTextArea in CENTER.