I want to create a windows 7 loading bar on the taskbar. something like this:
I already have a jframe frame where a game loads in it.
I want to make the loadingbar show the progress of downloading the cache of the game. The jframe and the downloading are handled in two seperate classes.
When I looked on the web, I found 2 solutions.
SWT: where you can create the loadingbar, but I think you can't combine that with a jframe.
bridj: which is possible to add to jframe, but I don't have any idea how to do this with an existing jframe and the progress and the jframe handled in two different classes.
There is not a direct solution to what you ask since the progress task bar is OS unique, but trashgod actually got this answered at his post here.
You could create an icon which is affected by your progress & update it, so the taskbar will show what you ask for.
I was inspired, so had to indicate it in case OP didn't catch this. Nice job!
private static class ProgressIcon implements Icon {
private static final int H = 16;
private static final int W = 3 * H;
private Color color;
private int w;
public ProgressIcon(Color color) {
this.color = color;
}
public void update(int i) {
w = i % W;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
g.fillRect(x, y, w, H);
}
public int getIconWidth() {
return W;
}
public int getIconHeight() {
return H;
}
}
Related
I’m trying to create some animation ( boy who runs whenever key is pressed) using JPanel and painComponent.
So, first of all I declare some images, Image array and some methods for drawing. I created timer and added it to constructor.
Image img1;
Image img2;
Image img3;
Image img4;
int index = 0;
Image currentImage l;
Image[] images = new Image[4]
public class Animation extends JPanel implements ActionListener
{
public Animation()
{
loadImages();
getTimer();
imgAdder();
addFirstImage();
}
public void serCurrentImage(Image currentImage)
{
this.currentImage = currentImage;
}
public void getTimer()
{
Timer timer = new Timer(20,this)
timer.start();
}
public void imgAdder()
{
images[1] = img1;
...
}
public void addFirstImage()
{
currentImage = img1;
}
private void loadImages()
{
try
{
BufferedImage img = ImageIO.read(getClass.getResource(“/resources/images/img1.png”);
img1 = img;
// and so on for every image
}catch(IOexception ioe )
ioe.printStackTrace();
}
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.drewImage(currentImage,0,0,this);
requestsFocus();
}
public class FieldKeyListener extends KeyAdapter
{
public void move()
{
setCurrentImage(image[index]);
index++;
if( index == 4 )
index = 0;
}
public void keyPressed(KeyEvent e)
{
super.keyPressed(e);
int key = e.getKeyCode();
if(key == Key.Event.VK_LEFT)
move();
}
}
}
Then drew all images through paintComponent using loop for my array.
Also I declared class which extends KeyAdapter.
Everything seems to be fine and my animation works, but problem is that it works not as smoothly as I wanted. When I press and hold key, images are changing too fast and process look unnatural. I want , for instance , 3 or 4 images change per second instead of 20.
May I added timer in wrong method ? May be there is something like time delay. I don’t know how exactly it works , and which listener should I mention as argument in timer.
P.s. I’m just beginner and my code may look incorrectly in terms of coding standards. Also I wrote just crucial parts of my project which represent problem. I hope you help me with this. Thanks in advance.
Animation is a complex subject, with lots of boring theory. Basically, animation is the illusion of change over time. This is very important, as everything you do in animation will based around time.
In something like a game, you will have a bunch of entities all playing at a different rates of time. One of the challenges is taking the time to devise a solution which allows a entity to play over a period of time while been decoupled from the refresh cycle (ie frame count), unless you have sprite with the correct number of frames to match you refresh cycle, but even then, I'd be concerned, as the system won't be flexible enough to adapt to situations where the OS and hardware can't keep up.
The following is a simple example which takes a sprite sheet (a series of images stored in a single image), the number of expected images/frames and the time to complete a full cycle.
It calculates the individual frame size and returns a frame based on the amount of time that the sprite has been animated...
public class Sprite {
private BufferedImage source;
private int imageCount;
private int imageWidth;
// How long it takes to play a full cycle
private Duration duration;
// When the last cycle was started
private Instant startedAt;
public Sprite(BufferedImage source, int imageCount, int cycleTimeInSeconds) throws IOException {
this.source = source;
this.imageCount = imageCount;
imageWidth = source.getWidth() / imageCount;
duration = Duration.ofSeconds(cycleTimeInSeconds);
}
public BufferedImage getFrame() {
if (startedAt == null) {
startedAt = Instant.now();
}
Duration timePlayed = Duration.between(startedAt, Instant.now());
double progress = timePlayed.toMillis() / (double)duration.toMillis();
if (progress > 1.0) {
progress = 1.0;
startedAt = Instant.now();
}
int frame = Math.min((int)(imageCount * progress), imageCount - 1);
return getImageAt(frame);
}
protected BufferedImage getImageAt(int index) {
if (index < 0 || index >= imageCount) {
return null;
}
int xOffset = imageWidth * index;
return source.getSubimage(xOffset, 0, imageWidth, source.getHeight());
}
}
nb: It also needs a means to be reset or stopped, so you can force the sprite back to the start, but I'll leave that to you
Next, we need some way to play the animation
public class TestPane extends JPanel {
private Sprite sprite;
public TestPane(Sprite sprite) {
this.sprite = sprite;
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage img = sprite.getFrame();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
There's nothing really special here, it's a simple Swing Timer set to a high resolution (5 milliseconds) which constantly updates the UI, requesting the next frame from the sprite and painting it.
The important part here is the sprite and the refresh cycle are independent. Want the character to walk faster, change the sprite duration, want the character walk slower, changed the sprite duration, the refresh cycle doesn't need be altered (or any other entity)
So, starting with...
Same cycle, first over 1 second, second over 5 seconds
You can also have a look at something like How to create a usable KeyReleased method in java, which demonstrates the use of key bindings and a centralised Set as a "action" repository
I'm new to Java and I want to try some graphic things with it. I want to generate two circles with two different colors and different positions. My code:
Paint Class:
package de.test.pkg;
import javax.swing.*;
public class paint {
public static void main(String[] args) throws Exception{
JFrame frame = new JFrame("Titel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
frame.setSize(600,200);
frame.setVisible(true);
}
}
Circle class
package de.test.pkg;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Circle extends JPanel {
private double iconRadius = 100;
private Color defaultColor = new Color(89,104,99);
private int positionX = 0;
private int positionY = 0;
private Ellipse2D iconBody = new Ellipse2D.Double(getPositionX(),getPositionY(),iconRadius,iconRadius);
public Icon(){
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
this.setBackground(new Color(255,255,255));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(getDefaultColor());
g2d.draw(iconBody);
g2d.fill(iconBody);
}
}
CircleRed class
package de.design.pkg;
import java.awt.Color;
public class CircleRed extends Circle {
private Color defaultColor = Color.RED;
private int positionX = 120;
private int positionY = 0;
public CircleRed() {
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
}
The Result is that the Circles have the same positions.
My questions are:
Why do they have the same positions?
Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if I want to return array[position]?
If I want to set the Position from the Main function. How can I do this?
The Result is that the Circles have the same positions.
(1) Why do they have the same positions?
Not really. The result is that only CircleRed is displayed. Your problem here is not with painting, it's with adding components to a container with a suitable layout manager. The lines
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
add r instead of d. This is because JFrame uses BorderLayout by default and you are replacing the center component d with r the line after. Just to show the point, add the line
frame.setLayout(new GridLayout(1, 2));
(2) Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
It depends on what you are aiming to do. I would venture a guess that if you want to practice inheritance, it would be better for you to create an abstract class for a general circle with shared code and then subclass it with concrete implementation and specific code for the various types. Otherwise, you can just create a single customizable circle class and instantiate that one with different parameters.
It's not a good practical approach in any case because the placement of the circles (which are JPanels) will be determined by the layout manager. The painting only determines the location of the painted shape in the panel. It would be better to just paint the shapes on a single big panel and not with using multiple panels.
There are a few very good answers on the site about moving components around.
(3) Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if i want to return array[position]?
There are effectively 2 positions in your design. One is for the panels in the frame, the other is for the shapes in the panels.
For the latter, I would use a Point or just an int x, y fields in the class itself. Getters and setters are the standard ones, the setters will control the position (you will need to call repaint() though).
For the first, it is determined by the layout manager and you don't (shouldn't) control it in a pixel-prefect way. You just instruct the layout manager with "guidelines" and it does the calculations for you.
(4) If I want to set the Position from the Main function. How can i do this?
Again, depends on which position you are talking about. See above.
What your doing is very overkill for just creating two colored circles. You can just use the paint method in java.awt
public void paint(Graphics g){
g.setColor(Color.YELLOW);
g.fillOval(20,20,160,160);
g.setColor(Color.RED);
g.fillOval(60,60,80,80);
}
fillOval takes the following parameters (int x, int y, int width, int height)
You can use g.setColor(Color.NAME) to change the color of your circle. Just call this method before your draw calls.
They're in the same position because the paintComponent() method in Circle is being used for both - and it's using the position variables defined in Circle. When you have CircleRed extend Circle, you don't need to define the position variables again - you inherit them from Circle. Instead, call the setPosition() methods on CircleRed. (You don't need to define these either, they're also inherited.)
There are a variety better solutions, I think the biggest improvement would be to improve your use of inheritance.
That's a fine way to hold the position. If anything else, you could also use a Point object. (Already in Java)
To set the position from the main function, you just call for example
Circle c = new Circle();
c.setPositionX(120);
c.setPositionY(40);
You are going wrong way. You can simply draw two circles by overriding paint method of JFrame class.
Here is a sample demo program.
import java.awt.*;
/**
*
* #author Pankaj
*/
public class TestFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public TestFrame() {
initComponents();
setTitle("Graphics Demo");
setSize(200,200);
}
/**
* You need to override this method.
*/
#Override
public void paint(Graphics g) {
int X1 = 10; //X coordinate of first circle
int X2 = 60; //X coordinate of second circle
int Y1 = 100; //Y coordinate of first circle
int Y2 = 100; //Y coordinate of second circle
int width = 50; //Width of the circle
int height = 50; //Height of the circle
Color color1 = Color.RED; //Color of first circle
Color color2 = Color.BLUE; //Color of second circle
g.setColor(color1);
g.fillOval(X1, Y1, width, height);
g.setColor(color2);
g.fillOval(X2, Y2, width, height);
}
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
pack();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
}
And here's the output
So what I want to achieve, is to create a simple program that lets the user create rectangles on the screen and then move them around.
I know that I can declare a new object in the code (i.e rectangle i = new rectangle(x,y,sizex,sizey)) however that will create only one, moreover it forces me to declare it in the code:
block1 = new block
block2 = new block
etc
Question is: How can I let the user create infinite rectangles with the use of lets say a button (not necessarily a button, it can be anything) and then let the user be capable of modyfing them (location/size etc).
Examples would be nice. I just feel there is a better way than declaring a gazillion objects in the code and then displaying them one by one. In C++ i could declare a malloc expandable container that would just hold the values, and then just display things using these values, not sure for java.
Simple code for reference:
public static void main(String[] args){
JFrame frame = new JFrame("A.L.T.E.S");
//Container container = frame.getContentPane();
frame.setSize(1024, 768);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Block object = new Block(10,10,20,20);
frame.add(object);
object.reDraw();
}
public class Block extends JPanel{
int yPos;
int xPos;
int xSize;
int ySize;
public Block(int xPos, int yPos, int xSize, int ySize){
this.xPos = xPos;
this.yPos = yPos;
this.xSize = xSize;
this.ySize = ySize;
}
public void setYPos(int yPos){
this.yPos = yPos;
}
public void setXPos(int xPos){
this.xPos = xPos;
}
public void setXSize(int xSize){
this.xSize = xSize;
}
public void setYSize(int ySize){
this.ySize = ySize;
}
public int getYPos(){
return yPos;
}
public int getXPos(){
return xPos;
}
public int getYSize(){
return ySize;
}
public int getXSize(){
return xSize;
}
public void reDraw(){
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(xPos, yPos, xSize, ySize);
}
}
Nothing in Java is simple.
First, Java already has a Rectangle class that holds the origin and size of a Rectangle. In your code, you're making all the rectangles blue. Suppose you want the user to set the color of a Rectangle. You can define your Block class like this.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Block {
private Color color;
private Rectangle rectangle;
public Block(int x, int y, int width, int height) {
this(new Rectangle(x, y, width, height));
}
public Block(Rectangle rectangle) {
this.rectangle = rectangle;
this.color = Color.BLUE;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Rectangle getRectangle() {
return rectangle;
}
public void draw(Graphics g) {
g.setColor(getColor());
g.fillRect(rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
}
}
Next, you need a model class to hold all of the Blocks that your user defines.
Something like this BlockList class.
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class BlockList {
private List<Block> blockList;
public BlockList() {
this.blockList = new ArrayList<Block>();
}
public void init() {
this.blockList.clear();
}
public void addBlock(Block block) {
this.blockList.add(block);
}
public void draw(Graphics g) {
for (int i = 0; i < blockList.size(); i++) {
blockList.get(i).draw(g);
}
}
}
Now that you have your GUI model defined, you would build your GUI. Your drawing JPanel would call the draw method in your BlockList class.
I strongly suggest that you go through the Oracle tutorial on Swing. Go through the complete tutorial before you attempt to create a Swing GUI.
In java, use a Collection. In this case, use a List. You can create an ArrayList<Block>, then invoke add to add new rectangles. Then, you can iterate through this collection by using iterator, then calling hasNext and next on the iterator to find all the elements. I'm sure this brief hypnosis is going to be confusing, and if so, check out the Java Tutorial on Collections, which explains everything in all the detail you are going to need.
This is my first time working with extends and stuff like that :)
In mt most recent program, I have BasicTile extending Tile.
I construct the basic tile with a Bitmap.
The bitmap is not an actual bitmap, its a class that I wrote that contains an array of integers (holding color values).
When I render with the bitmap, I get a black screen. This goes away when I make the bitmap static (I do not want that because I want multiple basic tiles like grass, bushes, etc.)
It also goes away if I set the texture right in the render method (I don't want to do that either bc it would load 60*256 bitmaps a second).
I tested some and in the constructor of the BasicTile the array in the bitmap contains the right values. In the render method it changed to only be the number -16777216 though.
The information seems to get lost somewhere in between. I am having problems finding where it gets lost because I do not do anything to the bitmap in between the constructor and the render method.
This is my Tile, BasicTile, and Bitmap classes:
public abstract class Tile {
public static final Tile[] tiles = new Tile[576];
public static final Tile VOID = new BasicTile(0, Art.spritesheet[0][0]);
public static final Tile STONE = new BasicTile(1, Art.spritesheet[1][0]);
public static final Tile GRASS = new BasicTile(2, Art.spritesheet[3][0]);
protected byte id;
protected boolean solid;
protected boolean emitter;
public Tile(int id, boolean isSolid, boolean isEmitter){
this.solid = isSolid;
this.emitter = isEmitter;
tiles[id] = this;
}
public byte getId(){
return id;
}
public boolean isSolid(){
return solid;
}
public boolean isEmitter(){
return emitter;
}
public abstract void render(Screen screen, int x, int y);
}
public class BasicTile extends Tile{
protected int tileId;
protected Bitmap texture;
public BasicTile(int id, Bitmap bitmap) {
super(id, false, false);
texture = bitmap;
}
public void render(Screen screen, int x, int y) {
/*for(int i = 0; i < texture.h; i++){
for(int j = 0; j < texture.w; j++){
System.out.println(texture.pixels[j + i * texture.w]);
}
}*/ //the algorithm I used to debug (getting the values of the int array)
screen.render(texture, x, y);
}
}
public class Bitmap {
public int w, h;
public int[] pixels;
public Bitmap(int w, int h){
this.w = w;
this.h = h;
this.pixels = new int[w * h];
}
}
when I render to the screen, it renders it to another bigger array of ints :)
Added examples:
normal code: see above (sorry I can only post 2 links)
result: black screen
making bitmap static: in the BasicTile change "protected Bitmap texture;" to "protected static Bitmap texture;"
result
set it in the render method
result: same as the one with the bricks (so it works)
P.S.: If you need anything else to solve this issue please tell me :)
I figured out it was not displaying a black screen but instead the void tile...
I don't know why (I'm working on a fix and it will be posted here) but if I change the
public static final Tile VOID = new BasicTile(0, Art.spritesheet[0][0])
to
public static final Tile VOID = new BasicTile(0, Art.spritesheet[3][0])
it renders the bricks :)
I've created a JToggleButton and when it is selected the image is shown. It all works perfectly except the image isn't centered on the button. The top left corner of the image is on the center point of the button and then the image goes down and out towards the bottom right corner of the button.
JToggleButton LayoutButton = new JToggleButton();
LayoutButton.setIcon(new ImageIcon());
LayoutButton.setSelectedIcon(new ImageIcon("Image.png"));
Any ideas how I center the image?
Thanks
The problem is that your initial image does not match the dimensions of the selected image so, the selected image will appear in a different location, bottom right in this case.
You could create a placeholder for your initial 'unselected' image:
public class PlaceHolderIcon implements Icon {
private final int width;
private final int height;
public PlaceHolderIcon(int width, int height) {
this.width = width;
this.height = height;
}
public int getIconHeight() {
return height;
}
public int getIconWidth() {
return width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
}
}
and replace your first zero-dimension image with:
ImageIcon selectedIcon = new ImageIcon("Image.png");
Image image = selectedIcon.getImage();
PlaceHolderIcon placeHolderIcon = new PlaceHolderIcon(image.getWidth(this), image.getHeight(this));
JToggleButton layoutButton = new JToggleButton();
layoutButton.setIcon(placeHolderIcon);
layoutButton.setFocusPainted(false);
layoutButton.setSelectedIcon(selectedIcon);
You should use the setHorizontalAlignment(...) and setVerticalAlignment(...) methods of JToggleButton (actually of AbstractButton). Pass SwingConstants.CENTER in as the parameter to center all.
Though note that the default value for the horizontalAlignment and verticalAlignment properties already are SwingConstants.CENTER. So if this doesn't help, consider posting a small compilable and runnable program that uses images off of the net readily available to us to show us your problem, an sscce as well as posting images of what your current buttons look like.