I'm testing JavaCV to update a JPanel with the image from my webcam. It works well except when i use setSize of JFrame to set width to my resolution (my resolution is 1366 x 768).
When i make this (set width to 1366), the repaint of the JPanel does not work properly and the image freeze. When i set width to 1365 or 1367 it works very well.
To test, i created a button that adds 8 to width in every click. I start the form with 1350 in width and when width is changed to 1366 (after 2 clicks) the repaint stops.
Anybody knows what happens? Below my code.
package com.pictap;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import org.apache.log4j.Logger;
import com.googlecode.javacv.FrameGrabber;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
public class PicTap {
private static final Logger logger = Logger.getLogger(PicTap.class);
private static JFrame form;
private static ImagePanel panel;
private static FrameGrabber grabber;
private static JTextPane status;
private static Integer counter = 0;
public static void main(String[] args) {
//Declare FrameGrabber to import output from webcam
grabber = new OpenCVFrameGrabber("");
try{
IplImage img;
BufferedImage bi;
// Show GUI
form = new JFrame("PicTap");
form.setSize(1350, 768);
form.setLayout(new BorderLayout());
form.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new ImagePanel();
panel.setDoubleBuffered(true);
panel.setBackground(Color.BLACK);
form.add(panel, BorderLayout.CENTER);
panel.setVisible(true);
JButton increase = new JButton("Aumentar");
form.add(increase,BorderLayout.NORTH);
increase.setVisible(true);
increase.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
form.setSize(form.getSize().width + 8, 768);
}
});
JButton close = new JButton("Sair");
form.add(close,BorderLayout.SOUTH);
close.setVisible(true);
close.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
// Stop the processor doing the movie capture first
try {
grabber.stop();
} catch (Exception e3) {
logger.error("Exception 3" + e3.getMessage());
e3.printStackTrace();
}
form.setVisible(false);
System.exit(0);
}
});
status = new JTextPane();
status.setText("Status");
form.add(status, BorderLayout.SOUTH);
status.setVisible(true);
form.setAlwaysOnTop(true);
form.setUndecorated(true);
//form.setLocationRelativeTo(form);
form.setVisible(true);
// Start grabber to capture video
grabber.start();
while (true) {
logger.debug("Counter loop: " + counter++);
// insert grabed video fram to IplImage img
img = grabber.grab();
//IplImage grayImage = IplImage.create(width, height, IPL_DEPTH_8U, 1);
bi = img.getBufferedImage();
panel.updateImage(bi, status);
panel.invalidate();
panel.repaint();
form.repaint();
form.invalidate();
form.repaint();
}
} catch (Exception e1) {
logger.error("Exception 1" + e1.getMessage());
e1.printStackTrace();
}
}
}
class ImagePanel extends JPanel {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(ImagePanel.class);
private static Integer counter = 0;
BufferedImage localImage;
public ImagePanel(){
}
public void updateImage(BufferedImage image, JTextPane status){
localImage = image;
}
public void paintComponent(Graphics g){
logger.debug("Counter paint: " + counter++);
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(localImage, null, 0, 0);
}
}
Related
I checked this code for hours, but the rectangle is not showing, can anyone tell me why it is not showing?:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
int resx = 700,resy = 500;
frame.setSize(resx,resy);
frame.setLocationRelativeTo(null);
frame.setTitle("Game");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
try {
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:\\Users\\ivans\\Pictures\\Cookies.png")))));
} catch (IOException e) {
}
frame.repaint();
frame.setLayout(new FlowLayout());
frame.add(new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(50,50,450,650);
}
}, BorderLayout.CENTER);
frame.repaint();
frame.setVisible(true);
}
}
Every time I try to activate the background, the rectangle is not shown, and every time I activate the rectangle, the background is not shown. Please help!
You're setting the JFrame's contentPane to a JLabel, a container that uses no layout, and so adding a component to it will not allow that component to be displayed unless you fully specify that component's size and position, i.e., its bounds. This is one reason I avoid using JLabels for contentPanes (also that it will not set its preferred size based on the components it holds) and instead in general prefer to do my drawing in a background JPanel's paintComponent method.
Side recommendations:
You've too much going on in the main method -- unless this program is not for anything other than demonstration purposes
You set the JFrame's original contentPane (a JPanel) to FlowLayout, but understand that this is meaningless once you change the contentPane.
Despite your assuming that the contentPane uses FlowLayout, you're trying to add the drawing JPanel into a BorderLayout position, something that doesn't make sense.
You have an empty catch block, something that almost never should be done.
Get your images as resources, not files.
Avoid using absolute file paths and prefer use of relative paths to resources.
Don't set sizes of things if you can avoid it.
Avoid so-called "magic numbers", e.g., g.fillRect(50,50,450,650); as this makes your code hard to debug and enhance.
For example, something like:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShowRectangle extends JPanel {
private static final int RECT_X = 50;
private static final int RECT_Y = RECT_X;
private static final int RECT_W = 200;
private static final int RECT_H = 200;
private static final String URL_SPEC = "https://duke.kenai.com/guitar/DukeAsKeith-daylightSmall.png";
private BufferedImage img;
public ShowRectangle(BufferedImage img) {
this.img = img;
}
// have same JPanel draw image and graphic element
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// avoid magic numbers
// g.fillRect(50,50,450,650);
g.fillRect(RECT_X, RECT_Y, RECT_W, RECT_H);
}
// Size the JPanel to the image size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
private static void createAndShowGui(BufferedImage image) {
ShowRectangle mainPanel = new ShowRectangle(image);
JFrame frame = new JFrame("ShowRectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
URL imageUrl = new URL(URL_SPEC);
BufferedImage img = ImageIO.read(imageUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
If you avoid using "magic" numbers for instance, it's easy to make the black rectangle draggable, since it is now be drawn by variable values, values that you can change inside of a MouseAdapter (MouseListener and MouseMotionListener combined). For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShowRectangle extends JPanel {
private static final int RECT_X = 50;
private static final int RECT_Y = RECT_X;
private static final int RECT_W = 200;
private static final int RECT_H = 200;
private static final String URL_SPEC = "https://duke.kenai.com/guitar/DukeAsKeith-daylightSmall.png";
private int rectX = RECT_X;
private int rectY = RECT_Y;
private BufferedImage img;
public ShowRectangle(BufferedImage img) {
this.img = img;
MouseAdapter myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
// have same JPanel draw image and graphic element
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
// avoid magic numbers
// g.fillRect(50,50,450,650);
g.fillRect(rectX, rectY, RECT_W, RECT_H);
}
// Size the JPanel to the image size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
return new Dimension(img.getWidth(), img.getHeight());
}
private class MyMouse extends MouseAdapter {
private Point p1;
private Point rectP = null;
#Override
public void mousePressed(MouseEvent e) {
p1 = e.getPoint();
if (new Rectangle(rectX, rectY, RECT_W, RECT_H).contains(p1)) {
rectP = new Point(rectX, rectY);
}
}
#Override
public void mouseDragged(MouseEvent e) {
moveRect(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
moveRect(e.getPoint());
rectP = null;
}
private void moveRect(Point p2) {
if (rectP == null) {
return;
}
rectX = rectP.x + p2.x - p1.x;
rectY = rectP.y + p2.y - p1.y;
repaint();
}
}
private static void createAndShowGui(BufferedImage image) {
ShowRectangle mainPanel = new ShowRectangle(image);
JFrame frame = new JFrame("ShowRectangle");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
URL imageUrl = new URL(URL_SPEC);
BufferedImage img = ImageIO.read(imageUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
Its there just it was going out of boundary and hence not visible.
replace these two lines and check
g.setColor(Color.BLACK);
g.fillRect(0,0,250,250);
Try this,
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle clipBounds = g.getClipBounds();
System.out.println(clipBounds.getX() +" "+ clipBounds.getY() + " "+ clipBounds.getHeight() + " " + clipBounds.getWidth());
g.setColor(Color.BLACK);
g.fillRect(0,0,450,450);
}
You will get 0.0 0.0 10.0 10.0
as output meaning the fill reactangle container is starting from 0,0 till 10,10 and hence it was not shown
Change the layout to GridLayout() will solve your problem,
frame.setLayout(new GridLayout());
frame.add(new JPanel(new GridLayout()){
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Rectangle clipBounds = g.getClipBounds();
System.out.println(clipBounds.getX() +" "+ clipBounds.getY() + " "+ clipBounds.getHeight() + " " + clipBounds.getWidth());
g.setColor(Color.BLACK);
g.fillRect(frame.getWidth()/2,0,frame.getWidth(),frame.getWidth());
}
}, BorderLayout.CENTER);
As per doc,
void java.awt.Graphics.fillRect(int x, int y, int width, int height)
Fills the specified rectangle. The left and right edges of the rectangle are at x and x + width - 1. The top and bottom edges are at y and y + height - 1. The resulting rectangle covers an area width pixels wide by height pixels tall. The rectangle is filled using the graphics context's current color.
Parameters:
x the x coordinate of the rectangle to be filled.
y the y coordinate of the rectangle to be filled.
width the width of the rectangle to be filled.
height the height of the rectangle to be filled.
So that's the issue
I am having trouble with my Java project for school.
The plan was to make a simple game where you need to catch the ball and if you catch the ball you will get points.
At the moment I have 2 problems:
I have no idea how I make the balls appear at a random width and make it stay at that width (cause random value is constantly changing ).
How can I make a statement that checks if the catcher caught the ball?
This is my current code:
import instruct.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.Timer;
public class opdracht extends WindowPanel implements MouseMotionListener {
List<comet> comets;
Image afb1;
Image afb2;
Image comet;
int xmuis;
int score;
int random;
int h;
int plaats;
static int randomNum;
private static final int D_W = 700;
private static final int X_INC = 10;
public opdracht() throws IOException {
score = 0;
h = -100;
afb1 = ImageIO.read(new File("afb/space.jpg"));
afb2 = ImageIO.read(new File("afb/pipe.png"));
BufferedImage cometbuf = ImageIO.read(new File("afb/comet.png"));
File output = new File("comet.png");
ImageIO.write(cometbuf, "png", output);
comet = ImageIO.read(new File("comet.png"));
addMouseMotionListener(this);
try {
drawcomet();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
plaats = randomNum;
comets = new LinkedList<>();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Iterator<comet> it = comets.iterator();
while (it.hasNext()) {
comet ball = it.next();
if (ball.h > D_W) {
it.remove();
System.out.println(comets.size());
} else {
ball.h += X_INC;
repaint();
}
}
}
});
timer.start();
}
public void paintComponent(Graphics g) {
g.drawImage(afb1, 0, 0, 1200, 800, this);
g.setColor(Color.yellow);
g.setFont(new Font("TimesRoman", Font.PLAIN, 30));
g.drawString("score = " + score, 1020, 30);
for (comet ball : comets) {
ball.drawcomet(g);
}
g.drawImage(afb2, xmuis, 730, 70, 75, this);
}
public static void randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
randomNum = rand.nextInt((max - min) + 1) + min;
System.out.print(randomNum);
}
public void drawcomet() throws InterruptedException {
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
comets.add(new comet(comet));
}
}, 0, 2, TimeUnit.SECONDS);
}
public class comet {
protected int h;
Image comet;
public comet(Image image) {
comet = image;
}
public void drawcomet(Graphics g) {
g.drawImage(comet, plaats, h, 75, 50, null);
}
}
public void mouseMoved(MouseEvent e) {
xmuis = e.getX();
repaint();
}
public void mouseDragged(MouseEvent e) {
// do something
}
public static void main(String[] a) throws IOException {
new opdracht().createGUI();
}
}
package instruct;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WindowPanel extends JPanel {
JFrame frame;
public WindowPanel() {
this.setPreferredSize(new Dimension(1200, 800));
this.setFocusable(true);
this.requestFocusInWindow();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// System.out.println( "class: "+ getClass().getName() );
frame.setTitle("Space Game");
}
protected void createAndShowGUI() {
frame = new JFrame();
frame.setSize(1200, 800);
frame.setLocation(300, 100);
frame.setResizable(false);
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor =
Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0),
"blank cursor");
// Set the blank cursor to the JFrame.
frame.getContentPane().setCursor(blankCursor);
}
public void createGUI() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public JFrame getFrame() {
return frame;
}
}
First question: "I have no idea how i make the ball's appear at a random width."
I assume you want to give the ball (= an instance of the comet class) a random x position (= the plaats field)? You could make the following changes (which make the randomNum field no longer required, this could now be a local variable):
//plaats = randomNum;
plaats = randInt(0, 1200);
// more code...
//public static void randInt(int min, int max) {
public static int randInt(int min, int max) {
// more code...
return randomNum;
}
Second question: "And how can make a statement that checks if catcher cached ball."
To determine whether the ball is catched, you could compare xmuis to plaats when the y coordinate of the ball (the h field?) is equal to the top of the pipe (around 730).
I've been trying to move, and display an image (e.g. heart rate image). Here is what I have so far. The image keeps moving to the left forvever; so far so good. But I need to embed this moving image inside another frame. I know my question seems very
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class HeartBeat extends JPanel{
public static void main(String[] args) throws Exception {
new HeartBeat();
}
public HeartBeat(){
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel j = new JPanel();
j.add(new HeartBeat2());
frame.add(j);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
class HeartBeat2 extends JPanel{
BufferedImage bi;
public HeartBeat2(){
try {
bi = ImageIO.read(new URL("http://i.stack.imgur.com/i8UJD.jpg"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Runnable r = new Runnable() {
#Override
public void run() {
final BufferedImage canvas = new BufferedImage(
bi.getWidth(), bi.getHeight(),
BufferedImage.TYPE_INT_RGB);
final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
ActionListener animator = new ActionListener() {
int x = 0;
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g = canvas.createGraphics();
// paint last part of image in left of canvas
g.drawImage(bi, x, 0, null);
// paint first part of image immediately to the right
g.drawImage(bi, x + bi.getWidth(), 0, null);
// reset x to prevent hitting integer overflow
if (x%bi.getWidth()==0) x = 0;
g.dispose();
animationLabel.repaint();
x--;
}
};
Timer timer = new Timer(40, animator);
timer.start();
JPanel j = new JPanel();
JOptionPane.showMessageDialog(null, animationLabel);
timer.stop();
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}}
The problem with the code is
The animationLabel is being added to the JOptionPane, but you never add it to the HeartBeat2
The JOptionPane.showMessageDialog is a blocking (modal) call, so it blocks any code occurring after it (i.e. timer.stop()). But if you remove that JOptionPane (to try and add the label to the panel) the timer.stop() will automatically be called (The timer is controlling the image/animation). And if you just leave the JOptionPane there, the adding the label to panel won't work, as each component can only have one parent
So you need to
First of all, completely strip out the Runnable. You don't need it.
Take out the JOptionPane, and simply add(animationLabel) to the HeartBeat2
Take out the timer.stop()
public HeartBeat2() {
try {
bi = ImageIO.read(new URL("http://i.stack.imgur.com/i8UJD.jpg"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
final BufferedImage canvas = new BufferedImage(
bi.getWidth(), bi.getHeight(),
BufferedImage.TYPE_INT_RGB);
final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
add(animationLabel);
ActionListener animator = new ActionListener() {
int x = 0;
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g = canvas.createGraphics();
// paint last part of image in left of canvas
g.drawImage(bi, x, 0, null);
// paint first part of image immediately to the right
g.drawImage(bi, x + bi.getWidth(), 0, null);
// reset x to prevent hitting integer overflow
if (x % bi.getWidth() == 0) {
x = 0;
}
g.dispose();
animationLabel.repaint();
x--;
}
};
Timer timer = new Timer(40, animator);
timer.start();
}
I am setting up a screenmanager for my game and it is not working as I want it to. I developed methods for toggling between fullscreen and windowed on a JFrame that is passed to this screenmanager but it gives me bugs that should not be present. In order to get exclusive fullscreen I want to remove the decoration on the frame via setUndecorated and this requires the frame to not be visible. So I apply setVisible(false) right before any setUndecorated yet it has no effect. SetUndecorated still complains about visibility when the printout clearly shows the frame is NOT visible.
Edit: On discussions with the helpful commenter below, I discovered that my bufferstrategys content is completely lost when toggling out of fullscreen, how do you avoid this?
Called from fullscreen before toggle, visible? false
Called from fullscreen after toogle, visible? false
Called from windowed before toggle, visible? true
Exception in thread "main" java.awt.IllegalComponentStateException:
The frame is displayable.
at java.awt.Frame.setUndecorated(Unknown Source)
at gfx.ScreenManager.setWindowed(ScreenManager.java:100)
at gfx.ScreenManager.main(ScreenManager.java:145)
Called from windowed after toggle before decorated, visible? false
The current iteration of my screenmanager:
package gfx;
import java.awt.DisplayMode;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class ScreenManager {
private JFrame frame;
private GraphicsDevice gd;
private DisplayMode defaultMode;
private DisplayMode[] supportedModes;
// Use with frame from elsewhere
public ScreenManager(JFrame frame) {
this();
this.frame = frame;
}
// Used with a frame that is tied to instance
public ScreenManager() {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
this.gd = ge.getDefaultScreenDevice();
this.defaultMode = new DisplayMode(800, 600, 16, 60);
this.setSupportedModes();
this.frame = new JFrame();
}
// Get the supported displayrates from current graphicsdevice
private void setSupportedModes() {
this.supportedModes = gd.getDisplayModes();
}
// Check if the supplied displaymode is supported by current device
public boolean isSupportedDisplayMode(DisplayMode odm) {
for (DisplayMode dm : this.supportedModes) {
if (dm.getHeight() == odm.getHeight()
&& dm.getWidth() == odm.getWidth()
&& dm.getBitDepth() == odm.getBitDepth()
|| odm.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI
&& dm.getRefreshRate() == odm.getBitDepth()
|| odm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN)
return true;
}
return false;
}
public void setFullScreen(DisplayMode displayMode) {
this.setFullScreen(displayMode, frame);
}
// Set fullscreen if supported displaymode, else default displaymode
public void setFullScreen(DisplayMode displayMode, JFrame frame) {
if (gd.isFullScreenSupported()) {
// Fullscreen on visible frame not allowed
System.out
.println("Called from fullscreen before toggle, visible? "
+ frame.isVisible());
frame.setVisible(false);
System.out.println("Called from fullscreen after toogle, visible? "
+ frame.isVisible());
// Remove decoration and unresiable
frame.setUndecorated(true);
frame.setResizable(false);
frame.setIgnoreRepaint(true);
// Set frame as fullscreenwindow
gd.setFullScreenWindow(frame);
// Set default if requested not supported or null
if (displayMode == null || !isSupportedDisplayMode(displayMode))
gd.setDisplayMode(defaultMode);
else
gd.setDisplayMode(displayMode);
// Create bufferstrategy
frame.createBufferStrategy(2);
}
}
// Make windowed
public void setWindowed() {
// Windowed from fullscreen if fullscreen, otherwise we are probably
// windowed already
if (gd.getFullScreenWindow() != null) {
System.out.println("Called from windowed before toggle, visible? "
+ frame.isVisible());
frame.setVisible(false);
System.out
.println("Called from windowed after toggle before decorated, visible? "
+ frame.isVisible());
frame.setUndecorated(false);
frame.setVisible(true);
frame.setIgnoreRepaint(false);
gd.setFullScreenWindow(null);
// gd.getFullScreenWindow().dispose(); < Clears frame, you lose all
// info, da fuck is the point of this except on gamexit from
// fullscreen?
}
}
// Get the drawing graphics of this ScreenManagers bufferstrategy
public Graphics2D getGraphics() {
Window frame = gd.getFullScreenWindow();
if (frame != null) {
BufferStrategy bufferStrategy = frame.getBufferStrategy();
return (Graphics2D) bufferStrategy.getDrawGraphics();
}
return null;
}
public void update() {
Window frame = gd.getFullScreenWindow();
if (frame != null) {
BufferStrategy bufferStrategy = frame.getBufferStrategy();
if (!bufferStrategy.contentsLost())
bufferStrategy.show();
}
Toolkit.getDefaultToolkit().sync();
}
// Display in readable format, eg 800x600x32#60
public String displayModeToString(DisplayMode dm) {
return dm.getWidth() + "x" + dm.getHeight() + "x" + dm.getBitDepth()
+ "#" + dm.getRefreshRate();
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
frame.setSize(800, 600);
ScreenManager sm = new ScreenManager(frame);
sm.setFullScreen(new DisplayMode(1680, 1050, 32, 60));
Thread.sleep(3000);
sm.setWindowed();
}
The interesting methods are setWindowed and setFullScreen.
Edit: To the comment below, this new main draws a string on the fullscreen buffer, displays it, then when exiting fullscreen it is completely gone, this is without disposing and not worrying about decorations. This is quite odd considering that I go into fullscreen first and the fullscreen method creates a buffer that is attached to the JFrame so even if I leave fullscreen the JFrame now has a bufferstrategy attached to it. So the buffercontent is lost for some reason between the transitions..
// Make windowed
public void setWindowed() {
// Windowed from fullscreen if fullscreen, otherwise we are probably
// windowed already
if (gd.getFullScreenWindow() != null) {
// gd.getFullScreenWindow().dispose();
gd.setFullScreenWindow(null);
// frame.setUndecorated(false);
frame.setVisible(true);
}
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
frame.setSize(800, 600);
ScreenManager sm = new ScreenManager(frame);
sm.setFullScreen(new DisplayMode(1680, 1050, 32, 60));
Graphics2D g2d = sm.getGraphics();
g2d.setColor(Color.red);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("Serif", Font.PLAIN, 96);
g2d.setFont(font);
g2d.drawString("jade", 40, 120);
g2d.dispose();
sm.update();
Thread.sleep(3000);
sm.setWindowed();
}
I created something that out of this space constalations can fired various exceptions :-), and big sorry there is the same with setUndecorated(false), but required to stopping ImageGnerator, then waiting for all events are done on EDT, then to change decorations type, .........
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class FullScreen {
private static final long serialVersionUID = 1L;
private GraphicsDevice device;
private JButton button = new JButton("Close Meeee");
private JPanel myPanel = new JPanel();
private JFrame frame = new JFrame();
private JLabel imageLabel;
private Dimension halfScreenSize;
private Random random;
private JProgressBar memory;
private Dimension d;
private Font bigFont = new Font("Arial", Font.BOLD, 30);
private int count = 0;
private int startMem = 0;
private int maxMem = 0;
private int peakMem = 0;
private int useMem = 0;
private javax.swing.Timer timer = null;
public FullScreen() {
startMem = ((int) Runtime.getRuntime().freeMemory());
maxMem = ((int) Runtime.getRuntime().freeMemory());
peakMem = ((int) Runtime.getRuntime().freeMemory());
d = Toolkit.getDefaultToolkit().getScreenSize();
halfScreenSize = new Dimension(d.width, d.height);
//halfScreenSize = new Dimension(d.width - 11, d.height - 51);
random = new Random();
imageLabel = new JLabel(new ImageIcon(convertToFromBytes(getImage())));
memory = new JProgressBar(0, (int) Runtime.getRuntime().maxMemory());
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
myPanel.setLayout(new BorderLayout(10, 10));
myPanel.add(imageLabel, BorderLayout.CENTER);
myPanel.setFocusable(true);
myPanel.add(button, BorderLayout.NORTH);
myPanel.add(memory, BorderLayout.SOUTH);
frame.add(myPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke("ENTER"), "clickENTER");
frame.getRootPane().getActionMap().put("clickENTER", new AbstractAction() {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
exitFullScreen();
}
});
enterFullScreen();
frame.setVisible(true);
Runnable doRun = new Runnable() {
#Override
public void run() {
System.out.println(frame.getBounds());
}
};
SwingUtilities.invokeLater(doRun);
Runnable r = new Runnable() {
#Override
public void run() {
while (true) {
try {
d = Toolkit.getDefaultToolkit().getScreenSize();
halfScreenSize = new Dimension(d.width, d.height);
imageLabel.setIcon(new ImageIcon(convertToFromBytes(getImage())));
memory.setValue((int) Runtime.getRuntime().freeMemory());
memory.setStringPainted(true);
useMem = ((int) Runtime.getRuntime().freeMemory());
Thread.sleep(500);
} catch (InterruptedException ex) {
//something with exception
} finally {
//alive that if required
}
}
}
};
Thread t = new Thread(r);
t.start();
}
private void enterFullScreen() {
GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
device = graphicsEnvironment.getDefaultScreenDevice();
if (device.isFullScreenSupported()) {
device.setFullScreenWindow(frame);
frame.validate();
}
}
private void exitFullScreen() {
startOne();
}
private void startOne() {
timer = new javax.swing.Timer(70, setFullScreenWindowFalse());
timer.start();
timer.setRepeats(false);
}
public Action setFullScreenWindowFalse() {
return new AbstractAction("setFullScreenWindowFalse") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
device.setFullScreenWindow(null);
startTwo();
}
};
}
private void startTwo() {
timer = new javax.swing.Timer(70, hideJFrame());
timer.start();
timer.setRepeats(false);
}
public Action hideJFrame() {
return new AbstractAction("hideJFrame") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
startThree();
}
};
}
private void startThree() {
timer = new javax.swing.Timer(250, showJFrame());
timer.start();
timer.setRepeats(false);
}
public Action showJFrame() {
return new AbstractAction("showJFrame") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
myPanel.setPreferredSize(new Dimension(400, 300));
frame.pack();
frame.setVisible(true);
}
};
}
private BufferedImage getImage() {
GradientPaint gp = new GradientPaint(0f, 0f, new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)),
(float) halfScreenSize.width, (float) halfScreenSize.width, new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(halfScreenSize.width, halfScreenSize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, halfScreenSize.width, halfScreenSize.height);
g2d.setFont(bigFont);
g2d.setColor(Color.BLACK);
if (maxMem < ((int) Runtime.getRuntime().freeMemory())) {
maxMem = ((int) Runtime.getRuntime().freeMemory());
}
if (peakMem > ((int) Runtime.getRuntime().freeMemory())) {
peakMem = ((int) Runtime.getRuntime().freeMemory());
}
useMem = ((int) Runtime.getRuntime().freeMemory()) - useMem;
g2d.drawString("" + ++count, 20, 100);
g2d.drawString("JVM memory status ---> ", 20, 195);
g2d.drawString("tot. memory ---> " + ((int) Runtime.getRuntime().totalMemory()), 20, 240);
g2d.drawString("max. memory ---> " + ((int) Runtime.getRuntime().maxMemory()), 20, 270);
g2d.drawString("free on startUp ---> " + startMem, 20, 300);
g2d.drawString("max free memory ---> " + maxMem, 20, 350);
g2d.drawString("min free memory ---> " + peakMem, 20, 380);
g2d.drawString("act free memory ---> " + ((int) Runtime.getRuntime().freeMemory()), 20, 410);
g2d.drawString("usage of memory ---> " + useMem, 20, 450);
return bi;
}
private Image convertToFromBytes(BufferedImage image) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
FullScreen fullScreen = new FullScreen();
}
};
SwingUtilities.invokeLater(doRun);
}
}
I've got an editor with lots of image thumbnails. I'd like a double-click on an image to display the full resolution image using a modal undecorated dialog. Ideally, this would be animated, to show the image zooming up to full resolution on the center of the screen, then any click would make the image go away, either zooming back out or fading away.
I'm not concerned with establishing an exact behavior, I just want something slick. I've found plenty of JavaScript examples for this, but is there anything built for Swing?
This piece of code does more or less the trick...
There is still a problem in the way I'm setting the dialog's location...
Hope it helps.
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class OpenImageZooming {
private static final int NB_STEPS = 30;
private static final long OPENING_TOTAL_DURATION = 3000;
public static void main(String[] args) {
OpenImageZooming me = new OpenImageZooming();
me.openImage(args[0]);
}
private JFrame frame;
private JDialog dialog;
private JPanelZooming panelZooming;
private void openImage(final String imagePath) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame = new JFrame();
frame.setTitle("Open image with zoom");
JPanel p = new JPanel(new BorderLayout());
p.add(new JLabel("click on button to display image"), BorderLayout.CENTER);
JButton button = new JButton("Display!");
frame.setContentPane(p);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread t = new Thread() {
#Override
public void run() {
displayImaggeWithProgressiveZoom(imagePath);
}
};
t.start();
}
});
p.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 100);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected void displayImaggeWithProgressiveZoom(String imagePath) {
try {
final BufferedImage image = ImageIO.read(new File(imagePath));
for (int i = 0; i < NB_STEPS; i++) {
displayDialog(i, NB_STEPS, image);
Thread.sleep(OPENING_TOTAL_DURATION / NB_STEPS);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void displayDialog(final int i, final int nbSteps, final BufferedImage image) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
if (dialog == null) {
dialog = new JDialog(frame);
dialog.setUndecorated(true);
dialog.setModal(false);
panelZooming = new JPanelZooming(image);
dialog.setContentPane(panelZooming);
dialog.setSize(0, 0);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
int w = (i + 1) * image.getWidth() / nbSteps;
int h = (i + 1) * image.getHeight() / nbSteps;
panelZooming.setScale((double) (i + 1) / nbSteps);
dialog.setSize(w, h);
dialog.setLocationRelativeTo(null);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#SuppressWarnings("serial")
public static class JPanelZooming extends JPanel {
private BufferedImage image;
private double scale = 1.0d;
public JPanelZooming(BufferedImage image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
AffineTransform at = g2.getTransform();
AffineTransform oldTransform = (AffineTransform) at.clone();
at.scale(scale, scale);
g2.setTransform(at);
g2.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g2.setTransform(oldTransform);
}
public void setScale(double scale) {
this.scale = scale;
}
}
}
You can create a custom control that displays the image at the scale you want.
1) Create a BufferedImage from the image file you want using ImageIO.read(file) (you can also create it from an InputStream)
2) Extend the JComponent or Canvas class and overload the paint function to draw the animated image using Graphics.DrawImage() and set the width and height based on how long the window has been open. Set a timer or use another thread to repeatedly have the component redraw itself for however long you want the animation to play.
I haven't done much with customized modal dialogs (I mostly find them annoying), but you can use a JDialog and and your component to it.