Java jframe adding canvas and jpanel to it - java

The following class creates a window/frame.
public class Window {
private int width, height;
private JFrame frame;
private Canvas canvas;
private String title;
private JButton button;
private JPanel panel;
public Window(String title){
System.out.println("Initialization Window...");
this.title = title;
width = Reference.width;
height = Reference.height;
button = new JButton("cool button");
CreateWindow();
}
private void CreateWindow(){
frame = new JFrame(title);
frame.setSize(width, height);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel = new JPanel();
panel.add(button);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(width, height));
canvas.setMaximumSize(new Dimension(width, height));
canvas.setMinimumSize(new Dimension(width, height));
canvas.setFocusable(false);
frame.add(canvas);
frame.add(panel);//my problem is in this line
frame.pack();
}
i added to the frame canvas and jpanel when i run it. the size of frame is set to very small a size of a button that i have made. but removing "frame.add(panel) will make it back to normal size. did i miss something?
in case why im using jpanel and canvas. well im using canvas because i use bufferstategy for the drawing graphic, and i need jpanel to add buttons and other things too.

When you add two components in a default fashion to any container that uses BorderLayout, such as a JFrame's, both are added by default in the BorderLayout.CENTER postion and the second component covers the first, and so here the JPanel covers the Canvas, and since the Canvas is not displayed, its preferred size is ignored.
You will instead want to figure out exactly where you want components relative to each other, specifically the JPanel, the Canvas and how they're placed in the JFrame, and then use the layout managers to their advantage rather than fighting the layout manager as your code currently does.
whatever you do, avoid the null layout like the plague.
It's usually a bad idea to mix AWT and Swing components. Are you absolutely positive that you need to use Canvas? JPanels are double buffered by default and that usually smooths out any animation if that's your goal.

I must say, It would have been simpler if you had just extended JFrame unless you want to extend something else.
You need to understand that for code readability and reuseability, you need to follow conventional Java rules and best practices.
#Hovercraft Full Of Eels has explained all you need above. All I do here is to set you right by example so there is no need duplicating what he has said.
FlowLayout may be the easiest and simplest layout manager in Java but it is not that very powerful compared to say GridLayout or GrdiBagLayout.
Here is the code:
public class Window extends JFrame {
private int width, height;
private Canvas canvas;
private String title;
private JButton button;
private JPanel panel;
public Window(String title){
super( title );
System.out.println("Initialization Window...");
this.title = title;
setLayout( new FlowLayout() );
//width = Reference.width;
//height = Reference.height;
button = new JButton("cool button");
createWindow();
}
private void createWindow(){
setSize(width, height);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
panel = new JPanel();
panel.add(button);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(200, 200));
canvas.setMaximumSize(new Dimension(400, 400));
canvas.setMinimumSize(new Dimension(200, 200));
canvas.setFocusable(false);
add(canvas);
add(panel);//my problem is in this line
pack();
}
}

Related

Adding Canvas on JPanel on JFrame

I hope the title wasn´t too confusing.
First off, I am still a beginner, I only started learning java a few months ago and didn´t start working with graphic components until a few weeks ago. Here is my problem:
I got a JFrame as a container and then a Canvas "canvas" to store BufferedImages and JPanel "bPanel" to hold three JButtons. For some reason, even though I used bPanel.setOpaque(false) and/or bPanel.setBackground(new Color(0, 0, 0, 0) the JPanel would still block the Canvas, no matter which one I add first and which one I add second, no matter if I add the Canvas onto the JFrame or the JPanel.
I looked around the internet for hours and tried at least 5 different solutions that did not work. For some reason, I can´t get loading images through a JPanel to work, probably because my display class is not extending anything.
Anyway, let´s continue:
Here is the code I have (yes I know I could go for Display extends JFrame but that doesn´t solve the problem, I already tried that).
public class Display {
private Game game;
private JFrame frame;
private Canvas canvas;
private JPanel bPanel;
private String title;
private int width, height;
private JButton stand, draw, reset;
private Icon drawIMG, standIMG, resetIMG;
private int bwidth, bheight;
public Display(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
createDisplay();
}
private void createDisplay() {
frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(width, height));
canvas.setMaximumSize(new Dimension(width, height));
canvas.setMinimumSize(new Dimension(width, height));
canvas.setFocusable(false);
bPanel = new JPanel();
bPanel.setSize(width, height);
bPanel.setPreferredSize(new Dimension(width, height));
//bPanel.setOpaque(false);
bPanel.setBackground(new Color(0, 0, 0, 0));
bPanel.setLayout(null);
drawIMG = new ImageIcon(this.getClass().getResource("/textures/button_draw.png"));
standIMG = new ImageIcon(this.getClass().getResource("/textures/button_stand.png"));
resetIMG = new ImageIcon(this.getClass().getResource("/textures/button_reset.png"));
draw = new JButton(drawIMG);
stand = new JButton(standIMG);
reset = new JButton(resetIMG);
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent drawClicked) {
if (game.getPhase() == 1)
game.playerDraw();
}
});
stand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent standClicked) {
if (game.getPhase() == 1)
{
game.setPhase(2);
removeButtons();
}
}
});
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent resetClicked) {
game.reset();
}
});
bwidth = 300;
bheight = 100;
//bPanel.add(new JLabel(new ImageIcon(getClass().getResource("/textures/background.png"))), BorderLayout.CENTER);
addButton(draw);
addButton(stand);
addButton(reset);
draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
reset.setBounds(((width/2)-40), (height-120), 80, 80);
frame.add(canvas);
frame.add(bPanel);
frame.pack();
}
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
public void setGame(Game game) {
this.game = game;
}
public void addButton(JButton button) {
bPanel.add(button);
bPanel.setLayout(null);
}
public void showButtons() {
draw.setVisible(true);
stand.setVisible(true);
}
public void removeButtons() {
draw.setVisible(false);
stand.setVisible(false);
}
public void removePanel(JPanel panel) {
frame.remove(panel);
}
public Canvas getCanvas() {
return canvas;
}
public JFrame getFrame() {
return frame;
}
public JPanel getBPanel() {
return bPanel;
}
}
In this try of mine for example the picture was only displayed after the JButton "stand" was pressed:
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
I am pretty desperate bc I spent many hours trying to figure out a solution to load graphics in.
Thanks for help in advance :D
Several issues:
Don't use a null layout. Swing was designed to be using with layout managers.
The default layout manager for a JFrame is a BorderLayout. If you don't specify a constraint, the component is added to the CENTER. Only one component can be displayed in the CENTER. So you can't just keep adding components to the frame. You need to have a parent/child hierarchy.
Don't use a Canvas. That is an AWT component. If you want to do custom painting in Swing you can use the JPanel
So your code might be something like:
//addButton(draw);
//addButton(stand);
//addButton(reset);
bPanel(draw);
bPanel(stand);
bPanel(reset);
The default layout manager for a JPanel is a FlowLayout. So the buttons will be added from left to right and centered on the panel.
//frame.add(bPanel);
frame.add(bPanel, BorderLayout.PAGE_START);
Now all the buttons will be added at the top of the frame.
//private Canvas canvas;
private JPanel canvas;
….
//canvas = new Canvas();
canvas = new JPanel(new BorderLayout());
…
//frame.add(canvas);
frame.add(canvas, BorderLayout.CENTER);
Now the "canvas" will be added to the CENTER of the BorderLayout of the frame, which means it will take up all the space not used by the button panel.
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
You can't add the image directly to the frame because you have already added other components to the frame. Instead use:
//frame.add(jl);
//frame.repaint();
canvas.add(jl);
canvas.repaint();
So the image is added to the canvas which is added to the frame so you have a parent/child hierarchy.
//draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
//stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
//reset.setBounds(((width/2)-40), (height-120), 80, 80);
Above code is not needed, since it is the job of the layout manager to set the size and location of each component based on the rules of the layout manager.
So basically you need to start over and learn some Swing basics. Maybe the Swing tutorial will help. There are demos of how to use each of the layout managers.

how to make jpanel in jframe visible

I try to write a menue for a little game in Java. I thought it would be a good idea to have a Window class (extending JFrame) and then put a JPanel in it for the different Screens (Menue, Game, GameOver etc)
If I put the buttons and stuff directly in the JFrame everything is shwown correct, but when I try to put a JPanel into the JFrame it doesn't work. Here is the code:
public class Window extends JFrame{
private final int WIDTH = 800;
private final int HEIGTH = 600;
private final int QUADRAT = 50;
JButton startButton;
JButton exitButton;
JButton anleitungButton;
JLabel gameTitle;
public Window() {
super("Study Run");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setSize(WIDTH, HEIGTH);
setResizable(false);
getContentPane().add(new MenuePanel());
setVisible(true);
setLocationRelativeTo(null);
}
And this is my Panel:
public class MenuePanel extends JPanel{
JButton startButton;
JButton exitButton;
JButton anleitungButton;
JLabel gameTitle;
public MenuePanel() {
super();
setBackground(Color.CYAN);
gameTitle = new JLabel("StudyRun", SwingConstants.CENTER);
gameTitle.setBounds(200, 25, 400, 75);
gameTitle.setFont(new Font("Arial", Font.ITALIC, 36));
add(gameTitle);
startButton = new JButton("start");
startButton.setBounds(325, 125, 150, 50);
add(startButton);
anleitungButton = new JButton("anleitung");
anleitungButton.setBounds(325, 200, 150, 50);
add(anleitungButton);
exitButton = new JButton("exit");
exitButton.setBounds(325, 450, 150, 50);
add(exitButton);
CloseListener closeListener = new CloseListener();
StartListener startListener = new StartListener();
AnleitungListener anleitungListener = new AnleitungListener();
startButton.addActionListener(startListener);
anleitungButton.addActionListener(anleitungListener);
exitButton.addActionListener(closeListener);
}
The only help I found online was, that I needed to add the panel before I set the frame visible. That didn't work. Putting pack() or revalidate() anywhere in the code didn't work either. Also setting the Panel on opaque or visible didn't do anything. I don't know what else to try?!
Your problem is here:
setLayout(null);
When you use null layouts, you the coder are completely responsible for the location and size of all added components. Your added component has no size and so defaults to 0, 0.
A (bad) solution: give the MenuePanel a size or bounds
A much better solution: learn and use the layout managers (as all your searches most assuredly already told you).
It's best to remember that Java uses Flowlayout() as a default.
public Window() {
setLayout(new FlowLayout());
}
So your basically overwriting the layout to null as explained in the previous answer.Also if you plan to use different class and panels to add to a JFrame from different classes use a getter
class SomePanel{
public JComponent getPanel(){
return panel;
}
}
Then add to JFrame..
class MyFrame{
add(new SomePanel().getPanel());
}

Java Canvas doesn't resize correctly

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();
}
});
}
}

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.

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