Jframe with canvas and Jpanel layout - java

I'm just beginning on making a GUI for a lwjgl engine. I have a canvas on the left hand side and I want to have a JPanel on the right for previewing textures. However as you can see, the image is barely visible. I've tried different Borderlayouts, trying to resize etc.. However I think I'm just doing something fundamentally wrong.
My panel class
public class Panel extends JPanel {
BufferedImage image;
public Panel(){
try {
image = ImageIO.read(new
File("C:/Users/tom/Desktop/raj/Jtest/src/AWT/house.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
// super.paint(g);
g.drawImage(image,0, 0, null);
}
and here is how I'm trying to implement it.
public static void main(String[] args)
{
Panel panel = new Panel();
UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
JFrame frame = new JFrame("World Editor");
frame.setLayout(new BorderLayout());
final Canvas canvas = new Canvas();
button1.setSize(100, 100);
button1.setLocation(600, 10);
button1.setText("Test");
canvas.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{ canvas.setSize(800, 600);
newCanvasSize.set(canvas.getSize());
}
});
frame.setBackground(Color.black);
frame.add(button1);
frame.add(panel,BorderLayout.EAST);
frame.getContentPane().add(canvas,BorderLayout.CENTER);
try {
Display.setParent(canvas);
Display.setVSyncEnabled(true);
frame.setPreferredSize(new Dimension(1600, 1400));
frame.setMinimumSize(new Dimension(800, 600));
frame.pack();
frame.setVisible(true);
Display.create();
etc...
the setup should of been like this http://i.imgur.com/Zitizdx.png
ePanel panel = new ePanel(0, 0);
UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
JFrame frame = new JFrame("World Editor");
frame.setLayout(new BorderLayout());
canvas = new Canvas();
canvas.setSize(1200, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
button1.setSize(100, 100);
button1.setText("TEST");
frame.add(button1);
frame.add(canvas,BorderLayout.WEST);
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

Do you already tried to set the image for a background label and resize it? Something like this:
http://www.java2s.com/Code/Java/Swing-JFC/Labelbackgroundiconalign.htm

Don't use a Canvas. That is an AWT class and you should not mix AWT components in a Swing application. I'm not sure what the point of the Canvas is, but you should probably be using a JPanel.
Don't call you class "Panel". There is an AWT class with that name already. Class names should be more descriptive.
In fact, don't even create a custom class. Just use a JLabel with an ImageIcon to display the image. I'm guessing the problem is that you didn't override the getPreferredSize() method of the "Panel" class so the size is (10, 10) by default which is the size the panel will have because you are using a FlowLayout. So either use a JLabel (easy solution) or implement the getPreferredSize() method to reflect the size of the image.

Set a GridLayout to the JFrame new GridLayout(0, 2)
http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html
That way, the JFrame has left and right side. Then create and add two JPanels to the Jframe. Do not forget resize the panels and the frame.
After that, create a label, set to it an icon image, resize it and add it to the right panel.

Related

Set margin about a JPanel of GridLayout in Swing

I'm trying to setup the margin about the JPanel that it has inside the GridLayout refer to the JFrame, but I don't found the solution using other answer. I don't know if it's important problem, but also it show only the first button before I go to each button with mouse.
The image is an example, I want to setup the JPanel to start from the corner of the grid of image, because the image has a border (not from code, but from decoration board), the blue squares are the button inside the GridView, but I'm trying to fit the gridView to the image draw grid, using the set property (using proportion of pixel).
public class Gui extends JPanel implements View {
private final JPanel gui = new JPanel(new BorderLayout(3, 3));
private JButton[][] chessBoardSquares = new JButton[5][5];
private JPanel chessBoard;
private ImageIcon ArrayWithoutPlayer[] = new ImageIcon[7]; //{1,2,3,4,10,11,12}
private ImageIcon ArrayWithPlayer[] = new ImageIcon[3]; //{1,2,3}
private JFrame frame; //This is the whole frame
public Gui() {
createAndShowGUI();
}
private void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("TextDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window.
frame.setSize(800, 800);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
//frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
//frame.pack();
frame.getContentPane().add(new ImagePanel( setImageIconFromUrl("/home/amministratore/Documenti/Java/ing-sw-2020-palini-rigutti-vangi/image/SantoriniBoardR.png",800,800).getImage()));
chessBoard = new JPanel(new GridLayout(0, 5));
chessBoard.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
//chessBoard.setLayout(new BoxLayout());
//chessBoard.setPreferredSize(new Dimension(400, 100));
chessBoard.setBackground(Color.blue);
//chessBoard.setAlignmentX((float) (2.2/21)*frame.getWidth());
//chessBoard.setAlignmentY((float) (2.2/21)*frame.getHeight());
//chessBoard.setMaximumSize(new Dimension((16/21)*frame.getWidth(),(16/21)*frame.getHeight()));
//chessBoard.setAlignmentX(JLabel.LEFT_ALIGNMENT);
//chessBoard.setBorder(new LineBorder(Color.BLACK));
Insets buttonMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < chessBoardSquares.length; ii++) {
for (int jj = 0; jj < chessBoardSquares[ii].length; jj++) {
JButton b = new JButton();
b.setMargin(buttonMargin);
b.setBorder(null);
b.setBorderPainted(false);
b.setContentAreaFilled(false);
b.setOpaque(false);
chessBoardSquares[ii][jj] = b;
b.setText("AA");
chessBoard.add(chessBoardSquares[ii][jj]);
}
}
//chessBoard.setOpaque( false );
chessBoard.setBackground(new Color(255,0,0,0));
frame.dispose();
frame.add(chessBoard);
frame.setVisible(true);
//chessBoardSquares[0][0].setIcon( ArrayWithoutPlayer[0]); //This is the method to set Icon inside the button
}
}
I'm trying to setup the margin about the jpanel that it has inside the GridLayout
//b.setMargin(buttonMargin);
//b.setBorder(null);
//b.setBorderPainted(false);
I don't think you need all that code.
Instead just set the Border of the button:
b.setBorder( new EmptyBorder(5, 5, 5, 5) );
Edit:
frame.getContentPane().add(new ImagePanel(...));
…
frame.add(chessBoard);
First of all frame.getContentPane().add(…) and frame.add(…) is the same thing. That is the component will be added to the content pane. The second format is just a shortcut for the first.
So you are attempting to add two components to the BorderLayout.CENTER. This will not work as the BorderLayout will only support a single component in any location.
Swing was designed with a parent/child relationship so it appears you want something like:
JFrame (content pane)
ImagePanel
chessBoard
So your logic should be something like:
ImagePanel background = new ImagePanel(…);
background.setLayout( new BorderLayout() );
background.add(chessPanel, BorderLayout.CENTER);
frame.add(background, BorderLayout.CENTER);
Now you have your parent/child relationship between the components.
frame.setSize(800, 800);
Don't set the size of the frame. (800, 800) is the wrong size. If your ImagePanel is (800, 800) then the frame must be bigger because the frame also includes the title bar and the border.
So instead your logic should be:
frame.pack();
frame.setVisible(true);
The pack() method will allow the frame to determine its own preferred size AFTER all the components have been added to the frame.
Note:
In you ImagePanel class you will also need to implement the getPreferresSize() method of your Image. This will allow the pack() method to work properly. Read the section from the Swing tutorial on Custom Painting for a working example.

How do you make it so that a button doesn't interfere with the location of drawn shape?

So basically when I add a button it essentially pushes the black rectangle drawn in this program down, putting it out of its given location. How would you fix this?
import javax.swing.*;
import java.awt.*;
public class Grid {
public class homeGraphics extends JComponent {
homeGraphics() {
setPreferredSize(new Dimension(450, 600));
}
public void paint(Graphics g) {
super.paint(g);
g.fillRect(200, 275, 50, 50);
}
}
public void homeFrame() {
JFrame frame1 = new JFrame();
frame1.setSize(450, 600);
frame1.setResizable(false);
frame1.setDefaultCloseOperation(frame1.EXIT_ON_CLOSE);
JButton playButton = new JButton("Play");
playButton.setPreferredSize(new Dimension(60, 30));
JPanel panel1 = new JPanel();
panel1.add(playButton);
panel1.add(new homeGraphics());
frame1.add(panel1);
frame1.setVisible(true);
}
public static void main(String args[]) {
Grid frame = new Grid();
frame.homeFrame();
}
}```
it essentially pushes the black rectangle drawn in this program down, putting it out of its given location.
What do you mean out of its location? Painting is always done relative to the component. So your painting will always be done at (200, 275) of the component.
If you are attempting to paint at (200, 275) relative to the "frame", then don't. That is NOT how painting works.
Other problems with your code:
Don't attempt to set the size of your frame. If the custom panel is (450, 600) how can the frame possibly be the same size? The frame also contains the "title bar" and "borders". Instead of using setSize(), you invoke frame.pack()just beforeframe1.setVisible(….)`.
Class names start with an upper case character. Learn by example. Have you ever seen a class name in the JDK that doesn't start with an upper case character?
Custom painting is done by overriding paintComponent(…), not paint().
By default a JPanel uses a FlowLayout. So what you see it the button on one line and then the "HomeGraphics" class is too big to fit on the same line so it wraps the to the second line.
You should be more explicit when you do frame layout. So your code should be something like:
JPanel wrapper = new JPanel();
wrapper.add( playButton );
//JPanel panel1 = new JPanel();
//panel1.add(playButton);
//panel1.add(new homeGraphics());
JPanel panel1 = new JPanel( new BorderLayout() );
panel1.add(wrapper, BorderLayout.PAGE_START);
panel1.add(new HomeGraphics(), BorderLayout.CENTER);
Now the code shows your layout attempt more clearly.

Adding JPanel created on netbeans on top of to anotherJpanel created programatically

I have a panel that I am drawing some stuff on and I want to have an interface on top of it. I created an interface as a JPanel on netbeans, visually. But interface is not displayed properly.
Here is my code
public static void main(String[] args) {
JFrame frame = new JFrame("WorldGen");
Interface inter = new Interface();
JLayeredPane lpane = new JLayeredPane();
frame.setPreferredSize(new Dimension(600, 400));
frame.setLayout(new BorderLayout());
frame.add(lpane, BorderLayout.CENTER);
lpane.setBounds(0, 0, 600, 400);
lpane.add(panel, new Integer(0), 0);
lpane.add(inter, new Integer(1), 0);
panel.setBounds(0,0,600,400);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main = new Main();
}
Panel is declared as a static JPanel.
static JPanel panel = new JPanel()
Here is my result:
This is the Interface class that is created in netbeans visually
When I add this line:
inter.setBounds(0,0,600,400);
inter.setOpaque(true);
this is what I get:
Just a blank screen. I don't expect it to be transparent since I set it to opaque myself but It seems I have another problem. The button is not showing whether I set it to opaque or not.
Why is the button not showing? I am hoping that the button will still be visible when I set opaque to false, after I resolve this problem.
I've solved it by creating a JFrame in netbeans visually, adding a JPanel to it. Then using that panel(by overriding the paint method) to draw my image.

JPanel adding background

How to resize the inputpanel and gamepanel so it can take the whole frame? the inputpanel.setsize() wont work and the other problem is that the gamepanel wont display its background image.
what I did is I added a mainpanel to the frame that contains the other 2 panel the inputpanel and the gamepanel. Both panels displays with their borders but the size is very small and I needed them to fit the screen
public class GameMaster {
JFrame frame = new JFrame();
JPanel gamepanel = new Gamepanel();
JPanel mainpanel = new JPanel();
JPanel inputpanel = new JPanel();
JButton button1 = new JButton("Hoy!");
public GameMaster(){
frame.setTitle("gayEdward vs Charlie's angels");
frame.setSize(800,600);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setLayout(new FlowLayout());
gamepanel.setSize(600, 600);
inputpanel.setSize(200, 600);
mainpanel.setSize(800, 600);
gamepanel.setBorder(BorderFactory.createLineBorder(Color.black));
inputpanel.setBorder(BorderFactory.createLineBorder(Color.black));
mainpanel.setLayout(new FlowLayout());
mainpanel.add(gamepanel);
mainpanel.add(inputpanel);
frame.add(mainpanel);
}
This is the Gamepanel class where The Gamepanel should set the image as its background
public class Gamepanel extends JPanel {
Image image;
public Gamepanel(){
try
{
image = ImageIO.read(getClass().getResourceAsStream("C:\\Users\\phg00159\\workspace\\Mp2\\pvzbg.jpg"));;
}
catch (Exception e) { /*handled in paintComponent()*/ }
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0,0,this.getWidth(),this.getHeight(),this);
}
}
You need to override getPreferredSize() in the GamePanel class. You should always do this when doing custom painting. The panel has no preferred size because it has no components. And the layout you are using FlowLayout takes the preferred size into consideration. Then just pack() the frame, instead of setting the size. Also note that setSize() for components is generally used for null layouts (which I strongly am against). With layout managers, they are determine by preferredSize
public class GamePanel extends JPanel {
private Image image;
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(this), image.getHeight(this));
// or whatever you want the size to be
}
}
Aside:
/*handled in paintComponent()*/ - A null check isn't a substitute for an empty catch block.
frame.setVisible() should the last thing you do after adding all your components
UPDATE
As #MadProgrammer pointed out to me, you want the panel to resize with the frame. In order to do that, you need to use a different layout manager. The two that won't respect the preferred size of your panels will be either GridLayout or BorderLayout. These will "stretch your components to fit". So choose one of them, or a combination of both, seeing as you have nested panels. But you should also keep the overriden getPreferredSize() and still pack() your frame This will give you the initial size of the frame, based on your preferred size

Java Swing Application - buttons do not appear if resizable is set to false

I have the following code. Class KochSnowflakesMenu is a grid JPanel with three buttons. Class KochSnowflakesDraw currently draws a circle using drawOval:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakes
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.repaint();
}
}
This works if I comment out frame.setResizable(false). When I don't the buttons don't appear. Why is that? As you can see, I have tried using repaint(). I had previously the problem that the buttons would not show up until I manually resized the window...
Also, as a bonus question, if anyone can tell me how to get the dimensions of a JPanel that would be great. The reason why I can't use a resizable layout manager such as BorderLayout, which really is what I want to use, is that I can't figure out the dimension of the JPanel that occupies the center (and hence have no idea how to large to draw the things I'm drawing).
EDIT:
As requested, here is the KockSnowflakesMenu class:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesMenu extends JPanel
{
public KochSnowflakesMenu()
{
setLayout(new GridLayout(3,1));
setBounds(0,0,200,400);
JButton button_red = new JButton("Red");
JButton button_yellow = new JButton("Yellow");
JButton button_blue = new JButton("Blue");
add(button_red);
add(button_yellow);
add(button_blue);
}
}
And, just to be sure I didn't mess something up with KochSnowflakesDraw, here's that class as well:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesDraw extends JPanel
{
public KochSnowflakesDraw()
{
setLayout(null);
setBounds(200, 0, 400, 400);
}
public void paintComponent(Graphics g)
{
g.setColor(Color.RED);
g.drawOval(0,0,400, 400);
}
}
A general point, when using JFrame, you should be using the contentPane, rather than the JFrame itself, so to add items, try
frame.getContentPane().add(.....);
For your first question, try using pack on your JFrame.
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Window.html#pack()
For your bonus question, JComponent has a getWidth and getHeight method. This will tell you the current size of the JPanel.
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JComponent.html#getWidth()
Adding more info to the previous answers...
The size is random until the component is drawn so make sure you have a setVisible(true) on your frame. Here's your code w/some modifications that let you use the BorderLayout and get the size of your drawing panel. I substituted some fake buttons for your interfaces but you'll get the drift.
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout());
buttons.add(new JButton("MENU"));
buttons.add(new JButton("DRAW"));
frame.add(buttons, BorderLayout.SOUTH);
JPanel drawArea = new JPanel();
drawArea.setBackground(Color.BLUE);
frame.add(drawArea, BorderLayout.CENTER);
frame.setVisible(true);
Dimension drawAreaDim = drawArea.getSize();
System.out.println(drawAreaDim);
When you add components to a visible frame the code should be something like:
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes required
Make sure you create your Swing objects on the Event Dispatch Thread (EDT). In your example you aren't, and that is often the candidate when you get weird, inconsistent behavior. Swing isn't thread-safe, and relies on creation and modification of Swing objects on the EDT.
To remedy, just wrap the contents of your main method in a SwingUtilities.invokeLater call like so:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.setVisible(true);
}
});
}
That will create your JFrame and other components on the EDT thread. Does that fix the inconsistent "it doesn't work most of the time" behavior?
Also, I prefer to call setVisible last...though it probably doesn't matter.

Categories