setDefaultLookAndFeelDecorated affects JFrame resize behaviour - java

This is my code:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test{
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
JPanel jp = new JPanel();
jp.setMinimumSize(new Dimension(200, 200));
jp.setPreferredSize(new Dimension(200, 200));
//frame.getContentPane().setMinimumSize(new Dimension(200, 200));
//frame.getContentPane().setPreferredSize(new Dimension(200, 200));
frame.getContentPane().add(jp);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
It behaves exactly the way I want. User can resize the JFrame but it'll always be large enough to hold 200px x 200px JPanel. But when I remove:
JFrame.setDefaultLookAndFeelDecorated(true);
user can resize JFrame to any size.
Why does default look and feel decoration affect resizing? How can i make it work without setDefaultLookAndFeelDecorated(true)? I know I can set frames minimum size manually (JFrame#setMinimumSize(new Dimension dim)) and I will if there is no smarter solution.
I'm using jdk 1.7 on Windows 7.

This use to be a bug, the page speaks of work arounds like:
override setSize() and check if the new size is less than the desired
inside paint(Graphics g) of JFrame check height and width and "re-create" frame to new minimum size
however a person claims it to be fixed as the original example issued for the bug proposal omitted the call to setMinimumSize(...), this is needed because JFrame does not enforce minimum size
Here is the snippet which shows that persons' code:
import java.awt.Dimension;
import javax.swing.*;
public class JavaApplication118 {
private final Dimension m_dim = new Dimension(200, 150);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JavaApplication118().createAndShowUI();
}
});
}
private void createAndShowUI() {
// JFrame.setDefaultLookAndFeelDecorated(true);
final JFrame frame = new JFrame("Test") {
#Override
public Dimension getMinimumSize() {
return m_dim;
}
};
frame.setMinimumSize(m_dim);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
// frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void initComponents(JFrame frame) {
JPanel jp = new JPanel();
jp.setMinimumSize(new Dimension(200, 200));
jp.setPreferredSize(new Dimension(400, 400));//for testing
frame.getContentPane().add(jp);
}
}
EDIT
The snippet overrode getMinimumSize() though this seems redundant after calling setMinimumSize(..), I kept it included as that's how I found the snippet (I did remove the overridden getPreferredSize() method of the JFrame which the snippet included).

Why does default look and feel decoration affect resizing?
Because then the window sizing is under the complete control of the LAF while dragging: The mouseHandler installed by (f.i.) MetalRootPaneUI doesn't resize the window below the min returned by the LayoutManager. Without setting the frame's minimumSize, you can still decrease its size programatically.
The only way (unfortunately) to enforce a window's minimum size always is to manually set it. Unfortunate, as that implies keeping track of dynamic changes of that minimum and update it as appropriate.
A snippet to play with (un/comment the defaultDecoration and frame min setting)
JFrame.setDefaultLookAndFeelDecorated(true);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
Dimension m = getMinimumSize();
// visualize the min
g.drawRect(0, 0, m.width - 1, m.height -1);
}
};
// BEWARE: for demonstration only, NEVER do in production code
panel.setMinimumSize(new Dimension(400, 400));
panel.setPreferredSize(panel.getMinimumSize());
final JXFrame frame = new JXFrame("", true);
Action action = new AbstractAction("resize") {
#Override
public void actionPerformed(ActionEvent e) {
frame.setSize(300, 300);
LOG.info("succeeded? " + frame.getSize());
}
};
panel.add(new JButton(action));
frame.add(panel);
frame.pack();
// set minimum is required to enforce the minimum
frame.setMinimumSize(frame.getMinimumSize());
Update
Looking at the Window source, turns out that you can have auto-magic dynamic respect of min size by overriding isMinimumSizeSet and returning true uncondinionally:
final JXFrame frame = new JXFrame("", true) {
#Override
public boolean isMinimumSizeSet() {
return true;
}
};
...
// no longer needed
// frame.setMinimumSize(frame.getMinimumSize());
not tested for side-effects, though

Related

Graphics not appearing in window

I'm trying to draw a normal blue rectangle on to a JFrame, when I press play no window appears at all (with no blue rectangle)
I know that there are tutorials online showing how to draw a rectangle to a JFrame, but I would like to know the problem with the following code and why it does not work.
public class Window extends JFrame {
public Window() {
initialize();
}
private void initialize() {
JFrame frame = new JFrame();
frame.setBounds(100, 100, 600, 600);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(new Display());
}
public static void main(String[]args) {
Window window = new Window();
}
}
public class Display extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
public void reDraw() {
repaint();
}
}
Overall, I want to know the problems of the code above and how to fix it so that a blue rectangle is drawn on to a window when the program is played.
Thanks for reading : )
Your main issues are:
frame.getContentPane().setLayout(null); - This is generally a bad idea to start with. There are so many issues with this approach that it's difficult to list them all.
null layouts require you take full responsibility for the container's children's locations and sizes. They don't take into consideration different platform rendering systems and traits
You'll find it difficult to accurately size the parent window, as the available content size is the frame size MINIUS the frame borders, so while you're setting the frame to 600x600, the actual available content space is going to be smaller
A component's default size and position is 0x0 - so unless you're willing to take control of this (which is what layout managers do anyway), it will never be displayed (Swing's not dumb, but it is lazy ;))
Not calling setVisible on the JFrame
Not providing a sizing hint for the Display panel
Extending JFrame ... and not making any use of it. Extending JFrame is generally discouraged, but in your case, it's just adding unwanted noise
Work example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {//extends JFrame {
public Test() {
initialize();
}
private void initialize() {
JFrame frame = new JFrame();
//frame.setBounds(100, 100, 600, 600);
//frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.getContentPane().setLayout(null);
frame.getContentPane().add(new Display());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
Test window = new Test();
}
public class Display extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
// Not sure what benefit this provides
//public void reDraw() {
// repaint();
//}
}
}
You might want to take a look at Laying Out Components Within a Container to get a better understanding of the layout managers and what they do and how they work (and why you should use them ;))

Why doesn't the image paint over my JPanel?

I have been struggling with this for some time. At first, I only used ActionListener, then I added the paintComponent, but I have no idea what to put there. I read some tutorials and used their code as an example, but it still doesn't work. Right now, the end result is the same as it was without PaintComponent.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Scream extends JPanel {
private JButton button = new JButton("OK");
private Color screenColor;
private JPanel panel = new JPanel();
private JFrame frame;
private Dimension screenSize;
private ImageIcon image;
private JLabel label = new JLabel(image);
private int x;
private int y;
private boolean mouseClicked;
public Scream() {
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e ) {
if (e.getSource() == button) {
mouseClicked = true;
frame.getContentPane().add(label);
frame.setSize(image.getIconWidth(), image.getIconHeight());
panel.repaint();
}
}
});
frame = new JFrame ("Existential angst");
screenColor = new Color(150, 100, 0);
panel.setBackground( screenColor );
frame.add(button, BorderLayout.PAGE_END);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1300, 700);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
image.paintComponent(this, g, 1300, 700);
}
public static void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Scream scream = new Scream();
}
});
}
}
If you are trying to dynamically add an image to a panel then you need to add the label to the panel. There is no need for any custom painting.
The basic code for adding components to a visible GUI is:
panel.add(...);
panel.revalidate();
panel.repaint();
Also, don't attempt to set the size of the frame to the size of the image. A frame contains a titlebar and borders. Instead you can use frame.pack();
I noticed a couple of issues:
image is never initialized to anything so it is null, effectively making the label empty. I assume maybe your example was just incomplete?
Once I initialized the image to something, your example still did not work. Turns out adding label without specifying any constraint basically does nothing (I assume since adding a component to a border layout without a constraint puts it in the center where panel already is). When I added the label to BorderLayout.NORTH, everything worked (though resizing the frame to the size of the image makes it only partially visible since the frame includes the OK button)

Why doesn't my button position properly on my JFrame no layout?

So I've got a JFrame which uses setLayout(null) so I can position my elements by hand.
However, when accessing the content pane and getting the size for the frame, it says its height is 1.0.
Does anyone know how I can fix this?
Here is the code:
import javax.swing.*;
import java.awt.*;
public class Launcher extends JFrame
{
public Launcher(String title) {
super(title);
setLayout(null);
pack();
setSize(new Dimension(LauncherUtil.LAUNCHER_WIDTH, LauncherUtil.LAUNCHER_HEIGHT));
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
displayComponents();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Launcher launch = new Launcher(LauncherUtil.LAUNCHER_TITLE);
launch.setVisible(true);
}
});
}
private void displayComponents() {
Dimension size = getContentPane().getSize();
JButton launchButton = new JButton("Launch Game");
System.out.println(size.getHeight());
launchButton.setBounds(0, (int)size.getHeight() - 60, (int)size.getWidth(), 60);
add(launchButton);
}
}
may be if you try to get the screen size by using Toolkit would be work like you want
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
it brings you the screen size where java program is running. Hope it helps.
The content pane is a JPanel whose default size is 1x1px. Since you did not put any components into the content pane and have not set a preferred size for the panel, the content pane's size remains 1x1px.
One way to fix this is to call these three methods in the following order:
setLayout(null);
setPreferredSize(new Dimension(300, 400));
pack();
However, you should be using a layout manager instead of managing
the size and position of your components by hand.

Java setResizable issue

package data;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main extends JFrame implements Runnable {
private JPanel contentPane;
private JPanel pp = new JPanel();
Thread page = new Thread();
public void run() {
while (!Thread.interrupted()) {
}
}
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 640 + 16, 480 + 39);
contentPane = new JPanel();
contentPane.setBounds(0, 0, 640, 480);
contentPane.setLayout(null);
setContentPane(contentPane);
pp.setBounds(0, 0, 640, 480);
pp.setBackground(Color.BLACK);
contentPane.add(pp);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
frame.setResizable(false);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
The above code works but setResizable causes an issue: http://i.stack.imgur.com/hQxPU.png
If I were to remove the setResizable then the grey at the bottom and right would be black like it's meant to. How can I disable resizing without causing this issue?
You're using an absolute layout (no LayoutManager set), and the black panel has fixed bounds. And that's exactly the reason the black panel won't fill its parent's bounds when the parent is resized.
Solution: use a LayoutManager which automatically recalculates the bounds of your content so it fills the available space.
// BorderLayout is your friend
contentPane.setLayout(new BorderLayout());
...
// delete this line, no need to set fixed bounds
// pp.setBounds(0, 0, 640, 480);
More on how to use layout managers in AWT/Swing:
The Java™ Tutorials - Using Layout Managers
Layout Managers have two purposes:
calculate the min/max/preferred size of a container
layout components by setting their bounds within the container.
If you want the black panel to have a size of 640x480, and the window to be non-resizable, you can set the preferred size and then pack the window, causing its size to become appropriate for the content's preferred dimensions:
pp.setPreferredSize(new Dimension(640, 480));
...
pack();

My JRadioButton change look with setOpaque(false)

I want to remove the background of my JRadioButton but still keeping the same look & feel.
Images will speak by themselves:
When I do this code:
JRadioButton myJRadioButton = new JRadioButton("My JRadioButton");
add(myJRadioButton);
I get this:
And when I run it with this code:
JRadioButton myJRadioButton = new JRadioButton("My JRadioButton");
myJRadioButton.setForeground(Color.white); //To see it on the black background.
myJRadioButton.setOpaque(false);
add(myJRadioButton);
I get this:
I've something like a "star" instead of a great and beautiful circle.
And what I want is to keep the great and beautiful circle of the first image but without the default background according to it.
Document says
public void setOpaque(boolean isOpaque)
If true the component paints every pixel within its bounds. Otherwise,
the component may not paint some or all of its pixels, allowing the
underlying pixels to show through. The default value of this property
is false for JComponent. However, the default value for this property
on most standard JComponent subclasses (such as JButton and JTree) is
look-and-feel dependent.
It says all.
You can create a class which extends the JRadioButton and add all the properties inside the class:
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
setForeground(Color.white);
setBackground(Color.BLACK);
Sample output:
Code:
public class Sample extends JPanel {
public Sample() {
super(new BorderLayout());
setBackground(Color.BLACK);
TransparentButton testButton = new TransparentButton("hello");
testButton.setSelected(true);
add(testButton, BorderLayout.LINE_START);
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Hello Word demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new Sample();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
class TransparentButton extends JRadioButton {
public TransparentButton(String string) {
super(string);
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
setForeground(Color.white);
setBackground(Color.BLACK);
}
}
}

Categories