I'm writing an application in Java that retrieves the cover art of books. Most of the images that I try retrieving are displayed just fine, but periodically, I'll run into one that doesn't display and I can't for the life of me figure out why. Maybe someone can help me. Here is the relevant code:
private BufferedImage cover;
try {
cover = ImageIO.read(new URL(coverArt.getImageURLs().get(0)));
} catch (IOException exception) {
System.out.println("error");
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//System.out.println(buttonPanel.getHeight());
if (LeftPanel.getCollectionTable().getSelectedRow() >= 0) {
g.drawImage(ComicBookCollection.getComicBookCollection().get(LeftPanel.getCollectionTable().getSelectedRow() + positionAdjust).getCover(),
12, 80, getWidth() - 25, getHeight() - 130, null);
} else {
repaint();
}
}
There is a list of strings of image urls that is compiled before this. I know that the list is being compiled correctly. For some reason, it is only for specific random titles. If I put Superman 2 in there, it doesn't come up, but if I put Superman 1 in there, it does. I've tried using the url of the problematic images in other programs and they display just fine. Maybe someone can figure out what is gong on.
The code looks fine, but it's non-standard so there may be some gotcha somewhere.
Try using standard Swing components for this. I.e. have the right panel be a JLabel, and make it show the image by wrapping it in an ImageIcon object and calling setIcon on the label.
Related
I'm working on some animation where I have a certain number of dots wandering around my JFrame and based on their distance they should be connected by lines of different strengths.
The base code for moving the dots works and actually I also had them displayed correctly in the beggining but I had some issues where the movement was stuttering (probably due to the repaint process). At that point the Window class handled the entire repaint procedure.
After reading some posts around here I adapted my code according to the github page linked in this post to use the individual Dots as JComponents and have them being repainted individually. However, now the problem is that although I still have 100 Dots as components on my JPanel, only one of them is being painted (however, the stuttering is gone at least). I also see that all components are being iterated and their repaint method is being called but they just don't display.
This is my paintComponent method in the Dot class:
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(new Color(0, 0, 0));
Ellipse2D.Double circle = new Ellipse2D.Double(x - 10 / 2, y - 10 / 2, 10, 10);
g2d.fill(circle);
}
And this is what my repaintTimer looks like:
final Timer repaintTimer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(Component component : window.getContentPane().getComponents()) {
component.repaint();
}
recalculateDots();
}
});
repaintTimer.start();
The result I get is something like this:
I tried some things of which I thought that it could solve the problem but nothing really helped and I'm really confused as to why this is happening. I'd appreciate any help very much because this issue doesn't make any sense for me.
I'm finishing my homework in OOP Java. The assignment is to load images on a JFrame, be able to move them around (top layer should be prioritized, it is currently not) and click them to "flip them" (change the source of the image essentially). I'm currently having trouble finding a solution on how to properly "layer" images that are visible on the screen and to prioritize the images on the top first (currently the bottom ones are being prioritized).
I also have issues finding a good way to change the source of the images, as our teacher has prohibited extending the Picture class with Swing.
My first attempt at solving this was saving the information of every individual "Picture" object in an ArrayList. This works to save the position of the images but does not solve my issue with the layering. I also wanted to use JLayeredPane but as I found out, it was harder than I thought as I have yet to find a viable solution this way (I might be missing some obvious facts about how it works).
I'm thinking what probably needs to happen is that I save the "position" of each image in some type of Array, then using this array to print out the images via paintComponent # ImagePanel. This is currently what I am doing but it does not act as I wish it to. I think my way of loading in the images in the "Picture" class might have something to do with it. I don't have a lot of experience in Java so all of this is new to me.
I don't want to print out all of my codes as I have 4 classes, so I'm going to print out what I feel are the essential methods in each class. If there's something missing that you guys need in order to guide me in the right direction I'll provide that aswell.
draw # Picture
public void draw(Graphics g, int i) {
try {
BufferedImage img = ImageIO.read(new File("images/icon_"+ i +".gif"));
g.drawImage(img, x, y, null);
} catch(IOException ie) {
System.out.println("Could not find images");
}
}
mousePressed & mouseDragged # MouseHandler
public void mousePressed (MouseEvent e) {
Point point = e.getPoint();
chosen = imagepanel.locateImage(point);
}
public void mouseDragged (MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (chosen != null) {
imagepanel.moveImage(chosen, x, y);
}
}
loadImages & paintComponent # ImagePanel
private final static int IMAGES = 7;
private ArrayList <Picture> imageCollection = new ArrayList<>();
private Picture im;
Random rand = new Random();
public void loadImages() {
for(int i=0; i<IMAGES; i++) {
int x = rand.nextInt(400) + 40;
int y = rand.nextInt(400) + 60;
im = new Picture(x,y);
imageCollection.add(im);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int i = 0;
for (Picture im : imageCollection) {
i++;
im.draw(g, i);
}
}
I expect the images to stack on top of eachother whenever "flipped" (clicked) or moved (dragged). They do not currently do this as they just maintain their "depth" position. I've tried implementing an Image[] without success.
I also have a flip method where I tried using setIcon (I was using ImageIcon instead of Image previously) but this did not really work for some reason.
I also would love for any feedback on the code so far and any improvements that could be made as I always want to improve.
EDIT: I manage to solve my problems, however I'm sure there's a better way to do this.
public void placeFirst(Picture im) {
int pos = imageCollection.indexOf(im);
imageCollection.remove(pos);
imageCollection.add(0, im);
}
public void flipImage(Picture im) {
im.flip();
placeFirst(im);
repaint();
}
public void moveImage(Picture im, Point point) {
im.move(point.x-(im.getWidth(im)/2), point.y-(im.getHeight(im)/2));
placeFirst(im);
repaint();
}
public Picture locateImage(Point point) {
for (int i=0; i<imageCollection.size(); i++) {
Picture im = imageCollection.get(i);
if (im.fits(point)) {
return im;
}
}
return null;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// There probably exists a better and visually nicer way of doing this
for (int i=imageCollection.size()-1; i>=0; i--) {
Picture im = imageCollection.get(i);
im.draw(g);
}
}
chosen = imagepanel.locateImage(point);
Well, we don't know how the locateImage(...) method works, but I would guess you just iterate through the array until you find a match.
So you will always find the same match.
So if you want an image to stack on top you have two issues:
you need to modify the search order so that when you click on an image you move it to position 0 in the ArrayList so it is always found first
but know when you paint images you need to paint images from the end of the ArrayList to the beginning, so the first image in the ArrayList gets painted last.
I'm currently trying to draw an image to a JFrame (just a nonsense test image). In the code bite below, the image is drawn to the JFrame, but the area around the image that doesn't fill JFrame is black that rapidly flashes.
Here is the code below:
try {
myImage = ImageIO.read(ImagesMain.class.getResource("/Textures/TestImage.png"));
}catch(Exception e) {
e.printStackTrace();
}
BufferStrategy strategy = null;
while(strategy == null) {//I know this is terrible practice, just doing this way because its inside main
strategy = myCanvas.getBufferStrategy();
if(myCanvas.getBufferStrategy() == null) {
myCanvas.createBufferStrategy(3);
}
}
myFrame.setVisible(true);
//Rendering part
while(true) {
do {
do {
g = strategy.getDrawGraphics();
g.setColor(Color.WHITE);
g.drawImage(myImage, 20, 20, null);
g.dispose();
}while(strategy.contentsRestored());
strategy.show();
}while(strategy.contentsLost());
}
I've tested and retested my code several times to no avail. I should also add that this is all done in the main method (for testing purposes). Long story short, how do I display my image without the unnecessary black flashing around the image?
When this happens, it is because one is not clearing the Frame to which they are drawing. In this instance,
g.clearRect(x, y, height, width); is needed to clear the drawing frame and display a clear image.
Answer courtesy of #MadProgrammer above, in comments.
I searched google for this problem, but i can't really resolve them.
More info on code below.
Here are the two snippets of code, relevant:
//prepare
g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0,0,getWidth(),getHeight());
for(ListIterator<Chunk> it = chunkvector.listIterator();it.hasNext();){
Chunk r = it.next();
r.drawChunk(g);
}
for(ListIterator<Entity> it = vectorpainter.listIterator();it.hasNext();){
Entity r = it.next();
r.drawObjects(g);
}
//Chat
if(coni.getVerified()){
try {
chat.update(g);
} catch (IOException e) {
println("I/O Exception while updating chat! "+e.toString());
}
//Framerate Anzeige
if(fps_on){
g.setColor(Color.red);
g.drawString("FPS: "+fps, 20, 20);
}
//Tickberechnung & Anzeige
tick++;
if(tick>=65536)
tick=0;
if(tick_on){
g.setColor(Color.red);
g.drawString("Tick: "+tick,80,20);
}
//end drawing
g.dispose();
strategy.show();
interesting about that:
Chunks, Entities are painted, white rect also, but fps and tick NEVER (both are true, of course), i even wrote System.out.print("..."); into the if-clauses, and it is executed! :S
I think it is something about GPU acceleration, so i added the second code block, how images are loaded. One entity does also drawString, (showing playername above head) and it works, but in the main thread not? :(
second:
public Image[] loadPics(String path, int cnt){
Image[] anim = new Image[cnt];
BufferedImage source = null;
BufferedImage temp;
URL pic_url = getClass().getResource(path);
if (pic_url == null) {
fail("Can't find ref: "+path);
}
try{
source = ImageIO.read(pic_url);
}catch(IOException e){
fail("Failed to load: "+path);
}
// create an accelerated image of the right size to store our sprite in
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
for(int x=0;x<cnt;x++){
temp = source.getSubimage(x*source.getWidth()/cnt, 0,
source.getWidth()/cnt, source.getHeight());
anim[x]= gc.createCompatibleImage(temp.getWidth(), temp.getHeight(), Transparency.BITMASK);
anim[x].getGraphics().drawImage(temp,0,0,null);
}
System.out.println(pic_url+" - loaded.");
return anim;
}
second one i copied from a tutorial, maybe a bit edited.Before that i"ve painted with paintComponent(Graphics g) ... this worked, tutorial have said i could get better performance using this method, so i tried, and want to manage it somehow.
Now it is drawing in a run loop, when i copy everything to paintComponent, no Images are drawn.
For those who managed to get past all the text a little bit of extra work:
The program runs fine on a university pc - not that good hardware ^^ , and bit of laggy at mine, which should be more than double the computationpower. Any ideas? :(
Java(c) 1.7
Many thanks, even you just read that! :)
Okay, this can be closed. My drawing problem had nothing to do with the code above.
Problem was, that things i wanted to paint were not in the picture. That I achieved through giving statements like:
fillRect(50,50,2/3*frame.getHeight(),130);
the 2/3 resolves to 0, multiplied with frameHeight...
Trick was to write (int)(2./3.*frame.getHeight())
and one time I also tried to draw a String into the panel section, where closing , maximize buttons are, that wont work too , of course.
THanks anyway!
I have a stickynote png image and I want to basically at runtime, grab the data in the database and then print out as many images onto the JPanel as there are records in the database, then print text over each png so there is a sticky note type of look and feel.
My problem is when I loop through and try to create images, do I need a separate image object reference for each one or can I reuse the same image object in the loop? This code would be in paintComponent in a class extending JPanel. I feel like I am thinking about this all wrong...
for example for(i=0;i<recordCount; i++
{
Image image = new ImageIcon("mysticky.png").getImage
}
My problem is that I think that this will overwrite each new image put on the Jpanel. What is the best way to do this? Thanks!
You need just one image.
Use:
ImageIcon image = new ImageIcon("mysticky.png");
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(ImagePanelImage nextim : backgroundImages) {
g.drawImage(image.getImage(), 0, 0, image.getIconWidth(), image.getIconHeight(), this);
}
}
You may want to search the web for the concept of 'background image' in java.