so I am new to designing graphics in Java I was wondering if anyone could help me here. I have two classes and I want to display both of them at the same time in a JFrame. But only one or the other get displayed.
public class Tutorial extends JPanel implements ActionListener {
Background bc = new Background();
Timer tm = new Timer(5,this);
int x =0, velX = 2;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 30);
tm.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if(x<0 || x>550){
velX = -velX;
}
x = x+ velX;
repaint();
}
public static void main(String [] args){
Background bc = new Background();
Tutorial t = new Tutorial();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(600,400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
jf.add(bc);
}
My second class
public class Background extends Canvas {
public void paint(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(0,0,600,125);
g.fillRect(0,250,600,125);
g.setColor(Color.black);
g.fillRect(0,125,600,125);
}
For some reason I can only get either Background to be displayed or Tutorial?
Can anyone point me in the right direction or tell me where I am going wrong. I want to be able to display multiple things like these classes in the one window
The default layout manager of a JFrame is a BorderLayout.
By using the single-argument JFrame.add() function, you're adding both of the components to the BorderLayout.CENTER portion of your JFrame. This means that you'll only see one of the components.
The solution is to either use a different layout manager, or to add the components to different sections of your BorderLayout.
More info here: http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Related
I've been trying to make this work so that there are 20 boxes each with 3 different sizes and 3 different colours that chosen at random, but i cant make them come out at different times and they just glitch into eachother and the colours are glitching together and stuff like that, anyone know how to fix it? Heres what i got so far:
import java.awt.*;
import javax.swing.*;
public class testwork extends JPanel { //JPanel is a class
int l = 0;
private int x = 10;
private int y = 500;
private void move()
{
x++;
}
boolean red = false;
boolean blue = false;
boolean green = false;
#Override
public void paint(Graphics g) { //JPanel is a class defined in
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color rectColor = new Color(0, 66, 89);
g2d.setColor(rectColor);
//belt
g2d.setColor(Color.lightGray);
g2d.fillRect(0,450,1500,200);
g2d.fillRect(700,0,200,1000);
g2d.setColor(Color.orange);
for (int i = -10000; i<10000; i=i+50) {
int m= i++;
g2d.fillRect(m, 450, 25, 200);
}
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(700, 450, 200, 200);
//boxes
while (l<=20) {
if (Math.random() < 0.5)
{g2d.setColor(Color.RED);;}
else if (Math.random() < 0.5) {g2d.setColor(Color.GREEN);}
else {g2d.setColor(Color.BLUE);}
if (Math.random() < 0.5)
{g2d.fillRect(x,y,50,50);}
else if (Math.random() < 0.5) {g2d.fillRect(x,y,50,100);}
else {g2d.fillRect(x,y,100,50);}
l++;
}
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Frame"); //Add our JPanel to the frame
frame.add(new attempt());//instantiate a new object
frame.setSize(1500, 1000);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
testwork p = new testwork();
frame.add(p);
while (true)
{
p.move(); //Updates the coordinates
p.repaint();
Thread.sleep(10); //Pauses for a moment
}}
}
Unfortunately, you are doing a number of things incorrectly.
Override paintComponent and not paint.
Don't use Thread.sleep. Use a Swing timer and an ActionListener
You are doing too much in the painting method. All event handling including calls to repaint() is done on the Event Dispatch Thread(EDT). So all your updating are done inside of paintComponent so only the last painted objects will be shown when you exit. Update your coordinates, data structure and anything else that needs to be painted outside of your paint method.
Put your boiler plate code inside your Testwork class constructor. Here is an example.
public Testwork() {
setPreferredSize(new Dimension(1000, 700));
Timer timer = new Timer(0, this);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
// sizes the frame and jpanel and organizes the components.
frame.pack();
// centers the window in the screen
frame.setLocationRelativeTo(null);
// sets the delay in milliseconds
timer.setDelay(100);
// starts the timer
timer.start();
}
Here would be your actionListener code.
public void actionPerformed(ActionEvent ae) {
// update any variables that need to be used int he
// paint routine here. That means if you want to move something
// update the coordinates here and then use them in the paint method.
}
when you start up, your app, do it like this
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Testwork());
}
There is much more to painting. I recommend checking out Custom Painting in the Java tutorials. Here is another example on this (SO) site.
I'm absolutely stumped as to why Paint Component isn't running in this code:
public class GraphicsWindow extends JPanel {
public static final int Width = 1000, Height = 800;
GraphicsWindow(){
setPreferredSize(new Dimension(Width, Height));
}
public void PaintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.red);
for(int i = 0; i < Width/10; i++){
g.drawLine(i * 10, 0, i*10, Height);
}
System.out.println("paint ran");
}
}
Main function:
public static void main(String[] args) {
GraphicsWindow Graphics = new GraphicsWindow();
Graphics.setBackground(Color.green);
Graphics.setSize(1000, 800);
JFrame Window = new JFrame("Snake");
Window.add(Graphics);
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Window.setBounds(650, 200, 1200, 1000);
Window.setVisible(true);
Graphics.repaint();
}
I have been at it for about an hour looking at forum page after forum page and gotten nowhere. I can tell that it is the paint component not running because the console never gets the "Paint ran" printout. I am sorry ahead of time if it is a really stupid mistake and for the possibly messy code, I am a bit new to java.
Java names are case sensitive:
public void PaintComponent(Graphics g){
should be:
public void paintComponent(Graphics g){
When you override a method you should be using:
#Override
public void PaintComponent(Graphics g){
and the compiler will give you an error message when you don't override an existing method.
Variable names should NOT start with an upper case. Learn Java conventions by looking at examples and follow those examples.
Graphics.repaint();
There is no need for the repaint(). Swing will paint all the components when the frame is made visible.
Read the Swing Tutorial for Swing basics and working examples to get you started.
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?
I'm trying this very simple code. It runs but doesn't show the animation. I'm new to animations, so I don't know what I'm missing.
package sample;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Sample extends JPanel implements ActionListener {
Timer tm = new Timer(5, this);
int x = 0, Velx = 5;
public void paint(Graphics g) {
g.setColor(Color.RED);
g.fillRect(x, 30, 50, 50);
tm.start();
}
public void actionPerformed(ActionEvent e) {
x = x + Velx;
repaint();
}
public static void main(String[] args) {
Sample X = new Sample();
JFrame a = new JFrame();
a.setTitle("Rectangle RED");
a.setSize(500,500);
a.setVisible(true);
}
}
Sample X = new Sample();
X is never added to the frame. See first tip (the bold part) for how to add X to the frame.
Other tips:
Sample should #Override the getPreferredSize() method to return a sensible size for the canvas. Then we can dispense with a.setSize(500,500); and instead a.add(X); a.pack(); to get the frame to be the exact right size to display the rendering.
The Timer should be started in some place other than the paint methods! I'd go for the constructor.
Custom painting in any JComponent should be done in the paintComponent(Graphics) method.
In all custom painting, we should immediately call the super method to ensure that previous drawings are erased by painting the BG and border of the container.
Please learn common Java nomenclature (naming conventions - e.g. EachWordUpperCaseClass, firstWordLowerCaseMethod(), firstWordLowerCaseAttribute unless it is an UPPER_CASE_CONSTANT) and use it consistently.
JFrame a = new JFrame(); a.setTitle("Rectangle RED"); could be shortened to JFrame a = new JFrame("Rectangle RED");
Hi I am trying to get my program to move the shapes I create across the screen and for some reason its not working Im not sure whats happening? It has to be something small can anyone point me in the right direction.
public class MultipleObs extends JFrame {
private JPanel paintPanel;
public MultipleObs() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setMinimumSize(new Dimension(300, 300));
paintPanel = new PaintPanel();
getContentPane().add(paintPanel, BorderLayout.CENTER);
pack();
}
class PaintPanel extends JPanel implements ActionListener {
private java.util.List<Shape> shapes;
private Shape mouseOverShape=null;
int x=0, velX=2;
javax.swing.Timer tm = new javax.swing.Timer(5,this);
public PaintPanel(){
super();
shapes = new ArrayList<Shape>();
shapes.add(new Rectangle2D.Float(x,25,25,25));
shapes.add(new Ellipse2D.Float(x, 15, 60, 30));
shapes.add(new Ellipse2D.Float(x, 35, 60, 30));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (Shape s : shapes){
g2.draw(s);
}
tm.start();
}
#Override
public void actionPerformed(ActionEvent e) {
x = x+ velX;
repaint();
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MultipleObs().setVisible(true);
}
});
}
}
Two issues:
Do not ever start a Swing Timer inside of paintComponent. That method should be for painting and painting only. Instead start the Timer in the constructor.
When you create an Ellipse2D object, its position is fixed. Changing one of the variables used to create it will have no effect on the already created object.
A possible solution is to not use Ellipse2D's but instead draw ovals using Graphics#drawOval(...) inside of paintComponent and use the changing x field in that method call. If you must use Ellipse2D's, then you will need to translate them some way, perhaps by using an AffineTransform, but this way is a bit more complicated since I think that you'd have to wrap your Ellipse2D into a Path2D for this to work.
Another option: create a BufferedImage sprite, draw your complex shapes into the BufferedImage using a Graphics2D object obtained from the BufferedImage, and then draw that within paintComponent via drawImage(myImage, imageX, imageY, null), and change the imageX in your Timer.