Is it Better to Paint or Use a JLabel - java

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.
}
}
}

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:
Lesson: Performing Custom Painting: for the nuts and bolts
Painting in AWT and Swing: for the gory details.
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).

Using JLabel will occupy space in container.
While drawing on container will not occupy container's space.

Related

Java Swing: Resizing component in JFrame without affecting other components

I have a very simple game I'm creating as a novice project. It's based on an online card game called "Castlewars". There are two players, each with a tower which is affected by cards they and their opponent play. At the moment I have the basic framework of collections and classes I need to make the game operate at a very simple level, but I'm having problems displaying these effects to the user. I have the following code, which should update, amongst other things, two jLabels on a jFrame GUI (constructed in NetBeans 7.4) which represent the player's towers:
private void adjustScreen(){
System.out.println (Integer.toString(jLabel1.getSize().height));
jLabel1.setSize(100, (playerRed.getTower().currentHeight() * 2));
System.out.println(Integer.toString(playerRed.getTower().currentHeight() * 2));
System.out.println (Integer.toString(jLabel1.getSize().height));
jLabel2.setSize(100, (playerBlue.getTower().currentHeight() * 2));
jLabel5.setText(Integer.toString(playerBlue.getTower().currentHeight()));
jLabel6.setText(Integer.toString(playerBlue.getGold()));
jLabel9.setText(Integer.toString(playerRed.getTower().currentHeight()));
jLabel10.setText(Integer.toString(playerRed.getGold()));
if (TurnBlue){
jPanel21.setBackground(inPlay);
jPanel10.setBackground(outPlay);
}else{
jPanel10.setBackground(inPlay);
jPanel21.setBackground(outPlay);
}
}
When I run it, i get the following output:
(Initial label height) - 200
(adjusted Tower().height) - 100
(adjusted label height) - 100
Which suggests that what I'm trying to do is working on some level, but the actual labels visually stay the same size.
At start (the initiation of the game should have set the labels to half their visible size):
After a couple of plays - the Blue's new tower height is shown in the top left
I've played around with enabling and disabling the resize property, both on the label and on the frame, and I did once manage to get it to resize, but it then shifted the other components of the frame in an unfortunate way. As you can see, the "Cards" at the bottom do seem to resize themselves, although I am not explicitly instructing them to do this (maybe an effect of the text length in the "Cards"?) What am I doing wrong?
After re-reading the question I realized the answer is not really an answer to the question but more of a list of suggestions. Rather than deleting it, I'll leave it up in case someone can gain something from it :-)
"What am I doing wrong?"
Welcome to the world of "Why I should use Layout Managers"
There's an ocean of problems that may arise from null layouts and trying to set size and location to everything. Swing was made to be used with Layout Managers.
Some layout managers will respect preferred sizes and some wont.
Use the correct layout manager and make use of nested JPanel with different layout managers to get your desired result
Make use of EmptyBorder and vgap and hgap for empty space.
Don't set size or location to anything. Let the layout managers take care of that for you.
Go over Laying out Components withing a Container to learn the different layout managers.
EDIT
If you're using Netbeans GUI BUilder take a look at this answer for some help with how to use different layout managers using the design tool.

How to make a jlabel resizable according to the window

I am using netbeans to design a JFrame.
now when i compile and run.It executes and opens a window
now the problem is when i maximixe the window..I want the image or Jlabel to cover the width of the jframe.
SO how can i do it.Plz Help
First stop using visual designer. Stop now. Immediately. Forget that it exists. Visual designers create non-maintainable code. They save 5 minutes at the beginning and cause you to spend hours later.
Now, take a look on any java layouts tutorial. For example this one: http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Once you read and understood it go back to your application. Think what layout(s) you need. Design the application. Implement it. If you still have problem that you cannot solve yourself within reasonable time ask more specific question again.
When you understand layouts good enough and want to implement real application with a lot of dialogs take a look on MigLayout.
A JLabel always paints the Icon at it actual size.
If you want dynamic scaling of the image then you need to do custom painting. Basically you would override the paintComponent(..) method of a JComponent with code like:
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
Of course you would need to pass the image as a parameter when you create the class. It also assumes you add the component directly to the content pane which uses a BorderLayout by default.
For fancier or more flexible solutions you could:
Use the Background Panel
Use Stretch Icon on a JLabel

How to resize components when resizing a JFrame? Using Null Layout

I am using the NetBeans Designer to create a JFrame. Also it is worth mentioning I am fairly new to Java so I might not understand some things / do things correctly. The frame has about 100 panels, more buttons than I would even think about counting, about ~40 tables, basically most swing components the NetBeans designer provides are being used within the frame. Also for the main frame I am using Null Layout (in order to have a background image inside a JLabel). I know it is not recommended but it doesn't affect the general layout of things as I'm using panels/LayeredPane/TabbedPane for everything, each with it's own design (most of them on Free Design with no Layout specified - that's how I started, didn't know about Layouts and it would take ages now to rearange everything after using Grid Bag Layout for example).
Now getting to my problem, I need to be able to resize the frame and make it resize all components contained. I have to carry a presentation tomorrow of it and I just noticed it doesn't fit on smaller displays (and resizing it doesn't do it properly, it just hides components). I do not care much if it's just an improvisation / not the best approach to the problem as after the 15 min presentation I will probably never open it again.
Thanks.
I would try to go through all the components tree and try to set them smaller font and reduce all their bounds to some static %.
In other words for each component multiply x,y,widht,height to e.g. 0.75 and call setFont() passing derived font of 25% smaller.

Animation with JComponents on Top

i wanted to ask, if somebody might have a solution about a problem i face. I am working at an application, which draws an animation - for instance a map with objects moving onto. My problem is, that on top of the drawing, a Jtable, Jlist as well as other Components are also placed.
In my particular example all of those components have been added to the Panel, which holds the map. In result each component gets redrawn as often as good my fps is. Therefore making one of the tables invisible reduces the already high cpu usage of sometimes around 50% to less than 30%.
My question is, how can i avoid calling somewhat static visual contents paintComponent() method, without having the "background" - the map - whited out the menu.
Since the animation redraws permanently the menu is not shown at all, if its separated from the corresponding JPanel.
First thoughts move into following directions:
Clipping - actually not as good as i would like to, since id like to enable moving around the menus.
JLayeredPane - already tried but seemed to turn out, that the paintComponent method of menus still gets called frequently.
JWindow/Internal Frame - had that thought a couple of minutes ago. Having a complete independent container shall be able to handle my regard, or?
I am looking forward, if somebody has an elegant idea, how to fix that and reduce the cpu usage significantly.
Thanks!!
Best regards.
I would create a custom Shape for clip. Use Area class and subtract from the Area all the children components' bounds.
For painting over JComponent(s) placed into JPanel you have look at
JLayer (Java7) based on JXLayer(Java6)
GlassPane, notice all JComponents must be lightweight, otherwise is GlassPane behind heavyweight (J)Components
is possible painting to the JViewport,
EDIT
you have to use Swing Timer for moving with Icon (in the JLabel) placed into JXLayer, GlassPane or JViewport, don't use Runnable#Thread and never, not by using plain Thread.sleep(int)

JPanel flipping out, FlowLayout not working as intended

The other day this code was working. I changed some things and re-ran it and now it doesn't work as intended. Obviously something I changed altered the behaviour, but I have gone back and reverted all of those changes and it still doesn't work. Disregarding that bit of information (to start), why does this code not place a 15x15 grid of JLabels inside of a JPanel?
gameBoard.setLayout(new FlowLayout());
for (int i = 0; i < 15; i++)
{
for (int j = 0; j < 15; j++)
{
JLabel tile = new JLabel("");
tile.setHorizontalAlignment(SwingConstants.CENTER);
tile.setPreferredSize(new Dimension(27, 27));
tile.setBorder(new EtchedBorder());
tile.setEnabled(false);
gameBoard.add(tile);
}
}
gameBoard is a JPanel defined through NetBeans' GUI Builder. It has a preferred size, a maximum size (same as preferred). The horizontal/vertical resizable options are disabled, yet when this code runs every button extends horizontally in a row without ever breaking.
If I understand correctly, FlowLayout is supposed to wrap elements when they reach the end of their containing element. This was happening before today, I don't really know why this behaviour stopped?
It would be much better to use a GridLayout.
GridLayout gridLayout = new GridLayout(15, 15);
The flow layout may have changed due to using a new look and feel, different fonts or some Java VM upgrade. Defining a flow layout for this use is not recommended as you're reliant on underlying sizes that can vary across virtual machines or look and feels.
In the interests of teaching a man how to fish:
Revision control systems are great. Even your system is making a back up of your source at frequent intervals.
A useful debugging technique is to take away things until it does work. Does setting a border cause you code to break. Going the other way, can you write a trivial program that demonstrates the problem.
I've found great success and control using TableLayout and I would recommend it to anyone. You can define the columns and rows using specific number of pixels, or you can just use TableLayout.PREFERRED for each column and/or row. Very nice and flexible Layout. We use it everywhere.
I figured it out. Apparently I had to set the preferredSize within the code itself. Just setting it in the Netbeans properties window is not enough. Strange.

Categories

Resources