Java window contents resize, but not beyond a minimum size - java

I have a Java apps I've written using NetBeans (yes, I've read plenty of complaints here about NetBeans). When I resize the window, the contents resize with the window, until I shrink the window (the height, actually) below a certain size. Then the window resizes, but the contents just get clipped.
I've checked all of the component widgets. They all have min sizes of zero or very small numbers. The only ones with nonzero preferred sizes are those that do not resize with their parents, and they are also small. When shrinking, I'm not bumping into any of the widgets. At the point where I cannot shrink anymore, there is a sizable gap between the bottom of the panel and the widgets inside towards the bottom.
Is there any way I can tell what is limiting the size in this way? Is there another property I should be looking for that might be involved?
Thanks.

yes and very simple solution just override and return getMinimumSize()
for example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class CustomComponent extends JFrame {
private static final long serialVersionUID = 1L;
public CustomComponent() {
setTitle("Custom Component Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponents(), BorderLayout.NORTH);
add(new CustomComponents(), BorderLayout.CENTER);
add(new CustomComponents(), BorderLayout.SOUTH);
add(new CustomComponents(), BorderLayout.EAST);
pack();
// enforces the minimum size of both frame and component
setMinimumSize(getMinimumSize());
setPreferredSize(getPreferredSize());
setVisible(true);
}
public static void main(String[] args) {
CustomComponent main = new CustomComponent();
main.display();
}
}
class CustomComponents extends JLabel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(200, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}

Can we see some example code? I believe that its not the window but the content inside the window that's not resizing beyond a certain point.

Related

Putting 2 jpanels in borderlayout

I am trying to put 2 JPanels in borderLayout. Such that, one JPanel will be of size pane1(600,600)and the other one would be pane2(200,600). I am hoping to pack them such that the big one would be on the left and other one would be on right.
I am setting the size of each jpane but it looks like both of them occupy the complete space and kind of overlap on each other.
I am a complete newbie here and have no clue what is going wrong. Any help is appreciated.
JFrame frame = new JFrame("Simple Graph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
int pane1_width = FRAME_WIDTH-200;//800-200
Pane1 myPlots = new Pane1(graph_panel_size, FRAME_HEIGHT);
frame.add(myPlots);
Pane2 simpleInfo = new Pane2(200,FRAME_HEIGHT);
frame.add(simpleInfo);
frame.pack();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setResizable(false);
frame.setVisible(true);
This is a base frame class. For JPanel
public Pane2(int width,int height){
this.setSize(width,height);
Border blackline = BorderFactory.createTitledBorder("ola");
this.setBorder(blackline);
The other panel also has similar constructor. But both the Jpanels overlap each other and I cant place them separately.
The problem is that you are calling setSize(). When using LayoutManager's (which you should absolutely always do), using setSize/setBounds/setLocation is completely useless.
Additionnaly, calling setPreferredSize()/setMinimumSize/setMaximumSize is not recommended and can be counterproductive.
Either your component have a good reason to have a given size (because you are doing custom painting, for example), then you should override getPreferredSize, or you simply don't have to do anything, and only use an appropriate LayoutManager.
You can also check out the tutorial on LayoutManager of Oracle
See this example with overrides of getPreferredSize():
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestCustomPainting {
private static class MyTriangle extends JPanel {
private final int width;
private final int height;
public MyTriangle(int width, int height) {
this.width = width;
this.height = height;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillPolygon(new int[] { 0, getWidth(), 0 }, new int[] { 0, 0, getHeight() }, 3);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.add(new MyTriangle(200, 45), BorderLayout.EAST);
frame.add(new MyTriangle(85, 600), BorderLayout.WEST);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
NB: I must admit, there are more interesting to paint :-)

How do I change the position of JLabel or any other Component I add?

I am trying to create a translucent window which has no border or background other than the JLabel image's I put in it, using OverlayLayout and an extended JPanel...
My problem is when I try to add more components over the one I initially added which would be the background, I have no idea how to enable changing of the new components position.. x,y etc...
Please if possible show me what I can do and don't just point me to layoutmanagers, I need an example please if anyone is willing to show me.
Or better yet, show me what I need to do to my code in order to get the desired effect.. like changing "text" (A JLabel) position to be 10,10 ... x and y.
package core;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.OverlayLayout;
public class App {
// Window & Panel...
public JWindow frame;
public TranslucentPanel panel;
// OverlayLayout
public LayoutManager overlay;
// Components
public JLabel bg;
public JLabel test;
// Constructor
public App() {
try {
// Basics...
frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
// Overlay
panel = new TranslucentPanel();
overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
frame.setContentPane(panel);
// initComponents
initComponents();
// Finalize Frame
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
catch(Exception e) {
e.printStackTrace();
}
}
// Initialize Additional Components
public void initComponents() throws Exception {
test = new JLabel("test");
test.setForeground(Color.WHITE);
frame.add(test);
bg = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/ball.png"))));
frame.add(bg);
// What must I do to be able to do this???
test.setLocation(10, 0);
}
// TranslucentPanel Class...
public class TranslucentPanel extends JPanel {
private static final long serialVersionUID = 1L;
public TranslucentPanel() {
setOpaque(false);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
}
One way would be to discard the Overlayout manager, set the TranslucentPanel's layout manager to something like BorderLayout and use the JLabel, bg as a container in of itself...
bg = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/ball.png"))));
frame.add(bg);
// Set the layout of the JLabel
bg.setLayout(new GridBagLayout());
test = new JLabel("test");
test.setForeground(Color.WHITE);
// Add the test label to the bg JLabel...
bg.add(test);
Personally, I don't like this, as JLabel doesn't take into consideration the components (or the layout manager) when it makes it's calculations for it's preferred size.
Personally, I would create a custom background component that was responsible for painting the background image. Then, onto this, I would place the other components, using what ever combination of components and layout managers I need to produce the desired results.
Pixel perfect layouts are an illusion within modern UI design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
After reading the following pieces from your codes :
// What must I do to be able to do this???
test.setLocation(10, 0);
If I understand correctly , you want to arrange position of your component based on custom coordinates. If so then You can use Insets class http://docs.oracle.com/javase/7/docs/api/java/awt/Insets.html to achieve that.
So you can set position of your component according to position you want
Insets insets = panel.getInsets();
Dimension size =test.getPreferredSize();
// just replace 10 & 0 according to X & Y postion you want.
test.setBounds(10 + insets.left, 0 + insets.top,size.width, size.height);
Here is you modified version:
*Note that I don't have your Icon , so I just put text on your label to help you see the result.
import java.awt.*;
import javax.swing.*;
public final class App{
// Window & Panel...
public JWindow frame;
public TranslucentPanel panel;
// OverlayLayout
public LayoutManager overlay;
// Components
public JLabel bg;
public JLabel test;
// Constructor
public App() {
try {
// Basics...
frame = new JWindow();
// Overlay
// Overlay
panel = new TranslucentPanel();
overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
frame.add(panel);
initComponents();
// Finalize Frame
frame.pack();
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
catch(Exception e) { e.printStackTrace();}
}
// Initialize Additional Components
public void initComponents() throws Exception {
test = new JLabel("test");
test.setForeground(Color.RED);
panel.setLayout(null);
panel.add(test);
Insets insets = panel.getInsets();
Dimension size =test.getPreferredSize();
test.setBounds(10 + insets.left, 0 + insets.top,
size.width, size.height);
frame.add(panel);
}
// TranslucentPanel Class...
class TranslucentPanel extends JPanel {
private static final long serialVersionUID = 1L;
public TranslucentPanel() {
setOpaque(false);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public static void main (String args []){
App ap = new App();
}
}
The output :
If you declare your position as test.setBounds(500 + insets.left, 10 + insets.top,size.width, size.height); then the output would be :

My JFrame doesn't show anything

I am trying to build a simple basic to a game for my class in Game Engine Architecture. But my JFrame just wont show anything.
My code is currently structured like this:
Implementation.java (This is some arbitrary implementation of the Engine-package I'm creating)
public class Implementation {
public static void main(String[] args){
World w = new World("Hej", "M:\\workspace\\SP6\\pics\\tulips.jpg",1024,768);
}
}
World.java
public class World extends JFrame{
private static final long serialVersionUID = 1L;
private SpritePanel spritePanel;
private JPanel bottom;
private int width;
private int height;
public World(String windowCaption, String bgPath, int width, int height){
super(windowCaption);
spritePanel = new SpritePanel(bgPath);
add(spritePanel, BorderLayout.CENTER);
System.out.println(spritePanel);
bottom = new JPanel();
bottom.add(new JLabel("Hej"));
add(bottom, BorderLayout.SOUTH);
Dimension size = new Dimension(width,height);
setSize(size);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
validate();
repaint();
}
SpritePanel.java
public class SpritePanel extends JPanel {
private static final long serialVersionUID = 1L;
private ImageIcon background;
private ArrayList<Sprite> sprites = new ArrayList<Sprite>();
public SpritePanel(String bgPath){
background = new ImageIcon(bgPath);
setLayout(null);
Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(background.getImage(), 0, 0, this);
System.out.println("painted panel");
}
}
So the basic action flow at the moment (from what I can see):
I create a new World object in the Implementation
The World-constructor is called with the given parameters
The window caption is set (this works)
I create a new SpritePanel object with the given bgPath
The SpritePanel-constructor is called and sets the ImageIcon to the image that exists in the given path
The SpritePanel is added to the frame in BorderLayout.CENTER
I add a new JPanel to the frame in BorderLayout.CENTER
I set size and stuff
I pack and set the frame to visible
I validate and repaint
The thing is the paintComponent methods in the JPanel and SpritePanel doesn't seem to get called. As you can see I added a System.out.println in the paintComponent for SpritePanel and that line is never executed.
Another thing I noticed is that the pack seems to know that the components are there. Because if I comment the three lines
spritePanel = new SpritePanel(bgPath);
add(spritePanel, BorderLayout.CENTER);
System.out.println(spritePanel);
The windows size when I run the program is reduced to the size of the "bottom"-JPanel. I can't see the JLabel that I added to the panel but the window size is the size of it. So the pack() method seems to be finding the dimensions of my components.
If I comment the three lines that adds the bottom panel as well the window size is reduced to no height and the width it gets from the standard icons.
I've been trying different things to get it to work but to no avail. I have programmed with Swing before and made working programs but I just can't seem to find the problem here.
Help very much appreciated.
Something may be wrong with your with your String path. What you should do though, instead o reading a file, you should be reading a URL, loading from the class path. At time of deployment, you'll find out that the file path won't work, so it's better to package your image as an embedded resource, putting the image in the class path. I had no problems when doing this. Here's what I did.
Change the path to a path relative to my class path
World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
Changed loading from a file to loading from a URL from my class path
background = new ImageIcon(SpritePanel.class.getResource(bgPath));
Put the image in resources package in my class path
Everything works fine
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Implementation {
public static void main(String[] args) {
World w = new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
}
}
class World extends JFrame {
private static final long serialVersionUID = 1L;
private SpritePanel spritePanel;
private JPanel bottom;
private int width;
private int height;
public World(String windowCaption, String bgPath, int width, int height) {
super(windowCaption);
spritePanel = new SpritePanel(bgPath);
add(spritePanel, BorderLayout.CENTER);
System.out.println(spritePanel);
bottom = new JPanel();
bottom.add(new JLabel("Hej"));
add(bottom, BorderLayout.SOUTH);
Dimension size = new Dimension(width, height);
setSize(size);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
validate();
repaint();
}
class SpritePanel extends JPanel {
private static final long serialVersionUID = 1L;
private ImageIcon background;
//private ArrayList<Sprite> sprites = new ArrayList<Sprite>();
public SpritePanel(String bgPath) {
background = new ImageIcon(SpritePanel.class.getResource(bgPath));
setLayout(null);
Dimension size = new Dimension(background.getIconWidth(), background.getIconHeight());
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background.getImage(), 0, 0, this);
System.out.println("painted panel");
}
}
}
Side Notes
No need to setSize(). You already pack(). It better to just pack anyway.
Put the pack() before the setLocationRelativeTo(). If you pack() after, you'll notice your frame won't be in the desired location.
Run your Swing apps from the Event Dispatch Thread (EDT) like this
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new World("Hej", "/resources/stackoverflow5.png", 1024, 768);
}
});
}
If you want to make the frame fill the screen, don't set the size. Different machines have different screen sizes. Instead use setExtendedState(JFrame.MAXIMIZED_BOTH);
Also, your setSize() won't work anyway because you're calling pack() after.
My problem was that I hade overridden the getWidth() and getHeight() methods in my World-class.
But look to peeskillets response for how to make things better!

JComponent.setBounds the last JComponent in the wrong place

I have been having a some issues with Swing lately. I'm trying to make something like in the image below on the fly, to illustrate the data structures for algorithms.
(source: ius.edu)
All that I was trying to do in the following class is draw out some rectangles with numbers on them. and translate them, however the last rectangle draws at 0,0. I'm stumped.
If you add the JPanel (commented out) after the loop then it draws as expected.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawingRect {
public static void main(String[] args) {
DrawingRect d = new DrawingRect();
}
public DrawingRect() {
JFrame frame = new JFrame("Drawing a rect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel swingPanel = new JPanel();
swingPanel.setPreferredSize(new Dimension(500, 500));
swingPanel.setVisible(true);
swingPanel.setLayout(new BorderLayout(0, 0));
int base = 15;
for (int i = 1; i <= 25; i++) {
Graphic re = new Graphic(i);
//translating the graphic
re.setBounds(base + 30 * i, base + 20 * i, 110, 110);
swingPanel.add(re);
}
// if say I add a JPanel in here as the last element
// then the boxes will draw correctly.
//swingPanel.add(new JPanel());
swingPanel.setPreferredSize(new Dimension(800, 600));
frame.getContentPane().add(swingPanel);
frame.pack();
frame.setVisible(true);
}
public class Graphic extends JComponent {
private static final long serialVersionUID = 1L;
private static final int PREF_W = 100;
private static final int PREF_H = 100;
int id;
public Graphic(int id) {
this.id = id;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.setColor(Color.black);
g2.drawRoundRect(0, 0, 30, 30, 20, 20);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("", Font.PLAIN, 13);
g2.setFont(font);
g2.drawString("" + id, 15, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
}
The default layout of JPanel is FlowLayout, but you're positioning components as if the layout were null. Moreover, you're drawing content that a nested component could do automatically.
Instead, add several JPanels containing JLabel's to a containing panel having GridLayout. Use empty panels as required. Override paintComponent() in the outer panel to draw connecting lines.
Addendum: Anytime one is tempted to use Absolute Positioning, JInternalFrame may be an alternative. Related examples may be found here and here.
Addendum: If the project grows beyond the prototype stage, also consider a Custom Layout Manager.
It is because you are using BorderLayout. You can test this by changing your add line to include a specific layout location: swingPanel.add(re,BorderLayout.SOUTH).
As for a solution, why not draw all the rectangles on a picture and update it at the end of the loop? Or is the adding to JPanel part of your demonstration?

How to make JTabbedPane autoresize to fit page dimensions?

I have only JTabbedPane inside JFrame. JTabbedPane sets its dimensions to biggest page width/height.
As pages has different size is it possible to force JTabbedPane to change its dimensions when selecting other page?
http://grab.by/3hIg
Top one is how it behave now and bottom one is how i want it to behave (i resized frame by hand)
This is fairly simple. It involves dynamic calculation of differences between your pages dimensions and the using them to force preferred size on you JTabbedPane. I did a quick experiment and it worked. So instead of putting a lot of text here - here is the code. It is not perfect but you should get an idea. Questions are welcome, of course.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
private static int maxW = 0;
private static int maxH = 0;
public static void main(String[] args) {
final JFrame f = new JFrame();
final JTabbedPane tabs = new JTabbedPane();
tabs.add( createPanel(Color.RED, 100, 100), "Red");
tabs.add( createPanel(Color.GREEN, 200, 200), "Green");
tabs.add( createPanel(Color.BLUE, 300, 300), "Blue");
final Dimension originalTabsDim = tabs.getPreferredSize();
tabs.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
Component p = ((JTabbedPane) e.getSource()).getSelectedComponent();
Dimension panelDim = p.getPreferredSize();
Dimension nd = new Dimension(
originalTabsDim.width - ( maxW - panelDim.width),
originalTabsDim.height - ( maxH - panelDim.height) );
tabs.setPreferredSize(nd);
f.pack();
}
});
f.setContentPane(tabs);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static final JPanel createPanel( Color color, int w, int h ) {
JPanel p = new JPanel();
p.setBackground(color);
p.setPreferredSize( new Dimension(w, h));
maxW = Math.max(w, maxW);
maxH = Math.max(h, maxH);
return p;
}
}
I think another option is to dynamically change the panels of each tab when the tab is selected:
install a listener on JTabbedPane selection
install an empty panel on every tab but the selected tab by default (that contains the real panel for that tab)
in the selection listener:
remove the panel from the previously selected tab (ie, replace it with an empty panel)
change the empty panel by the real panel in the newly selected tab
call pack() on the window/dialog containing the JTabbedPane
Disclaimer: I haven't tested this approach but I believe it should work according to what you want.
Please also note that dynamically changing the size of the dialog based on the selected tab is not very user-friendly from a pure GUI viewpoint.
How about this?
tabbedPane.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
Component mCompo=tabbedPane.getSelectedComponent();
tabbedPane.setPreferredSize(mCompo.getPreferredSize());
BasicFrame.this.pack();
}
});

Categories

Resources