JFrame window dimensions

E

Eustace

package temporary;

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class Temp extends JFrame {
Graphics2D painter2D;
static int W = 1200;
static int H = 600;
static int B = 10; // border

public Temp() {
super("Temp");
setSize(W + 8, H + 36); // necessary adjustment
System.out.println("1 " + getWidth() + " " + getHeight());
// 1 1208 636
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
Container contentArea = getContentPane();
CustomPanel panel = new CustomPanel();
contentArea.add(panel);
setContentPane(contentArea);
}

public static void main(String[] args) {
Temp instance = new Temp();
}

class CustomPanel extends JPanel {
public void paintComponent(Graphics painter) {
System.out.println("2 " + getWidth() + " " + getHeight());
// 2 1200 600
painter2D = (Graphics2D) painter;
painter2D.translate(0, H / 2); // middle horizontal 0

// draw the frame
Color clr = Color.black;
drawFrame(clr);
}

private void drawFrame(Color clr) {
double x, y, w, h;
x = 0 + B;
y = -H / 2 + B;
w = W - 2 * B;
h = H - 2 * B;
Rectangle2D.Double frame = new Rectangle2D.Double(x,y,w,h);
painter2D.setColor(clr);
painter2D.fill(frame);
}
}
}

In the above program, I want the active window (that is the area I am
working in, without the top bar and the borders) to be 1200 by 600. To
do so, I had to use

setSize(W + 8, H + 36);

to compensate for the width and height of the top bar and borders I have
in my system. If I do not make this adjustments, the frame will be
off-center. I found them empirically, by using

System.out.println("2 " + getWidth() + " " + getHeight());

within the

public void paintComponent(Graphics painter) {

Is there a way to get the necessary adjustment values of the system
automatically instead of empirically? Is there a way to reset the size
after I know the values of the adjustments in the
paintComponent(Graphics painter)?

Thanks,

emf
 
J

John B. Matthews

[...]
In the above program, I want the active window (that is the area I am
working in, without the top bar and the borders) to be 1200 by 600.
To do so, I had to use

setSize(W + 8, H + 36);

to compensate for the width and height of the top bar and borders I
have in my system. If I do not make this adjustments, the frame will
be off-center. I found them empirically, by using

System.out.println("2 " + getWidth() + " " + getHeight());

within the

public void paintComponent(Graphics painter) {

Is there a way to get the necessary adjustment values of the system
automatically instead of empirically? Is there a way to reset the
size after I know the values of the adjustments in the
paintComponent(Graphics painter)?

Set the preferred size of the panel and use pack(), which "causes this
Window to be sized to fit the preferred size and layouts of its
subcomponents."

The method setBorder() sets the border of a component; it's easy to "put
the component in a JPanel and set the border on the JPanel."

As suggested previously, don't neglect to build your GUI on the EDT.

import java.awt.*;
import javax.swing.*;

/** @author John B. Matthews */
public class Temp extends JFrame {

private static final int B = 10; // border

public Temp() {
super("Temp");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout());
panel.setBorder(BorderFactory.createEmptyBorder(B, B, B, B));
panel.add(new CustomPanel());
this.add(panel);
this.pack(); // adjust to the preferred size of subcomponents.
this.setLocationRelativeTo(null);
this.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp();
}
});
}

private static final class CustomPanel extends JPanel {

private static final int W = 1200;
private static final int H = 600;

public CustomPanel() {
this.setPreferredSize(new Dimension(W, H));
this.setBackground(Color.black);
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(getWidth() + " " + getHeight());
}
}
}
 
L

Lew

John said:
As suggested previously, don't neglect to build your GUI on the EDT. ....
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp();
}
});
}

And don't run the GUI from the constructor.

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp().setVisible(true);
}
});
}
 
J

John B. Matthews

[QUOTE="Lew said:
As suggested previously, don't neglect to build your GUI on the EDT. ...
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp();
}
});
}

And don't run the GUI from the constructor.

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp().setVisible(true);
}
});
}[/QUOTE]

Lew: Ah, a subtle trap for the unwary. Thanks for highlighting it. IIUC,
this is predicated on the idea that the constructor should complete
before invoking the instance's public methods.

Eustace: More on the recommended approach is shown in the "Initial
Threads" section of the tutorial [1]. Here's another idiom that avoids
the peril and obviates extending JFrame. Also, I've found it instructive
to run the program in a profiler while resizing the window, paying
particular attention to the event queue.

import java.awt.*;
import javax.swing.*;

/** @author John B. Matthews */
public class Temp implements Runnable {

private static final int B = 10; // border

public static void main(String[] args) {
EventQueue.invokeLater(new Temp());
}

@Override
public void run() {
JFrame frame = new JFrame("Temp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout());
panel.setBorder(BorderFactory.createEmptyBorder(B, B, B, B));
panel.add(new CustomPanel());
frame.add(panel);
frame.pack(); // adjust to the preferred size of subcomponents.
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

private static final class CustomPanel extends JPanel {

private static final int W = 1200;
private static final int H = 600;

public CustomPanel() {
this.setPreferredSize(new Dimension(W, H));
this.setBackground(Color.black);
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(getWidth() + " " + getHeight());
}
}
}

[1]<http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/
concurrency/initial.html>
 
M

markspace

John said:
Eustace: More on the recommended approach is shown in the "Initial
Threads" section of the tutorial [1]. Here's another idiom that avoids
the peril and obviates extending JFrame.> /** @author John B. Matthews */
public class Temp implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater(new Temp());
}

@Override
public void run() {


This is interesting, but "Temp" isn't really a great name for any
variable, let alone a class. Most things that are "run" on another
thread can be described as a "task." This task above creates a GUI, so...

public class CreateGuiTask implements Runnable {

public static void main(String[] args) {
EventQueue.invokeLater(new CreateGuiTask());
}

@Override
public void run() {
// etc.


This is just a bit more readable, imo.
 
J

John B. Matthews

markspace said:
This is interesting, but "Temp" isn't really a great name for any
variable, let alone a class. Most things that are "run" on another
thread can be described as a "task." This task above creates a GUI,
so...

public class CreateGuiTask implements Runnable {

public static void main(String[] args) {
EventQueue.invokeLater(new CreateGuiTask());
}

@Override
public void run() {
// etc.


This is just a bit more readable, imo.

Much better! Alas, I am cursed with a heavy editorial hand, and "Test"
was the last thing I _hadn't_ changed. :)

A correspondent prompted me to consider creating a template. At least,
NetBeans will require a different name, if not a good one.

import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class ${name} extends JPanel implements Runnable {

public static void main(String[] args) {
EventQueue.invokeLater(new ${name}());
}

@Override
public void run() {
JFrame f = new JFrame("${name}");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

public ${name}() {
this.setPreferredSize(new Dimension(640, 480));
}
}
 
E

Eustace

[QUOTE="Lew said:
As suggested previously, don't neglect to build your GUI on the EDT. ...
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp();
}
});
}
And don't run the GUI from the constructor.

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
new Temp().setVisible(true);
}
});
}

Lew: Ah, a subtle trap for the unwary. Thanks for highlighting it. IIUC,
this is predicated on the idea that the constructor should complete
before invoking the instance's public methods.

Eustace: More on the recommended approach is shown in the "Initial
Threads" section of the tutorial [1]. Here's another idiom that avoids
the peril and obviates extending JFrame. Also, I've found it instructive
to run the program in a profiler while resizing the window, paying
particular attention to the event queue.

import java.awt.*;
import javax.swing.*;

/** @author John B. Matthews */
public class Temp implements Runnable {

private static final int B = 10; // border

public static void main(String[] args) {
EventQueue.invokeLater(new Temp());
}

@Override
public void run() {
JFrame frame = new JFrame("Temp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridLayout());
panel.setBorder(BorderFactory.createEmptyBorder(B, B, B, B));
panel.add(new CustomPanel());
frame.add(panel);
frame.pack(); // adjust to the preferred size of subcomponents.
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

private static final class CustomPanel extends JPanel {

private static final int W = 1200;
private static final int H = 600;

public CustomPanel() {
this.setPreferredSize(new Dimension(W, H));
this.setBackground(Color.black);
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println(getWidth() + " " + getHeight());
}
}
}

[1]<http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/
concurrency/initial.html>[/QUOTE]

Thanks for your replies. It was only reasonable that it had to be an
automatic way to make the dimensions of the window the desired ones.

The border was not the main issue in my original posting. I could just
as well have drawn any rectangle equidistant to the sides of the window
to make my point, or a circle inscribed in it.

In my program I follow an example of the book "Java In Easy Steps"
(Painting application fonts and colors, p.150-1). This is by far the
shortest of the 3 books I studied learning Java, (keeping the programs -
exercises in them handy to consult in the future when necessary as a
first source of help,) and yet I find it the most helpful for quick
answers. One of the others was for preparation for the certification
exam, and it included topics like Threads and Streams, things that I did
not expect to need any time soon. However, I do not remember
encountering "EventQueue.invokeLater()" or "@Override" there. I would
prefer to solve the problem without using things I do not yet
understand, it seems, however, I have to follow your approach above to
do so.

Thanks again,

emf
 
L

Lew

Eustace said:
However, I do not remember
encountering "EventQueue.invokeLater()" or "@Override" there. I would
prefer to solve the problem without using things I do not yet
understand, it seems, however, I have to follow your approach above to
do so.

Read the Javadocs and the Swing tutorial for the former, and Javadocs for the
latter. The former (or its sister 'invokeAndWait()') are mandatory to put GUI
events on the EDT. '@Override' marks that a method overrides a parent type's
method, e.g., 'equals()' from 'Object'. If you goof, for example in

public class Foo
{
@Override
public boolean equals( Foo foo )
{
...

the annotation produces a compile-time error instead of silently approving a
bug that would really bite if not diagnosed until production.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top