Position problem with adding something to JFrame in Java - java

I want to add JLabels to JFrame directly. I don't want use JPanel. But I have a position problem. I set layout as null.
I tryed draw line to see what's going on.
#Override
public void paint(Graphics g){
g.setColor(Color.red);
g.drawLine(0, 31, super.getWidth(), 31);
}
And the zero is actually 31.
Drawing screenshot
Why? And how can I fix that?

I want to add JLabels to JFrame directly. I don't want use JPanel.
If you're adding the JLabel "to the JFrame" then you're adding it to the contentPane which is almost always a JPanel, so 99% of the time, you're still using a JPanel, even without trying to.
But I have a position problem. I set layout as null.
Which is almost always a bad thing to do. This makes for GUI's that don't work on all platforms, fighting against the Java philosophy and structure.
And the zero is actually 31.
Why? And how can I fix that?
Because of the top part of the JFrame is taken up by the OS window's menu bar. The contentPane, starts 31 pixels below the top of the JFrame (in your case -- different for different OS's and screen resolutions).
Best to avoid drawing directly on the JFrame, which is actually composed of many sub-components -- the content pane, the root pane, the glass pane,... and instead draw within the paintComponent method of a JPanel that you either add to the contentPane or make as the contentPane. Then 0,0 is the top left of the usable portion of your main window.
Also, please elaborate more on the underlying reason why you're trying to avoid use of a JPanel. Your issue may in fact be an XY Problem type issue.

Positions in a JFrame are relative to the edge of the window, not the content pane. To get the dimensions of the content pane, use getContentPane().getWidth() and getContentPane().getHeight().

Related

Set maximum size of JFrame

I'm starting my journey with Java and I'm playing with swing. I made some simple JFrame with JScrollPane inside and I'm looking for a way to restrict my frame to preset minimum and maximum size. I've searched the net about setMaximum and setMinimum and how wrong they are, but I haven found nothing(Except some weird ComponentListener). However setMinimum is working fine(at least for now) but i can't get setMaximum to work. How can I set such constraints?
EDIT:
What I mean by "Except some weird ComponentListener" is that it lets me resize frame, then just resize it back. What I want to achive is invisible bound, that prevents frame from going more.
EDIT2:
It seems that this problem concerns my OS(which is OSX), ComponentListener works fine on Windows. But on Mac, when I start dragging the window out, ComponentMoved is called and only when I release mouse button ComponentResized is called. When I copy code from Resized to Moved, first, window resize itself over MaximumSize for fraction of second, then apropiet code is called and everything is fine, but this flicker is far from acceptable. I've even overloaded paint(Graphics g) to first reset size and then call super.paint but with same result.
You can add a ComponentListener to your frame and check into componentResized(ComponentEvent e) if the new values for width&height are allowed and, in case they are, you resize the frame through setSize.

Adding JPanel to Canvas

Since JPanel and Canvas are both same-level components, the solution would probably be some sort of a 'hack'. This question says that you won't be able to add the lightweight component to the heavyweight canvas (I want JPanel transparent).
If this isn't posible, then would putting a transparent Component work? Also, is it feasible to add Swing components to the Component (it just has to work, even if it's bad). And how would I go about actually putting it over the canvas (since they are both same-level components)?
Note: I would never do something like this in a real app, I just need it in this case
One possiblity is to add the JPanel to whatever container the Canvas is on, then setting the color of the JPanel to have an alpha of 0. This should add it over the old one, without blocking out the Canvas. Is this what you want?
EDIT: Thinking about it, the JPanel's default color is transparent... You should just be able to add the JPanel the Canvas's parent, and lay it over it

Drawing text or images on top of gridlayout

I am writing a Tetris-based game, and I am using a GridLayout to display the actual shaft which the Tetris pieces fall down. The GridLayout is filled with little JLabel objects. The shaft is itself a JPanel inside another JPanel, the panel I am using to contain and control the entire game. When the game ends, I want the words "GAME OVER" to appear on top of the grid, possibly accompanied by a small image.
My shaft is an instance of ShaftPanel, which extends JPanel (so that I could override paintComponent) and is a nested private class (so it has access to private instance variables of the larger JPanel). The private instance variable it needs to access is boolean game, which is true when the game is in session and set to false when the game is over. Here is the code for my ShaftPanel class:
public class ShaftPanel extends JPanel {
public ShaftPanel(GridLayout g){
super(g);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(game)
return;
g.setColor(Color.WHITE);
g.setFont(new Font("Courier New", Font.BOLD, 15));
char[] c = {'G','A','M','E',' ','O','V','E','R'};
g.drawChars(c,0,c.length,45,45);
}
}
I have one method in the larger class calling the repaint() method of shaft at the appropriate time. Adding a print statement indicates that the paintComponent method is being called when I want it to, and the setColor, setFont, drawChars methods are all being called at the correct times. However, nothing shows up. I highly suspect that the text is being drawn underneath the grid of JLabels, so that it can't be seen, but I don't know how to fix this problem. The JLabels inside the grid have to stay opaque, because the program relies on them being different colors. Is there a way to tell paintComponent to draw the text on top of anything else in the panel?
See the section from the Swing tutorial on Using a Glass Pane for an example and explanation on how a glass pane works.
Another option is to use a JWindow to display a label with your message and icon.
I would probably not have made tetris this way, but one way to test this would be to remove the "if(game)" and see if game over is being written even when no JLabels are there (unless they are always there and sometimes are blank).
At any rate, I think what might be useful though I don't think I have ever used it is a GlassPanel.... This is a panel that can be overlayed on your current JFrame etx...
Look Here for more code and info: http://www.java2s.com/Code/Java/Swing-JFC/Paintonglasspane.htm

Is this possible to do with images in java?

Is there any way I can print/show images on top of each other. The picture on top will always be positioned a little lower so that the one under will show partially. How can I decide which image is on top of what image? What layout lets me do this kind of positioning?
Is there any way that I can make a border appear on the image when I click it, and then move to (doesnt have to be animated, can be a "jump") where I click next inside the JFrame.
I've been trying to do this whole day now (I'm pretty new to swing), before I carry on I'd like to know if I'm trying something impossible.
So far I've been printing the images right on to the JFrame as JPanels... Inside the JPanel I add in the paintComponent(Graphics g) method: g.drawImage
Sounds like a Swing tutorial is in order.
What you're describing shouldn't be very hard. Instead of painting the images directly, load them up in ImageIcons, and pass those to JLabels. That way you can manipulate your images as JComponents, using layout managers, or direct coordinates by setting the layout to null. You can set the Z-Order with setComponentZOrder regardless of the layout you choose. You can draw borders by adding swing borders (see BorderFactory) to the JLabels. You can handle the manipulation with MouseListeners.
Look into Root Panes. You may be able to do something with the Layered Pane or the Glass Pane. I would try the Layered Pane first.

JPanel size by inner components

Is it possible to tell JPanel to set its size to fit all components that it contains? Something like pack() for JFrame.
edit: The trick with preferredSize didn't help. I've got JSplitPane, where in one part there is GridBagLayout with many labels (see screenshot) and labels overlap each other.
screenshot http://foto.darth.cz/pictures/screen.png
After looking at the source code for pack(), I came up with:
panel.setPreferredSize(panel.getPreferredSize());
This forces the panel to recalculate its preferred size based on the preferred sizes of its subcomponenents.
You may or may not have to call validate() afterward; in my tiny example, it seemed to make no difference, but the Javadoc says:
The validate method is used to cause a container to lay out its subcomponents again. It should be invoked when this container's subcomponents are modified (added to or removed from the container, or layout-related information changed) after the container has been displayed.
So I guess it depends on why you're having to repack your JPanel.
By default Containers have a preferred size that matches the preferred layout size given by the container. So literally all you have to do is:
panel.setSize(panel.getPreferredSize());
Presumably you are doing something odd with the parent to stop the parent's layout manager doing the equivalent of this.
maybe you can do something like that by removing from your panel
setResizable(false);
I would try:
panel.revalidate();
panel.repaint();
This will not necessarily set the panel to its preferred size, that is more dependent on what the layout manager decides to use.
This is useful in cases where you have added/removed components from a panel that is currently displayed and visible.
Update:
Based on your screenshot I can say the following:
1) Consider programatically changing the divider location.
2) Consider programatically resizing the window itself horizontally since it seems to be a little tight to show both sides of the split pane.
Or both.
You can set the divider location by doing
splitPane.setDividerLocation(newSize);
Keep in mind that there are two overloaded methods for this, one taking a float one taking an int. The float does a percentage of the size while the int is the size in pixels. The size is for the left hand panel (or top panel for that orientation).
I would consider possibly changing the divider location based on the preferred width of the panels.
The javax.swing mysteries reveal themselves only gradually, and only to those who are prepared to offer many libations (particularly torn out clumps of hair, hours burning the midnight oil, etc.) to the gods of Swing.
However, for this case in point I would suggest the following as a sort of Swiss army knife which usually does what you think the framework should do anyway:
myJPanel.getTopLevelAncestor().validate()
As the sacred text says, "Validates this container and all of its subcomponents." (Container.validate). NB getTopLevelAncestor() is a JComponent method.
Can't remember how JSplitPane fits into this: try it and you'll probably find that it validates both components (right and left, top and bottom), but I would be surprised if changing the divider doesn't do this for you anyway.
I had a similar issue using Netbeans GUI Builder. My inner panels were getting weird sizes; I was trying to adjust the minimum and preferred sizes manually, which was a frustrating exercise.
The problem was solved when I reset all the minimum and preferred sizes back to default (In Netbeans GUI Builder: right click JPanel component -> Properties -> preferredSize -> Reset to Default). When there is no imposed size, the jpanel takes the size of the inner component.
Note: GridBaLayout was used in my case
JSplitPanes are a bit fussy when it comes to its children's sizes, have a look at the Java tutorial. Are you using the GridBagLayout correctly? Looks like it's not setting the right JPanel's minimum size properly.
Here's an example of a panel which:
Resizes with it's parent.
Sets the width to the width of the parent.
Sets the height according to sum of the height of all of it's children.
JPanel panel = JPanel(new GridBagLayout())
panel.setMaximumSize(new Dimension(panel.getMaximumSize().width, panel.getPreferredSize().height))
panel.validate()
panel.repaint()

Categories