Originally (See my previous question "Java how to make JFrames start off as a maximised window") I wanted to make a window which starts out maximised.
This code accomplishes this:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
However, if this window is restored down it becomes a practically non-existent bar. To solve this I set a size for the window using setSize(). This works but presents another problem, the window can still be resized.
To solve this problem I set setResizable(false); and this is my code so far:
public static void main(String[] args) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
JFrame frame = new JFrame("Jedia");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setSize(screenSize);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
However, now the window starts out at its specified size (rather than maximised) and cannot be restored up.
So, my question is, how can I either make the window start out maximised, give it a size for when it is restored down and make resizing it impossible? Or make a window that starts out maximised and cannot be restored down?
There is a simple fix that works almost all the time: make your frame not resizable after having set visible. So only modifies your code this way:
public static void main(String[] args) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
JFrame frame = new JFrame("Jedia");
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setSize(screenSize);
frame.setVisible(true); // FIRST visible = true
frame.setResizable(false); // THEN resizable = false
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
This way, the frame will start maximized and the maximize button will be greyed out, preventing user to use it. (I don't really know why you have to do this. I suppose the maximized state is really applied only when the window becomes visible, and if you make it unresizable before, it will not apply.)
It works almost all the time because on Windows 7 at least you can make the window goes out of the maximized state by clicking the title bar and dragging it. But it will be at the size you have set it earlier. Problem is that your user will not be able to maximize it again, and I haven't found the way with listeners to make the window back to maximized state. ( Edit: #David Kroukamp shows in the last part of his answer that it is possible to force the maximized state by using a ComponentListener. Therefore you don't have to use setResizable(false) This way you still have a problem with Windows 7 because the dragging action is not catched by this event for whatever reason but users will be able to use the maximized button to put it back where it should be.)
Now, there is almost never a reason to do this kind of things. Users don't really like when you prevent them to manipulate their windows (maximized windows can not be moved, for example, and that can be annoying when you have multiple screens). An exception is if you are making a game, which is typically full-screen. But then you wouldn't want a JFrame because you don't want all the decoration, but a Window.
If your problem is that the default window size is very small, it's normal. You have to put something in your frame first (some controls, buttons, what you want in your application), using layouts (that's important) then call the method pack() on your frame. It will chose a nice default size for your window.
Finally, a last word. I've put my example code in a main method as a shortcut, but you should always do Swing stuff in the Swing EDT by using SwingUtils.invokeLater().
Sometimes, you have to be careful about the order you set JFrame parameters.
Also, you should be using Swing components on the event dispatch thread.
Try this and see if it helps.
public static void main(String[] args) {
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Jedia");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(screenSize);
frame.setResizable(false);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
});
}
What environment are you running on? I tried this with JDK1.6 / JDK1.7 under Win7 and it works as expected (window starts maximized, minimizes to task bar).
I have kind of a hack for you that might work.
Try this code (it worked for me):
public static void main(String[] args) {
final JFrame frame = new JFrame("Jedia");
frame.setMinimumSize(new Dimension(600, 400));
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
frame.addComponentListener(new ComponentListener(){
#Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
#Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
#Override
public void componentResized(ComponentEvent e) {
if (!e.paramString().startsWith("COMPONENT_RESIZED (-8,-8"))
frame.setSize(new Dimension(600, 400));
}
#Override
public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub
}
});
}
e.paramString() returns a String that looks like "COMPONENT_RESIZED (-8,-8, [screensize])" when a restore action takes place.
Related
When I compile the code below in Eclipse, I expect a window to appear with a button on the upper left corner of the window. Instead, the button has the same size as the window and fills the window completely, although I suppose to have restricted the size of the button in line 11 with "button.setBounds(20, 20, 200, 50);". Can anybody tell me what I did wrong or what I forgot?
import javax.swing.*;
import java.awt.*;
public class BeobachterGUI {
public BeobachterGUI() {
JFrame frame = new JFrame("A frame");
frame.setSize(new Dimension(600, 600));
JButton button = new JButton("Click me");
button.setBounds(20, 20, 200, 50);
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new BeobachterGUI();
}
});
}
}
JFrames automatically give themselves a default BorderLayout, which is what is making your button fill the entire screen. If you want to have direct control over the size and position of your button, you have to get rid of that layout manager. Use this line of code:
frame.getContentPane().setLayout(null);
A word of advice, though: working without a layout manager is OK for fun and experimentation, but you shouldn't make a habit of it. You'll get a better GUI (and the users of your GUI get a better experience) if you learn to design with layout managers.
To see an example of what I mean, just watch what happens when you resize your window: if you make the window too small, the button can get cut off or hidden completely. A layout manager would try to reposition and/or resize the button so it stays visible.
I'm just new to Java GUI Programming and I'm having a problem that the components inside my panel is missing when I place the setVisible()function at the beginning of the function called by the constructor but it works fine when it is at the end. See code below:
public static void main(String[] args)
{
new MainClass();
}
public MainClass()
{
setFrame();
}
private void setFrame()
{
JFrame frame = new JFrame();
frame.setSize(400,400);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Some area where the object of my components inside the panel is created and initialized.
// If I just place a label and a button, it will appear on the panel. However if I add the JTextArea, all the components in my panel is gone. Just like the code below.
textArea1 = new JTextArea(20,34);
textArea1.setWrapStyleWord(true);
textArea1.setLineWrap(true);
JScrollPane scroll =
new JScrollPane(textArea1,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scroll);
frame.add(panel);
// Works fine when setVisible(true); it placed here.
}
What could the problem possibly be with regard to placing the setVisible() function to the beginning or to the end of the method.
As already pointed out in the comments and the other answer:
You should call setVisible(true) at the end, after all components have been added.
This does not directly answer your question. The answer to your question is: Yes, it makes a difference. If you call setVisible before all compoents have been added, it may work, in some cases, with some programs, on some PCs, with some Java versions, with some operating systems - but you always have to expect that it may not work as expected in some cases.
You will find dozens of related questions here on stackoverflow and elsewhere. The usual symptoms of these problems are that some components are not displayed properly, and then suddenly appear when the window is resized. (Resizing a window basically triggers a layout and a repaint).
The likeliness of unexpected behavior is increased when you violate the threading rules of Swing. And, in some sense, you did violate the threading rules of Swing: You should always create the GUI on the Event Dispatch Thread!
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SomeSwingGUI
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
// This method may (and will) only be called
// on the Event Dispatch Thread
private static void createAndShowGUI()
{
JFrame f = new JFrame();
// Add your components here
f.setVisible(true); // Do this last
}
}
And by the way: Timothy Truckle pointed out in a comment that you should not invoke setVisible from the constructor. This is true. More importantly: You should usually not directly create a class that extends JFrame. (In some (rare!) cases, this is appropriate, but the general guideline should be to not extend JFrame)
The components cannot be shown, because you add them after you call the setVisible() method of the Frame.
The Componet's add() method changes layout-related information, and invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component, as pointed here
.
So in order to show the items, you should either call the revalidate() method of the frame or call setVisible() after all your components are added.
Unless there is no special need, you should call setVisible() after you have added every other component.
public class TestMain extends JFrame {
public static void main(String[] args) {
JFrame test = new TestMain();
//if the setVisible() is called too early, you have to revalidate
test.revalidate();
}
public TestMain() {
setFrame();
}
private void setFrame() {
setSize(400,400);
setResizable(false);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new FlowLayout());
setVisible(true);
JTextArea textArea1 = new JTextArea(25,15);
textArea1.setWrapStyleWord(true);
textArea1.setLineWrap(true);
panel.add(textArea1);
JScrollPane scroll =
new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// this method invalidates the component hierarchy.
getContentPane().add(scroll);
}
}
I'm trying to make a program, and I want it to start out maximized, but I also want to be able to resize it. The only problem is that, whenever I call frame.pack(), it snaps back to the size I set it when I called frame.setExtendedState(int) which I made java.awt.Frame.MAXIMIZED_BOTH so as to make the frame maximized when I first open it. Is there a way to prevent this?
and I want it to start out maximized,
That is a one time setting of the state which can be changed at any time.
So you should be able to use:
frame.setExtendedState(JFrame.NORMAL);
frame.pack();
// or pack() / setExtendedState(...)
That will not prevent the user from clicking on the maximize icon later if they desire to do so.
maximized and resizable,
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH);
final Timer tt = new Timer(68, e -> {
Dimension r = f.getSize();
f.setExtendedState(java.awt.Frame.NORMAL);
f.pack();
f.setSize(r);
});
tt.setRepeats(false);
tt.start();
f.setVisible(true);
});
}
}
Recently I have been working on a project which uses Java Swing to build the GUI. I want to print the text in a JTextArea and therefore I wrote something like
boolean printed = textArea.print();
This brings up a modal dialog. However the dialog seems to have no parent and the main frame (the one containing textArea) blocks the print dialog.
As you see, the print dialog (the thin line at the bottom) goes behind the main JFrame.
Code:
import java.awt.*;
import java.awt.print.*;
import javax.swing.*;
public class JTextAreaPrintBug {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,600);
frame.setLocationRelativeTo(null);
frame.setAlwaysOnTop(true);
//now add JTextArea
frame.setLayout(new BorderLayout());
JTextArea textArea = new JTextArea();
frame.add(textArea, BorderLayout.CENTER);
frame.setVisible(true);
try {
textArea.print();
} catch (PrinterException ex) {}
}
});
}
}
Is it possible to bring the print dialog to front (or explicitly set the parent of the print dialog), preferably not reinventing the wheel? Thanks in advance.
Edit: I know there is a line frame.setAlwaysOnTop(true);. What I really want is to bring the print dialog to the very front even if the main frame is always on top.
Edit (2): I finally opted for a workaround which uses a WindowFocusListener and the getOppositeWindow() method in WindowEvent to obtain a reference to the print dialog. Still I resort to reflection (getting the name of the instance's class) to check whether the "opposite window" is a print dialog, or just an ordinary dialog in my application. Anyway, welcome for more elegant solutions.
It's because of this
frame.setAlwaysOnTop(true);
So change it to false to see the print window.
or
Remove that line, if you don't want your main window to block other windows. Default value is false anyway.
Example:
public class JFrameTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JButton button = new JButton("Hello!");
frame.getContentPane().add(button);
frame.getContentPane().add(button);
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
In the above example 'button' object is added only once even though there are no errors. The reason why I ask this is, I would like to add a same JPanel object on JFrame and on JDialog (on some table double click for edit/delete feature). I am able to solve it by having two JPanel objects but just wanted to know why it is not possible.
You can only add Swing components once in the Swing hierarchy as you already found out. This is documented in the 'Using top-level components tutorial'
Each GUI component can be contained only once. If a component is already in a container and you try to add it to another container, the component will be removed from the first container and then added to the second.
Not completely sure whether there were technical limitations that let to this decision, but I could imagine that for example the getParent method would give strange results if you were able to add the same component to two Containers