Drawing Canvas on JFrame - java

I'm trying to draw simple shapes with Canvas, in this class I've set the painting
public class Game extends Canvas{
//FIELDS
public int WIDTH = 1024;
public int HEIGHT = WIDTH / 16 * 9;
//METHODS
public void start(){
Dimension size = new Dimension (WIDTH, HEIGHT);
setPreferredSize(size);
paint(null);
}
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillOval(100, 100, 30, 30);
}
}
And in this the Window
public class MainW {
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.start();
}
}
It works, but the JFrame is not adapting to the Canvas. I have to manually resize the window to see the objects. How can I pack it so that JFrame automatically encompasses the Canvas?
EDIT:
That's really weird. While frame.pack() is indeed essential, it's not enough.
What I did was change the start method and turn it into a constructor, like that:
public class Game extends Canvas{
//FIELDS
public int WIDTH = 1024;
public int HEIGHT = WIDTH / 16 * 9;
//METHODS
public void Game(){
Dimension size = new Dimension (WIDTH, HEIGHT);
setPreferredSize(size);
}
then, from the other class, Eclipse complained about calling the constructor directly(E.G. ga.Game), so I followed it's tip and changed to:
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.getName();
}
This way I achieve what I have in mind but I really don't know why I can't call the constructor.

I don't know what it is you're trying to do, but you should NEVER be calling paint and especially not pass it null.
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing for details about how painting works.
In order to get the window to size to you component, you need to provide it some important information.
While Window#pack is the method you are looking for, it will not help you unless you provide appropriate sizing hints.
In this case, you need to override the getPreferredSize method of you component and provide an appropriate size value. Window#pack will use this value to determine what size it needs to be in order to accommodate it.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestPaint {
public static void main(String[] args) {
new TestPaint();
}
public TestPaint() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillOval(100, 100, 30, 30);
}
}
}
The paint chain is very important and you should avoid breaking it at all coasts. Make sure you always call super.paintXxx or be prepared for some serious weirdness
Also may want to have a read of Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

Use java.awt.Window.pack (JFrame indirectly extends Window):
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents.
// ...
frame.add(ga);
frame.pack();
frame.setVisible(true);
// ...

After painting on canvas try repaint the JFrame
public static void main(String[] args) {
Game ga = new Game();
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(ga);
frame.setVisible(true);
ga.start();
//repaint here
frame.repaint();
}
Also note that:
frame.pack for fixing the size issue.
frame.revalidate sometimes help when adding or removing components in runtime.

Related

Java problems with gif in label

A gif that I tried to put into a JPanel isn't showing up after clicking the button that triggers it until I resize the window. When it does show up, it does not fit the JPanel and is not animated. I looked at several posts that dealt with this but I don't understand how to use them in my case.
/*
* Author: Raymo111
* Date: 13/04/2018
* Description: Wishes happy birthday to a special someone
*/
//Imports java GUI classes
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
// Main class with JFrame and ActionListener enabled
public class Happy_Birthday_GUI extends JFrame implements ActionListener {
// Class variables
private static JButton startButton = new JButton("CLICK TO START");
private static JPanel startPanel = new JPanel(), gifPanel = new JPanel();
private static Color blue = new Color(126, 192, 238), pink = new Color(255, 192, 203);
private static GridLayout grid1 = new GridLayout(1, 1);
// Constructor
public Happy_Birthday_GUI() {
// Initial screen
startButton.addActionListener(this);
startButton.setFont(new Font("Comic Sans MS", Font.PLAIN, 50));
startPanel.setLayout(grid1);
startPanel.add(startButton);
startPanel.setBorder(BorderFactory.createLineBorder(blue, 100));
startButton.setBackground(pink);
getContentPane().add(startPanel);
// Sets title, size, layout (grid 1x1), and location of GUI window (center)
setTitle("Happy Birthday from Dolphin");
setSize(840, 840);
setLayout(grid1);
setLocationRelativeTo(null);
setVisible(true);
}
// Main method
public static void main(String[] args) {
new Happy_Birthday_GUI();
}
// Action Performed method
public void actionPerformed(ActionEvent event) {
// Proceed to gif and song
if (startButton == event.getSource()) {
getContentPane().removeAll();
BufferedImage dolphin;
gifPanel.setLayout(grid1);
gifPanel.setBorder(BorderFactory.createLineBorder(pink, 100));
try {
dolphin = ImageIO.read(new File("C:\\Users\\raymo\\Pictures\\dolphin.gif"));
JLabel gifLabel = new JLabel(new ImageIcon(dolphin));
gifPanel.add(gifLabel);
} catch (IOException e) {
e.printStackTrace();
}
getContentPane().add(gifPanel);
}
}
}
Here is dolphin.gif. It's cute.
How do I get it to show up immediately after clicking the start button as an animated gif that fits the JPanel? Thanks in advance.
BufferedImage doesn't support painting animated Gifs, instead, you'll need to make use of Image (or preferably, ImageIcon).
This could then be applied directly to a JLabel, which will perform the animation operation itself.
animated gif that fits he JPanel?
Okay, that's a much more complex problem. One approach would be to convert the Gif to the required size, but needless to say, that's very, very complex.
A simpler solution might be to use a AffineTransform and scale the image to meet the requirements of the component itself. This would require a custom component, capable of calculating the scale and painting each frame of the image.
Luckily for you, JPanel is an ImageObserver, this means it's capable of painting the gif animation
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageIcon image;
public TestPane() {
image = new ImageIcon("/Users/swhitehead/Downloads/NbENe.gif");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 600);
}
#Override
protected void paintComponent(Graphics g) {
int imageWidth = image.getIconWidth();
int imageHeight = image.getIconHeight();
if (imageWidth == 0 || imageHeight == 0) {
return;
}
double widthScale = (double)getWidth() / (double)imageWidth;
double heightScale = (double)getHeight() / (double)imageHeight;
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(image.getImage(), AffineTransform.getScaleInstance(widthScale, heightScale), this);
g2d.dispose();
}
}
}
I tried to put into a JPanel isn't showing up after clicking the button
When you add (or remove) components from a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
The revalidate() is need to invoke the layout manager so the component is given a size.
is not animated.
Use a JLabel with an ImageIcon to display images. A JLabel will animated the gif.
When it does show up, it does not fit the JPanel and
You can try the Stretch Icon which is designed to fill the space available to the label.
I ended up doing:
gifPanel.add(new TestPane());
getContentPane().add(gifPanel);
revalidate();
repaint();
using camickr's revalidate and repaint, and MadProgrammer's TestPane class,
which worked very well to get the gif to animate, resize correctly and display immediately.

How does pack() work and what does it looks for [duplicate]

This question already has answers here:
Using Java pack() method
(3 answers)
Closed 7 years ago.
I was messing with some code and came across the pack method which is suppose to find the "optimum" size for a window. But when I tried to out it simply made a window as small as possible even though I drew a circle before calling pack(). Why is that? What elements does pack() look for? I also frequently have found code that uses both pack() and setSize() which Oracle explicitly says not to do. What is the point since they both set size?
Here is that part of the code incase it was me who did something wrong:
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 30, 30);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Extreme Pong");
Game game = new Game();
frame.add(game);
frame.pack();
}
Edit:
Apparently I either was not clear to most of you since the linked answer to the "duplicate" did not answer my question. The mad programmer did answer my question, so thank you to you.
pack makes use of the layout manager API and "asks" the frame's contentPane for it's preferredSize, this allows pack to "pack" the windows decorations around the content. You have to remember, a windows size includes the windows decorations, so a window of 800x600 will have a viewable which is noticeably smaller
If you add a component to the frame whose size is undefined (in the case of JComponent and JPanel which return a preferredSize of 0x0, the frame will be packed to its smallest possible size, not really what you want.
So, for example, something like...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.fillOval(10, 10, 30, 30);
g2d.dispose();
}
}
}
generates a window of 200x222 on my Mac, but the TestPane will be 200x200
You might also like to have a look at Laying Out Components Within a Container, Painting in AWT and Swing and Performing Custom Painting for some more details
Using .pack() and .setSize() no make sense, all depend which one is last one in the code but i recommendable use:
frame.setMinimumSize(new Dimension(x,y));
And please do not forget to add :
frame.setVisible(true);

Why doesnt my rectangle draw to the JFrame?

I'm trying to draw a rectangle in a window. The window is appearing, but not the rectangle, what am I doing wrong? Can someone just give me a simple explanation, thanks
import java.awt.Graphics;
import javax.swing.JFrame;
public class Moving{
public static void main (String[]args) {
Main();
drawShape(null);
}
public static void Main () {
JFrame frame= new JFrame () ;
frame.setVisible(true);
frame.setSize(400, 400);
}
public static void drawShape(Graphics g) {
g.drawRect(0, 0, 100, 100);
}
}
First off, there isn't much point to having 2 main methods, so it would be best to combine them. Second, you need a Graphics object in order to draw and you're passing null. What do you think will happen with (null graphic).draw()? You need to pass the graphic your frame is using.
public static void main (String[]args) {
JFrame frame= new JFrame ();
frame.setSize(400, 400);
Graphics g = frame.getGraphics();
drawShape(g);
frame.setVisible(true);
}

How to make a transparent jframe resizable?

Here is my code:
package trialruns;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TransparentFrame extends JFrame
{
JButton b1;
public TransparentFrame()
{
setTitle("Transparent Frame Demo");
setSize(400,400);
setLayout(new GridBagLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUndecorated(true);
setVisible(true);
setResizable(true);
setOpacity(0.4f);
}
public static void main(String args[])
{
new TransparentFrame();
}
}
The problem is if I setOpacity<1.0 i get an error :
The frame is decorated at java.awt.Frame.setOpacity(Frame.java:960)
And if I make do setUndecorated(true) then I cant resize the Jframe
I need to be able to resize a transparent JFrame
I also need to be able to access the folders under the transparent frame
I mean if the transparent window is sitting on the desktop and I want to open a particular folder placed under the window then I should be able to do so without the jframe getting minimized.
Is there any way to do this??
I searched online but couldn't find a suitable solution.
Resizing of the frame is handled by the frame itself. When you remove the Border decorations you lose the resizing functionality.
So, you need to manage the resizing of the frame yourself. Check out Component Resizer for a class that will allow you to resize any component.
The change to your code would be:
//setResizable(true); // not needed as this is the default anyway
setOpacity(0.4f);
new ComponentResizer( this );
But is it possible to keep the border opaque
Yes, but you will only get the Swing decorated Border, not the platform Border and decorations:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TransparentFrame2 extends JFrame
{
public TransparentFrame2()
{
setTitle("Transparent Frame Demo");
setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
setBackground( new Color(0, 0, 0, 0) );
setSize(400,400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String args[])
{
new TransparentFrame2();
}
}
Also it is still not possible to access the content behind the frame
Yes, but you need full transparency. If you don't use full transparency then the mouse event is passed to the frame, not the component underneath the frame.
If you what semi transparency then theoretically you could add a MouseListener to the frame to intercept the MouseEvent. Then you can make your frame invisible. Then you could use a Robot to generate a new MouseEvent which will now be dispatched to the screen. You would next to use the frames locationOnScreen(...) method to convert the mouse point from the frames coordinates. I have never tried this approach.
try this.. working for me..
import java.awt.*;
import static java.awt.GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT;
import javax.swing.*;
class TransparentFrame extends JFrame {
JButton b1;
public TransparentFrame() {
setTitle("Transparent Frame Demo");
setSize(400, 400);
setAlwaysOnTop(true);
setLayout(new GridBagLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
setResizable(true);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if (g instanceof Graphics2D) {
final int R = 255;
final int G = 255;
final int B = 255;
Paint p =
new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0),
0.0f, getHeight(), new Color(R, G, B, 0), true);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
};
setContentPane(panel);
JButton button = new JButton("Button");
setBackground(new Color(0,0,0,0));
panel.add(button);
}
public static void main(String args[]) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
boolean isPerPixelTranslucencySupported = gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
//If translucent windows aren't supported, exit.
if (!isPerPixelTranslucencySupported) {
System.err.println("PerPixel Translucency is not supported");
System.exit(0);
}
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TransparentFrame tw = new TransparentFrame();
tw.setVisible(true);
}
});
}
}
referenced from this

repaint() in Java [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Java GUI repaint() problem?
I write a Java code, but I have a trouble with GUI problem. When I add a component into JFrame object, then I call repaint() method in order to update the GUI but it doesn't work. But when I minimize or resize this frame, the GUI is updated.
Here is my code:
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(460, 500);
frame.setTitle("Circles generator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
String input = JOptionPane.showInputDialog("Enter n:");
int n = Integer.parseInt(input);
CircleComponent component = new CircleComponent(n);
frame.add(component);
component.repaint();
}
If you added JComponent to already visible Container, then you have call
frame.getContentPane().validate();
frame.getContentPane().repaint();
for example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(460, 500);
frame.setTitle("Circles generator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
String input = JOptionPane.showInputDialog("Enter n:");
CustomComponents0 component = new CustomComponents0();
frame.add(component);
frame.getContentPane().validate();
frame.getContentPane().repaint();
}
static class CustomComponents0 extends JLabel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(200, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}
}
Simply write :
frame.validate();
frame.repaint();
That will do .
Regards
You're doing things in the wrong order.
You need to first add all JComponents to the JFrame, and only then call pack() and then setVisible(true) on the JFrame
If you later added JComponents that could change the GUI's size you will need to call pack() again, and then repaint() on the JFrame after doing so.
You may need to call frame.repaint() as well to force the frame to actually redraw itself. I've had issues before where I tried to repaint a component and it wasn't updating what was displayed until the parent's repaint() method was called.

Categories