Java : explain the repaint behavior how to control it when resizing - java

Here is a very simple JTable on a JFrame example that I extracted from another web site.
import javax.swing.*;
public class JTableSimpleSample {
JFrame f;
JTableSimpleSample(){
f=new JFrame();
String data[][]={ {"101","Amit","670000"},
{"102","Jai","780000"},
{"101","Sachin","700000"}};
String column[]={"ID","NAME","SALARY"};
JTable jt=new JTable(data,column);
jt.setBounds(30,40,200,300);
JScrollPane sp=new JScrollPane(jt);
f.add(sp);
f.setSize(300,400);
f.setVisible(true);
}
public static void main(String[] args) {
new JTableSimpleSample();
}
}
When resizing this window, the behavior is slightly different depending upon which edge is being used for resizing.
Top - resize the frame by clicking the top edge and it looks pretty clean except it does appear the bottom edge of the JFrame is continually getting repainted making it look like multiple lines exist.
Bottom - resize the frame by clicking the bottom edge looks pretty good as making it large shows a black area until the frame gets to repaint. Depending on how fast you resize the frame determines how much of the black area is visible.
Right - resize the frame by clicking the right edge is very similar to when the bottom edge is used when resizing.
Left - resize the frame by clicking the left edge looks terrible. It is no only similar to when it is resized using the top by showing multiple lines on the right edge, but at times the data itself looks a mess.
Using any of the corners results in a combination of 2 from any of the above scenarios.
Question/Objective :
1 - Why such different behavior?
2 - Is it possible to have it so that only an outline of the frame is shown when resizing and instead of a black background when resizing, have it transparent. Something like the following if the bottom right corner is used for resizing. The red lines are used to make it obvious as to the objective but it can very well remain black :
I did review Black outline while resizing JFrame but didn't fully understand the usage of the timer. Was not sure if there exists a property or if this would be managed via a mouse handler tied to the JFrame.

Related

Position problem with adding something to JFrame in 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().

JFrame larger than it's window

I've been using Java Swing for quite some time now and I never found a solution to this problem. When I create a JFrame the window surrounding it is actually smaller than the frame. In the included picture below my JFrame size is 800x600. The 2 white lines crosses at the center of the frame, 400,300. As you can see they are not at the center of the window. If I stretch the window right and down I can see some of the black background of the frame was hidden. When the black background is revealed you can see the the lines do indeed cross at the center (2nd picture).
Why is it working like that? Anything I can do to solve this problem? Im making a game where the playable character is in the center of the screen so this causes me a lot of problem. The 1st image is larger because i've left the code in the background. As we can see it's a standard JFrame creation.
Not centered because part of the frame is hidden:
centered when frame is fully revealed:
my JFrame size is 800x600
You are doing things backward.
The frame has decorations (ie. the title bar and borders). The panel where you do the painting is added to the frame, so therefore it will be less than the size of the frame.
The proper approach is to override the getPreferredSize() method of the JPanel where you do the custom painting to return the desired size of the panel.
Then you add the panel to the frame you invoke the pack() method on the frame. Now the frame will be sized slightly larger (to fit the complete panel and the frame decorations) and your painting will be accurate.

Applet Stand alone issue

I attempted to make an applet program I have Stand alone by adding in:
public static void main(String[] args) {
JFrame frame = new JFrame("StartingPoint");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StartingPoint sp = new StartingPoint();
frame.getContentPane().add(sp);
sp.init();
frame.pack();
frame.setVisible(true);
sp.start();
}
Right after my public class. When running as just the applet this does nothing, but when Running it as an application it runs as a very small, nearly flat box aside from the heading, and when manually resized, the screen is blank other then the backround color.
Any idea what may cause this?
I have also noticed, each time I resize the frame, what is on it freezes,as if a screen shot of what should happen, and when the screen is resized to nearly full screen I can see at the tip top of the screen a sliver of what should be moving.
I'd just like to say, that dropping an applet into a frame is a really bad idea. You are better off writing the application contents into a separate container (such as JPanel) and adding that to your applet or frame - IMHO.
From the Java Docs...
Window#pack
Causes this Window to be sized to fit the preferred size and layouts
of its subcomponents. The resulting width and height of the window are
automatically enlarged if either of dimensions is less than the
minimum size as specified by the previous call to the setMinimumSize
method.
If the window and/or its owner are not displayable yet, both of them
are made displayable before calculating the preferred size. The Window
is validated after its size is being calculated.
This would suggest that your applet needs to provide a preferredSize if you wish to use pack
You need to set the size of the JFrame:
frame.setSize(500, 400);
It sounds as if you are overriding the paint() method. If so, you will need to call
super.paint(g);
to repaint all child components of the applet container on resize.

setSize() doesn't work for JFrame

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
class Demo
{
JFrame jf;
Demo()
{
jf=new JFrame("Demo");
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setSize(5000,5000);
jf.setVisible(true);
System.out.println(jf.getSize());
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Demo();
}
});
}
}
I use jf.setSize(5000, 5000) for JFrame but after that getSize returns other size: java.awt.Dimension[width=1386,height=788] (my screen resolution is 1366x768) Can I set frame size greater than screen size? probably such behaviour is provided with some frame properties but I don't know about them.
Try using setPreferredSize instead of setSize. Works in my case (Ubuntu 12.04+GNOME 3).
The javadoc says this:
"The method changes the geometry-related data. Therefore, the native windowing system may ignore such requests, or it may modify the requested data, so that the Window object is placed and sized in a way that corresponds closely to the desktop settings."
This covers the behavior that you are observing / complaining about.
It is not crystal clear, but one reason that Window.setSize(...) has this behaviour is that window managers (outside of Java) typically veto application attempts to do this. Presumably, that's because it is open to abuse and "not what the user wants". Anyway, it is ultimately not your application's call to override the window manager's restrictions.
Just for Friday fun (that is, nothing you should consider doing in production environment :-) - playing a bit further with #jinguy code, I noticed that the bigger-than-life size was used after minimizing the frame. Doing so programmatically let it appear as monster right from the start
jf.setPreferredSize(new Dimension(5000,5000));
jf.setMinimumSize(new Dimension(5000,5000));
jf.pack();
jf.setVisible(true);
jf.setState(Frame.ICONIFIED);
jf.setState(Frame.NORMAL);
System.out.println(jf.getSize());
I tried out a few combinations of calls, and the following seemed to work:
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setPreferredSize(new Dimension(5000,5000));
jf.setMaximumSize(new Dimension(5000,5000));
jf.setMinimumSize(new Dimension(5000,5000));
jf.pack();
jf.setVisible(true);
It still prints out a different size, but the window appears to be far larger than it prints.
These are my observations (used 1.6, now I'm using 1.7 under XP):
You can have undecorated frame of "almost" any size -- I use screen resolution of 1280x1024 (rotated) and didn't noticed any problems with frame 1500x1500, although some frames 2000x2000 look uncompleted (but work) and frame of 4000x4000 displays its thumb in taskbar but this thumb is unactive and the frame itself doesn't appear. I think the largest possible size of undecorated JFrame is dependent on system capabilities which is dependent on the graphic hardware.
With decorated frames there is a simple story -- they can be a little larger than screen size (by few pixels in generally).
In my application with size determined during runtime (e.g. games where you set board size dynamically) I use the following approach:
1). before packing set frame location relative to null. It places the upper-left corner of JFrame in the middle of the screen (before pack the JFrame is (0,0) dimensioned)
2). set preferred sizes of my frame content (I always use single JPanel) and remember them
3). pack the frame
4). if frame sizes after pack don't match those before pack dispose the frame, remove content's JPanel, add JScrollPane with this JPanel and set the preferred sizes of JScrollPane as JPanel preferred sizes PLUS the JScrollBar fixed dimensions (i.e. a width of the vertical scrollbar and a height of the horizontal one).
5). pack again -- this guarantees only the necessary scrollbars appear (if you don't increase the JFrame sizes then both scrollbars will always appear -- there is also a need to remove the JScrollPane default border).
6). set new location of the frame by moving it left and up by the half of the corresponding size to center it.

Java Swing: component that resizes itself but doesn't influence the layout

I'll try to explain my problem as simply as possible but it's a tricky topic and people who haven't encountered the issue probably won't know what I'm talking about.
I want to use a BorderLayout using west, east, north, south, etc. components that are my "normal" components (JLabels, JButtons, etc.) then I want the center component to be an "image" (that is: pixels). To this end I'm using a BufferedImage and using setIcon on a JLabel that is inside a panel that is part of the "center".
However I want my image/pixels to be "fluid": whenever the user resizes the app, I want to compute the exact size of the JLabel (icon/text gap is set to 0) and then create a new image (pixels that I manipulate directly in a BufferedImage but whatever) that has exactly that size.
Now it does work fine. But only when I resize the main window ("window" as in "one of the window of the operating system) by making it bigger.
It doesn't work when I downsize my main window.
The reason, after a lot of testing, is obviously because the size of my JLabel (in which I did a setIcon( img ) is influencing the computation of the layout manager.
So here comes the billion dollar question: how should I use a BorderLayout (or any other layout) so that I can create a "fluid" rectangle of pixels in the center of my app?
Answering my own question with an answer that I will not accept even tough it does work...
The problem can be "worked around" by creating a picture a few pixels smaller than the getVisibleRect of the center area.
So in my case I create an ImageIcon from a BufferedImage that is 20 pixels smaller (both in width and height) than the area that will hold it.
What happens then is that because the picture is smaller it doesn't "block"/prevent the layout manager from putting everything at their correct place when downsizing the main window.
So by using such an hack I get the "fluid" behavior I want.
This is however an hack whose level of hackyness cannot be understated and I'm sure there's a very clean way to solve this.
The reason, after a lot of testing, is
obviously because the size of my
JLabel (in which I did a setIcon( img
) is influencing the computation of
the layout manager.
The preferred size of the JLabel is used in the preferred size of the panel, but this size is ignored when you resize the frame, since the CENTER only gets whatever space is left over after the preferred size of the other 4 components is considered.
To this end I'm using a BufferedImage
and using setIcon on a JLabel that is
inside a panel that is part of the
"center".
Sounds to me like it should work.
Create the panel with a BorderLayout. Add the JLabel to the Center of your main panel. Then add a ComponentListener to the panel. Now when the frame is resized the center panel size will be adjusted to take the space available to it. Now that you know the size of the center panel you can recreate the Icon and add it to your JLabel,
This is how you write a SSCCE:
import java.awt.*;
import javax.swing.*;
public class LabelTest2 extends JFrame
{
public LabelTest2()
{
JLabel picture = new JLabel(new ImageIcon("???.jpg"));
add(picture);
}
public static void main(String[] args)
{
LabelTest2 frame = new LabelTest2();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}

Categories