Java Canvas doesn't resize correctly - java

I have to programm a game with the exact resolution of 128x128 but the Canvas dont want to match.
public class Window extends Canvas{
private static final long serialVersionUID = 1L;
private JFrame frame;
public Window(BufferedImage icon){
this.setMinimumSize(new Dimension(128, 128));
this.setMaximumSize(new Dimension(128, 128));
this.setPreferredSize(new Dimension(128, 128));
this.setSize(128, 128);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
if(icon != null){
frame.setIconImage(icon);
}
}}
The size of the Canvas (getWidth(), getHeight) is 134*128 instad of 128*128..

I would think getHeight would return the 134. That would. Be the title of the window. Is the Jframe obviously the bigger portion?

Don't call your class Window. There is an AWT component using that name so it is very confusing. Class names should be more descriptive.
Don't extend Canvas. When using Swing your would extend JComponent or JPanel for custom painting.
Don't create the frame in your class. The frame is not a property of the class and doesn't belong there.
I have to programm a game with the exact resolution of 128x128
Works fine for me on Windows.
Its definetly the getWidth(),
There is a minimum width of the frame. The frame must be able to paint all the buttons in the title bar and the left/right borders.
So I would guess that because you are using a BorderLayout, the frame is being resized to its minimum and then your custom class is resized based on the rules of the layout manager.
So if you want the preferred size of the panel to be respected, try a different layout manager on the frame. For example use a FlowLayout, it will respect the size of any component added to it.
Simple example:
import java.awt.*;
import javax.swing.*;
public class GamePanel extends Canvas
{
public GamePanel()
{
setBackground( Color.RED );
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(128, 128);
}
private static void createAndShowGUI()
{
GamePanel panel = new GamePanel();
JFrame frame = new JFrame("GamePanel");
frame.setLayout( new FlowLayout() );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
System.out.println(panel.getSize());
System.out.println(frame.getSize());
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}

Related

Java JFrame inner size

How can I make the inner size 500x500 pixel?
Or should I hardcode the 28px macOS top-bar for windows?
My simple code:
import javax.swing.JFrame;
public class Hello {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
}
Don't set the JFrame size. Use a JPanel and add that to the JFrame and set the size of the JPanel.
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(500,500));
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null); // centers on screen.
frame.setVisible(true);
If you are extending JPanel it is best to set the size by overridding the following:
#Override
public Dimenison getPreferredSize() {
return new Dimension(500,500);
}
It is also considered best practice to do most layouts and especially painting inside JPanel(s) and not the JFrame.

How to call the JFrame from another class?

I have a class that creates a frame.
public class GameDisplay{
....
public void createDisplay(){
frame=new JFrame(title);
canvas=new Canvas();
canvas.setPreferredSize(new Dimension(width,height));
canvas.setFocusable(false);
frame.setSize(width,height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setResizable(false);
frame.add(canvas);
frame.pack();
}
public Canvas getCanvas(){
return this.canvas;
}
public JFrame getFrame(){
return frame;
}
If I have another class that would add Panels and Buttons to the frame, how can I add them?
I have tried:
GameDisplay g;
Container c;
c = g.getFrame().getContentPane();
But it returns NullPointer Error. Thus, I can't seem to add panels to it.
Attach your JFrame made in createDisplay() to a static variable. Then access that static variable from another class.
Like this
public static JFrame frame1;
Then in createDisplay()
GameDisplay.frame1 = frame;
In another class to get the content pane just do
c = GameDisplay.frame1.getContentPane();
Hope this helped!

Strange JFrame size

So I set the setSize(500,500).. add some panels, the sum of panels Y is 500 like the JFrame but executing it shows an count Y of 525 am I missing something?
JPanel panel = new JPanel();
panel.setLayout(null);
getContentPane().add(panel);
//--------------------
JPanel top_panel = new JPanel();
top_panel.setLayout(null);
top_panel.setBackground(Color.blue);
top_panel.setBounds(0, 0, 500, 40);
panel.add(top_panel);
//------------------------------
JPanel middle_panel = new JPanel();
middle_panel.setLayout(null);
middle_panel.setBackground(Color.yellow);
middle_panel.setBounds(0, 40, 500, 385);
panel.add(middle_panel);
//-----------------------------
JPanel bottom_panel = new JPanel();
bottom_panel.setLayout(null);
bottom_panel.setBackground(Color.black);
bottom_panel.setBounds(0, 425, 500, 75);
panel.add(bottom_panel);
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
40+385+75 = 500 but to show all the panels i must
setSize(500,525);
then it fits
here's an image:
The frame size is the light blue rectangle outside bounds including the title bar. Your panels are appearing in the inner bounds which is frame size less than the frame border and frame title bar. Do you see how your marked space at the bottom is strangely the same height as the title bar?
After adding your panels/component to the frame and just before calling frame.setVisible(true), call frame.pack().
It would be also preferable if you embrace a layout manager (such as FlowLayout) and when necessary call setPreferredSize and let the layout manager do the layout. Normally one would call setPreferredSize over setBound, setSize, setMininumSize, setMaximumSize.
import javax.swing.*;
import java.awt.*;
public class FrameSize {
private JFrame frame;
FrameSize create() {
frame = createFrame();
frame.getContentPane().add(createContent());
return this;
}
private JFrame createFrame() {
JFrame frame = new JFrame(getClass().getName());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}
void show() {
// frame.setSize(500, 500);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private Component createContent() {
JPanel panel = new JPanel(null);
JPanel topPanel = new JPanel(null);
topPanel.setBackground(Color.blue);
topPanel.setBounds(0, 0, 500, 40);
panel.add(topPanel);
JPanel middlePanel = new JPanel(null);
middlePanel.setBackground(Color.yellow);
middlePanel.setBounds(0, 40, 500, 385);
panel.add(middlePanel);
JPanel bottomPanel = new JPanel(null);
bottomPanel.setBackground(Color.black);
bottomPanel.setBounds(0, 425, 500, 75);
panel.add(bottomPanel);
panel.setPreferredSize(new Dimension(500, topPanel.getBounds().height + middlePanel.getBounds().height + bottomPanel.getBounds().height));
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new FrameSize().create().show();
}
});
}
}
You shouldn't be setting size or calling setSize(...) or setBounds(...) as that's setting you up for similar problems in the future, or worse problems when you try to show your GUI on a different platform. Instead let the preferredSizes of your components and the layout managers do this work for you. If you absolutely must set the size of a component, then override getPreferredSize() and return a Dimension that is calculated to work for you. And yes, as per javajon, you should call pack() on the JFrame before displaying it.
For more discussions on the null layout, please read what one of the best Swing experts on this site, MadProgrammer, has to say in his answer here.

Why does setting the layout to BorderLayout mean the paintComponent is never called

In the following example program, if you set useBorderlayout to true, the paintComponent method is never called - why?!
import javax.swing.*;
import java.awt.*;
public class PaintComponentTest extends JPanel {
private final boolean useBorderLayout;
public PaintComponentTest(boolean useBorderLayout){
this.useBorderLayout = useBorderLayout;
initialiseComponents();
}
public void initialiseComponents(){
setOpaque(true);
setBackground(Color.RED);
if(useBorderLayout){
//this appears to be the offending line:
setLayout(new BorderLayout());
}
final JPanel panel = new JPanel();
panel.setOpaque(true);
panel.setBackground(Color.GREEN);
add(panel, BorderLayout.CENTER);
}
#Override
public void paintComponent(Graphics g){
System.out.println("PaintComponentTest.paintComponent");
super.paintComponent(g);
}
public static void main(String [] args){
final boolean useBorderLayout = (args.length == 1 && Boolean.parseBoolean(args[0]));
System.out.println("Running with"+(useBorderLayout?"":"out")+" BorderLayout as layout manager...");
SwingUtilities.invokeLater(new Runnable(){
public void run(){
final JFrame frame = new JFrame("BorderLayout/PaintComponent test");
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().setLayout(new BorderLayout());
final PaintComponentTest componentTest = new PaintComponentTest(useBorderLayout);
frame.getContentPane().add(componentTest);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Because it doesn't need to. The PaintComponentTest class is a JPanel that has one green JPanel as content. When the BorderLayout is set, the green panel takes up all the space in panel and the PaintComponent method is not needed.
Add this method to your code and you should see it happen:
#Override
public void paintChildren(Graphics g){
System.out.println("PaintComponentTest.paintChildren");
super.paintChildren(g);
}
Because the nested panel covers all the component. Damaged region (to be repainted) is past to the children because the child bounds cover all the damaged region.

Wrong packing of JFrame using JPanel in borderlayout

I am writing a simple application in Java that does some particle simulation on a bunch of sheep (don't ask). For this I want a window with a JPanel for graphics (which will be resizable with a simple combobox that contains some standard resolutions) and some other elements like buttons to start and pause the simulation etc.
My question: I'm using the JFrame.pack method to pack everything nicely together using a borderLayout. But for some reason the JPanel is packed wrong, it seems like the packing ignores it, so the window is resized to fit the size of only the two buttons that I have now. What am I doing wrong?
This is the code so far (bit of a newbie, so no comments on my dumbness if there is any ;)):
public class Window {
public Sheepness sheepness;
public ButtonPanel buttonPanel;
public PaintPanel paintPanel;
public JFrame frame;
public Window(Sheepness sheepness, int width, int height) {
this.sheepness = sheepness;
frame = new JFrame("Sheepness simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.setSize(width, height);
BorderLayout frameLayout = new BorderLayout();
JPanel background = new JPanel(frameLayout);
background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
buttonPanel = new ButtonPanel(this);
background.add(BorderLayout.SOUTH, buttonPanel.buttonBox);
paintPanel = new PaintPanel(this);
paintPanel.setSize(600, 600);
background.add(BorderLayout.CENTER, paintPanel);
frame.getContentPane().add(background);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
public class PaintPanel extends JPanel {
public Window window;
public PaintPanel(Window window) {
this.window = window;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.blue);
g.fillRect(0, 0, 300, 200);
}
}
public class ButtonPanel {
public Window window;
public Box buttonBox;
public JButton startButton;
public JButton resetButton;
public ButtonPanel(Window window) {
this.window = window;
buttonBox = new Box(BoxLayout.X_AXIS);
startButton = new JButton("Start");
startButton.addActionListener(new startButtonListener());
buttonBox.add(startButton);
resetButton = new JButton("Reset");
resetButton.addActionListener(new resetButtonListener());
buttonBox.add(resetButton);
}
}
Try:
paintPanel.setPreferredSize(600, 600);
As Window.pack() sizes to the preferred sizes of its subcomponents and JPanel gets its preferred size from its child components (in your case there are none).

Categories

Resources