I'm trying to create a GUI for "Connect Four" with java swing but can't figure out how I can set the play field that will be filled up with the pawns(sorry if it isn't the right word but I'm Italian). Could anyone help me out?
You need to create a custom JPanel:
class BackgroundPanel extends JPanel {
private BufferedImage image;
public BackgroundPanel() {
URL resource = getClass().getResource("background.jpg");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
e.printStackTrace();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
and add it to your JFrame
I'm working on a program that will read a folder of images into a JList, and the picture that is selected in the JList will be drawn into a JPanel. I have two classes: ImageViewerPanel, which creates the panel to display the selected picture. I then have ImageViewerUI which will draw the JList, and the ImageViewerPanel will be added into the ImageViewerUI class. Here is the relevant code from the ImageViewerPanel class.
public ImageViewerPanel() {
initComponents();
}
public void setImage(BufferedImage image) {
this.image = image;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled == false) {
g.drawImage(image, 0, 0, null);
}else if(scaled == true) {
g.drawImage(image, 0, 0, 80, 80, null);
}
Here is the code from the ImageViewerUI class that is to refresh the panel with the image:
ImageViewerPanel imagePanel = new ImageViewerPanel();
BufferedImage displayedImage;
BufferedImage originalImage;
public ImageViewerUI() {
initComponents();
loadListWithImageFilenames();
updateImagePanel();
updateThumbnailImagePanel();
}
public final void updateImagePanel() {
try {
String currFile = (String) ("Images/" + imageList.getSelectedValue());
displayedImage = ImageIO.read(new File(currFile));
imagePanel.setImage(displayedImage);
} catch (IOException ex) {
Logger.getLogger(ImageViewerUI.class.getName()).log(Level.SEVERE, null, ex);
}
public final void updateThumbnailImagePanel() {
try {
String currFile = (String) ("Images/" + imageList.getSelectedValue());
originalImage = ImageIO.read(new File(currFile));
imagePanel.setScaled(true);
imagePanel.setImage(originalImage);
imageViewerPanel1.add(imagePanel);
imagePanel.repaint();
} catch (IOException ex) {
Logger.getLogger(ImageViewerUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
The issue I am having is that the image is not being displayed in the panel. Anyone know why?
imageViewerPanel1.add(imagePanel);
imagePanel.repaint();
When you add components to a visible GUI the code should be:
imageViewerPanel1.add(imagePanel);
//imagePanel.repaint();
imageViewerPanel1.revalidate();
imageViewerPanel1.repaint();
All components are created with a size of (0, 0) so there is nothing to paint. The revalidate() invokes the layout manager which in turn gives a size to the compoenent.
As mentioned above you will also need to override the getPreferredSize() method of you imagePanel so the layout manager can determine the proper size of the panel.
This is my first time asking a question on here, and I'm hoping I get an answer or an idea that will help me.
I am drawing a large image and scaling it down with drawImage(). I then immediately draw another image with drawImage() that I expect to be drawn on top of the previous one (second). The problem is that drawImage returns immediately, even if it takes ~50 ms to scale and render the first image. Most of the time the second image ends up underneath the first one because it's painted first while the big first one is being processed. Basically is there anyway to force drawImage() to block until it's done, or to somehow check when it has completed?
I'm aware of the ImageObserver parameter, which works fine when downloading an image from the Internet or something, but when using an already-loaded BufferedImage, it never fires ImageUpdate() just after scaling and drawing. Basically since the first image is already "loaded" it never contacts the ImageObserver, it just takes like ~50 ms in it's own thread to process, never notifying when it completes.
Does anyone know how to either force it to block or wait until it's completely done scaling and blitting an image? And obviously using Thread.sleep(xx) is a complete hack and not viable due to differences between computer speeds. All this rendering is happened on the Event thread inside the paint(Graphics g) method.
Thanks!
EDIT: The following is code I currently have to give you an idea of the issue:
public void paint(Graphics window)
{
window.setColor(Color.WHITE);
window.fillRect(0, 0, Settings.width * Settings.aaFactor, Settings.height * Settings.aaFactor);
Graphics2D window2D = (Graphics2D) window;
window2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
window2D.drawImage(this.image, 0, 0, Settings.width, Settings.height, null);
try
{
Thread.sleep(50);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
window2D.drawImage(this.image2, 0, 0, null);
repaint();
}
EDIT 2: To better explain the problem I'm talking about, I made some sample code that does better what I'm trying to explain. Run it and you will see it flickering where sometimes the first image is on bottom (like it's supposed to be), but most of the time it will be one top (second), which is wrong. Just change the File paths to a small image and a large image.
public class Main extends Applet implements ImageObserver
{
private BufferedImage imageA;
private BufferedImage imageB;
#Override
public void init()
{
try
{
this.imageA = ImageIO.read(new File("C:\\LargeImage.jpg"));
this.imageB = ImageIO.read(new File("C:\\SmallImage.jpg"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public void update(Graphics g)
{
paint(g);
}
#Override
public void paint(Graphics g)
{
Graphics2D w = (Graphics2D) g;
w.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
w.drawImage(this.imageA, 0, 0, 50, 50, this);// This takes a while to do (scaling down and drawing)...
w.drawImage(this.imageB, 10, 10, null);// While this is drawn quickly, before A is done.
repaint();
}
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
System.out.println("ImageObserver fired, done drawing image. NEVER CALLED!");
return false;
}
}
The last argument to drawImage (where you pass null) is an ImageObserver. If you provide your own implementation of that interface (see JavaDoc), you will be informed when the image has been actually drawn.
It is impossible to know when Swing will actually render the contents of a Graphics object to the screen. What is know is it won't happen until AFTER the paint methods return (as the Graphics object hasn't been finalised for rendering until it does).
What you should do is let the Component you are painting to make the decision as to when something needs to updated, this is the way it was designed...(Component implements ImageObserver)
The below example continuously re-scales the master background image as the frame is resized
public class TestPaint03 {
public static void main(String[] args) {
new TestPaint03();
}
public TestPaint03() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PaintPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PaintPane extends JPanel {
private BufferedImage background;
private BufferedImage foreground;
private Image scaled;
public PaintPane() {
try {
background = ImageIO.read(new File("/path/to/background/image));
foreground = ImageIO.read(new File("path/to/foreground/image"));
} catch (Exception e) {
}
}
#Override
public void invalidate() {
scaled = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
if (scaled == null) {
int size = Math.min(getWidth(), getHeight());
scaled = background.getScaledInstance(-1, size, Image.SCALE_SMOOTH);
}
int x = (getWidth() - scaled.getWidth(this)) / 2;
int y = (getHeight() - scaled.getHeight(this)) / 2;
g.drawImage(scaled, x, y, this);
x = (getWidth() - foreground.getWidth()) / 2;
y = (getHeight() - foreground.getHeight()) / 2;
g.drawImage(foreground, x, y, this);
}
}
}
}
While I'm sure you have your reasons, personally I would avoid Applet in favor of JApplet and in fact, I would personally avoid applets or together. I started my career coding applets, they are simply a pain, especially when all you're trying to do is test an idea.
I have an applet. I set its image background. It works fine.
Now I want to set a background image to a JSlider.
How can I do that?
You will need to create a custom JSlider class and override the paintComponent method. Be sure to call setOpaque(false) on your slider object.
public class CustomSlider extends JSlider
{
private Image img = null;
public CustomSlider()
{
try
{
img = ImageIO.read(new File("background.jpg"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g)
{
// Draw the previously loaded image to Component
g.drawImage(img, 0, 0, null);
super.paintComponent(g);
}
}
I am trying to use Painter to make a certain jpg become my background.
mapScreen = new Form("Map");
try
{
Image image = Image.createImage("/res/try.jpg");
map = new Map(image);
mapScreen.addComponent(map);
} catch (Exception e)
{
System.out.print("Error\n\n"+e.getMessage());
mapScreen.addComponent(new Label(e.getMessage()));
}
And for the map class,
public Map(Image image)
{
this.mapImage = image;
painter = new Painter()
{
public void paint(Graphics g, Rectangle clippingRect)
{
g.clipRect(0, 0, getWidth(), getHeight());
g.drawImage(mapImage, getX(), getY());
}
};
}
public void initComponent()
{
setX(0);
setY(0);
getSelectedStyle().setBgTransparency(0);
getSelectedStyle().setBgPainter(painter);
getUnselectedStyle().setBgTransparency(0);
getUnselectedStyle().setBgPainter(painter);
}
The problem with this is that the image doesn't show up at all and when I try to debug, It doesn't even enter the paint(Graphics g, Rectangle clippingRect)...
The code
try
{
Image image = Image.createImage("/res/try.jpg");
map = new Map(image);
mapScreen.addComponent(map);
}
is successful.
Can anyone tell me how to do it properly?
And also, if anyone know how to do panning on an image larger than the size of the screen, Can you help me with that also? Thanks.
Use setBgTransparency to 255 and don't call the clipRect method.
You can look at the bg painter code within Component.java which is pretty flexible.