I am trying to put 2 JPanels in borderLayout. Such that, one JPanel will be of size pane1(600,600)and the other one would be pane2(200,600). I am hoping to pack them such that the big one would be on the left and other one would be on right.
I am setting the size of each jpane but it looks like both of them occupy the complete space and kind of overlap on each other.
I am a complete newbie here and have no clue what is going wrong. Any help is appreciated.
JFrame frame = new JFrame("Simple Graph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
int pane1_width = FRAME_WIDTH-200;//800-200
Pane1 myPlots = new Pane1(graph_panel_size, FRAME_HEIGHT);
frame.add(myPlots);
Pane2 simpleInfo = new Pane2(200,FRAME_HEIGHT);
frame.add(simpleInfo);
frame.pack();
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setResizable(false);
frame.setVisible(true);
This is a base frame class. For JPanel
public Pane2(int width,int height){
this.setSize(width,height);
Border blackline = BorderFactory.createTitledBorder("ola");
this.setBorder(blackline);
The other panel also has similar constructor. But both the Jpanels overlap each other and I cant place them separately.
The problem is that you are calling setSize(). When using LayoutManager's (which you should absolutely always do), using setSize/setBounds/setLocation is completely useless.
Additionnaly, calling setPreferredSize()/setMinimumSize/setMaximumSize is not recommended and can be counterproductive.
Either your component have a good reason to have a given size (because you are doing custom painting, for example), then you should override getPreferredSize, or you simply don't have to do anything, and only use an appropriate LayoutManager.
You can also check out the tutorial on LayoutManager of Oracle
See this example with overrides of getPreferredSize():
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestCustomPainting {
private static class MyTriangle extends JPanel {
private final int width;
private final int height;
public MyTriangle(int width, int height) {
this.width = width;
this.height = height;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillPolygon(new int[] { 0, getWidth(), 0 }, new int[] { 0, 0, getHeight() }, 3);
}
}
protected static void initUI() {
JFrame frame = new JFrame("test");
frame.add(new MyTriangle(200, 45), BorderLayout.EAST);
frame.add(new MyTriangle(85, 600), BorderLayout.WEST);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
NB: I must admit, there are more interesting to paint :-)
Related
what's the easiest way to have a drawing in a JPanel that resizes whenever the user resizes the JFrame?
I know that I can auto resize the panel with a BorderLayout but the drawings are not resized in this case. I am new to java and GUI programming and there are probably numerous solutions.
please give me a hint into the right direction to make e.g. the rectangle in
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawRect(20, 20, 100, 100);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
auto-resizing whenever the frame is resized.
Provide positions and sizes as a proportion of the width and height of the panel. Whenever the panel is resized, the rendering engine will schedule a call to the paintComponent() method and the rectangle will be drawn proportionally. E.G.
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class DrawRect extends JPanel {
#Override
protected void paintComponent(Graphics g) {
int w = getWidth();
int h = getHeight();
g.drawRect(w/10, h/10, w/2, h/2);
}
/* A custom component should give the layout manager hints as to
its preferred size. */
#Override
public Dimension getPreferredSize() {
return new Dimension(200,200);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
DrawRect panel = new DrawRect();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
frame.getContentPane().setLayout(new BorderLayout());
Insert the line before you add the component to the GUI.
You should study layoutmanagers, since it is a unique concept in Java.
Im trying to add a JScrollpane to my JPanel. The problem is that the scrollpane doesn't recognize that my drawing is outside the frame. So how do I add the JScrollpane correctly?
Main class:
public MainFrame() extends JFrame{
public MainFrame() {
Container container = getContentPane();
container(new BorderLayout());
container.add(new JScrollPane(new Drawing()));
setSize(1280,720);
setVisible(true);
}
Drawing class:
public class Drawing() extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawLine(10, 100, 30000, 10);
}
}
There are a couple of errors in your code, let's step through each of them:
You're extending JFrame, and you should avoid it, see: Extends JFrame vs. creating it inside the program for more information about it. You're actually not changing its behavior so it's not needed to extend it.
For your JScrollPane to show the whole line, you need to change your window's size to be the same size of your line (as shown in this answer by #MadProgrammer).
Related to point 2, avoid the use of setSize(...) and instead override getPreferredSize(): See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information
You forgot to call super.paintComponent(...) method in your paintComponent() method.
Related to points 2, 3, you need to call pack() so Swing calculates the best preferred size for your component.
See this example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LongDraw {
private JFrame frame;
private Drawing drawing;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LongDraw()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
drawing = new Drawing();
JScrollPane scroll = new JScrollPane(drawing);
frame.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Drawing extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(10, 100, 3000, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3000, 500);
}
}
}
Which produces something similar to this:
i am making a simple GUI in which small boxes should appear on the Jpanel according to their x,y coordinates. So i in my structure i have got three classes:
1: MyFrame which contains the main JFrame
2: MyPanel extends JPanel
3: Icon extends JComponent
In my MyFrame i want to have a MenuBar through which i can open a file of X,Y coordinates and below the menu bar i want to have the MyPanel which will have all the Icons for each X,Y coordinates. The first problem i have is that the Icon do not appear on MyPanel when i add the Icons.
My code can be seen below:
public class MyFrame {
private JFrame frame;
private MyPanel panel;
public MyFrame(){
panel = new MyPanel();
}
/*
*HERE GOES THE `FILE OPEN` LISTENER
* it creates `Coordinate` for each line
* passes the coordinate to panel.makeIcons()
*/
public void createGui(){
frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
//create, get and set the Jframe menu bar
//createMenuBar() returns a JMenuBar
frame.setJMenuBar(createMenuBar());
Container frame_pane = frame.getContentPane();
panel.setBounds(0, 0, frame.getWidth(), frame.getHeight());
frame_pane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
MyFrame window = new MyFrame();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
window.createGui();
}
});
}
}
Code For the panel for holding icons:
public class MyPanel extends JPanel{
private Set<Icon> points;
public MyPanel(){
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
}
}
Code for Icon which needs to be shown on the above panel:
public Icon extends JComponent{
private Coordinate location;
public Icon(Coordinate obj){
location = obj;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(location.getX(), location.getY(), 20, 20);
g.setColor(Color.BLACK);
g.drawRect(location.getX(), location.getY(), 20, 20);
}
}
First Problem: The Icons do not show up in the panel with the above code.
Second Problem: When i change the makeIcon method in MyPanel.class to below. It shows the Icons By the MenuBar erases them when the MenuBar appears on any of the icons:
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
temp.paintComponent(this.getGraphics());
revalidate();
}
Any help is appreciated. Thanks
Don't call paintComponent (or any paint) method yourself, ever. This is not how painting works.
The core reasons why a component won't be painted are because:
it's size is 0x0
it's invisible
it's not added to a container that is (indirectly) added to a native peer.
Based on my brief observation, I would say you're suffering from point number 1, in part due to the use of a null layout
Also, remember, when painting a component, the component's Graphics context has already been translated so that 0x0 is the top/left corner of the component. This means, based on your code, you'd most likely be painting beyond the visible bounds of the component any way.
So, you basically have two choices. Implement your own layout manager, which uses the Coordinate information to place the Icons with in the container (which would then need to override getPreferredSize in order to provide sizing hints) or, paint it yourself
Which might look something like this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(new MyPanel());
frame.pack();
frame.setVisible(true);
}
});
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class Icon {
private Coordinate coordinate;
public Icon(Coordinate coordinate) {
this.coordinate = coordinate;
}
public Coordinate getCoordinate() {
return coordinate;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, 20, 20);
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, 20, 20);
}
}
public class MyPanel extends JPanel {
private Set<Icon> points;
public MyPanel() {
points = new HashSet<>();
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj) {
points.add(new Icon(obj));
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Icon icon : points) {
Graphics2D g2d = (Graphics2D) g.create();
Coordinate coordinate = icon.getCoordinate();
// I'd have a size component associated with the Icon
// which I'd then use to offset the context by half its
// value, so the icon is paint around the center of the point
g2d.translate(coordinate.getX() - 10, coordinate.getY() - 10);
icon.paint(g2d);
g2d.dispose();
}
}
}
}
I've not seeded any values, I'm lazy, but that's the basic idea
Im trying to understand a Paint Graphics, but my oval can't be drawn. Can someone tell me what am I doing wrong and oval is not drawing?
Where did I make a mistake?
Main class:
import java.awt.EventQueue;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Frame frame = new Frame();
}
});
}
Frame class:
public class Frame extends JFrame {
private static final long serialVersionUID = 1L;
public static Grafika grafika;
public Frame() {
JFrame frame = new JFrame("Title");
grafika = new Grafika();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLayout(null);
// frame.addKeyListener(this);
frame.add(grafika);
}
}
And last Grafic class:
public class Grafika extends JComponent {
int x = 200;
int y = 200;
public void paint(Graphics g) {
Graphics2D oval = (Graphics2D) g;
oval.setColor(Color.BLACK);
oval.fillOval(x, y, 100, 100);
oval.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
}
Several issues, but the biggest is that you're using a null layout on your JFrame, and then adding a JComponent whose preferred size and size are both 0,0. So while you're adding your Grafika to the JFrame, it doesn't have a chance of being displayed.
Suggestions:
Never use null layout, except in very specific exceptional circumstances.
Give your Grafika component a preferred size, best by overriding getPreferredSize(), but at this stage, I think that it would be OK to call setPreferredSize(...) on it.
Add it to the JFrame, pack() the JFrame and then lastly, only after all components have been added to the JFrame, make it visible.
Also
You should be overriding paintComponent not paint
You should call the super painting method within your override.
Always use the #Override annotation when you think that you're overriding a parent method. You could be wrong, and you want the compiler to tell you.
Set the RenderingHints before drawing. Else the hints will have no effect on the drawing.
Avoid giving your classes names that clash with the names of core Java classes, such as Frame. This will potentially confuse others and your future self.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
public class MyGrafika extends JComponent {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color OVAL_COLOR = Color.RED;
private int ovalX = 200;
private int ovalY = 200;
private int ovalWidth = 100;
private int ovalHeight = 100;
public MyGrafika() {
setPreferredSize(new Dimension(PREF_W, PREF_H));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(ovalX, ovalY, ovalWidth, ovalHeight);
}
private static void createAndShowGui() {
MyGrafika mainPanel = new MyGrafika();
JFrame frame = new JFrame("MyGrafika");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Since you are using Swing you should override paintComponent and not paint, you should also take care using null layout. But the point is that you should have added your Grafika component before making the frame visible:
frame.add(grafika);
frame.setVisible(true);
// frame.setLayout(null); REMOVE THIS!
If you really need to add a component after the frame has been made visible, then you should call revalidate+repaint on the frame or the panel that contains the added component:
frame.setVisible(true);
// frame.setLayout(null); REMOVE THIS!
frame.add(grafika);
frame.validate();
frame.repaint();
I recently started with Java GUIs a few weeks ago and I have a difficulty with alignment.
Basically, I'm trying to have two Panels with a different background image (top Bar and content) and I want to align them one after another.
The problem is, that I can't use BorderLayout.NORTH and BorderLayout.SOUTH, because the background image loses his original size and gets very tiny.
How can I align them correctly, without losing the original size?
Here's my code:
package main;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageTest {
public static void main(String[] args) {
ImageFrame frame = new ImageFrame("topBar.png", "contentImage.png");
frame.setSize(640,480);
frame.setVisible(true);
}
}
class ImagePanel extends JPanel {
private Image img;
public ImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img) {
this.img = img;
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
class ImageFrame extends JFrame {
public ImageFrame(String topBar, String body) {
setLayout(new BorderLayout());
ImagePanel topPanel = new ImagePanel(topBar);
ImagePanel bodyPanel = new ImagePanel(body);
add(topPanel, BorderLayout.NORTH);
add(bodyPanel, BorderLayout.SOUTH);
pack();
}
}
There are a number of issues that popup out at me
You're not calling super.paintComponent. This is very important and can not be understated
You really should be using ImageIO to load your images. Ala from the fact it supports a wider range of image formats, it also loads images concurrent and throws useful exceptions when something goes wrong
You're not supplying any preferredSize values. This is used by the layout manager to decide how best to layout your component. Remember though, this are only hints and layout managers are well within there rights to ignore them
Check out Reading/Loading an Image for more details on ImageIO
..the background image loses his original size and gets very tiny.
That is because the preferred size for a panel is 0x0 until components are put in it.
There are at least two ways to solve this:
Add content to the panels.
Override getPreferredSize() to return the Dimension of the image.
The first is optimal, but I'll show how to do the 2nd (less code).
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageTest {
public static void main(String[] args) {
ImageFrame frame = new ImageFrame();
//frame.setSize(640,480);
frame.pack();
frame.setVisible(true);
}
}
class ImagePanel extends JPanel {
private Image img;
public ImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img) {
this.img = img;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// a panel IS an ImageObserver, so use it here.
g.drawImage(img, 0, 0, this);
}
#Override
public Dimension getPreferredSize() {
int w = img.getWidth(this);
int h = img.getHeight(this);
return new Dimension(w,h);
}
}
class ImageFrame extends JFrame {
public ImageFrame() {
setLayout(new BorderLayout(2,2));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
ImagePanel topPanel = new ImagePanel(new BufferedImage(200,20,BufferedImage.TYPE_INT_RGB));
ImagePanel bodyPanel = new ImagePanel(new BufferedImage(200,100,BufferedImage.TYPE_INT_RGB));
add(topPanel, BorderLayout.NORTH);
add(bodyPanel, BorderLayout.SOUTH);
pack();
}
}