Java Swing Jcomponent "Size"

Setting the width and height of a JComponent as instance variables

Setting a components size is up to the component. So in constructor the default size is 0. Later on if you add the component into a layout manager (like you did when adding your component to the frame which has a default layout manager) it will set the size according to preferred/minimum/maximum this - which is 0/0 to max-int by default. So layout manager will resize the component to the size of the frame.

There is no need to store the size in a local copy as getWidth()/Height() will read the size from a local copy in the component class.

Java swing JComponent size

I assume your image contains ONLY 4 'customWidget' objects (in a 2x2 grid).

Your code is working as I would expect. Your MouseListener methods are responding to MouseEvents for 'customWidget' (not the image drawn in 'customWidget'), which is sized to take up 1/4 of the image, so they will respond when it enters the enlarged area. The error is actually in your Test program, because you are allowing the custom button widget to be larger than the image.

If you want a Test program that provides an image similar to yours, you should create a larger grid (say 4x4), and then only place your buttons in every other grid node. Place an empty component into the gaps.

How to set size of swing components

Let the layout manager take care of the dimensions of your Swing components, but if you absolutely must, use setPreferredSize in combination with a layout manager that respects that property.

Can I get the right JComponent size before it's shown?

I sometimes check the sizes of my components when debugging to find out why I can't see them for instance. In most cases, the sizes will be realized when the GUI has been rendered. This can occur when pack() or setVisible(true) has called on the top-level window. My usual sequence of method calls is to call pack() first as this tells the layout managers to lay out the components that they are responsible for, and sets the sizes of the components and the GUI, then call setLocationRelativeTo(null) to center my GUI, then call setVisible(true) to display it.

How to get the painted size of a Swing component?

I don't think this is particular or practically achievable.

The problem is, the button is using the "unpainted" area to paint other elements, like the focus highlight.

You could try look at the AbstractButton#set/getMargin

How can I get the size of a component when using a layout for my frame?

You can try the JPanel methods, getWidth() and getHeight():

int getWidth();
int getHeight();

They will return the height and width of the JPanel.

You can also get the bounds of the JPanel using the method getBounds():

Rectangle getBounds();

It will return a Rectangle of the bounds. You can use it to get the location and size of the JPanel.

Return actual size of JComponent, as displayed

What you're trying to accomplish seems to be surprisingly difficult, because you have to rely on Swing's method of calculating the size of your various components, and then manage to get the correct values out to perform the calculations on them. While it looks fairly trivial based on the available API methods, a glance at the source code reveals a different story. This is additionally complicated by the fact that some values are only correctly calculated when the component is actually displayed, meaning that the values you try to get before that aren't representative of what you see on the screen (as you found out).

That aside, it seems like it should be possible to do what you're aiming for. Keep in mind though that when adding elements to a BoxLayout, the expected behaviour is that the entire space of the container to which you've assigned the layout manager is utilized in positioning the child components. This means that as you add JTextPane objects to your JPanel, they will stretch so that their summed heights takes up all 600 pixels you've specified. As a result, you need to go about determining when you've exceeded the available height a little differently, since the rendered height of each component might change in-process.

After playing around with it a little and cursing Swing repeatedly, I had though I had come up with a solution by using getBounds() (which BoxLayout uses in delegation to its LayoutParameters to determine the component height), but the method I had turned out to not be very reliable. I'm going to keep playing around with it, so hopefully I'll come up with some usable code, or someone else will come along with a solution that I've overlooked.

Edit: For completeness, here's a code sample that calls doLayout() to calculate the necessary sizes before showing the form (still with the drawbacks of BoxLayout). It won't run on my JRE 1.5 due to some ArrayIndexOutOfBoundsException in SizeRequirements, but that bug seems to have been fixed in 1.6. In 1.5, if your list of components wasn't too large, you could add them all, call doLayout() after the loop (as this seems to work in 1.5 for whatever reason), then just traverse the array returned by getComponents(), removing everything after the maximum height has been exceeded.

As a final note, I'm personally a fan of using MigLayout for more complex layouts, since I find its positioning and styling mechanism a bit easier to work with than the current built-in layout managers. Not overly relevant here, but worth a mention anyway.

import java.awt.Dimension;
import java.awt.Rectangle;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.StyledEditorKit;

public class TestFrame extends JFrame {
private static final int CONTENT_HEIGHT = 600;
private static final int CONTENT_WIDTH = 300;

public static void main(String[] args) {
TestFrame frame = new TestFrame();

frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public TestFrame() {
super("Test Frame");
this.addComponents();
this.pack();
}

private void addComponents() {
JPanel panel = new JPanel();

panel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
panel.setBounds(new Rectangle(CONTENT_WIDTH, CONTENT_HEIGHT));
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

String text = "This is a long String that represents the length of" +
" stings in my application. This will vary in the real" +
" application.<ul><li>It uses html</li><li>not just</li>" +
"<li>plain text</li></ul>I'd like only as many as will fit" +
" in the fame to be added.\n";

this.setContentPane(panel);

int height = 0;

while(height < CONTENT_HEIGHT) {
JTextPane textPane = createTextPane(text);

panel.add(textPane);
panel.doLayout();

// The height on the preferred size has been set to reflect
// the rendered size after calling doLayout()
height += textPane.getPreferredSize().getHeight();

// If we've exceeded the height, backtrack and remove the
// last text pane that we added
if (height > CONTENT_HEIGHT) {
panel.remove(textPane);
}
}
}

private JTextPane createTextPane(String text) {
JTextPane textPane = new JTextPane();

textPane.setEditorKit(new StyledEditorKit());
textPane.setEditable(false);
textPane.setOpaque(false);
textPane.setContentType("text/html");
textPane.setText(text);

return textPane;
}
}


Related Topics



Leave a reply



Submit