3

I am working on a Swing application that will have some images in the background. I was wondering which of the following ways are more efficient (or better), or if you had another to suggest:

getGraphics().drawImage(t.getImage().getImage(), i * 16, j * 16, this);

or

JLabel tile = new JLabel(t.getImage());
tile.setBounds(i * 16, j * 16, t.getImage().getIconWidth(), t.getImage().getIconHeight());
add(tile);

Edit:

This is where the stuff will happen:

for (int j = 0; j < 3; j++) {
            for (int i = 0; i < 3; i++) {
                Tile t = map.getTiles()[j][i];
                if (t != null) {
                    // Draw it somehow.
                }
            }
        }
Roman C
  • 49,761
  • 33
  • 66
  • 176
nrubin29
  • 1,522
  • 5
  • 25
  • 53
  • I think(not sure) using the `JLable` is more safe, because it will draw the image with the thread which has been initialized the `JLable`. –  Oct 27 '13 at 18:02
  • @user2511414: no, neither technique has any thread safety issues. It's wrong to keep re-reading the image in whenever it is to be drawn however, but this is not a thread safety issue but rather is a slow down your program issue. – Hovercraft Full Of Eels Oct 27 '13 at 18:20
  • @HovercraftFullOfEels good point about the `repainting the image`, so I've got it wrong. thanks buddy :) –  Oct 27 '13 at 18:26

2 Answers2

6

Regarding:

getGraphics().drawImage(t.getImage().getImage(), i * 16, j * 16, this);

You should never draw with a Graphics object obtained by calling getGraphics() on a component as the Graphics object thus obtained will be short-lived, and your drawing can become unstable. To see what I mean, try using your technique, and then after your GUI has been created, minimize and restore it, and you'll likely see a portion or all of your image has disappeared. Instead you should either draw inside of the JPanel (or other JComponent-derived class)'s paintComponent(...) method using the Graphics object given you.

Also don't read in the image every time you want to draw it as doing this causes an unnecessary slowing of your program. Instead, if the images aren't huge, read them in once at program start up, put them in a BufferedImage or ImageIcon variable (depending on the need), and use them when and where needed in the application.


Regarding:

JLabel tile = new JLabel(t.getImage());
tile.setBounds(i * 16, j * 16, t.getImage().getIconWidth(), t.getImage().getIconHeight());
add(tile);

This is fine except for the setBounds(...) part which suggests that the program is not using layout managers appropriately. Let the JLabel and its ImageIcon set its own preferred size and let the layout managers use this when setting out components and sizing the GUI.

Note that you can give JLabel's layout managers and add components to them just as if they were a JPanel. The main difference is that JLabels are not opaque by default.


Regarding which is better, using a JLabel to hold the image or drawing in the paintComponent(...): often it depends on if the image must resize to fit the component. If so, draw in the JPanel's paintComponent(...). Otherwise use the JLabel.


Edit
Per your comments:

Regarding part two, I am not using a layout manager.

Then your GUI's are at risk of being ugly on different OS's, and are at risk of not being very extensible. The layout managers are one of the most powerful aspects of Swing programming, and if you use them your GUI's will be much easier to code, to update, to enhance, and to work well on other systems.

Regarding part two, what Graphics object am I passing to paintComponent()?

You don't pass any Graphics object into a JPanel's paintComponent(Graphics g). This is a method that is called by the JVM's repaint manager at either your suggestion (by calling repaint()) or the suggestion of the operating system.

Finally, are you saying that it doesn't really matter which of the two options I use?

No, I didn't say that. Please re-read my recommendation just above this edit.


Edit 2
Key Links:


Edit 3
For a tile map, I'd use ImageIcons for my tile images, and then would have them displayed within a grid of JLabels. This way, swapping tiles would be as trivial as calling setIcon(nextIcon) on the JLabel of interest.

For example, please see TrashGod and my answers to this question: jlabel images array.

Regarding:

As far as the layout manager, I have a good reason. I've made many GUIs with layout managers, but this one is special ;).

Do so at your own risk, and I'm willing to wager a beer that your reasoning for this is incorrect.


Edit 4

The reason why I am not using a layout manager is because I am trying to make a small RPG game in Swing.

Then the tiles would be best held in a container that uses a GridLayout, and that container could possibly be held in a JScrollPane so that you could scroll in whichever direction. You could then either have your sprites sit in the JLabels (by giving them an appropriate layout), or on top by using a JLayeredPane.

I don't want any comments telling me I can't or I shouldn't because if it is impossible, I'll find out on my own.

  • We're not here to tell you that you can't do anything, of course, but otherwise you can't stipulate what we should or shouldn't tell you. You've come here asking for our advice, and we have an obligation to tell you what we think would work best. You have a right to follow our advice or not since it's your program, but again, you can't stipulate what we can or can't tell you, other than that you should not tolerate or allow rude or offensive statements (flag the moderators if you see this, and they'll take care of it).
Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Regarding part two, I am not using a layout manager. Regarding part two, what `Graphics` object am I passing to `paintComponent()`? Finally, are you saying that it doesn't really matter which of the two options I use? – nrubin29 Oct 27 '13 at 18:21
  • Also, thanks for the part about not loading every time; I fixed that. – nrubin29 Oct 27 '13 at 18:22
  • As far as the layout manager, I have a good reason. I've made many GUIs with layout managers, but this one is special ;). As for `paintComponent()`, I assume you mean to override it, but I was confused before. All images drawn this way will always be the same size (16px by 16px). – nrubin29 Oct 27 '13 at 18:34
  • I see nothing in compare with previous..., any light at end of tunnel, answers are based on your effort, for better help sooner post an [SSCCE](http://sscce.org/), short, runnable, compilable – mKorbel Oct 27 '13 at 18:42
  • @HovercraftFullOfEels I have no reason to move the tiles, as they are static background images. I'm just going to go with the JLabels because they are easier. – nrubin29 Oct 27 '13 at 18:49
  • The reason why I am not using a layout manager is because I am trying to make a small RPG game in Swing. I don't want any comments telling me I can't or I shouldn't because if it is impossible, I'll find out on my own. – nrubin29 Oct 27 '13 at 18:51
  • @PogoStick29: please see **Edit 4**. – Hovercraft Full Of Eels Oct 27 '13 at 18:56
  • 4
    +1 for all the edits, @PogoStick29 `I have no reason to move the tiles, as they are static background images.` - One of the few potential. reasons (in my mind) for NOT using a layout manager is when you have random dynamically moving images. However, since you are using static images they should be positioned using a LayoutManager. Basically the code you are writing is duplicating the function of a layout manager anyway. One of the rules of programming is to not reinvent the wheel. – camickr Oct 27 '13 at 19:03
0

Using JLabel will occupy space in container.

While drawing on container will not occupy container's space.

nullptr
  • 3,320
  • 7
  • 35
  • 68
  • Are you sure that you can't put components over a JLabel? Even if you give it a decent layout manager? – Hovercraft Full Of Eels Oct 27 '13 at 18:10
  • Well you can put sibling components over JLabel, BUT many layout managers will restrict that! Now don't tell me that JLabel is also container, and can have contained components! Or using Z-Order, placing sibling components over each other. The purpose of JLabel is to label something! – nullptr Oct 27 '13 at 18:19
  • True the *main* purpose of a JLabel is to "label something", but it can be used as a container just like a JPanel, and no, the layout managers won't restrict anything about this as long as they are used correctly. Many of us Swing aficionados have been doing just this for years. – Hovercraft Full Of Eels Oct 27 '13 at 18:21
  • Yes, that's what I am saying, we can do anything, I can give you components placed over JLabel, or contained inside JLabel in 5 minutes, but I use JLabel to label something, or just like OP, to display some logo using JLabel. And using label in this normal way, will occupy space, but drawing with Graphics will not occupy space on container. – nullptr Oct 27 '13 at 18:26
  • Yes correct, and I respect you, but as far as I understood, OP is not using JLabel as container. OP is using JLabel with icon as component inside some container, and that's why I answered it will occupy space. If one is using FlowLayout, layout will not allow to place sibling component over JLabel. – nullptr Oct 27 '13 at 18:39
  • 1
    Cool, I've never seen that page. Regarding this issue I usually refer to my [Background Panel](http://tips4java.wordpress.com/2008/10/12/background-panel/) link which contains both solutions to allow the OP to make a choice and hopefully it will help people understand a little better how Swing works. Yes a label is generally used to label something, but I also like to challenge people to "think outside the box" a little when it comes to problem solving. – camickr Oct 27 '13 at 18:54