1

I am in the process of writing a program which pings a server and returns a value.

I have been trying to overlay the ping to a JFrame, where a JLabel displays the ping in a transparent window.

However, every time I call the method DrawOverlay(), the JLabel simply redraws on top of the previously drawn label.

For context, DrawOverlay() is called from another class, PingTest.

void DrawOverlay(String ping)
{
    JLabel lbl_ping = new JLabel(ping);
    lbl_ping.removeAll();//attempts at clearing the previously drawn label
    lbl_ping.revalidate();
    lbl_ping.repaint();

    if (!frame.isUndecorated())
    {
        frame.setUndecorated(true);
    }

    frame.setFocusableWindowState(false);
    frame.setBackground(new Color(0, 0, 0, 0));
    frame.setAlwaysOnTop(true);
    frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);
    frame.getContentPane().setLayout(new java.awt.BorderLayout());
    lbl_ping.setFont(new Font("serif", Font.PLAIN, 48));
    lbl_ping.setForeground(Color.WHITE);
    lbl_ping.setText(ping);
    frame.add(lbl_ping);
    frame.setVisible(true);
    frame.pack();
}

Is there any way to redraw a JFrame or JLabel to remove the previous data?

Alfabravo
  • 7,493
  • 6
  • 46
  • 82
Matt Harris
  • 33
  • 1
  • 3
  • *"...the JLabel simply redraws on top of the previously drawn label"* All the configuration made in `DrawOverlay` should be donde once, and on `DrawOverlay` you should have a method that should be called by `PingTest` and all it should do is call `lbl_ping.setText(ping)`. Note that you should `pack()` your `JFrame` **before** making it visible... – Frakcool Jun 07 '17 at 17:15
  • Would you be able to elaborate some more? I'm unsure about how to implement what you have said. (besides packing the JFrame). – Matt Harris Jun 07 '17 at 17:40
  • This use-case seems better suited to a [`JToolTip`](https://docs.oracle.com/javase/8/docs/api/javax/swing/JToolTip.html). Why reinvent the wheel? – Andrew Thompson Jun 07 '17 at 18:01
  • I've just tried implementing what you have said, I'm still getting the same issue of the text overlapping when calling `lbl_ping.setText(ping)` Here is an [example](http://imgur.com/a/PVumL) of it: I may have done something wrong. – Matt Harris Jun 08 '17 at 00:00
  • It seems like those JLabels are unrelated judging from the picture. One seems to be the ping "80" and one is simply "test". Check for any JLabels you have created (using new) and adjust the position or use a layout. But this is subject to a different question. – Shiro Jun 08 '17 at 00:17
  • Sorry, i added the "test" manually to show it was overlapping more obviously. Does this help to understand the issue? – Matt Harris Jun 08 '17 at 00:27
  • The 'overlapping' is the redrawing that I am trying to fix – Matt Harris Jun 08 '17 at 00:34
  • Every JLabel that appears on the screen was created by one ´new´ and added to the content pane. Search for "new JLabel" and check where the second JLabel comes from and remove it. If you call repaint on frame every JComponent on the ContentPane will be redrawn, which means, first it will be removed (visually) and second it will be redrawn. So any duplicates you have were created somewhere. – Shiro Jun 08 '17 at 00:41

1 Answers1

2

Each time you call DrawOverlay you create a new JLabel:

JLabel lbl_ping = new JLabel(ping);

After setting the properties you call frame.add(lbl_ping); which adds your new JLabel to your JFrame.

You're JLabel does not get overwritten or removed.

What you want to do is declare JLabel lbl_ping; as a private member in your class and then when creating your JFrame you want to also initialize your JLabel and set all those properties:

lbl_ping = new JLabel();

frame.setFocusableWindowState(false);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setAlwaysOnTop(true);
frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);
frame.getContentPane().setLayout(new java.awt.BorderLayout());
lbl_ping.setFont(new Font("serif", Font.PLAIN, 48));
lbl_ping.setForeground(Color.WHITE);
lbl_ping.setText(ping);
frame.add(lbl_ping);

// pack() first then setVisible()
frame.pack();
frame.setVisible(true);

Have a look at this. It explains what pack() does.

Then in DrawOverlay you simply set the text value and update your JFrame:

void DrawOverlay(String ping)
{
    lbl_ping.setText(ping);
    frame.getContentPane().validate(); // You modified child component lbl_ping (changed its size by setting a new text) so you need to recalculate all the child components
    frame.getContentPane().repaint(); // Redraws the content pane and all of its children
}
Shiro
  • 2,610
  • 2
  • 20
  • 36
  • I made the mistake of calling the initialise method every update. You were right all along! I'm not sure if its the right way to do it but, I used a static int and an if statement to only initialise once. – Matt Harris Jun 08 '17 at 01:28