Still trying to grasp how classes and methods work in Java. To experiment, I tried to create a graphics class, with a void draw box method inside. Then, I try to call that method in the main method to try to draw those boxes. I'm getting "cannot be resolved to variable" errors which I believe means the main class can't see my other class for some reason?
Boxymain.java:
import java.awt.*;
import javax.swing.JFrame;
public class Boxymain extends Canvas {
public static void main(String[] args){
BoxyMethod c = new BoxyMethod();
c.drawBox(window, Color.RED, 200, 300);
JFrame win = new JFrame("Boxy Main");
win.setSize(800,600);
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Boxymain canvas = new Boxymain();
win.add(canvas);
win.setVisible(true);
}
}
BoxyMethod.java:
import java.awt.*;
import javax.swing.JFrame;
public class BoxyMethod {
public void drawBox(Graphics window, Color c, int x, int y){
window.setColor(c);
window.fillRect(x, y, 100, 100);
window.setColor(Color.WHITE);
window.fillRect(x+10,y+10,80,80);
}
}
Error text: "window cannot be resolves to a variable."
The error message is telling you exactly what is wrong. You're passing in a window variable into the drawBox method, but you don't declare or initialize such a variable in the main method before doing so, and so this cannot be done in Java.
BoxyMethod c = new BoxyMethod();
// *** window variable below is used but never declared prior to use
c.drawBox(window, Color.RED, 200, 300);
More importantly though, you're not doing Swing drawing correctly.
Instead, you should create a class that extends JPanel, give it a paintComponent(Graphics g) method override, and draw in that method. Then place that JPanel in a JFrame and display the JFrame. Please check out the Performing Custom Painting Swing graphics tutorial for more detail on how to do Swing graphics.
As an aside, do not follow that tutorial that you've linked to as it is 30 years out of date.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class BoxyTest {
private static void createAndShowGui() {
JFrame frame = new JFrame("Boxy Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new BoxyPanel(200, 300));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class BoxyPanel extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private int myX;
private int myY;
public BoxyPanel(int myX, int myY) {
this.myX = myX;
this.myY = myY;
}
#Override // so my JPanel will be big enough to see
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
// call super method so that the JPanel can do housekeeping painting
super.paintComponent(g);
g.fillRect(myX, myY, 100, 100);
g.setColor(Color.WHITE);
g.fillRect(myX + 10, myY + 10, 80, 80);
}
}
Related
heres what my code looks like
import java.awt.*;
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
MyDrawPanel shape = new MyDrawPanel();
frame.getContentPane().add(shape);
frame.setSize(500,500);
frame.setVisible(true);
}
}
class MyDrawPanel extends JPanel{
public void paintComponent (Graphics g) {
g.setColor(Color.ORANGE);
g.fillRect(20, 50, 100, 100);
}
}
When I run it, the only thing that shows up is the frame, not the actual shape. Is there something I'm missing?
Note that this answer does not answer your direct question of why your posted code doesn't work, because while your code has problems, it should still display the square. But having said that, this post is meant to offer some suggestions on "better" practices:
Avoid magic values and magic numbers
Use #Override annotations for any method that you think is an override
The paintComponent method is protected, not public
Call the super's method in your override
Best to override getPreferredSize of the JPanel if you need to fix its size
Start the Swing GUI on the Swing event thread for thread-safety
Avoid hard-coding your graphic drawing positions, especially if you're thinking of animating it at a later date
This is a better representation of your code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class Test2 extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color RECT_COLOR = Color.ORANGE;
private static final int RECT_WIDTH = 100;
private static final int INIT_X = 20;
private static final int INIT_Y = 50;
private int rectX = INIT_X;
private int rectY = INIT_Y;
public Test2() {
// TODO any initialization code goes here
}
// override annotation
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// avoid magic values and numbers
g.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
}
// best way to set size safely
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Test2 mainPanel = new Test2();
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
// be sure to start the GUI on the event thread
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
package Main;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
I'm using Java's JFrame. So this isn't recognising the paint method and cant figure out why. I've been looking on YouTube videos and having a look to see if anyone has had similar problems, however everything I've found doesn't seem to help the problem.
when i set the background colour in the main part, it works, bit in paint, it doesn't seem to do anything and leaves it blank.
Its a white line over a black background, so i should easily be able to see it.
Admittedly, I don't know much about Swing (I prefer JavaFX). However, it's clear that your Main class is a JFrame, so you should not make a new one within it. All of those methods you call on display are built in your current class. Basically, within your JFrame you made a new JFrame. However, your paint method was being called on the parent JFrame, which you never made visible. This solves your problem (you may have to fullscreen the window):
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Main extends JFrame{
public static void main(String[] args) {
new Main();
}
public Main() {
int width = 800;
int height = 600;
String title = "Test";
setTitle(title);
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.WHITE);
g.drawLine(100, 100, 800, 300);
getContentPane().setBackground(Color.black);
}
}
You are creating an instance of JFrame with
JFrame display = new JFrame();
But the JFrame class has no logic to draw a white line on a black background. That logic is in your custom class Main. So instead, you should create an instance of Main:
JFrame display = new Main();
However, that change along still won't fix the problem because you are setting the background color of the "content pane" but trying to draw directly on the JFrame itself. The preferred solution here is to extend JPanel instead of JFrame and override its paintComponent() method. Then create an instance of your new class to use as the content pain:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainPanel extends JPanel{
public static void main(String[] args) {
int width = 800;
int height = 600;
String title = "Test";
JFrame display = new JFrame();
display.setTitle(title);
display.setSize(width, height);
display.setVisible(true);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setContentPane(new MainPanel());
}
public MainPanel() {
setBackground(Color.black);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.drawLine(0, 100, 800, 300);
}
}
Notes:
I call setBackground() in the constructor because it does not rely on the Graphics instance passed to paintComponent(). This also avoids the overhead of another function call for each render.
In paintComponent(), I call super.panitComponent(). This allows JPanel to clear the area to be painted and any other necessary initialization.
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 am trying to learn how to make a graphics program, but some of the methods in java AWT are giving me unexpected results.
I have made a window, and I place a rectangle and that works. I want another figure, a circle, to appear after 1 second. I have tried the wait(x) method, which just places the circle immediately, and now I have tried the Thread.sleep(x) method, which does work, however I get the following behaviour:
After one second, the circle is displayed on the screen, but after a split second it disappears again, and another split second later it reappears and stays on the screen. I don't want it to temporarily disappear. What am I doing wrong?
import java.awt.*;
class Example extends Canvas{
public static void main(String[] args){
Example graphicProgram = new Example();
Frame graphics = new Frame();
graphics.setSize(300, 300);
graphics.add(graphicProgram);
graphics.setVisible(true);
}
public Example(){
setSize(200, 200);
setBackground(Color.white);
}
public void paint(Graphics g){
g.fillRect(20, 150, 100, 100);
try{
Thread.sleep(1000);
} catch (Exception ex){
}
g.fillOval(150, 20, 100, 100);
}
}
Never call Thread.sleep from within a paint type of method. Doing this will make your GUI completely unresponsive.
Yes, do call the super painting method from within your painting method (as per muhammad's answer).
You should not call Thread.sleep(...) from the event thread either as this too will freeze your application.
You should skip doing AWT and move to Swing.
When you do so, do your drawing in the paintComponent(Graphics g) method of a JComponent or JPanel object.
Call the super's paintComponent(g) within your paintComponent method override.
Use a Swing Timer to do any delay or animation.
e.g.,
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class DrawFoo extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final Stroke BASIC_STROKE = new BasicStroke(3f);
private static final Color RECT_COLOR = Color.blue;
private static final Color OVAL_COLOR = Color.red;
private boolean drawCircle = false;
private int rectX = 20;
private int rectY = 150;
private int rectWidth = 100;
public DrawFoo() {
int delay = 1000;
Timer timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
drawCircle = true;
repaint();
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return 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.setStroke(BASIC_STROKE);
g2.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, rectWidth, rectWidth);
if (drawCircle) {
g2.setColor(OVAL_COLOR);
g.fillOval(rectY, rectX, rectWidth, rectWidth);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawFoo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawFoo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
put this line as the first statment in your paint method super.paint(g);
it will be good to place also Graphics2D g2 = (Graphics2D)g; after above statment to use the improved performance and extra methods offered by Graphics2D
I am working on the basics of a graphics program in swing and java2D to practice. I am having a problem wherein I cannot show my images. I have divided my code into 4 classes so that when the program gets larger it's easier to manage.
The idea is that I have very little in the Main, that Frame initializes my first screen, that the screens can all be subdivided into their own classes, TitleScreen being one of these, and PullImage does all of the work of buffering and printing images which bothered me.
When I run this I get an empty window and no errors, so I cannot figure out where the problem is.
Please and Thank you for your help.
Main
package com.game.pack;
import javax.swing.JFrame;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
public final static void main(String[] args)
{
new Frame().initialize();
new TitleScreen().openScreen();
}
}
Frame
package com.game.pack;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame{
private static final long serialVersionUID = 1L;
public final void initialize()
{
JFrame frame = new JFrame("Game");
JPanel panel = new JPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800,600);
panel.setSize(800,600);
frame.setLayout(null);
panel.setLayout(null);
frame.setLocationRelativeTo(null);
this.getContentPane().add(panel);
panel.setVisible(true);
frame.setVisible(true);
}
public final void close()
{
dispose();
}
}
TitleScreen
package com.game.pack;
public class TitleScreen {
public void openScreen()
{
new PullImage().printARGB("icons/titleBG.png",800,600,0,0);
new PullImage().printARGBFromSheet("icons/titleButtons.png",
200, 125, 400, 200, 200, 40, 0, 0);
while (1!=2)
{
}
PullImage
package com.game.pack;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
public class PullImage {
public void printARGB(String source, int sizeX, int sizeY, int locX, int locY)
{
Image Icon = new ImageIcon(source).getImage();
BufferedImage BuffedImage = new BufferedImage(sizeX, sizeY, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = BuffedImage.getGraphics();
graphics.drawImage(Icon,locX,locY,null);
}
public void printARGBFromSheet(String source, int sizeX, int sizeY, int locX, int locY, int width, int height, int sheetLocX, int sheetLocY)
{
Image Icon = new ImageIcon(source).getImage();
BufferedImage BuffedImage = new BufferedImage(sizeX,sizeY,BufferedImage.TYPE_INT_ARGB);
Graphics graphics = BuffedImage.getGraphics();
graphics.drawImage(Icon, locX, locY, locX+width, locY+height, sheetLocX, sheetLocY, sheetLocX+width, sheetLocY+height, null);
}
}
One problem lies here:
public final void initialize()
{
this.getContentPane().add(panel);
}
This is setting the content pane of your frame to the panel, not the JFrame you created. Essentially you're not adding it to the actual visible window. Just replace it with
frame.getContentPane().add(panel);