Jslider is laggy after overriding paint method - java

After overriding the paintTrack and paintThumb method of my JSlider it lags if I drag its thumb.
I've replaced the track and thumb with images. Any ideas how to solve the problem?
public class test {
private static JFrame frame;
private static JSlider slider;
public static void main(String[] args) throws IOException {
frame = new JFrame();
slider = new JSlider();
slider.setUI(new MySliderUI(slider));
frame.add(slider);
frame.setVisible(true);
frame.pack();
frame.setSize(1200, 720);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static class MySliderUI extends BasicSliderUI {
private BufferedImage imgTrack;
private BufferedImage imgThumb;
public MySliderUI(JSlider slider) throws IOException {
super(slider);
imgTrack = ImageIO.read(new File("icon/track.png"));
imgThumb = ImageIO.read(new File("icon/thumb.png"));
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Rectangle t = trackRect;
g2d.drawImage(imgTrack, t.x, t.y, t.width, t.height, null);
}
#Override
public void paintThumb(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
Rectangle t = thumbRect;
g2d.drawImage(imgThumb, t.x, t.y, null);
}
}
}
EDIT:
Solved it, I also had to override the getThumbSize()
#Override
protected Dimension getThumbSize() {
return new Dimension(imgThumb.getWidth(), imgThumb.getHeight());
}

Related

More JPanel and background image

Should I set a background with a central start button. When click on button "start" you must load a "bersaglio" made in another class.
When I run it does not appear the background image but only the start button, I also tried to change the path of the image. Also, when I click on the button shows a "bersaglio".
Where am I wrong?
Home class
public class Home extends JFrame implements ActionListener{
JFrame frame;
JButton b1;
public Home(){
frame= new JFrame();
frame.setSize(200, 200);
frame.setTitle("Bersaglio");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//aggiungo lo sfondo e il bottone
b1=new JButton("START");
Sfondo sfondo=new Sfondo();
JPanel panelsecondo=new JPanel();
panelsecondo.add(b1,BorderLayout.CENTER);
sfondo.add(panelsecondo);
frame.getContentPane().add(sfondo);
b1.addActionListener(this); //aggiungo ascoltatore
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
System.out.println("entra");
//bersaglio
Bersaglio bersaglio = new Bersaglio();
frame.add(bersaglio);
repaint();
}
}
Sfondo class
class Sfondo extends JPanel{
Image img;
public Sfondo(){
img = Toolkit.getDefaultToolkit().createImage("\\Esdicembre\\EsVacanze\\sfondo");
loadImage(img);
}
private void loadImage(Image img) {
try {
MediaTracker mt = new MediaTracker(this);
mt.addImage(img, 0);
mt.waitForID(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
protected void paintComponent(Graphics g) {
//setOpaque(false);
g.drawImage(img, 0, 0, null);
super.paintComponent(g);
}
}
class Bersaglio
public class Bersaglio extends JComponent implements MouseListener {
Ellipse2D.Double circle;
Ellipse2D.Double circle1;
Ellipse2D.Double circle2;
Ellipse2D.Double circle3;
/*public void setup(){
x=0;
y=0;
}
/*Color c;
int hight;
int weight;
public Circle() {
super();
}
public Circle(int x,int y,int hight,int weight) {
this.x=x;
this.y=y;
this.hight=hight;
this.weight=weight;
} */
public void paintComponent(Graphics g){
Graphics2D g2;
g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
circle1 = new Ellipse2D.Double(30, 30, 100, 100);
g2.fill(circle1);
//c1.fillOval(30,30,100,100);
//secondo cerchio medio
g2.setColor(Color.RED);
circle2 = new Ellipse2D.Double(50,50,60,60);
g2.fill(circle2);
//c1.fillOval(50,50,60,60);
//terzo cerchio piccolo
g2.setColor(Color.BLACK);
circle3 = new Ellipse2D.Double(70,70,20,20);
g2.fill(circle3);
//c1.fillOval(70,70,20,20);
addMouseListener(this);
//scrivere qualcosa
//g2.drawString("Ciao", 50, 100);
}
public void mouseClicked (MouseEvent e) {
//x = e.getX();
//y = e.getY();
Point p = e.getPoint();
if(circle3.contains(p)) {
System.out.println("Circle3 contains point");
}else{
if(circle2.contains(p)) {
System.out.println("Circle2 contains point");
}else {
if(circle1.contains(p)) {
System.out.println("Circle1 contains point");
}
}
}
Graphics g = getGraphics();
Graphics2D g2 = (Graphics2D) g;
circle = new Ellipse2D.Double(p.getX(),p.getY(),10,10);
g2.fill(circle);
revalidate();
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}

How draw oval image in JLabel

I want to draw a oval image in a JLabel, using Graphics. This is my code, but a dont know about Graphics.
class imagePanel extends JLabel {
//private PlanarImage image;
private BufferedImage buffImage = null;
private void drawFingerImage(int nWidth, int nHeight, byte[] buff) {
buffImage = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_BYTE_GRAY);
buffImage.getRaster().setDataElements(0, 0, nWidth, nHeight, buff);
Graphics g = buffImage.createGraphics();
g.drawImage(buffImage, 0, 0, 140, 150, null);
g.dispose();
repaint();
}
public void paintComponent(Graphics g) {
g.drawImage(buffImage, 0, 0, this);
}
}
I have this
you need the help of setClip() method as mentioned here and here.
when it comes to code it should look like this
public class OvalImageLabel extends JLabel {
private Image image;
public OvalImageLabel(URL imageUrl) throws IOException {
image = ImageIO.read(imageUrl);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setClip(new java.awt.geom.Ellipse2D.Float(0f,0f, getWidth(),getHeight()/2));
g.drawImage(image, 0, 0, this);
}
}
and a running application that using this class
public class UsageExample extends JPanel {
public UsageExample() {
super(new BorderLayout());
OvalImageLabel l;
try {
l = new OvalImageLabel(new File("/path/to/image.png").toURI().toURL());
} catch (Exception e) {
e.printStackTrace();
return;
}
add(l, BorderLayout.CENTER);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setContentPane(new UsageExample());
frame.setSize(200, 200);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Saving a JPanel as an Image (object) and drawing it back onto a JPanel

I've had a look around and tried using other queries, but I just can't seem to get this to work.
I am trying to retain an image from a JPanel drawn via the g.draw/fill methods.
I've attempted to save the drawing in a buffered image, but when I display it in a messageDialog all I get is the background and none of the drawings
These two methods are the important code (from the DrawingPanel class):
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
BufferedImage image = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
// call the Panels's paint method, using
// the Graphics object of the image.
this.paint(image.getGraphics());
return image;
}
They get called here:
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage bi = dp.getScreenShot();
dp.loadDrawing(bi);
}
Here is the whole program, it should run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class TestClass extends JFrame implements ActionListener {
DrawingPanel dp;
public TestClass() {
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel top = new JPanel();
JButton load = new JButton("Load Image");
load.addActionListener(this);
top.add(load);
dp = new DrawingPanel();
dp.setBackground(Color.CYAN);
add(top, BorderLayout.NORTH);
add(dp, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args) {
new TestClass();
}
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage bi = dp.getScreenShot();
dp.loadDrawing(bi);
}
private class DrawingPanel extends JPanel implements
MouseListener, MouseMotionListener {
private int xPos, yPos;//mouse positions
private DrawingPanel() {
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
public void mousePressed(MouseEvent me) {
xPos = me.getX();
yPos = me.getY();
}
#Override
public void mouseDragged(MouseEvent me) {
int x = me.getX(), y = me.getY();
Graphics g = getGraphics();
g.setColor(Color.BLACK);
g.drawOval(xPos, yPos, 30, 30);
xPos = x;
yPos = y;
}
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
BufferedImage image = new BufferedImage(this.getWidth(),
this.getHeight(), BufferedImage.TYPE_INT_RGB);
// call the Panels's paint method, using
// the Graphics object of the image.
this.paint(image.getGraphics());
return image;
}
//unused abstract method
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
}
I need to be able to store the graphics from the panel and retrieve it.
Help would be heavily appreciated.
Every attempt to draw something into the Graphics object that was obtained from a Component by calling getGraphics will fail sooner or later. This Graphics object merely serves as a "path" to the actual screen (that is only valid while the component is actually painted on the screen). It is not a "buffer", and it does not "store" anything that was drawn.
If you want to create a simple painting program, you should draw to a BufferedImage. And when the DrawingPanel is to be painted, you only paint this BufferedImage. The additional advantage here is that when you want to make a screenshot, you basically just have to return a copy of this BufferedImage.
I sketeched the basic approach in your DrawingPanel class, with some in-lined comments. It could be cleaned up and beautified, and there are some aspects to consider (e.g. what should happen when the DrawingPanel is resized?), but it shows how it should work in general:
private class DrawingPanel extends JPanel implements
MouseListener, MouseMotionListener {
// The image that will store what was drawn. In the
// mouseDragged method, the painting operations will
// go directly to this image. When this panel is
// painted, then ONLY this image will be painted.
private BufferedImage bufferedImage;
private int xPos, yPos;//mouse positions
private DrawingPanel() {
addMouseListener(this);
addMouseMotionListener(this);
}
// Make sure that the "bufferedImage" is non-null
// and has the same size as this panel
private void validateImage()
{
if (bufferedImage == null)
{
bufferedImage = new BufferedImage(
getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.dispose();
}
if (bufferedImage.getWidth() != getWidth() ||
bufferedImage.getHeight() != getHeight())
{
BufferedImage newBufferedImage = new BufferedImage(
getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = newBufferedImage.getGraphics();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.drawImage(bufferedImage, 0,0,null);
g.dispose();
bufferedImage = newBufferedImage;
}
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
validateImage();
// Paint the bufferedImage which stores
// what was drawn until now
g.drawImage(bufferedImage, 0, 0, null);
}
#Override
public void mousePressed(MouseEvent me) {
xPos = me.getX();
yPos = me.getY();
}
#Override
public void mouseDragged(MouseEvent me) {
int x = me.getX(), y = me.getY();
validateImage();
// Paint directly into the bufferedImage here
Graphics g = bufferedImage.getGraphics();
g.setColor(Color.BLACK);
g.drawOval(xPos, yPos, 30, 30);
repaint();
xPos = x;
yPos = y;
}
public void loadDrawing(BufferedImage bi) {
//opens a message dialog and displays the image parameter
JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
}
public BufferedImage getScreenShot() {
// This basically returns a "copy" of the
// bufferedImage that stores what was drawn
BufferedImage image = new BufferedImage(
getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.drawImage(bufferedImage, 0, 0, null);
g.dispose();
return image;
}
//unused abstract method
#Override
public void mouseClicked(MouseEvent me) {
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
Your getting your Graphics object by calling getGraphics() on a component, and images drawn with this will not persist. Why not instead draw to a BufferedImage with its Graphics object, and then simply save that BufferedImage. This would simplify things greatly, and your program would work.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class TestClass2 extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public TestClass2() {
JPanel northPanel = new JPanel();
northPanel.add(new JButton(new GetImageAction("Get Image")));
northPanel.add(new JButton(new ClearImageAction("Clear Image")));
setLayout(new BorderLayout(5, 5));
add(drawingPanel, BorderLayout.CENTER);
add(northPanel, BorderLayout.NORTH);
}
private class GetImageAction extends AbstractAction {
public GetImageAction(String name) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_G);
}
#Override
public void actionPerformed(ActionEvent evt) {
BufferedImage img = drawingPanel.getMainImage();
ImageIcon icon = new ImageIcon(img);
JOptionPane.showMessageDialog(TestClass2.this, icon);
}
}
private class ClearImageAction extends AbstractAction {
public ClearImageAction(String name) {
super(name);
putValue(MNEMONIC_KEY, KeyEvent.VK_C);
}
#Override
public void actionPerformed(ActionEvent evt) {
drawingPanel.clearImage();
drawingPanel.repaint();
}
}
private static void createAndShowGui() {
TestClass2 mainPanel = new TestClass2();
JFrame frame = new JFrame("TestClass2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class DrawingPanel extends JPanel {
public static final int BI_WIDTH = 400;
public static final int BI_HEIGHT = BI_WIDTH;
private static final Color BACKGROUND = Color.CYAN;
public static final Color DRAW_COLOR = Color.black;
public static final int OVAL_WIDTH = 30;
private BufferedImage mainImage;
public DrawingPanel() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
clearImage();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mainImage != null) {
g.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
public BufferedImage getMainImage() {
return mainImage;
}
public void clearImage() {
mainImage = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = mainImage.getGraphics();
g.setColor(BACKGROUND);
g.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g.dispose();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent mEvt) {
draw(mEvt);
}
#Override
public void mouseDragged(MouseEvent mEvt) {
draw(mEvt);
}
private void draw(MouseEvent mEvt) {
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(DRAW_COLOR);
g2.drawOval(mEvt.getX() - OVAL_WIDTH / 2, mEvt.getY() - OVAL_WIDTH / 2, OVAL_WIDTH, OVAL_WIDTH);
g2.dispose();
repaint();
}
}
}

Scaling an image quickly, and making sure it actually scales

I am trying to scale a screenshot taken by:
robot.createScreenCapture(SCREEN_RECT);
Im trying to get it down to an image that is 600X400 and fits into a JFrame that is 600X400
My program is using a swing worker to create an video out of each picture, or frames. The frames have a delay of 200ms per each. the image when told to rescale just shows the original image at the original dimensions. Does anyone know how to fix this, or should I just give up on the resize-ing?
#SuppressWarnings("serial")
public class temporaryShit extends JPanel
{
private static final int width = 600;
private static final int height = 400;
private JLabel displayedLabel = new JLabel();
public temporaryShit()
{
setLayout(new BorderLayout());
add(displayedLabel);
try {
MySwingWorker mySwingWorker = new MySwingWorker();
mySwingWorker.execute();
} catch (AWTException e) {
}
}
public void setLabelIcon(Icon icon) {
displayedLabel.setIcon(icon);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
private class MySwingWorker extends SwingWorker<Void, Icon>
{
private final Rectangle SCREEN_RECT = new Rectangle(0, 0, width, height);
private long delay = 200;
private Robot robot = null;
public MySwingWorker() throws AWTException
{
robot = new Robot();
}
#Override
protected Void doInBackground() throws Exception
{
Timer utilTimer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
BufferedImage capturedImage = captureScreen();
publish(new ImageIcon(capturedImage));
}
};
utilTimer.scheduleAtFixedRate(task, delay, delay);
return null;
}
#Override
protected void process(List<Icon> chunks)
{
for (Icon icon : chunks)
{
setLabelIcon(icon);
}
}
private BufferedImage captureScreen()
{
BufferedImage img = robot.createScreenCapture(SCREEN_RECT);
return createResizedImage(img, width, height);
}
public BufferedImage createResizedImage(Image original, int width, int height)
{
BufferedImage scaledBI = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return scaledBI;
}
}
private static void createAndShowGui()
{
temporaryShit mainPanel = new temporaryShit();
JFrame frame = new JFrame("SwingWorker Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGui();
}
});
}
}
You already have a new image with specified size - scaled, which you can use for rendering.
Here is a simple example:
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
class TestBrightness {
public static void main(String args[]) {
try {
URL imageUrl = new URL(
"http://duke.kenai.com/comfyChair/ComfyChairRadSmall.jpg");
BufferedImage ioImage = ImageIO.read(imageUrl);
JPanel panel = new JPanel();
Image scaledImg = ioImage.getScaledInstance(ioImage.getWidth() / 2,
ioImage.getHeight() / 2, Image.SCALE_SMOOTH);
panel.add(new JLabel(new ImageIcon(ioImage)));
panel.add(new JLabel(new ImageIcon(scaledImg)));
JOptionPane.showMessageDialog(null, panel, "100% vs 50%",
JOptionPane.INFORMATION_MESSAGE);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Failure",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}
}
As a side note, there are many ways to scale an image and Image.getScaledInstance() may not be the best. You may be interested to take a look at The Perils of Image.getScaledInstance() for some details on Image.getScaledInstance()
EDIT: question update
Last question update removed all the details regarding getScaledInstance and invalidated this answer. getScaledInstance is a very slow method and it is also asynchronous. Try this method to get a resized image:
public static BufferedImage createResizedImage(Image original, int width,
int height) {
BufferedImage scaledBI = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = scaledBI.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return scaledBI;
}
You may want to change rendering hints for better quality.
For a nicer and more complete image scaler take a look at getFasterScaledInstance() from Filthy Rich Clients book.
EDIT : last question update with posted code and SwingWorker
The implementation of SwingWorker is not correct. doInBackground() schedules java.Utils.Timer. This timer handles all updates, while the actual SwingWorker worker thread ends. All updates from the timer are fired not on Event Dispatch Thread. It may not be safe to allocate ImageIcon not on EDT. And for sure it is not safe to update UI, ie calling setLabelIcon() not on EDT. See Concurrency in Swing tutorial for details.
You can add while loop and Thread.sleep in doInBackground() and remove the timer. Alternatively, Swing timer may be more suitable for this case. Here is an example:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class DemoRobotPanel extends JPanel{
private static final long serialVersionUID = 1L;
private Image image;
private Robot robot;
private Rectangle CAPTURE_RECT;
private int TIMER_DELAY = 1000;
private int desiredWidth = 600;
private int desiredHeight = 400;
public DemoRobotPanel() {
CAPTURE_RECT = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
try {
robot = new Robot();
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
BufferedImage img = robot.createScreenCapture(CAPTURE_RECT);
setImage(img);
} catch (HeadlessException e) {
e.printStackTrace();
}
}
};
Timer timer = new Timer(TIMER_DELAY, taskPerformer);
timer.start();
} catch (AWTException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(desiredWidth, desiredHeight);
}
public void setImage(Image image) {
this.image = image;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
private static void createAndShowGui() {
final DemoRobotPanel panel = new DemoRobotPanel();
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Try this:
public BufferedImage resize(BufferedImage bufferedImage, int resizeWidth, int resizeHeight) {
// Create new (blank) image of required (scaled) size
BufferedImage scaledImage = new BufferedImage(resizeWidth, resizeHeight, BufferedImage.TYPE_INT_ARGB);
// Paint scaled version of image to new image
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(bufferedImage, 0, 0, resizeWidth, resizeHeight, null);
graphics2D.dispose();
return scaledImage;
}
You may want to try different RenderingHints.

How to apply affine transform to component's childs?

Is it possible to apply transformations to custom or premade controls in Swing? By one hand transformations are allowed, by other hand there are probably some gaps in implementation with this.
ATTENTION the question is about how to apply transfomations from control's parent, not about how to use transformations at all. I.e. transformation must be issued by the parent, while child should just obey it. So, please hint how to transform standard Swing controls or how to write custom controls which obey PARENT transformation.
Simple example which applies transform to Graphics before drawing childs and which doesn't work:
public class Tester_TransformDuringPaint_01 {
private static Logger log = LoggerFactory.getLogger(Tester_TransformDuringPaint_01.class);
private static class JPanelEx extends JPanel {
private AffineTransform transform = new AffineTransform();
public AffineTransform getTransform() {
return transform;
}
public void setTransform(AffineTransform transform) {
this.transform = transform;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.transform(transform);
super.paintComponent(g);
g2.drawOval(0, 0, 100, 100);
g2.setTransform(savedTransform);
}
#Override
protected void paintChildren(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.transform(transform);
super.paintChildren(g);
g2.setTransform(savedTransform);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JButton button = new JButton("Button");
button.setBounds(0,20,100,60);
JPanelEx panel = new JPanelEx();
panel.setLayout(null);
panel.setBounds(10, 10, 640, 480);
panel.setBackground(Color.PINK);
panel.setTransform(AffineTransform.getScaleInstance(2, 1));
panel.add(button);
JFrameEx frame = new JFrameEx();
frame.setLayout(null);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(0.5);
frame.center();
frame.setVisible(true);
}
});
}
}
draws the following:
while left half of the button looks alive, and bigger part looks dead.
This is because different pars of API draws button with different approach.
Modified O'Reilly hack 51
Below is the code based on #lbalazscs's example, which shows that transformations don't work even if they are "in bounds"
public class BackwardsJButton extends JButton {
public BackwardsJButton(String text) {
super(text);
}
public void paint(Graphics g) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
AffineTransform flipTrans = new AffineTransform();
double widthD = (double) getWidth();
//flipTrans.setToTranslation(widthD, 0);
//flipTrans.scale(-2.0, 1);
flipTrans.scale(0.5, 1);
g2.transform(flipTrans);
super.paint(g);
g2.setTransform(savedTransform);
} else {
super.paint(g);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
buildFrame();
}
});
}
private static void buildFrame() {
JFrame f = new JFrame("Test");
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.add(new BackwardsJButton("BackwardsJLabel"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
output follows (you may need to resize window and move mouse to see it, because Swing bug is located inside mouse hover code:
You have some innovative ideas how to abuse Swing :)
It is possible to apply affine transform while drawing components, but only if you are happy within the bounds of the component(for example you could mirror the text). If you override paint, you change how the component is drawn, but this will not change its size because the size depends on completely other variables, and you still cannot draw reliably outside its bounds.
I think it is not a good idea to transform the painting of premade components, because even if you succeed graphically, mouse clicks will be expected in the original places.
Note that you need to reset the transformation after you are done, because the same Graphics object will be used to paint other components.
AffineTransform savedTransform = g.getTransform();
g.setTransform(specialTransform);
... your drawing here
g.setTransform(savedTransform);
EDIT: here is a complete running example of a transformed component
import javax.swing.*;
import javax.swing.plaf.metal.MetalButtonUI;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class ScaledButton extends JButton {
public ScaledButton(String text) {
super(text);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Color savedColor = g2.getColor();
g2.setColor(getBackground());
g2.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2.setColor(savedColor);
AffineTransform backup = g2.getTransform();
g2.scale(0.5, 1);
super.paintComponent(g);
g2.setTransform(backup);
}
#Override
protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform backup = g2.getTransform();
g2.scale(0.5, 1);
super.paintBorder(g);
g2.setTransform(backup);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
buildFrame();
}
});
}
private static void buildFrame() {
JFrame f = new JFrame("Test");
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.add(new ScaledButton("ScaledButton"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

Categories