I'm trying to make my program object oriented and I'm attempting to split it into several classes. The short version is that I want to paint different objects in 1 JFrame. So I created a class per object that I wanted to paint, defined the object in my method and then add them to my frame. The problem is that only the last component is painted in the frame. I tried adding the objects to a JPanel first but that doesn't seem to work.
trees1
public class trees1 extends JComponent{
public final ImageIcon pokemontree;
public trees1(){
ImageIcon poke = new ImageIcon("pokemontree.png");
Image image = poke.getImage(); // transform it
pokemontree = new ImageIcon(newimg); // transform it back
}
public void paintComponent (Graphics g){
Graphics2D g2 = (Graphics2D) g;
pokemontree.paintIcon(this,g2 , 100,200);
}
}
testing
// main program
public class testing {
public static void main(String[] args){
JFrame win = new JFrame();
win.setSize(600,400);
win.setTitle("Test");
win.setResizable(false);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
trees1 exo = new trees1();
Playerwalking p1 = new Playerwalking(1,2);
win.add(exo);
win.add(p1);
win.setVisible(true);
}
JFrame content pane default uses BorderLayout
The default content pane will have a BorderLayout.
For BorderLayout, the "add()" method always set to "CENTER" if you don't specify the location (NORTH/EAST/SOUTH/WEST/CENTER etc) of the components you adding.
You need to specify your "getPreferredSize()" in your component, also understand how to use the BorderLayout (or other layout manager properly).
public class Test1 extends JFrame {
public static void main(String[] args) throws Exception {
JFrame win = new JFrame();
win.setSize(600,400);
win.setTitle("Test");
win.setResizable(false);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
win.add(new trees1(), BorderLayout.CENTER);
win.add(new trees1(), BorderLayout.SOUTH);
win.add(new trees1(), BorderLayout.EAST);
win.pack();
win.setVisible(true);
}
}
class trees1 extends JComponent {
public final ImageIcon pokemontree;
public trees1(){
ImageIcon poke = new ImageIcon("c:\\temp\\2.png");
Image image = poke.getImage(); // transform it
pokemontree = new ImageIcon(image); // transform it back
}
#Override
public Dimension getPreferredSize() {
return new Dimension(pokemontree.getIconWidth(), pokemontree.getIconHeight());
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
pokemontree.paintIcon(this,g2 , 0,0);
}
}
Related
So in the past few days I've tried to implement an easier version of a graph plotter.
One big problem I was confronted with was a bug that occured on repainting.
Basically I've designed my program in one class which is responsible for drawing the whole coordinate system and the given function after clicking a JButton in an other class. The other class contains the JButton which is pressed. After pressing the JButton it calls a function in the coordinate system class which repaints the picture. Both of those classes are extending JPanel.
The bug was that when I was doing the repainting on pressing the button, the button was drawn on the coordinate System and not in its original place, so in other words on the other JPanel even though I didn't change a thing about placements and stuff. Both classes were added to a JFrame which use a GridLayout.
Can anyone tell me why super.paintComponent(g); solved that bug?
Edit: Added Code
Window class
public class main {
public static void main(String[] args) throws SemanticFailureException {
int x = 800;
int y = 600;
JFrame frame = new JFrame();
frame.setLayout(new GridLayout());
frame.setTitle("Function plotter");
frame.setSize(2*x, 2*y);
Surface test = new Surface(x, y, 10);
CommandDraw test1 = new CommandDraw(x/2,y,test);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(test);
frame.add(test1);
frame.setVisible(true);
}
}
Coordinate System class: (changed drawing the coordinate system to a rectangle for simplicity, the bug still occures with only drawing a rectangle)
public class Surface extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
boolean drawFunct;
public Surface(int x1, int y1, int coordLength) {
setSize(x1,y1);
drawFunct = false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // without this the jbutton occures on the left
// create Graphics object to get more functions
Graphics2D g2 = (Graphics2D) g;
// draw Plotter
drawFunction(g2);
if (drawFunct)
g2.drawLine(0, 0, 80, 80);
}
public void drawFunction(Graphics2D g) {
g.drawRect(40, 40, 30, 30);
}
public void redraw() {
drawFunct = true;
repaint();
}
}
The Class with the JButton:
public class CommandDraw extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton makeDraw;
JTextField inputPoly;
Surface surf;
public CommandDraw(int x, int y, Surface surf) {
this.surf = surf;
setSize(x,y);
setLayout(new FlowLayout());
makeDraw = new JButton("draw Function");
makeDraw.setBackground(Color.LIGHT_GRAY);
makeDraw.setFocusable(false);
makeDraw.addActionListener( new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
surf.redraw();
}
});
add(makeDraw);
inputPoly = new JTextField("Input polynomial");
inputPoly.setHorizontalAlignment(JTextField.CENTER);
add(inputPoly);
}
}
Can anyone tell me why super.paintComponent(g); solved that bug?
Because the call to paintComponent(g) of the superclass (JPanel) will guarantee that panel will be rendered as expected before you do your paint operations. You need to make sure that your JPanel will behave, in the Graphics perspective, like any other JPanel.
A template for a customized JPanel to draw should be something like:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class MyDrawPanel extends JPanel {
#Override
protected void paintComponent( Graphics g ) {
super.paintComponent( g );
// create a new graphics context based on the original one
Graphics2D g2d = (Graphics2D) g.create();
// draw whatever you want...
g2d.dispose();
}
}
EDIT
You need to call super.paintComponent(g) to tell that the JPanel paintComponent(Graphics) version should be execute before you start doind your customized things. It's something like to ask the JPanel to prepare its paint capabilities to be used. A good starting point to these kind of doubts is the documentation: https://docs.oracle.com/javase/10/docs/api/javax/swing/JComponent.html#paintComponent(java.awt.Graphics)
The dispose() method is being called in the copy of the original Graphics. If you dispose the Graphics that is passed to the method, you may have some issues too. You could use the original Graphics to perform you painting operations, but you shouldn't, so a better practice is to make a copy of the original Graphics and dispose it after using.
Take a look here too: How does paintComponent work?
How would I add the backgroung image to my JPanel without creating a new class or method, but simply by inserting it along with the rest of the JPanel's attributes?
I am trying to set a JPanel's background using an image, however, every example I find seems to suggest extending the panel with its own class.
I have been looking for a way to simply add the image without creating a whole new class and within the same method (trying to keep things organized and simple).
Here is an example of the method that sets my JPanel:
public static JPanel drawGamePanel(){
//Create game panel and attributes
JPanel gamePanel = new JPanel();
Image background = Toolkit.getDefaultToolkit().createImage("Background.png");
gamePanel.drawImage(background, 0, 0, null);
//Set Return
return gamePanel;
}
I am trying to set a JPanel's background using an image, however, every example I find seems to suggest extending the panel with its own class
yes you will have to extend JPanel and override the paintcomponent(Graphics g) function to do so.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bgImage, 0, 0, null);
}
I have been looking for a way to simply add the image without creating a whole new class and within the same method (trying to keep things organized and simple).
You can use other component which allows to add image as icon directly e.g. JLabel if you want.
ImageIcon icon = new ImageIcon(imgURL);
JLabel thumb = new JLabel();
thumb.setIcon(icon);
But again in the bracket trying to keep things organized and simple !! what makes you to think that just creating a new class will lead you to a messy world ?
Simplest way to set image as JPanel background
Don't use a JPanel. Just use a JLabel with an Icon then you don't need custom code.
See Background Panel for more information as well as a solution that will paint the image on a JPanel with 3 different painting options:
scaled
tiled
actual
As I know the way you can do it is to override paintComponent method that demands to inherit JPanel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // paint the background image and scale it to fill the entire space
g.drawImage(/*....*/);
}
The other way (a bit complicated) to create second custom JPanel and put is as background for your main
ImagePanel
public class ImagePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private Image image = null;
private int iWidth2;
private int iHeight2;
public ImagePanel(Image image)
{
this.image = image;
this.iWidth2 = image.getWidth(this)/2;
this.iHeight2 = image.getHeight(this)/2;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image != null)
{
int x = this.getParent().getWidth()/2 - iWidth2;
int y = this.getParent().getHeight()/2 - iHeight2;
g.drawImage(image,x,y,this);
}
}
}
EmptyPanel
public class EmptyPanel extends JPanel{
private static final long serialVersionUID = 1L;
public EmptyPanel() {
super();
init();
}
#Override
public boolean isOptimizedDrawingEnabled() {
return false;
}
public void init(){
LayoutManager overlay = new OverlayLayout(this);
this.setLayout(overlay);
ImagePanel iPanel = new ImagePanel(new IconToImage(IconFactory.BG_CENTER).getImage());
iPanel.setLayout(new BorderLayout());
this.add(iPanel);
iPanel.setOpaque(false);
}
}
IconToImage
public class IconToImage {
Icon icon;
Image image;
public IconToImage(Icon icon) {
this.icon = icon;
image = iconToImage();
}
public Image iconToImage() {
if (icon instanceof ImageIcon) {
return ((ImageIcon)icon).getImage();
} else {
int w = icon.getIconWidth();
int h = icon.getIconHeight();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(w, h);
Graphics2D g = image.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
return image;
}
}
/**
* #return the image
*/
public Image getImage() {
return image;
}
}
Draw the image on the background of a JPanel that is added to the frame. Use a layout manager to normally add your buttons and other components to the panel. If you add other child panels, perhaps you want to set child.setOpaque(false).
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;
public class BackgroundImageApp {
private JFrame frame;
private BackgroundImageApp 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;
}
private void show() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private Component createContent() {
final Image image = requestImage();
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
for (String label : new String[]{"One", "Dois", "Drei", "Quatro", "Peace"}) {
JButton button = new JButton(label);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(Box.createRigidArea(new Dimension(15, 15)));
panel.add(button);
}
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private Image requestImage() {
Image image = null;
try {
image = ImageIO.read(new URL("http://www.johnlennon.com/wp-content/themes/jl/images/home-gallery/2.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BackgroundImageApp().create().show();
}
});
}
}
class Logo extends JPanel
{
Logo()
{
//code
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
ImageIcon img = new ImageIcon("logo.jpg");
g.drawImage(img.getImage(), 0, 0, this.getWidth(), this.getHeight(), null);
}
}
INITIALIZE YOUR JPANEL AS BELOW. NOTE THE MISSING SEMICOLON.. INSTEAD OPEN A CURLY BRACE THEN OVERRIDE THAT METHOD.. THIS WAY YOU DON'T HAVE TO EXTEND TO ANYTHING
ImageIcon img = new ImageIcon("background.jpg");
JPanel panel1 = new JPanel()
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(img.getImage(), 0, 0, null);
}
};
public demo1() {
initComponents();
ImageIcon img = new ImageIcon("C:\\Users\\AMIT TIWARI\\Documents\\NetBeansProjects\\try\\src\\com\\dd.jpeg"); //full path of image
Image img2 = img.getImage().getScaledInstance(mylabel.getWidth(), mylabel.getHeight(),1);
ImageIcon img3 = new ImageIcon(img2);
mylabel.setIcon(img3);
}
I have a problem with this following piece of code: the photo does not show in my JFrame...
Please help me.
My Java code:
public class ImageRead extends JFrame {
JPanel pan;
Image img1;
public ImageRead() throws IOException {
this.pan = new JPanel();
final Dimension d = new Dimension(500, 500);
this.img1 = ImageIO.read(new File("C:\\Users\\KHALED\\workspace\\"
+ "Universite Base De Donner\\src\\2.jpg"));
this.pan.setPreferredSize(d);
this.pan.add(new JButton("entre"));
this.pan.setBackground(Color.red);
this.getContentPane().add(this.pan);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setSize(500, 500);
this.setVisible(true);
this.setResizable(false);
}
public void paintComponents(final Graphics g) {
final Graphics2D g2 = (Graphics2D) g;
g.drawImage(this.img1, 0, 0, this.pan);
g2.finalize();
}
public static void main(final String[] args) throws IOException {
new ImageRead();
}
}
There are lots of problems with this, but probably the primary one is that you don't want to override paintComponent of the JFrame, you want to do that on the ContentPane. So create a JPanel derived class, and do that code in there, then call myframe.setContentPane(mypanel);
another issue is you don't want to call finalize() on g2
Chances are you want to use a classpath resource to load that image, rather than using File io.
You should probably use a proper layout and a real ImageIcon. Also, did you mean destroy(); instead of g2.finalize();?
How would I add the backgroung image to my JPanel without creating a new class or method, but simply by inserting it along with the rest of the JPanel's attributes?
I am trying to set a JPanel's background using an image, however, every example I find seems to suggest extending the panel with its own class.
I have been looking for a way to simply add the image without creating a whole new class and within the same method (trying to keep things organized and simple).
Here is an example of the method that sets my JPanel:
public static JPanel drawGamePanel(){
//Create game panel and attributes
JPanel gamePanel = new JPanel();
Image background = Toolkit.getDefaultToolkit().createImage("Background.png");
gamePanel.drawImage(background, 0, 0, null);
//Set Return
return gamePanel;
}
I am trying to set a JPanel's background using an image, however, every example I find seems to suggest extending the panel with its own class
yes you will have to extend JPanel and override the paintcomponent(Graphics g) function to do so.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bgImage, 0, 0, null);
}
I have been looking for a way to simply add the image without creating a whole new class and within the same method (trying to keep things organized and simple).
You can use other component which allows to add image as icon directly e.g. JLabel if you want.
ImageIcon icon = new ImageIcon(imgURL);
JLabel thumb = new JLabel();
thumb.setIcon(icon);
But again in the bracket trying to keep things organized and simple !! what makes you to think that just creating a new class will lead you to a messy world ?
Simplest way to set image as JPanel background
Don't use a JPanel. Just use a JLabel with an Icon then you don't need custom code.
See Background Panel for more information as well as a solution that will paint the image on a JPanel with 3 different painting options:
scaled
tiled
actual
As I know the way you can do it is to override paintComponent method that demands to inherit JPanel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // paint the background image and scale it to fill the entire space
g.drawImage(/*....*/);
}
The other way (a bit complicated) to create second custom JPanel and put is as background for your main
ImagePanel
public class ImagePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private Image image = null;
private int iWidth2;
private int iHeight2;
public ImagePanel(Image image)
{
this.image = image;
this.iWidth2 = image.getWidth(this)/2;
this.iHeight2 = image.getHeight(this)/2;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image != null)
{
int x = this.getParent().getWidth()/2 - iWidth2;
int y = this.getParent().getHeight()/2 - iHeight2;
g.drawImage(image,x,y,this);
}
}
}
EmptyPanel
public class EmptyPanel extends JPanel{
private static final long serialVersionUID = 1L;
public EmptyPanel() {
super();
init();
}
#Override
public boolean isOptimizedDrawingEnabled() {
return false;
}
public void init(){
LayoutManager overlay = new OverlayLayout(this);
this.setLayout(overlay);
ImagePanel iPanel = new ImagePanel(new IconToImage(IconFactory.BG_CENTER).getImage());
iPanel.setLayout(new BorderLayout());
this.add(iPanel);
iPanel.setOpaque(false);
}
}
IconToImage
public class IconToImage {
Icon icon;
Image image;
public IconToImage(Icon icon) {
this.icon = icon;
image = iconToImage();
}
public Image iconToImage() {
if (icon instanceof ImageIcon) {
return ((ImageIcon)icon).getImage();
} else {
int w = icon.getIconWidth();
int h = icon.getIconHeight();
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gd.getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(w, h);
Graphics2D g = image.createGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
return image;
}
}
/**
* #return the image
*/
public Image getImage() {
return image;
}
}
Draw the image on the background of a JPanel that is added to the frame. Use a layout manager to normally add your buttons and other components to the panel. If you add other child panels, perhaps you want to set child.setOpaque(false).
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;
public class BackgroundImageApp {
private JFrame frame;
private BackgroundImageApp 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;
}
private void show() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private Component createContent() {
final Image image = requestImage();
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
for (String label : new String[]{"One", "Dois", "Drei", "Quatro", "Peace"}) {
JButton button = new JButton(label);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(Box.createRigidArea(new Dimension(15, 15)));
panel.add(button);
}
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private Image requestImage() {
Image image = null;
try {
image = ImageIO.read(new URL("http://www.johnlennon.com/wp-content/themes/jl/images/home-gallery/2.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new BackgroundImageApp().create().show();
}
});
}
}
class Logo extends JPanel
{
Logo()
{
//code
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
ImageIcon img = new ImageIcon("logo.jpg");
g.drawImage(img.getImage(), 0, 0, this.getWidth(), this.getHeight(), null);
}
}
INITIALIZE YOUR JPANEL AS BELOW. NOTE THE MISSING SEMICOLON.. INSTEAD OPEN A CURLY BRACE THEN OVERRIDE THAT METHOD.. THIS WAY YOU DON'T HAVE TO EXTEND TO ANYTHING
ImageIcon img = new ImageIcon("background.jpg");
JPanel panel1 = new JPanel()
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(img.getImage(), 0, 0, null);
}
};
public demo1() {
initComponents();
ImageIcon img = new ImageIcon("C:\\Users\\AMIT TIWARI\\Documents\\NetBeansProjects\\try\\src\\com\\dd.jpeg"); //full path of image
Image img2 = img.getImage().getScaledInstance(mylabel.getWidth(), mylabel.getHeight(),1);
ImageIcon img3 = new ImageIcon(img2);
mylabel.setIcon(img3);
}
Good day.
I develop program which must show few shapes when user clicks the button. At least it doesn't show it. What is wrong?
Code is:
public class ShowFrame extends JFrame
{
public ShowFrame()
{
this.setTitle("Show data"); //Title
this.setSize( DEF_WIDTH, DEF_HEIGHT ); //Size of frame
this.setResizable(false);
//...
JButton testButton = new JButton("Test");
buttonPanel.add(testButton);
this.add(buttonPanel, BorderLayout.SOUTH);
testButton.addActionListener( new ActionListener() { //Add listener
public void actionPerformed(ActionEvent e) {
DrawStuff stuff = new DrawStuff(); //Create class which draws shapes
add(stuff, BorderLayout.CENTER);
System.out.println("Test Button");
}
} );
}
public static final int DEF_WIDTH = 600;
public static final int DEF_HEIGHT = 400;
private JPanel buttonPanel = new JPanel();
}
Class which draws shapes:
public class DrawStuff extends JComponent
{
public void paintComponent( Graphics g )
{
Graphics2D g2 = (Graphics2D) g;
//...
Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
Line2D line = new Line2D.Double(leftX, topY, 0, 0);
//...
g2.draw(rect);
g2.draw(line);
//...
}
}
When you add/remove components on a visible GUI the code should be:
panel.add(...);
panel.revalidate();
panel.repaint();
Your design of adding a new panel every time you click a button is not a very good one.
Instead you should create a custom painting panel and override the paintComponent() method. Then when you click a button you invoke a method in your custom component to set the shape you want to draw. The paintComponent() method should be smart enought to paint the shape. Then you invoke repaint() on the panel.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.