Hi i want to know how to call the paint method...
I am a novice programmer and am really just experimenting with things like paint.
The program i am trying to make is the game where there are 3 rungs and the aim of the game is to move different sized disks from the left/right rung to the right/left rung.
here is my code(no where near finished give me a break):
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int amount = 0;
// get the amount of rectangles to draw to represent disks
while (amount <= 1 && amount >= 5) {
System.out.print("Please enter amount of discs to use(less than 7 more than one).");
amount = scan.nextInt();
}
}
public void paint(Graphics g) {
// draw a certain amount of rectangles in ascending order
if (amount <= 1 && amount >= 5) {
for (int i = 0; i < amount; i++) {
g.fillRect(220 - (20 * i), 200 + (10 * i), 100 - (20 * i), 20);
}
}
}
The paint method will be called for the first time upon creation of the object.
To force the paint() method to be called again you can either call update(Graphics g) if you want to pass in a new Graphics object, but normally I would suggest using repaint() method, since this way it will be scheduled to be called asap.
You don't need to call it. Instead, you should use the main loop which Java creates for you.
The usual approach is to extend JPanel (see this question: How to make canvas with Swing?) and override the paint() method.
Now create a JFrame, add the new UI component to it and open the frame. Java will then make sure it gets rendered.
I am not expert or something else to teach others but you need to put your code to be painted to paintComponent(Graphics g) method instead of paint and then call repaint method.
Related
The simple version is that I'm drawing Graphics2D 60 times a second on a JPanel and it uses the drawstring method to create a bunch of labels. How would I go about making so I can click on those labels and have something happen?
Explanation: As it currently stands I have a system setup that says for every object in the world draw a string to the side (So I can see a list of all objects in the world). This is done with a for loop and the Graphics2D drawstring method.
The JPanel is being updated 60 times a second so this is being redrawn 60 times a second. I want to be able to click on these object labels so I can select the items, how would I go about turning them into buttons?
I messed around with JButton for awhile but it didn't seem to do me any good because whenever I added it the JPanel would go blank and only the button would render (Plus it didn't render to the right size).
More Details:
I use a
for(int I=0; I < sceneObjects.size(); I++) {
}
loop to grab every object in an object ArrayList. Each object has a String variable "Name". Before the loop class I sent an int called YPosition, and for every object the YPosition goes up by 20 so that the labels don't all stack on top of each other. I'm using the g2d.DrawString method to achieve this. But I need to be able to select the object labels.
I apologize if I forgot something in my question, let me know.
For those who are curious, the code looks exactly like this (Can't be compiled as is):
g2d.setFont(new Font("Arial", Font.PLAIN, hierarchyWidth / 26));
g2d.setColor(Color.black);
int oYPos = 20;
// For every object in existence
for(int i=0; i < engine.sceneObjects.activeObjects.size(); i++) {
GameObject theObject = engine.sceneObjects.activeObjects.get(i);
// If the scrollbar is within range of the hierarchy
// (Based on HierarchyHeight so that it's resolution friendly)
if(oYPos >= hierarchyScroll && oYPos < hierarchyScroll + hierarchyHeight) {
// If the object has no parent
if(theObject.transform.parent == null) {
g2d.drawString(theObject.name, hierarchyPosition.x + 5, hierarchyPosition.y + oYPos);
} else { // If the object has a parent
}
}
oYPos += 20;
}
// Track the last oYPos so that the scrollbar can adjust itself accordingly
lastOYPos = oYPos;
My guess would be some sort of class create for each of these labels and a Boolean stored called isSelected, and then rendering the label according to the class, but this seems a bit more complicated than I'd like to do
I've searched for similar threads like this but couldn't find any.
I am wondering if there is a more efficient way of rendering a tile, which only uses 1 image and draws the same image in a grid to cover an area.
I'm using the code below:
public void render(Graphics g) {
for(int r = 0; r <= tilePieces.length; r++) {
for(int c = 0; c <= tilePieces[0].length; c++) {
try {
tilePieces[r][c].render(g);
}
catch(Exception e) {
}
}
}
}
When I create a tile, I also create as many tile pieces (squares) it needs and I store them in an array.
Every time the render() method of the object is called, it loops through the array and calls their render() methods, which draw the image.
There is no lag in the game, but I find this way of doing this inefficient, since I have to create a bunch of objects for one tile and call their render methods.
That's why, I tried drawing the same one image in the method above, instead of calling the render() method of each tile piece, and that caused the game to run like 1 frame per 5 seconds. Which is weird, what is the difference between calling a method to draw your image and drawing your image directly in the loop?
I have done a program that numerically solves a set of differential equations which describes how an "arbitrary" illness move in an isolated and constant population, it was a programming assignment from a class I took a while ago. What I've done to extend it is to add some graphical components that can pause, reset and "play" the simulation, as well as some components that allows me to change some constants in the equations.
All this was an exercise in programming as I find it to be fun and exciting and want to become better.
However, at the moment I'm stuck, what I want to do now is to make a very simple form of animation of it. I want to visualize the data I get for the number of infected, susceptibles and resistants in a grid as points. I managed to create the grid and have an idea of how to place the dots.
The problem I have is how to draw the dots as the program is working, I can draw one dot in the grid but only as the grid is created, that's it. I need to be able to create a dot at a specific place in the grid, this goes on until the number of dots reaches a finite number, say 30. At that points I want to have the first dot, the one the left, removed, all the dots shifted to the left and place the new dot at the furthest right of the grid, the whole thing is then repeated.
I think I will be able to figure it out with some help/hints about the paintComponent() method and whether I need to use repaint() method at all, I can't get my head around these for some reason. I've read through my course literature on Java, but despite the extensive sections where he explains most of the different graphical components he does not say that much about those methods, only that you don't call for the paintComponent() method, it is done automatically.
If there is something unclear let me know and I'll try to clarify it.
Thanks in advance.
//
Fox Mulder
I think I will be able to figure it out with some help/hints about the paintComponent() method and whether I need to use repaint() method at all, I can't get my head around these for some reason.
Basically, say you create a custom component by extending JPanel. When you #Override the paintComponent() method, it get implicitly called for you, so you never have to call it. So what ever you paint inside the method, gets drawn on your surface. For example
public class DrawingPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 10, 10);
}
}
When you call repaint() you are basically causing the paintComponent method to be call implicitly. So to answer your question, Yes you will need to call it if you want to animate, as you will need to update some kind of variable (like the x and y) in the paintComponent() method, to see any change in the drawing.
You can see more at Performing Custom Painting
Not to handle the actual animation, you'll want to use a javax.swing.Timer. You can see more at How to use Swing Timers. Here's the basic construct
Timer ( int delayInMillis, ActionListener listener )
where delayInMillis is the time to delay between ticks(in this case animations) and the ActionListener listens for "ticks". Each tick, the actionPerformed of the ActionListener is called. There, you can put the code to update any variables you use for animation.
So for example you update the x and y, in the actionPerformed, then call repaint()
public class DrawingPanel extends JPanel {
int x = 50;
int y = 50;
public DrawingPanel() {
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
x += 5;
y += 5;
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 10, 10);
}
}
Now this was just a simple example. But in your case you want to animate a scatter plot. So what you can do is have a list of Points and in the actionPerformed you can add pull points from that list and push them into another list that is to be drawn. So say you have this
List<Point> originalPoints;
List<Point> pointsToDraw;
...
#Override
protected void paintComponent(Grapchics g) {
super.paintComponent(g);
for (Point point : pointsToDraw) {
g.fillOval(point.x - 5, point.y - 5, 10, 10);
}
}
Basically all the points in pointsToDraw list will be drawn. Initially it will be empty. And in the timer, you can add to the list, until the originalPoints list is exhausted. For example.
List<Point> originalPoints;
List<point> pointsToDraw;
private int currentIndex = 0;
public DrawingPanel(List<Point> originalPoints) {
this.originalPoints = originalPoints;
pointsToDraw = new ArrayList<>();
Timer timer = new Timer(40, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (currentIndex == originalPoints.size() - 1) {
((Timer)e.getSource()).stop();
} else {
pointsToDraw.add(originalPoints.get(currentIndex));
currentIndex++;
}
repaint();
}
});
timer.start();
}
So basicall you just keep a current index. When the index reaches the size of the original list, you stop the timer. Otherwise you just pop from the originalPoints and push to the pointsToDraw. For every point you add the pointsToDraw, a repaint() is called, and there will be another point for the paintComponent to draw a circle with.
The END
UDPATE
I just reread your question, and I think I have have misunderstood it. If you want all the points drawn, then basically just have one list. And draw all the points initially. with each tick, just remove the first index, advance all the rest up an index, and add a new one to the end. Though this is the implementation of a LinkedList so you may just want to use that
A LinearGradientPaint object from java.awt may appear nice once painted, but there's a problem I'm having with it for painting an animated background in some kind of game model that's taking me long to build.
I want to paint an animated rainbow gradient on the background using the Graphics2D paint object, except that when I do so, I notice a lot of lag in repainting the panel. It should repaint itself at least 30 frames per second, which is only possible if the Paint object the graphics object uses is not a rainbow gradient.
Even running it as a separate thread will not do the trick. Below is the code for what I am trying to do at the end of each frame:
gamePanel.executor.execute(new Runnable(){
public void run()
{
while(true)
{
if (Background.selectedBackgroundIndex >= Background.SKY_HORIZON_GRADIENT_PAINT &&
Background.selectedBackgroundIndex < Background.SPACE_PAINT)
{
float displacementValue = 1.0f;
if (Background.backgroundShape.y < ((-2990.0f) + CannonShooterModel.gamePanel.getSize().height) && gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = false;
else if (Background.backgroundShape.y > (-10.0f) && !gamePanel.horizonGoingDown)
gamePanel.horizonGoingDown = true;
Point2D.Double startPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getStartPoint()),
endPoint = (Point2D.Double)(((LinearGradientPaint)Background.background).getEndPoint());
if (gamePanel.horizonGoingDown)
Background.backgroundShape.y -= displacementValue;
else
Background.backgroundShape.y += displacementValue;
startPoint.setLocation(0, Background.backgroundShape.y);
endPoint.setLocation(0, Background.horizonGradientPaintHeight + Background.backgroundShape.y);
// Should be done in another thread, particularly in arithmetic calculations.
Background.background = new LinearGradientPaint(startPoint, endPoint,
((LinearGradientPaint)Background.background).getFractions(),
((LinearGradientPaint)Background.background).getColors());
}
for (int a = 0; a < PlayerUnit.weapon.bullets.length; a++)
{
if (PlayerUnit.weapon.bullets[a] != null)
{
if (PlayerUnit.weapon instanceof Pistol &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0 &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x <= CannonShooterModel.gamePanel.getSize().width &&
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y + ((Pistol)PlayerUnit.weapon).bulletWidth >= 0)
{
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x +=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).x -=
PlayerUnit.weapon.bulletSpeed * Math.cos(PlayerUnit.weapon.weaponAngles[a]);
if (PlayerUnit.weapon.weaponAngles[a] >= 0)
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y -=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
else
((Ellipse2D.Float)PlayerUnit.weapon.bullets[a]).y +=
PlayerUnit.weapon.bulletSpeed * Math.sin(PlayerUnit.weapon.weaponAngles[a]);
}
else
PlayerUnit.weapon.bullets[a] = null;
}
}
//System.out.println(Background.backgroundShape.y);
repaint();
try
{
Thread.sleep(1000 / 60);
}
catch (InterruptedException ex)
{
}
}
}
});
The classes Background, PlayerUnit, and CannonShooterModel are important to my game model. It's an upright shooting game supposed to be designed with various weapons and enemies.
This rainbow gradient I have uses an array of eight different Color objects. For every frame passed through, I change the y-coordinate for both Point2D.Float objects required for the gradient paint as desired. In order for the animation to work, I have to actually instantiate another object of LinearGradientPaint again, with some of the previous properties from the previous object, and have it be referenced by the variable background of type Paint.
Problem is, LinearGradientPaint does not have a method to where you can do a translate on the two end points, and the get methods do not return the actual object that LinearGradientPaint object contains. (what I mean is, the get methods return a new object of Point2D with the same values as those part of the LinearGradientPaint object.)
For every frame passed, I have to change not only the y-coordinate property of the shape that's associated with the gradient, but also set the locations of the two Point2D objects that are needed to instantiate LinearGradientPaint once again.
I would love to re-explain this much simpler, because I can have trouble with some knowledge of English, even though this is my primary language. Please let me know if you need re-explanation.
There are a couple of solutions you might try.
Instead of filling the entire paintable area, you could create a BufferedImage whose width is 1 pixel and height equal to the area you want to fill (assuming you are fill vertically). You would then apply the LinearGradientPaint to this BufferedImage's Graphics2D and fill it (don't forget to dispose of the Graphics context when your done).
Then, you would simply use Graphics#drawImage(Image, x, y, width, height, ImageObserver) to actually paint the image. Generally speaking, it appears that it's faster to rescale an image then it is to fill it with a LinearGradientPaint, especially when you consider you are only stretching the image horizontally.
The other choice would be to generate a basic BufferedImage which had the LinearGradientPaint already applied and you would simply paint this offset as required. This would probably require you to paint it at least twice to allow it to "stitch" toegther...
If you are just making the background gradient move up and down, could you write it to an image at initialization and then move and wrap the image vertically?
I'm writing a simple Game of Life program in Java and am having a bit of trouble getting it to animate. I've got a JComponent class called LifeDraw, which displays a grid of pixels, with the following paint method:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int y = 0; y < lGrid.getHeight(); y++) {
for (int x = 0; x < lGrid.getWidth(); x++) {
if (lGrid.getCell(x,y) == 1) {
g.setColor(Color.red);
g.fillRect(x * lGrid.getSqSize(), y * lGrid.getSqSize(), lGrid.getSqSize(), lGrid.getSqSize());
} else {
g.setColor(Color.white);
g.fillRect(x * lGrid.getSqSize(), y * lGrid.getSqSize(), lGrid.getSqSize(), lGrid.getSqSize());
}
}
}
}
And then another class LifeGrid that has a method run(), which when called will update the grid of pixels for one generation and then call LifeDraw.repaint(). However, if I try to call run() in a loop, the JComponent doesn't repaint until the loop is finished so all that is ever displayed is the first generation and the last one. I figured it was probably just updating too quickly to repaint, so I tried using Thread.sleep() between iterations but still had the same problem. Theoretically (or at least I was hoping it would), it should repaint the component between each iteration and display an animation of the pixels changing.
I'm not that well versed in Java GUI, so any help would be really appreciated. Hopefully I've explained it clearly enough, let me know otherwise!
I don't know if it would solve your problem, but you could try calling run() from a Timer instead of a simple for or while loop.
From the JavaDocs for repaint():
Adds the specified region to the dirty region list if the component is
showing. The component will be repainted after all of the currently
pending events have been dispatched.
All repaint does is signal that the area needs repainting.
Try paintImmediately or update.
Repaint has to be fired in the event loop, not in another thread.
Try replacing your call to repaint() with following code:
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});