How to Remove Black Rectangle on Window Resize? - java

I am developing a JFrame window with Swing and AWT, and when I resize the window, it looks like this:
Window resize
(I apologize for the low frame rate, stackoverflow wouldn't accept a larger file size)
As you can see, a lot of times when I resize the window, it shows a black rectangle where it is being resized and it doesn't go away until you pause for a moment. Additionally, the circle doesn't always update accurately with my resize event:
frame.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent componentEvent) {
width = frame.getWidth();
height = frame.getHeight();
springLayout.putConstraint(SpringLayout.SOUTH, panel, height, SpringLayout.NORTH, frame.getContentPane());
springLayout.putConstraint(SpringLayout.EAST, panel, width, SpringLayout.WEST, frame.getContentPane());
panel.repaint();
}
});
That's beside the point (though it is possible the two problems are linked). I have only ever encountered this problem when using Swing. JavaFX has never given me this problem. Is there any way I can remove the black rectangle when the window is resized?

I have only tested this on Windows 10.
This apparently has to do with the native window decorations of the window that hosts the JFrame. When disabling the native window decorations, you can remove the stuttering resizes and the black background bleeding through. See the documentation for JFrame.setDefaultLookAndFeelDecorated(boolean):
Provides a hint as to whether or not newly created JFrames should have their Window decorations (such as borders, widgets to close the window, title...) provided by the current look and feel. If defaultLookAndFeelDecorated is true, the current LookAndFeel supports providing window decorations, and the current window manager supports undecorated windows, then newly created JFrames will have their Window decorations provided by the current LookAndFeel. Otherwise, newly created JFrames will have their Window decorations provided by the current window manager.
Thus, you have two options. Either set the property once before you create your JFrame:
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
Or do it after the creation of the JFrame:
JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setWindowDecorationStyle(JRootPane.FRAME);
Note that in either case, you are bound to use Swing's Look and Feel for the window decorations. The title bar and handles of the window are therefore going to look different than before.

Related

JDialog under both Nimbus and Metal look and feel too wide

I have two simple JDialog dialogs that should be small. The first has a JTextField of 5 columns and a vertical slider under it. The second has a JLabel, a JSpinner and two JButton(s). Both, after pack() and setVisible(), are too wide. For example, the first dialog has a preferred size of about 80, but shows up with width of 258.
Here are a few things that do not work: 1) a custom layout with the right preferred size computations vs. GridBagLayout; 2) overriding getPreferredSize(); 3) setSize and setBounds before or after setVisible; 4) a custom root pane UI with a custom title pane; 5) a forced constant width set on componentResized; 6) removing the slider (in case there is confusion between vertical and horizontal sliders width and height); 7) removing all controls and the dialog title.
In general, the dialogs can be resized by the user to have smaller width (by dragging the corners), but not programmatically (they can be resized programmatically with setBounds to have smaller height).
The dialogs do have the right sizes under some commercial look and feels, but not under Metal or Nimbus. Under both Metal or Nimbus, the preferred and minimum sizes of the dialog, root panes, glass panes, layered panes make sense. The size of the dialog itself doesn't.
I have tested this without setting a look and feel (which, on Windows, presumably means Metal) and it does not work.
I know that the width of 258 is set in addNotify in Dialog, on getComponentFactory().createDialog(this).
I assumed this could be related to the title portion of the dialog, but the icons there are not of some significant size.
Any ideas are appreciated.
My next move will be to create a simple standalone JDialog or a JFrame that calls a JDialog, outside of the main application with which I am working now. However, I cannot see anything special happening in the larger application.
Here is the code that will produce a dialog with the same width (looks like):
public class Main
{
public static void main(String[] args)
{
JDialog dlg = new JDialog();
dlg.pack();
dlg.setVisible(true);
}
}

Swing layering - transparent component ignores underlying AWT element

First, to get it out of the way, I absolutely NEED to use heavyweight AWT component with a swing application. I need features from both of them.
The task is simple - render a heavyweight AWT Canvas (or any other element), render OpenGL scene directly onto it, then display Swing buttons above it for the UI.
My problem is that it works half-way.
I don't seem to have problems with Z-ordering. I am using jLayeredPanes for it, and I can move Canvas between layers and it actually works, popping on top or below other elements.
The problems are with transparency.
The thing is, Swing elements have Opaque parameter, and when it's set to false (non-opaque) - it should basically be transparent and you should see the next element below it. In my case, however, the AWT Canvas gets ignored, and you instead only see the next underlying SWING element.
Here are a couple of screenshots. They are taken from a standalone test project of mine. The canvas is stretched to the size of the frame, and in the upper left there is a JLayeredPane dummy element that is a simplified version of the menu.
On the first screenshot, the JLayeredPane's Opaque setting is set to true, and you can see that it's background property is set to Blue color.
On the second screenshot, everything is exactly the same but Opaque is set to false. Instead of displaying whatever is on the Canvas - what gets drawn in empty grey jFrame background.
Lastly, on the third screenshot I have put Canvas into a jPanel instead of leaving it on its own. As you can see, the Panel's orange color is seen through the transparent jLayeredPane, but the Canvas is yet again hidden.
Here's the code for the Frame layout. I would not post my rendering/context code right now
frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(width, height));
canvas = new Canvas();
canvas.setSize(width,height);
//this part exists only in the third example
JPanel p = new JPanel();
p.setSize(width,height);
p.setBackground(Color.orange);
p.add(canvas);
// third example end
JLayeredPane pane = new JLayeredPane();
JLayeredPane paneMenu = new JLayeredPane();
JButton button = new JButton();
button.setSize(20,20);
paneMenu.setSize(200,200);
paneMenu.add(button, new Integer(1));
paneMenu.setBackground(Color.BLUE);
paneMenu.setOpaque(false); //True for the first example
pane.add(p, new Integer(1)); // canvas for the first two examples
pane.add(paneMenu, new Integer(2));
pane.setOpaque(false);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
Could anyone please explain me what is going on and how to do what I need to do.
I will repeat again - I have to use heavyweight component as render target. I am aware of solutions like JOGL's GLPanel which is a lightweight Swing-compatible component. But I tried that method and the performance is really slow, because instead of directly rendering onto it as a context target - it reads FrameBuffer from memory, flips it, and then paints it as BufferedImage. This path is not fitting for the limited resources of an embedded system that I'll be running on.
c0der said: Please post minimal reproducible example
Errrrm.... Didn't I?
Here, you can have it in complete java class form if you want, but I literally changed some variables for constants.
import javax.swing.*;
import java.awt.*;
public class Main
{
public static void main(String[] args)
{
JFrame frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(500, 500));
Canvas canvas = new Canvas();
canvas.setSize(500,500);
canvas.setBackground(Color.RED);
//this part exists only in the third example
JPanel p = new JPanel();
p.setSize(500,500);
p.setBackground(Color.orange);
p.add(canvas);
// third example end
JLayeredPane pane = new JLayeredPane();
JLayeredPane paneMenu = new JLayeredPane();
JButton button = new JButton();
button.setSize(20,20);
paneMenu.setSize(200,200);
paneMenu.add(button, new Integer(1));
paneMenu.setBackground(Color.BLUE);
paneMenu.setOpaque(false); //True for the first example
pane.add(p, new Integer(1)); // canvas for the first two examples
pane.add(paneMenu, new Integer(2));
pane.setOpaque(false);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
}
}
A little update:
I initially suspected that because Swing elements delegate all their drawing to the underlying heavyweight element (In my case JFrame), then what happens is that the frame generates a single frameBuffer for itself and then displays on top of Canvas. Canvas itself is not handled in this generation and thus the frame "covers" over the canvas.
That doesn't seem to be the case. I tried making the JFrame undecorated, all panels non-opaque, and display the picture. The result - canvas is still "cut", and through the hole you can see the underlying IDE menu.
This makes me think that somewhere during Drawing, the Canvas itself detects that it is obscured by another element, and that it doesn't need to draw that area. So it "optimizes" itself and doesn't update these pixels.
Maybe I'm wrong. But here's another screenshot. This is the same example as before, but I took out 3d rendering and simply trying to display Canvas with background set to Red.
Once again, going to reply to my own question.
It turned out that I need to do
setComponentMixingCutoutShape(paneMenu, new Rectangle());
for the menu pane that lies underneath the button. That essentially tells java not to cut out the element from the heavyweight underlying component.

Center JFrame in combination with pack()

I'm trying to center a JFrame i used to pack(), and I got it, but I think it's not the clean way.
This is how I'm doing it atm:
JFrame window = new JFrame();
//filling
//window
//with
//stuff
window.pack();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int x = (dim.width - window.getPreferredSize().width) / 2, y = (dim.height - window.getPreferredSize().height) / 2;
window.setBounds(x, y, window.getPreferredSize().width, window.getPreferredSize().height);
I pack it after filling it to get the final PreferredSizes, so I can use those values in the setBounds method. But I don't like rebounding it after packing it.
Any better ideas?
To center a window in the screen you need to call window.setLocationRelativeTo(null) right after pack() call and before making your window visible:
JFrame window = new JFrame();
...
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
As per Window#setLocationRelativeTo(Component c) docs:
public void setLocationRelativeTo(Component c)
Sets the location of the window relative to the specified component
according to the following scenarios.
The target screen mentioned below is a screen to which the window
should be placed after the setLocationRelativeTo method is called.
If the component is null, or the GraphicsConfiguration associated with this
component is null, the window is placed in the center of the
screen. The center point can be obtained with the
GraphicsEnvironment.getCenterPoint method.
On the other hand
Some developers might advice you to use Window#setLocationByPlatform(boolean flag) instead of setLocationRelativeTo(...) in order to honor the default location for the native windowing system of the platform where your desktop application is running. This makes sense since your application must be designed to run in different platforms with different windowing systems and PLAFs.

Make transparent JFrame with visible borders

I'm trying to create a transparent JFrame, i.e. a window where the interior is completely transparent while the border, which is the top bar with the close button, minimize etc visible. I tried creating a new Jpanel and then using panel.setOpaque(false);, but it did not help.
I'm extremely new to swing and Java GUI and would love to get some help.
What you want to do is possible, but not in the way you're imagining it...
If you want your standard operating system's window decorations (i.e. window border, close, maximize, minimize buttons), it's impossible. Transparency cannot be applied to 'decorated' frames.
However, this can be done by using Java's default window decorations. Try out the code below:
public static void main(String[] args) {
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.drawRect(32,32,32,32);
}
};
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame();
f.add(panel);
f.setSize(256,256);
// The following two statements cause the window-transparency:
f.setUndecorated(true);
f.setBackground(new Color(0,255,0,0));
f.setVisible(true);
}
I personally don't find the Java window decorations very nice looking... Apart from that, OS-specific features (such as Window's Snap feature by 'half-maximizing' a window by moving it to the side of the screen) don't work... To me this is a deal-breaker, but depending on your needs, it could be an acceptable solution. :)

Create a rounded JFrame / ContentPane

I'm creating a login window with rounded corners in java. Everything is OK, see pic, but i'm having challenges making the JFrame / ContentPane transparent. There are white areas at each corner (shown by the arrows) that i seem not to be able to remove since i can't set opague to false for the JFrame or ContentPane.
Any ideas of how i can remove these white areas
Since Java 1.3 there's a trick which allows to make partially transparent windows, or windows fading in (I usually use this for my splash screens), or special FX (such as shadows):
Before opening the window, programmatically take a screenshot of the region where your window is going to be (using java.awt.Robot.createScreenCapture())
Set the screenshot as the background of your root container (JPanel with custom paintComponent() routine)
Now you can add all kinds of transparent components, or paint another semitransparent image on top of the background.
Example which creates a window with a semitransparent shadow using this technique:
http://www.eclipsezone.com/eclipse/forums/t17720.html
Not much help to you but Java7 will support transparent and shaped windows: More info here. These are available already in Java 6u10 but not publicly, ie, you need to use an unsupported com.sun... class that might change in future and break your program.
try this. its work :)
yourframe.setBackground(new Color(0, 0, 0, 180));
yourframe.setUndecorated(true);
yourframe.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
setShape(new RoundRectangle2D.Double(0, 0, getWidth(), getHeight(), 80, 80));
}
});
JFrame can not be made transparent as it is a heavyweight component. Only lightweight components such as JWindow can be made transparent.

Categories

Resources