I have a array of images stored in a BufferedImage array. I want to display these images in a JFrame in a table like layout. How can I do so. Note: the number of images in the buffered image array is dynamic
1) use JList there you can put Icon (from BufferedImage), Renderer returns JLabel/JComponent by default
2) all changes (remove, reordering, add) must be done on EDT, then better would be manage all these event from SwingWorker or Runnable#Thread
3) put these Objects to the DefaultListModel for JList
There's both topics to address in your question : draw some BufferedImage (which is done with Graphics) and layout images.
You can do your own layout, but this can be tricky.
To let Swing do this for you, use a already defined layout (for instance GridLayout or FlowLayout) and add as many JPanel as you have BufferedImage. Make sure your JPanel has a fixed dimension (cf. setPreferredSize()).
Custom drawing is done with Graphics/Graphics2D API.
On every JComponent, you can get the underlying Graphics instance to customize the rendering. Draw each BufferedImage in the graphics2D instance of every JPanel.
The last trick is to normalize images dimensions and don't forget respect ratios when calling Graphics.drawImage or crop images if you want to respect aspect ratio (which is what the users expect most of the time).
Create JPanel and set it's layout manager to a GridLayout with the number of rows and columns you want in the grid.
Then for each BufferedImage create a JLabel and set its icon to a new IconImage that contains the BufferedImage.
Finally add all the JLabels to the JPanel in the order you want and add the JPanel to the JFrame.
Here's an example from the top of my head; some pseudocode since I don't have images to work with:
JFrame frame = new JFrame("Title");
JPanel gridPanel = new JPanel();
//Layout as a grid with 4 rows and 3 columns
gridPanel.setLayout(new GridLayout(4,3));
//Pseudocode.
for(each BufferedImage in BufferedImageArray as img) {
gridPanel.add(new JLabel(new ImageIcon(img));
}
frame.add(gridPanel);
//Other frame stuff you want here
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,600);
frame.setVisible(true);
Related
So, I have been having trouble drawing multiple objects on a JFrame, and I know I need to use Layout managers, so I decided to test it with one object before I do multiple, however when I run this code:
fps = 30;
panel = new JPanel();
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.addKeyListener(new key());
running = true;
update = true;
ball = new Ball(0,0,1);
//panel.setBackground(Color.BLACK);
panel.add(ball);
panel.setVisible(true);
frame.add(panel, BorderLayout.CENTER);
frame.requestFocus();
frame.setVisible(true);
startTime = System.currentTimeMillis();
nothing draws (There is more to the code, i just didnt want to inlcude all of it). However, when I remove the comment and set the background to black, the JFrame turns black. So why is it that it wont draw my Ball object (which i know works) but will change the background? Is there a specific way you need to draw on a JPanel?
panel = new JPanel();
By default a JPanel uses a FlowLayout which respects the size of any component you add to the panel.
ball = new Ball(0,0,1);
I have no idea what the code in your Ball class looks like, but I would guess the preferred size is (0, 0).
You need to override the getPreferredSize() method of your Ball class to return the size of the Ball so that your layout manager can do its job.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
I know I need to use Layout managers,
The problem with a layout manager in this case is that the layout manager will control the position of the Ball which may or may not be what you want. If you want balls in random positions, then you will need to use a null layout. Then you will need to use the setSize() and setLocation() methods to control each Ball component.
Another option is to do custom painting of all your Balls. In this case you would add an object that you want to paint to an ArrayList. Then the custom painting code would iterate through the object in the list and paint them individually. See Playing With Shapes for ideas on this approach.
I have a 2 JPanels, 1 a button Panel and one a Graphic Panel. I would like the button panel to situated right below the graphic panel but the button panel cuts off the Graphics Panel in the middle. I've been trying the box layout which seems from discussions seems like the best format for what I am trying to do. Can anyone please give me some advice on my formatting problem.
JFrame canvas = new JFrame("Baseball Strike K");
JFrame canvas = new JFrame ("GraphicBoard");
canvas.setVisible(true);
canvas.setSize(1000,1000);
canvas.setDefaultCloseOperation(EXIT_ON_CLOSE);
//create two panels
//add them to contentPane
//set Layout
JPanel buttonPanel = createButtons();
JPanel mainPanel = new Graphic(); //extends JPanel and writes the paint method
mainPanel.setSize(1000, 1000);
Container content = canvas.getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(mainPanel);
content.add(buttonPanel);
mainPanel.setSize(1000, 1000);
The job of the layout manager is to determine the size of the component, so you would never invoke the setSize() method of a components.
Instead you give hints to the layout manager on what the size should be. You would do this by overriding the getPreferredSize() method to return an appropriate value. Also, I would pick a more reasonable size (1000, 1000) is a little big to display on most screens. If you really want your painting area this large then I would add the paint panel to a JScrollPane and then add the scrollpane to the frame.
Try getting your code to work using a BoxLayout. Then I would suggest a better layout manager would be to use a BorderLayout. Then you add the paint panel to the CENTER and the buttons to the SOUTH. Now as you resize the frame the paint panel will be adjusted in size.
canvas.setVisible(true);
Also, the placement of that line of code is wrong. You should add all your components to the frame first, before making the frame visible.
I am making a small JFrame in which I draw a large triangle. On all the sides of the triangle there has to be a label. I have to position these labels myself, because of the irregular shape of the triangle (yes, there will also be a non-right-angled triangle). (I have specified setResizable(false) on my JFrame, so there is no need for multiple sizes.)
Would there be any way to manually set the location of all my labels, WITH a layout manager?
If you want to have a canvas in the middle and then labels on any of the 4 sides, you could use a BorderLayout, like so:
JPanel framePanel = new JPanel(new BorderLayout());
JPanel triangleCanvas = ...
framePanel.add(triangleCanvas, BorderLayout.CENTER);
JPanel northLabels = ...
framePanel.add(northLabels, BorderLayout.PAGE_START);
JPanel southLabels = ...
framePanel.add(southLabels, BorderLayout.PAGE_END);
JPanel eastLabels = ...
framePanel.add(eastLabels, BorderLayout.LINE_END);
JPanel westLabels = ...
framePanel.add(westLabels, BorderLayout.LINE_START);
frame.getContentPane().add(framePanel);
The tricky part will be if you want to somehow align where your labels are depending on the currently drawn triangle (or whatever is in the container), but hopefully you don't want to do that.
How to Use BorderLayout
You say that you want to draw the labels at irregular places e.g. at corners and at the sides the dhapes. Then I would recommend to use drawString(String s, int x, int y) in the Graphics2D API. So place the labels and draw then when you draw the figure.
See Lesson: Working with Text APIs for more advanced options like e.g. Fonts and Font metrics.
When you want to specify the exact position of labels, is the only case when you shouldn't use an Layout Manager.
Continuing my quest of learning Java by doing a simple game, i stumbled upon a little issue. My gameboard extends JPanel as well as each piece of the board. Now, this presents some problems:
Cant set size of each piece, therefore, each piece JPanel ocupy the whole JFrame, concealing the rest of the pieces and the background (gameboard).
Cant set the position of the pieces.
I have the default flow manager. Tried setbounds and no luck.
Perhaps i should make the piece to extend other JComponent?
Added image:
That's the piece, now the greyed area is also the piece! Checked that by making a mousePressed listener and assigning some stuff to it. Below the grey area, is the gameboard (or at least, should be!), another JPanel.
alt text http://img42.imageshack.us/img42/2227/screenshotvdy.png
Some code:
package TheProject;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameWindow extends JFrame {
public GameWindow() {
setSize(800, 600);
setLocationRelativeTo(null);
Map map = new Map(800, 600, 2);
add(map);
MilitaryUnit imperialRussia = new MilitaryUnit(30, Color.BLACK, Color.YELLOW, Color.WHITE);
imperialRussia.setPreferredSize(new Dimension(30, 30));
add(imperialRussia);
}
}
This happens when i apply the pack() method:
alt text http://img442.imageshack.us/img442/5813/screenshot2ml.png
Packs around the Unit, not the map which is bigger and fills the JFrame.
For a game that has random movement of pieces you would probably use a "null layout".
Read the section from the Swing tutorial on Absolute Positioning for more information.
I wrote a few games using JPanel. Basically the way I use JPanel is like I'm using a Canvas, viz I draw directly on it by overriding the paint() method. The reason why I use JPanel is because I can determine the size of my game world, then use the setPreferredSize() to set the size of the panel. I then add the panel to a JScrollPane. So this will take care of the panning, etc.
Say I'm writing a 2D game. This is how I use JPanel. I have a logical map (a 2D array) which holds my game map. Say each location is 32x32 pixel. So you start drawing the ground and what is on that ground in that location. eg in x=1, y=2 which is screen location x=32, y=64, you draw the ground first, then draw what is on the ground. So a rough outline of the render loop would be something like this
for (int y = 0; y < map.length; y++)
for (int x = 0; x < map[y].length; x++) {
drawGround(map[y][x])
for very element on on map[y][x] - render them
}
You set a MouseListener listener to the JPanel, so every mouse click you translate back to the map eg. mouse click x=54, y=72 would correspond to x=1, y=2. The calculation is a bit tricky if you have an isometric view.
The thing you have to be careful here is that everytime when you scroll the panel via the scroll panel, paint() will be called. So it is good to render your game board on a BufferedImage and then in the paint() method just draw the BufferedImage otherwise it'll be too slow.
Have you tried NetBeans' visual editor? You can use it to drag, drop, and resize to your convenience Swing objects in Design View, and can then switch to Code View to see the generated code. You can learn that way.
Have you tried setPreferredSize(Dimension d)?
Edit: You need to call pack() on your JFrame, after you've added your components:
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(800,600));
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200,200));
frame.add(panel);
frame.pack();
frame.setvisible(true);
Also, you add a Map to your JFrame, which has the same dimensions as your JFrame - fine. But then afterwards, you add another component, to the default flowlayout. This cannot fit into your frame, as the Map already occupies 100% of the space.
I have been using the printComponent that was shown in another question. It works great for printing a JPanel if I first add that JPanel to a JFrame and draw that JFrame to screen. But if I don't do that before I print, I get a blank page printed. Why is this?
I've used code like the following to create a BufferedImage on a panel that is not visible on the frame:
JPanel panel = new JPanel();
... // add components
panel.setSize(300, 300);
panel.doLayout();
that is because the panel you wish to draw has an initial size of 0,0. Once added to a container with a layout manager and is displayed, then it gets its "normal" size.