-1

I am making a custom title bar in swing, and when I use a letter "x" for the close button, it works fine. But when I replace it with an icon, the whole title bar disappears, until I hover the close button, which makes only the close button appear. Here is a snippet of my code:

// Create title bar
JPanel titleBar = new JPanel();
titleBar.setBackground(new Color(0x343434));
titleBar.setSize(screenSize.width, 36);

JButton closeButton = new JButton();
closeButton.setBackground(new Color(0, 0, 0, 0));
closeButton.setIcon(new ImageIcon(ImageIO.read(new File("src/close.png")).getScaledInstance(16, 16, Image.SCALE_SMOOTH)));
closeButton.setSize(50, 36);
closeButton.setLocation(screenSize.width - 50, 0);
closeButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
    }
});
closeButton.addMouseListener(new java.awt.event.MouseAdapter() {
    public void mouseEntered(MouseEvent e) {
        closeButton.setBackground(Color.RED);
    }

    public void mouseExited(MouseEvent e) {
         closeButton.setBackground(new Color(0x343434));
    }
});
closeButton.setBorder(null);
closeButton.setFocusPainted(false);
titleBar.add(closeButton);

window.add(titleBar);

Edit: it works sometimes now, but sometimes it doesn't. Here is the new code:

public class Main {
    public static void main(String[] args) throws IOException {
        // Get screen size
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        // Create window
        JFrame window = new JFrame();

        //Get taskbar size
        Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(window.getGraphicsConfiguration());
        int taskBarHeight = screenInsets.bottom;

        // Configure window
        window.setSize(screenSize.width, screenSize.height - taskBarHeight);
        window.getContentPane().setBackground(new Color(0x232323));
        window.setUndecorated(true);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);

        // Create title bar
        JPanel titleBar = new JPanel();
        titleBar.setBackground(new Color(0x343434));
        titleBar.setSize(screenSize.width, 36);

        JButton closeButton = new JButton();
        closeButton.setBackground(new Color(0x343434));
        Image closeImg = ImageIO.read(new File("src/close.png")).getScaledInstance(16, 16, 4);
        closeButton.setIcon(new ImageIcon(closeImg));
        closeButton.setSize(50, 36);
        closeButton.setLocation(screenSize.width - 50, 0);
        closeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
            }
        });
        closeButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                closeButton.setBackground(Color.RED);
            }

            public void mouseExited(MouseEvent e) {
                closeButton.setBackground(new Color(0x343434));
            }
        });
        closeButton.setBorder(null);
        closeButton.setFocusPainted(false);
        titleBar.add(closeButton);

        window.add(titleBar);
    }
}
Lysander Mealy
  • 113
  • 1
  • 6
  • 3
    [mcve] plese?.. – Paul Samsotha Dec 01 '20 at 17:51
  • @PaulSamsotha I don't know that I can. The whole thing takes 65 lines, and all it does is create a window with that code. – Lysander Mealy Dec 01 '20 at 17:55
  • 2
    65 lines is not that long. You could also shorten it by just including the necessary code to reproduce the problem. Meaning just add the button that causes the problem and whatever else code to run the program. Test it make sure the code still reproduces the problem. That is what a _minimal reproducible problem_ is. Questions that include this are the ones that get the best help. If you help us out by making the code runnable and reproducible, it saves the volunteers' time and will make us want to help – Paul Samsotha Dec 01 '20 at 17:58
  • @PaulSamsotha *"65 lines is not that long."* Indeed! A 'ready to run' example of less than 100 lines of code is very minimal. Tip for the OP: One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). E.G. [This answer](https://stackoverflow.com/a/10862262/418556) hot links to an image embedded in [this question](https://stackoverflow.com/q/10861852/418556). – Andrew Thompson Dec 01 '20 at 18:06
  • 1
    @LysanderMealy *The whole thing takes 65 lines,*. and most of that 65 lines of code is irrelevant to you stated question. Your question is about display a close button on a JFrame. So for the [mre] you need a JFrame, a JPanel and a JButton. The ActionListener code and the MouseListener code is irrelevant for the stated problem. First you learn how to display the button correctly, Then you worry about adding the listeners to the button. This is how you make an "MRE". – camickr Dec 01 '20 at 18:49
  • @PaulSamsotha Done. – Lysander Mealy Dec 01 '20 at 22:24
  • (1-) Still not an [mre] and you haven't implemented any of the suggestion from my answer below so there is no need for me to continue to make suggestions. – camickr Dec 02 '20 at 01:42
  • Setting frame visible should be the _last_ thing you do. But it is the _first_ thing you do and then still try to build the window. Doesn't make sense. That's the delay you are seeing. – Paul Samsotha Dec 02 '20 at 03:02

1 Answers1

1
closeButton.setBackground(new Color(0, 0, 0, 0));

Don't use a transparent background. Swing doesn't paint components properly when you use transparency.

For full transparency you simply use:

closeButton.setOpaque( false );

Swing was designed to be used with layout managers:

closeButton.setSize(50, 36);
closeButton.setLocation(screenSize.width - 50, 0);

The above code will do nothing (so get rid of it). The default layout manager of a JPanel is the FlowLayout. Once the frame is visible the layout manager will be invoked and the size/location will be reset by the layout manager.

So let the layout manager do it's job. In your case you can use:

//JPanel titleBar = new JPanel();
JPanel titleBar = new JPanel( new FlowLayout(FlowLayout.RIGHT) );

Now any components you add to the panel will be aligned to the right edge.

window.add(titleBar);

The default layout manager for a JFrame is the BorderLayout. When you don't specify a constraint, the component is added to the CENTER.

For a title bar you would want that added to the top of the Frame. So you should be using:

//window.add(titleBar);
window.add(titleBar, BorderLayout.PAGE_START);

Read the Swing tutorial on Layout Managers for more information and working examples for both the FlowLayout and the BorderLayout.

Also, Swing components need to be added to the frame BEFORE the frame is made visible. The layout manager is initially invoked when the frame is "packed" or made "visible".

camickr
  • 321,443
  • 19
  • 166
  • 288