I have been experimenting with drawing on a JFrame, so I could use these experiments in the future for a program I might create. However, I have found a problem that I am not able to solve:
How to draw stuff while having a timer set up.
public static void MyTimer() {
JFrame frame = new JFrame("Colors");
int width = 700;
int height = 700;
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.pack();
frame.setSize(width, height);
frame.setVisible(true);
frame.setResizable(false);
TimerTask task;
task = new TimerTask() {
int a = 2;
#Override
public void run(Graphics g) {
g.drawRect(a, 2, a + 66, 68);
g.fillRect(a, 2, a + 66, 68);
a = a + 20;
}
};
timer.schedule(task, 0, 1000);
}
As you can see, I am trying to draw a new square every second. The problem is, I get an error in the code:
method does not override or implement a method from a supertype
How can I fix this?
How can I fix this?
The run() method does not take a parameter. Get rid of the Graphics parameter. That will get rid of the compile error.
However, that still will not help with your painting.
Instead you need to override the paintComponent(...) method of a JPanel then you add the panel to the frame. Then you use the Graphics object passed to the paintComponent() method to do your painting.
Read the section from the Swing tutorial on Custom Painting for more information and working examples to get you started.
Also you should NOT be using a TimerTask for animation. You should be using a Swing Timer. Then in the actionPerformed(...) method of the ActionListener you would change the properties of your custom painting (ie in your case add a new square object to be painted) and then invoke repaint() on the panel.
, I am trying to draw a new square every second
Check out the DrawOnImage example found in Custom Painting Approaches. It will show you how to add a Rectangle object to a BufferedImage.
Related
Why wil this not run.
Jframe isnt an option what can i use, and how come i have to have
graphics g as a component? as well as how is Graphics g set up as a parameter ?
class Tables{
public staic void main (String [] args){
Button mainscreen = new Button(Graphics g);
g.drawRect(10, 10, 50, 50);
}
}
will this work
No.
Read the section from the Swing tutorial on Custom Painting for working examples of how to do painting.
And yes you need a window of some kind (JFrame or JDialog) to display the panel.
If you don't want the borders then you can use an undecorated frame.
JFrame frame = new JFrame();
frame.setUndecorated(true);
I need a certain image to be redrawn at different locations constantly as the program runs. So I set up a while loop that should move an image across the screen, but it just redraws the image on top of itself over and over again. What am I doing wrong? Is there a way to delete the old image before drawing it in a new location?
JFrame frame = buildFrame();
final BufferedImage image = ImageIO.read(new File("BeachRoad_double_size.png"));
JPanel pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int num = 0;
boolean fluff = true;
while (fluff == true) {
num = num + 1;
g.drawImage(image, num, 0, null);
if (num == 105) {
fluff = false;
}
}
}
};
frame.add(pane);
You can't code a loop in the paintComponent() method. The code will execute so fast that the image will only be painted in the final position, which in your case should be with an x position of 105.
Instead you need to use a Swing Timer to schedule the animation every 100 milliseconds or so. Then when the timer fires you update the x position and invoke repaint() on the panel. Read the Swing tutorial on Using Swing Timers for more information.
Putting a while loop inside a paintComponent method is not the way to do it. Instead, there should be some setup like the following:
...
final int num = 0;
final JPanel pane;
Timer timer = new Timer(10, new ActionListener() {
public void actionPerformed(ActionEvent e) {
num++;
pane.repaint();
}
});
pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, num, 0, null);
}
});
timer.start();
This will move the image ever 10 milliseconds, as specified in the Timer constructor.
This is a common issue people starting out in animation have, as I did. You can't 'remove an image' from the screen. However, you can repaint the entire screen, then redraw your image at a new location.
In psuedocode:
while (condition)
background(white); //or whatever color your background is
drawImage(x,y);
The code above clears the screen so it's safe for you to redraw your image. This effectively 'deletes' your image.
Edit: I didn't read your code, I just addressed your question. So other answers that fix your code are probably better than mine.
I am trying to draw and paint some geometric shapes based on some calculations inside the paint() or paintComponent() methods. However, I realized that the printing and other calculation statements inside paint() or paintComponent() are executed 2 or sometimes 3 times. For example the print statement in the following code is executed twice and the word "help" is printed twice in the console:
public class Skeleton extends JPanel {
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawOval(50, 50, 100, 100);
System.out.println("help");
}
and then in the console the printed part is like this:
help
help
and here is my main() method
public static void main(String[] args) {
JFrame frame = new JFrame("Java 2D Skeleton");
frame.add(new Skeleton());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(870, 890);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
What is worse is that, if I have a class public variable and I am increasing its value by 1 within the paint() method. This results in having the value increased by 2.
I have read somewhere in this website such that the method paint() automatically invokes three other methods, which I thing they are causing this problem.
Also I have tried some suggested solution on another website to override the method paintComponent() instead of the method paint(). However I still have the same problem.
Please help me fix it.
You are right to override paintComponent instead of paint. I think the issue here is that paintComponent should do one thing, paint your component. Any number of things can cause a call to repaint() which will call your paintComponent, so it's not really guaranteed when and how often this method will execute. Doing calculations and keeping track of variables should probably be a part of a separate model class that your component can look at to know what to draw.
This question has probably been forgotten but I stumbled upon it and would like to help out anyone else who does too. The solution I found was to use JApplet's init() method. There you can do all the calculations you need. Then, if you want, you can also create a timer that responds at a specified interval to call repaint() and do iteration-ish work. That way, you can leave everything except the actual drawing code out of paint. It would look something like this:
public void init()
{
//do calculations here
javax.swing.Timer timer = new javax.swing.Timer(1000 / frameRate, new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
//this is called every so often. Can link to update loops or be an
//update loop itself.
repaint();
}
} );
timer.start();
}
public void paint(Graphics g)
{
//All the actual drawing code for the shapes goes here.
}
Inside my paintComponent() method, I have a drawRect() that paints the background of a jpanel. But because the jbutton is drawn on the screen before the paintComponent() method gets called, the jbutton is blocked out by the drawRect. Does anyone know how to fix this? My guess is to add the jbutton before repaint gets called, but I don't know how to do that?
Some code:
public Frame(){
add(new JButton());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(0,0,screenwidth,screenheight); //paints the background with a color
//but blocks out the jbutton.
}
Now, firstly, I will tell you what you're doing wrong here -- JFrame is not a JComponent, and has no paintComponent for you to override. Your code will probably never be called. Aside from that, drawRect merely draws a rectangle -- it does not fill one.
However, I believe there is a proper way to do this.
Since you're using a JFrame, you should take advantage of the container's layered pane via JFrame.getLayeredPane.
A layered pane is a container with depth such that overlapping components can appear one on top of the other. General information about layered panes is in How to Use Layered Panes. This section discusses the particulars of how root panes use layered panes.
Root panes are covered in How to Use Root Panes, a part of the Java Tutorials. A layered pane is a child of the root pane, and a JFrame, as a top-level container, utilizes an underlying JRootPane.
Anyways, since you're interested in creating a background, see the following diagram for how a layered pane generally looks inside a top-level container:
The table below describes the intended use for each layer and lists the JLayeredPane constant that corresponds to each layer:
Layer Name - Value - Description
FRAME_CONTENT_LAYER - new Integer(-30000) - The root pane adds the menu bar and content pane to its layered pane at this depth.
Since we want to specify our background is behind the content, we first add it to the same layer (JLayeredPane.FRAME_CONTENT_LAYER), as follows:
final JComponent background = new JComponent() {
private final Dimension size = new Dimension(screenwidth, screenheight);
private Dimension determineSize() {
Insets insets = super.getInsets();
return size = new Dimension(screenwidth + insets.left + insets.right,
screenheight + insets.bottom + insets.top);
}
public Dimension getPreferredSize() {
return size == null ? determineSize() : size;
}
public Dimension getMinimumSize() {
return size == null ? determineSize() : size;
}
protected void paintComponent(final Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, screenwidth, screenheight);
}
};
final JLayeredPane layeredPane = frame.getLayeredPane();
layeredPane.add(background, JLayeredPane.FRAME_CONTENT_LAYER);
Now, to make sure we draw our background before the content, we use JLayeredPane.moveToBack:
layeredPane.moveToBack(background);
I did this really quick test. As HovercraftFullOfEels has pointed out. JFrame does not have a paintComponent, so I used a JPanel instead.
Which was produced by this code
public class PanelTest extends JPanel {
private JButton button;
public PanelTest() {
setLayout(new GridBagLayout());
button = new JButton("Can you see me ?");
add(button);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle bounds = button.getBounds();
bounds.x -= 10;
bounds.y -= 10;
bounds.width += 20;
bounds.height += 20;
g.setColor(Color.RED);
((Graphics2D)g).fill(bounds);
}
}
I've I try and replicate the issue by using paintComponents on the JFrame, I don't see the rectangle. Even if I overwrite paint on the JFrame, the rectangle is still painted under the button (Not that I would ever recommend doing either).
The problem is, you haven't given us enough code to know what's going wrong
ps - drawRect won't "fill" anything
I encountered this before, although not jframe specifically and not the kind of the scenario that you have. Try this code,
this.getContentPane.repaint();
on your jframe. Im not sure about this, but give it a try.
I'm attempting to create my own custom ToolTip for a program I've ported to Java, I'm trying to match the original programs ToolTips (it was written in Delphi). I've got some code that allows me to draw "inside" a ToolTip but for some reason, if I Override paint(Graphics g, JComponent c) and leave it blank it still draws a ToolTip, and anything I attempt to draw will be drawn "inside" this little boxed ToolTip and I can't draw "outside" of it.
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicToolTipUI;
class MultiLineToolTipUI extends BasicToolTipUI {
#Override
public void paint(Graphics g, JComponent c) {
//int mY = 0;
//int mX = 0;
//int xPoints[] = {mX, mX, mX + 15};
//int yPoints[] = {mY, mY + 25, mY + 25};
//Polygon p = new Polygon(xPoints, yPoints, 3);
//g.setColor(Color.BLACK);
//g.fillPolygon(p);
//g.fillRoundRect(mX, mY, 100, 50, 30, 30);
}
public static void main (String args[])
{
JButton button = new JButton ("Mouse Over ME!") {
public JToolTip createToolTip() {
MultiLineToolTip tip = new MultiLineToolTip();
tip.setComponent(this);
return tip;
}
};
//JButton button = new JButton("Mouse Over ME!");
button.setToolTipText("Hello, World");
JFrame frame = new JFrame("Basic SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( button );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
static class MultiLineToolTip extends JToolTip
{
public MultiLineToolTip()
{
setUI(new MultiLineToolTipUI());
}
}
}
This is what I have, and like I said, even without the lines in paint it's drawing on it's own.
Any advice to get around this? Or a better way to go about what I'm trying to do?
CLARIFICATION: The first answer by Camickr was very helpful, however I should clarify my goal is to get the box that is automatically drawn from somewhere outside of paint to go away, or be invisible.
The size of the tool tip is determined by the text. Add:
System.out.println( c.getSize() );
to the paint(...) method to see the size of the tool tip. You are trying to paint outside its bounds. If you want to override the default size then you need to set the preferred size yourself. I think you want:
public Dimension getPreferredSize(JComponent c)
{
return new Dimension(100, 50);
}
Edit: A tooltip is a component with a border and a background. If you want to remove them you can use:
tip.setOpaque(false);
tip.setBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0));
This will only work when to tooltip is fully contained withing the frame. When the tooltip is displayed outside the bounds of the frame, then the tooltip is added to a JWindow, in which case you will see the background of the window. I don't know how to disable this behaviour because all Swing components must be painted within the bounds of a top level container.