java swing resize ImageIcon according to jLabel - java

i am a new programmer here and i have something to ask, i have browse a picture into my GUI (and set the path in text box also)which displays on a Label, but the label dimension is set only 100,100 while the picture is much bigger so when i open/display it into the label it get cropped , is there anyway to make it auto resize to the label size? below is my logic code on browse button and open dialog box
please any one tell me where i am wrong..
public class ImagePath extends javax.swing.JFrame {
private JPanel contentPane;
JLabel jLabel1;
String s2;
File targetFile;
BufferedImage targetImg;
public ImagePath() {
initComponents();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser jFileChooser1 = new JFileChooser();
int state = jFileChooser1.showOpenDialog(new JFrame());
jTextField1.setText("");
if (state == JFileChooser.APPROVE_OPTION) {
JOptionPane.showMessageDialog(new JFrame(), "hii");
File file = jFileChooser1.getSelectedFile();
s2 = file.toString();
jTextField1.setText(s2);
jLabel1 = new JLabel();
jLabel1.setName(s2);
jLabel1.setLocation(50, 50);
jLabel1.setSize(300, 300);
add(jLabel1);
BufferedImage bi1;
try {
bi1 = ImageIO.read(file);
ImageIcon icon1 = new ImageIcon(bi1);
jLabel1.setIcon(icon1);
Image img = icon1.getImage();
ImageIcon icon = new ImageIcon(file.getPath());
Image scaleImage = icon.getImage().getScaledInstance(28, 28, Image.SCALE_DEFAULT);
repaint();
pack();
} catch (Exception e) {
System.out.println(e);
}
} else if (state == JFileChooser.CANCEL_OPTION) {
JOptionPane.showMessageDialog(new JFrame(), "Canceled");
}
}
}

Unless you really want a nasty head ache, I would suggest taking advantage of the layout management system.
Instead of trying to set the size and location of components, let them decide how they wan to be displayed where possible.
While I personally take advantage of Netbeans form designer, I would encourage you to take the time to learn how to build your UI's by hand, it will give a greater apprication for what the form designers can do, as well ideas you can employee to make advanced UIs - IMHO
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class SimpleImageBrowser {
public static void main(String[] args) {
new SimpleImageBrowser();
}
public SimpleImageBrowser() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new SimpleImageBrowser.ImageBrowserPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImageBrowserPane extends JPanel {
private JFileChooser fcImage = new JFileChooser();
private SimpleImageBrowser.ImagePane imagePane;
public ImageBrowserPane() {
setLayout(new BorderLayout());
imagePane = new SimpleImageBrowser.ImagePane();
add(new JScrollPane(imagePane));
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int state = fcImage.showOpenDialog(SimpleImageBrowser.ImageBrowserPane.this);
switch (state) {
case JFileChooser.APPROVE_OPTION:
File file = fcImage.getSelectedFile();
try {
BufferedImage bi1 = ImageIO.read(file);
ImageIcon icon1 = new ImageIcon(bi1);
JLabel label = new JLabel(icon1);
label.setText(file.getPath());
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.BOTTOM);
label.setForeground(Color.WHITE);
label.setBorder(new LineBorder(Color.WHITE));
imagePane.add(label);
imagePane.revalidate();
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
});
JPanel buttons = new JPanel();
buttons.add(add);
add(buttons, BorderLayout.NORTH);
}
}
public class ImagePane extends JPanel {
public ImagePane() {
setLayout(new SimpleImageBrowser.WrapLayout());
setBackground(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return getComponentCount() == 0 ? new Dimension(200, 200) : super.getPreferredSize();
}
}
/**
* FlowLayout subclass that fully supports wrapping of components.
*/
public class WrapLayout extends FlowLayout {
private Dimension preferredLayoutSize;
/**
* Constructs a new
* <code>WrapLayout</code> with a left alignment and a default 5-unit
* horizontal and vertical gap.
*/
public WrapLayout() {
super();
}
/**
* Constructs a new
* <code>FlowLayout</code> with the specified alignment and a default 5-unit
* horizontal and vertical gap. The value of the alignment argument must be
* one of
* <code>WrapLayout</code>,
* <code>WrapLayout</code>, or
* <code>WrapLayout</code>.
*
* #param align the alignment value
*/
public WrapLayout(int align) {
super(align);
}
/**
* Creates a new flow layout manager with the indicated alignment and the
* indicated horizontal and vertical gaps.
* <p>
* The value of the alignment argument must be one of
* <code>WrapLayout</code>,
* <code>WrapLayout</code>, or
* <code>WrapLayout</code>.
*
* #param align the alignment value
* #param hgap the horizontal gap between components
* #param vgap the vertical gap between components
*/
public WrapLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap);
}
/**
* Returns the preferred dimensions for this layout given the
* <i>visible</i> components in the specified target container.
*
* #param target the component which needs to be laid out
* #return the preferred dimensions to lay out the subcomponents of the
* specified container
*/
#Override
public Dimension preferredLayoutSize(Container target) {
return layoutSize(target, true);
}
/**
* Returns the minimum dimensions needed to layout the <i>visible</i>
* components contained in the specified target container.
*
* #param target the component which needs to be laid out
* #return the minimum dimensions to lay out the subcomponents of the
* specified container
*/
#Override
public Dimension minimumLayoutSize(Container target) {
Dimension minimum = layoutSize(target, false);
minimum.width -= (getHgap() + 1);
return minimum;
}
/**
* Returns the minimum or preferred dimension needed to layout the target
* container.
*
* #param target target to get layout size for
* #param preferred should preferred size be calculated
* #return the dimension to layout the target container
*/
private Dimension layoutSize(Container target, boolean preferred) {
synchronized (target.getTreeLock()) {
// Each row must fit with the width allocated to the containter.
// When the container width = 0, the preferred width of the container
// has not yet been calculated so lets ask for the maximum.
int targetWidth = target.getSize().width;
if (targetWidth == 0) {
targetWidth = Integer.MAX_VALUE;
}
int hgap = getHgap();
int vgap = getVgap();
Insets insets = target.getInsets();
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
int maxWidth = targetWidth - horizontalInsetsAndGap;
// Fit components into the allowed width
Dimension dim = new Dimension(0, 0);
int rowWidth = 0;
int rowHeight = 0;
int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++) {
Component m = target.getComponent(i);
if (m.isVisible()) {
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
// Can't add the component to current row. Start a new row.
if (rowWidth + d.width > maxWidth) {
addRow(dim, rowWidth, rowHeight);
rowWidth = 0;
rowHeight = 0;
}
// Add a horizontal gap for all components after the first
if (rowWidth != 0) {
rowWidth += hgap;
}
rowWidth += d.width;
rowHeight = Math.max(rowHeight, d.height);
}
}
addRow(dim, rowWidth, rowHeight);
dim.width += horizontalInsetsAndGap;
dim.height += insets.top + insets.bottom + vgap * 2;
// When using a scroll pane or the DecoratedLookAndFeel we need to
// make sure the preferred size is less than the size of the
// target containter so shrinking the container size works
// correctly. Removing the horizontal gap is an easy way to do this.
Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
if (scrollPane != null && target.isValid()) {
dim.width -= (hgap + 1);
}
return dim;
}
}
/*
* A new row has been completed. Use the dimensions of this row
* to update the preferred size for the container.
*
* #param dim update the width and height when appropriate
* #param rowWidth the width of the row to add
* #param rowHeight the height of the row to add
*/
private void addRow(Dimension dim, int rowWidth, int rowHeight) {
dim.width = Math.max(dim.width, rowWidth);
if (dim.height > 0) {
dim.height += getVgap();
}
dim.height += rowHeight;
}
}
}
I've included WrapLayout by Rob Camick (who lurks about the place) because, to be quite frank, none of the other layout managers gave me the effect I wanted.
I also set the label's text with the path of the image
Take a look at Using layout Managers and A Visual Guide to Layout Managers
Take a look at WrapLayout
Updated with text fields
If you want to associate a text field with the image, then I suggest you add both the label and text field to a JPanel (using something like a BorderLayout) and then add that to your image pane...
public class ImagePane extends JPanel {
public ImagePane() {
setLayout(new SimpleImageBrowser.WrapLayout());
setBackground(Color.BLACK);
}
public void addImage(File file) throws IOException {
BufferedImage bi1 = ImageIO.read(file);
ImageIcon icon1 = new ImageIcon(bi1);
JPanel imgPane = new JPanel(new BorderLayout());
imgPane.setOpaque(false);
JLabel label = new JLabel(icon1);
imgPane.add(label);
JTextField field = new JTextField(file.getPath(), 20);
field.setEditable(false);
imgPane.add(field, BorderLayout.SOUTH);
add(imgPane);
revalidate();
}
#Override
public Dimension getPreferredSize() {
return getComponentCount() == 0 ? new Dimension(200, 200) : super.getPreferredSize();
}
}
And the updated ActionListener...
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int state = fcImage.showOpenDialog(SimpleImageBrowser.ImageBrowserPane.this);
switch (state) {
case JFileChooser.APPROVE_OPTION:
File file = fcImage.getSelectedFile();
try {
imagePane.addImage(file);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});

You should cut out the call to label.setSize. You should also place all your components in in the form designer instead of producing them when you click the button. Maybe you could also add a layout manager in the bargain? This will really involve a revolt against NetBeans.

Related

Displaying VLCJ in Jpanel in JFrame

So I'm desinging an application for offline quiz systems. Currently I'm working on the screen that is visible for the participants (only question, maybe possible answers and a media element).
This screen contains a slide (derived from JPanel) the screen itself is a JFrame. I have to use the JPanel in another JFrame. In the JPanel of the slide is another JPanel for displaying media. I succeeded to display an image in the JPanel. But the application also has to display video and audio. I use VLCj to realize this in my application. Here is the code of the JFrame of the SlideView.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
/**
* Created by bram on 30/03/17.
*/
public class SlideView
{
private SlidePanel slidePanel;
private JFrame frame;
public SlideView(){
slidePanel = new SlidePanel();
frame = new JFrame("SlideView");
frame.setLayout(new BorderLayout());
Dimension dim = new Dimension();
dim.setSize(800,450);
frame.setMinimumSize(dim);
frame.add(slidePanel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addComponentListener(new ComponentListener() {
public void componentMoved(ComponentEvent e){}
public void componentHidden(ComponentEvent e){}
public void componentShown(ComponentEvent e){}
public void componentResized(ComponentEvent e)
{
frame.add(slidePanel,BorderLayout.CENTER);
}
});
}
/**
* Display the information of the slide
* #pre slide has to be initialized
* #pre the slideview is initialized
* #param slide the slide that has to be displayed
* #post the slide will be displayed
*/
public void setSlide(Slide slide)
{
slidePanel.initializeSlide(slide);
}
/**
* Set the slide panel
* #param panel
*/
public void setSlidePanel(SlidePanel panel)
{
frame.remove(slidePanel);
slidePanel = panel;
frame.add(slidePanel);
}
/**
* Get the slide panel
* #return the slide panel
*/
public SlidePanel getSlidePanel()
{
return slidePanel;
}
}
And here is the code of the panel that contains the information of the slide:
import javax.swing.*;
import java.awt.*;
import java.net.URL;
/**
* Created by bram on 30/03/17.
*/
public class SlidePanel extends JPanel {
private ImageIcon bgImage;
private JLabel title, body;
private Slide slide;
private MediaView media;
public SlidePanel()
{
bgImage = new ImageIcon("/home/bram/Documenten/School/3 BA/PSOPV/LOCAL/src/Slides/slide_background.jpg");
this.setSize(800,450);
createComponents();
}
/**
* Get the media view for controlling it
*/
public MediaView getMediaView()
{
return media;
}
/**
* Initialize the slide
*/
public void initializeSlide(Slide slide)
{
this.slide = slide;
title.setText(slide.getTitle());
body.setText(slide.getBodyText());
media.setFile(slide.getMediaFile());
resizeComponents();
}
#Override
/**
* Actions that will be executed when the window is resized
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the background image.
g.drawImage(getResizedBackground().getImage(), 0, 0, this);
resizeComponents();
}
/**
* Resize the different components to the dimensions of the frame
*/
private void resizeComponents()
{
/*Calculate the growing factor of the screen (minimum size is 800*450)*/
float growFactor = (float) this.getWidth() / 800f;
/*Scale the title label*/
title.setFont(new Font("SansSerif", Font.BOLD, (int)(40*growFactor)));
title.setBounds((int)(20 * growFactor), (int)(20*growFactor),this.getWidth(), (int)(50 * growFactor));
/*Scale the body section*/
body.setFont(new Font("SansSerif", Font.PLAIN,(int)(25*growFactor)));
body.setBounds((int)(50*growFactor),(int)(0.25f*this.getHeight()),(int)((this.getWidth()-50*growFactor) * 0.5f), (int)(0.75f*this.getHeight()-20));
/*Scale the media section*/
media.setBounds((int)(this.getWidth()*0.5),(int)(this.getHeight()*0.30), (int)(this.getWidth() * 0.40),(int)(this.getHeight()*0.60-20));
}
/**
* Create the title label of the slide
*/
private void createTitle()
{
title = new JLabel("",SwingConstants.LEFT);
title.setForeground(Color.WHITE);
this.add(title);
}
/**
* Create the body of the slide
*/
private void createBody()
{
body = new JLabel("");
this.add(body);
}
/**
* Create the media section
*/
private void createMedia()
{
media = new MediaView();
media.setSize(100,100);
this.add(media);
}
/**
* Create the gui components for displaying a slide
*/
private void createComponents()
{
createTitle();
createBody();
createMedia();
}
/**
* Scale the background to the height and width of the panel
* #return the resized background
*/
private ImageIcon getResizedBackground()
{
Image img = bgImage.getImage();
img = img.getScaledInstance(this.getWidth(),this.getHeight(), Image.SCALE_DEFAULT);
return new ImageIcon(img);
}
}
And finally here is the JPanel that has to display the media:
import com.sun.jna.NativeLibrary;
import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface;
import uk.co.caprica.vlcj.player.media.Media;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import javax.swing.*;
import java.awt.*;
import java.net.URL;
/**
* Created by bram on 31/03/17.
*/
public class MediaView extends JPanel
{
private MediaFile file;
//Label for displaying a picture
private JLabel picture;
//Media player for video and audio
private EmbeddedMediaPlayerComponent mediaPlayer;
private int width,height;
private static final String NATIVE_LIBRARY_SEARCH_PATH = "lib";
/**
* Default constructor for the mediaview class
*/
public MediaView()
{
setOpaque(false);
setLayout(new GridBagLayout());
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), NATIVE_LIBRARY_SEARCH_PATH);
this.width = getWidth();
this.height = getHeight();
}
/**
* Add the appropriate components to the panel
*/
private void addComponents()
{
if(file.getFileType() == MediaFile.FileType.PICTURE)
{
picture = new JLabel();
this.add(picture);
}
if(file.getFileType() == MediaFile.FileType.VIDEO)
{
mediaPlayer = new EmbeddedMediaPlayerComponent();
setLayout(new BorderLayout());
add(mediaPlayer, BorderLayout.CENTER);
mediaPlayer.setSize(this.getWidth(),this.getHeight());
}
}
/**
* Set the media file to be displayed
* #pre the media file is initialized
* #param file the file that has to be displayed
*/
public void setFile(MediaFile file)
{
this.file = file;
addComponents();
generateView();
}
#Override
/**
* Actions that will be executed when the window is resized
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(this.height != getHeight() || this.width != getWidth())
{
generateView();
height = getHeight();
width = getWidth();
}
}
/**
* Generate the view of the file
*/
private void generateView()
{
if(file == null)
return;
if(file.getFileType() == MediaFile.FileType.PICTURE)
generateImage();
if(file.getFileType() == MediaFile.FileType.VIDEO)
generateVideo();
if(file.getFileType() == MediaFile.FileType.AUDIO)
generateAudio();
}
/**
* Generate the view of an audio file
*/
private void generateAudio()
{
}
/**
* Generate the view of a video
*/
public void generateVideo()
{
//Resize canvas
//Load native library of VLC
}
public void playMedia()
{
mediaPlayer.getMediaPlayer().playMedia(file.getPath());
}
/**
* Generate the view of an image
*/
private void generateImage()
{
/*Get the image by path*/
ImageIcon image = new ImageIcon(file.getPath());
/*Scale the image*/
Image img = image.getImage();
if(image.getIconHeight() > image.getIconWidth()) {
float growFactor = (float) this.getHeight() / (float) image.getIconHeight();
int width = (int) (image.getIconWidth() * growFactor);
img = img.getScaledInstance(width, this.getHeight(), Image.SCALE_DEFAULT);
} else {
float growFactor = (float) this.getWidth() / (float) image.getIconWidth();
int height = (int) (image.getIconHeight() * growFactor);
img = img.getScaledInstance(this.getWidth(),height,Image.SCALE_DEFAULT);
}
ImageIcon pic = new ImageIcon(img);
/*Set image as label icon*/
picture.setIcon(pic);
/*Set the bounds of the label*/
int xCoordinate = (this.getWidth() - pic.getIconWidth())/2;
int yCoordinate = (this.getHeight() - pic.getIconHeight())/2;
picture.setHorizontalAlignment(JLabel.CENTER);
picture.setVerticalAlignment(JLabel.CENTER);
picture.setBounds(xCoordinate,yCoordinate,picture.getWidth(),picture.getHeight());
}
}
But the video won't display (the video is a MP4 format). I tried several things (the above is the best result) does anyone can help me?

JDialog with transparent background which blurs things underneath

I'm trying to make a transparent JDialog, which blures what´s underneath it (for better readability). Already found this link, but there the contents of the dialog are blurred. Also I found this, but there everything (things underneath and contents of the Dialog) is blured and it's flickering.
Here's a screenshot for better understanding:
The top is what I already have and the bottom what I want to achieve.
After some testing it appears to be pretty tricky to get something like what you want to achieve. I ended up using a JLayeredPane which contains one layer for the blurred background and one for the actual content.
I am not entirely happy with the result but I didn't find a better solution now.
The problem is that Java does not provide a proper way to capture things behind the actual application which leads to the need of hiding the content before taking the screenshot. That also is the problem which causes the flickering you mentioned.
To avoid this I do only reaint the background if the application gets resized or moved. There should be put some more effort into this once really used, e.g. if the app gets minimized. But since this example cannot be resized ord minimized it's not really important right now.
The downside of this approach however is that it's completely ignoring whether or not the Background isn't static. If you use the application in front of a video for example, the current version does not change the background based on the videos current frame. This may be possible if you uncomment the Timer in my examples setVisible(...) but then we get the flickering back.
I'd suggest you to think about using JavaFx. Since CSS already provides a blur-functionality it may work for Fx as well. But since I didn't try that yet I cannot assure you it's working.
Long story short, here's the example. The blurring function is used from your link above.
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
#SuppressWarnings("serial")
public class BlurryFrame extends JFrame implements ActionListener, ComponentListener {
public static void main(String... sss) {
JLabel label1 = new JLabel("TestLabel 1");
label1.setSize(500, 100);
label1.setForeground(Color.RED);
JLabel label2 = new JLabel("TestLabel 2");
label2.setHorizontalAlignment(SwingConstants.CENTER);
label2.setForeground(Color.BLUE);
JPanel testPanel = new JPanel();
testPanel.setOpaque(false);
testPanel.setLayout(new BorderLayout());
testPanel.add(label1, BorderLayout.CENTER);
testPanel.add(label2, BorderLayout.SOUTH);
BlurryFrame frame = new BlurryFrame(800, 600, testPanel);
frame.setBackground(new Color(0, 0, 0, 100));
frame.setVisible(true);
}
private final BackgroundPanel backgroundPane;
private final JLayeredPane container;
private final JPanel containerPane;
private final Robot robot;
// This rectangle is going to be your screenshots bounds to keep the image only as big as necessary
private final Rectangle captureRect;
// This is going to be the blurred screenshot
private BufferedImage background;
public BlurryFrame() {
this(1280, 800);
}
public BlurryFrame(int width, int height) {
this(width, height, null);
}
public BlurryFrame(int width, int height, JComponent component) {
this.captureRect = new Rectangle();
try {
this.robot = new Robot();
} catch (AWTException e) {
throw new RuntimeException(e);
}
this.backgroundPane = new BackgroundPanel();
this.backgroundPane.setOpaque(false);
this.backgroundPane.setLayout(new BorderLayout());
this.backgroundPane.setBounds(0, 0, width, height);
this.backgroundPane.addComponentListener(this);
this.containerPane = new JPanel();
this.containerPane.setOpaque(false);
this.containerPane.setLayout(new BorderLayout());
this.containerPane.add(component, BorderLayout.CENTER);
this.containerPane.setBounds(0, 0, width, height);
this.setUndecorated(true);
this.setSize(width, height);
this.setLocationRelativeTo(null);
this.container = new JLayeredPane();
this.container.setOpaque(false);
this.container.setLayout(new BorderLayout());
this.container.add(this.backgroundPane, 1);
this.container.add(this.containerPane, 0);
this.getContentPane().add(this.container, BorderLayout.CENTER);
}
public void add(JComponent component) {
this.containerPane.add(component, BorderLayout.CENTER);
this.containerPane.repaint();
}
// This method does not really do much but ultimately triggers the screenshot by ending up in #componentHidden(...)
private void capture() {
this.containerPane.setVisible(false);
this.backgroundPane.setVisible(false);
this.repaint();
}
#Override
public void setVisible(boolean visible) {
super.setVisible(visible);
this.capture();
// XXX uncomment this if you want to see the flickering
// Timer timer = new Timer(60, this);
// timer.start();
}
#Override
public void setSize(int width, int height) {
super.setSize(width, height);
this.captureRect.setSize(width, height);
this.backgroundPane.setBounds(0, 0, width, height);
this.containerPane.setBounds(0, 0, width, height);
if (this.isVisible())
this.capture();
}
#Override
public void setSize(Dimension dimension) {
super.setSize(dimension);
this.captureRect.setSize(dimension);
this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height);
this.containerPane.setBounds(0, 0, dimension.width, dimension.height);
if (this.isVisible())
this.capture();
}
#Override
public void setPreferredSize(Dimension dimension) {
super.setPreferredSize(dimension);
this.captureRect.setSize(dimension);
this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height);
this.containerPane.setBounds(0, 0, dimension.width, dimension.height);
if (this.isVisible())
this.capture();
}
#Override
public void actionPerformed(ActionEvent e) {
this.capture();
}
int i = 0;
// This is where the magic happens. The capturing needs to be done here in order to assure the applications content has really been hidden
#Override
public void componentHidden(ComponentEvent e) {
int x = this.getLocationOnScreen().x;
int y = this.getLocationOnScreen().y;
this.captureRect.setLocation(x, y);
this.background = this.robot.createScreenCapture(this.captureRect);
//XXX uncomment this if you want to see what gets captured
// if (this.i < 1) {
// try {
// ImageIO.write(this.background, "png", new File(System.getProperty("user.home") + "\\test.png"));
// } catch (IOException ex) {
// ex.printStackTrace();
// }
// this.i++;
// }
this.containerPane.setVisible(true);
this.backgroundPane.setVisible(true);
this.repaint();
}
#Override
public void componentMoved(ComponentEvent e) {
this.capture();
}
#Override
public void componentResized(ComponentEvent e) {
this.capture();
}
private class BackgroundPanel extends JPanel {
private final float[] matrix = {
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
0.111f, 0.111f, 0.111f,
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (BlurryFrame.this.background != null) {
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, this.matrix));
BufferedImage blurryBack = op.filter(BlurryFrame.this.background, null);
g.drawImage(blurryBack, 0, 0, null);
}
}
}
#Override
public void componentShown(ComponentEvent e) {
}
}
I marked BenGe89s answer as accepted, cause it solves my problem.
However I wanted to share my extensions to make the frame moveable. I used this ComponentMover and modified it a bit, so the frame get's notified when the dragging starts and stops. While the frame is moved the background will be just transparent to avoid flickering.
package de.win;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
public class ComponentMover extends MouseAdapter {
// private boolean moveWindow;
#SuppressWarnings("rawtypes")
private Class destinationClass;
private DragNotifier dragNotifier;
private Component destinationComponent;
private Component destination;
private Component source;
private boolean changeCursor = true;
private Point pressed;
private Point location;
private Cursor originalCursor;
private boolean autoscrolls;
private Insets dragInsets = new Insets(0, 0, 0, 0);
private Dimension snapSize = new Dimension(1, 1);
/**
* * Constructor for moving individual components. The components must be regisetered using the registerComponent() method.
*/
public ComponentMover() {
}
/**
* * Constructor to specify a Class of Component that will be moved when drag events are generated on a registered child component. The events will be passed to the first ancestor of this specified class.
*
* #param destinationClass
* the Class of the ancestor component
* #param component
* the Components to be registered for forwarding drag events to the ancestor Component.
*/
public ComponentMover(#SuppressWarnings("rawtypes") Class destinationClass, DragNotifier dragNotifier, Component... components) {
this.destinationClass = destinationClass;
this.dragNotifier = dragNotifier;
registerComponent(components);
}
/**
* * Constructor to specify a parent component that will be moved when drag events are generated on a registered child component.
*
* #param destinationComponent
* the component drage events should be forwareded to
* #param components
* the Components to be registered for forwarding drag events to the parent component to be moved
*/
public ComponentMover(Component destinationComponent, DragNotifier dragNotifier, Component... components) {
this.destinationComponent = destinationComponent;
this.dragNotifier = dragNotifier;
registerComponent(components);
}
/**
* * Get the change cursor property
*
* #return the change cursor property
*/
public boolean isChangeCursor() {
return changeCursor;
}
/**
* * Set the change cursor property
*
* #param changeCursor
* when true the cursor will be changed to the Cursor.MOVE_CURSOR while the mouse is pressed
*/
public void setChangeCursor(boolean changeCursor) {
this.changeCursor = changeCursor;
}
/**
* * Get the drag insets
*
* #return the drag insets
*/
public Insets getDragInsets() {
return dragInsets;
}
/**
* * Set the drag insets. The insets specify an area where mouseDragged events should be ignored and therefore the component will not be moved. This will prevent these events from being confused with a MouseMotionListener that supports component resizing.
*
* #param dragInsets
*/
public void setDragInsets(Insets dragInsets) {
this.dragInsets = dragInsets;
}
/**
* * Remove listeners from the specified component
*
* #param component
* the component the listeners are removed from
*/
public void deregisterComponent(Component... components) {
for (Component component : components)
component.removeMouseListener(this);
}
/**
* * Add the required listeners to the specified component
*
* #param component
* the component the listeners are added to
*/
public void registerComponent(Component... components) {
for (Component component : components)
component.addMouseListener(this);
}
/**
* * Get the snap size
*
* #return the snap size
*/
public Dimension getSnapSize() {
return snapSize;
}
/**
* * Set the snap size. Forces the component to be snapped to the closest grid position. Snapping will occur when the mouse is dragged half way.
*/
public void setSnapSize(Dimension snapSize) {
this.snapSize = snapSize;
}
/**
* * Setup the variables used to control the moving of the component:
*
* source - the source component of the mouse event destination - the component that will ultimately be moved pressed - the Point where the mouse was pressed in the destination component coordinates.
*/
#Override
public void mousePressed(MouseEvent e) {
dragNotifier.dragStart();
source = e.getComponent();
int width = source.getSize().width - dragInsets.left - dragInsets.right;
int height = source.getSize().height - dragInsets.top - dragInsets.bottom;
Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width, height);
if (r.contains(e.getPoint()))
setupForDragging(e);
}
private void setupForDragging(MouseEvent e) {
source.addMouseMotionListener(this);
// Determine the component that will ultimately be moved
if (destinationComponent != null) {
destination = destinationComponent;
} else if (destinationClass == null) {
destination = source;
} else // forward events to destination component
{
destination = SwingUtilities.getAncestorOfClass(destinationClass, source);
}
pressed = e.getLocationOnScreen();
location = destination.getLocation();
if (changeCursor) {
originalCursor = source.getCursor();
source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
// Making sure autoscrolls is false will allow for smoother dragging of individual components
if (destination instanceof JComponent) {
JComponent jc = (JComponent) destination;
autoscrolls = jc.getAutoscrolls();
jc.setAutoscrolls(false);
}
}
/**
* * Move the component to its new location. The dragged Point must be in the destination coordinates.
*/
#Override
public void mouseDragged(MouseEvent e) {
Point dragged = e.getLocationOnScreen();
int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);
destination.setLocation(location.x + dragX, location.y + dragY);
}
/*
* * Determine how far the mouse has moved from where dragging started (Assume drag direction is down and right for positive drag distance)
*/
private int getDragDistance(int larger, int smaller, int snapSize) {
int halfway = snapSize / 2;
int drag = larger - smaller;
drag += (drag < 0) ? -halfway : halfway;
drag = (drag / snapSize) * snapSize;
return drag;
}
/**
* * Restore the original state of the Component
*/
#Override
public void mouseReleased(MouseEvent e) {
source.removeMouseMotionListener(this);
if (changeCursor)
source.setCursor(originalCursor);
if (destination instanceof JComponent) {
((JComponent) destination).setAutoscrolls(autoscrolls);
}
if (dragNotifier != null) {
dragNotifier.dragComplete();
}
}
interface DragNotifier {
public void dragComplete();
public void dragStart();
}
}
Modified BlurryFrame:
package de.win;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import de.win.ComponentMover.DragNotifier;
#SuppressWarnings("serial")
public class BlurryFrame extends JDialog implements ActionListener, ComponentListener, DragNotifier {
public static void main(String... sss) {
JLabel label1 = new JLabel("TestLabel 1");
label1.setSize(500, 100);
label1.setForeground(Color.RED);
JLabel label2 = new JLabel("TestLabel 2");
label2.setHorizontalAlignment(SwingConstants.CENTER);
label2.setForeground(Color.BLUE);
JPanel testPanel = new JPanel();
testPanel.setOpaque(false);
testPanel.setLayout(new BorderLayout());
testPanel.add(label1, BorderLayout.CENTER);
testPanel.add(label2, BorderLayout.SOUTH);
BlurryFrame frame = new BlurryFrame(800, 600, testPanel);
frame.setBackground(new Color(0, 0, 0, 100));
frame.setVisible(true);
new ComponentMover(frame, frame, testPanel);
}
private final BackgroundPanel backgroundPane;
private final JLayeredPane container;
private final JPanel containerPane;
private final Robot robot;
// This rectangle is going to be your screenshots bounds to keep the image only as big as necessary
private final Rectangle captureRect;
// This is going to be the blurred screenshot
private BufferedImage background;
public BlurryFrame() {
this(1280, 800);
}
public BlurryFrame(int width, int height) {
this(width, height, null);
}
public BlurryFrame(int width, int height, JComponent component) {
this.captureRect = new Rectangle();
try {
this.robot = new Robot();
} catch (AWTException e) {
throw new RuntimeException(e);
}
this.backgroundPane = new BackgroundPanel();
this.backgroundPane.setOpaque(false);
this.backgroundPane.setLayout(new BorderLayout());
this.backgroundPane.setBounds(0, 0, width, height);
this.backgroundPane.addComponentListener(this);
this.containerPane = new JPanel();
this.containerPane.setOpaque(false);
this.containerPane.setLayout(new BorderLayout());
this.containerPane.add(component, BorderLayout.CENTER);
this.containerPane.setBounds(0, 0, width, height);
this.setUndecorated(true);
this.setSize(width, height);
this.setLocationRelativeTo(null);
this.container = new JLayeredPane();
this.container.setOpaque(false);
this.container.setLayout(new BorderLayout());
this.container.add(this.backgroundPane, 1);
this.container.add(this.containerPane, 0);
this.getContentPane().add(this.container, BorderLayout.CENTER);
}
public void add(JComponent component) {
this.containerPane.add(component, BorderLayout.CENTER);
this.containerPane.repaint();
}
// This method does not really do much but ultimately triggers the screenshot by ending up in #componentHidden(...)
private void capture() {
this.containerPane.setVisible(false);
this.backgroundPane.setVisible(false);
this.repaint();
}
#Override
public void setVisible(boolean visible) {
super.setVisible(visible);
this.capture();
// XXX uncomment this if you want to see the flickering
// Timer timer = new Timer(60, this);
// timer.start();
}
#Override
public void setSize(int width, int height) {
super.setSize(width, height);
this.captureRect.setSize(width, height);
this.backgroundPane.setBounds(0, 0, width, height);
this.containerPane.setBounds(0, 0, width, height);
if (this.isVisible())
this.capture();
}
#Override
public void setSize(Dimension dimension) {
super.setSize(dimension);
this.captureRect.setSize(dimension);
this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height);
this.containerPane.setBounds(0, 0, dimension.width, dimension.height);
if (this.isVisible())
this.capture();
}
#Override
public void setPreferredSize(Dimension dimension) {
super.setPreferredSize(dimension);
this.captureRect.setSize(dimension);
this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height);
this.containerPane.setBounds(0, 0, dimension.width, dimension.height);
if (this.isVisible())
this.capture();
}
#Override
public void actionPerformed(ActionEvent e) {
this.capture();
}
int i = 0;
// This is where the magic happens. The capturing needs to be done here in order to assure the applications content has really been hidden
#Override
public void componentHidden(ComponentEvent e) {
int x = this.getLocationOnScreen().x;
int y = this.getLocationOnScreen().y;
this.captureRect.setLocation(x, y);
this.background = this.robot.createScreenCapture(this.captureRect);
// XXX uncomment this if you want to see what gets captured
// if (this.i < 1) {
// try {
// ImageIO.write(this.background, "png", new File(System.getProperty("user.home") + "\\test.png"));
// } catch (IOException ex) {
// ex.printStackTrace();
// }
// this.i++;
// }
this.containerPane.setVisible(true);
this.backgroundPane.setVisible(true);
this.repaint();
}
#Override
public void componentMoved(ComponentEvent e) {
this.capture();
}
#Override
public void componentResized(ComponentEvent e) {
this.capture();
}
private class BackgroundPanel extends JPanel {
private final float[] matrix = { 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, };
#Override
public void paintComponent(Graphics g) {
if (BlurryFrame.this.background != null) {
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, this.matrix));
BufferedImage blurryBack = op.filter(BlurryFrame.this.background, null);
g.drawImage(blurryBack, 0, 0, null);
}
}
}
#Override
public void componentShown(ComponentEvent e) {
}
#Override
public void dragComplete() {
this.capture();
}
#Override
public void dragStart() {
this.background = null;
this.backgroundPane.repaint();
}
}

Drag component within a JPanel using Gridbag layout manager

I am trying to implement dragging of a J component within a JPanel. The JPanel has to use Gridbag layout manager.
I reviewed many dragging codes, including Moving Windows. They all use component.setLocation(x, y); which has no effect when using Gridbag layout manager.
I need help with alternative approach.
if the JComponent is the only component in the JPanel, the task is not that complicated. Here is a small demo program that does it (with a bonus of re-sizing the component in response to mouse wheel events) :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class GridbagDragDemo extends JPanel {
/**
* Pixel width and height of positioned component.
*/
private float width, height;
/**
* Layout manger for this.
*/
private GridBagLayout gbl;
/**
* Layout horizontal weights for left and right gap, and component.
*/
private float leftWeight,xCompWeight, rightWeight;
/**
* Layout vertical weights for top and right gap, and component.
*/
private float topWeight,yCompWeight, bottomWeight;
/**
* Min and max weight values.
* These values can be changed to change the sensitivity of dragging.
* For better responsiveness W_MAX can be changed in respect to the JPanl's size.
* (also a different W_MAX can be set to horizontal and vertical axis.
*/
private float W_MIN = 0, W_MAX = 2;
/**
* Keep sum an even number for calculating (int) W_SUM/2
*/
private float W_SUM = W_MIN + W_MAX;
/**
* Represents the change in ratio between left / right weights
* and top/bottom weights for every pixel of mouse drag.
* The higher the factor the faster / more sensitive the
* component move is.
* Try different values to get the responsiveness you need.
*/
private float WEIGHT_DELTA = 0.01f;
/**
* Represents the change (in pixels) in component width and height
* and top/bottom weights for every mouse wheel notch.
* The higher the factor the faster / more sensitive the
* component resize.
* Try different values to get the responsiveness you need.
*/
private static final int ZOOM_FACTOR = 4;
/**
* Store mouse pressed position.
*/
private float pX, pY;
/**
* The dragged component
*/
private JComponent component;
public GridbagDragDemo() {
//set initial position to center
leftWeight = W_SUM/2 ; xCompWeight = 0; rightWeight = W_SUM/2;
topWeight = W_SUM/2 ; yCompWeight = 0; bottomWeight = W_SUM/2;
setPreferredSize(new Dimension(400, 300));
gbl = new GridBagLayout();
gbl.columnWidths = new int[] {0, 0, 0};
gbl.rowHeights = new int[] {0, 0, 0};
gbl.columnWeights = new double[]{leftWeight , xCompWeight, rightWeight };
gbl.rowWeights = new double[]{topWeight,yCompWeight, bottomWeight};
setLayout(gbl);
setBackground(Color.YELLOW);
component = new JPanel();
component.setPreferredSize(new Dimension(75,75));
component.setMinimumSize(new Dimension(15,15));
component.setMaximumSize(new Dimension(225,225));
component.setBackground(Color.ORANGE);
component.setBorder(new LineBorder(Color.black, 3));
//add drag listeners
component.addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseDragged(MouseEvent me) {
int mouseX = me.getXOnScreen();
int mouseY = me.getYOnScreen();
float moveX = mouseX - pX;
float moveY = mouseY - pY;
pX = mouseX;
pY = mouseY;
moveComp(moveX , moveY);
}
});
component.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
//store pressed position
pX = me.getXOnScreen();
pY = me.getYOnScreen();
}
});
//add resize listener
component.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent me) {
//change sign so rolling "up" will be positive
reSizeComp(- me.getWheelRotation());
}
});
GridBagConstraints gbc_panel = new GridBagConstraints();
gbc_panel.fill = GridBagConstraints.BOTH;
gbc_panel.gridx = 1;
gbc_panel.gridy = 1;
add(component, gbc_panel);
width = component.getPreferredSize().width;
height = component.getPreferredSize().height;
}
private void moveComp(float moveX, float moveY) {
if(Math.abs(moveX)>0) {
leftWeight += WEIGHT_DELTA * moveX;
leftWeight = (float) setValueInRange(leftWeight, W_MIN, W_MAX);
rightWeight = W_SUM - leftWeight;
}
if(Math.abs(moveY)>0) {
topWeight += WEIGHT_DELTA * moveY;
topWeight = (float) setValueInRange(topWeight, W_MIN, W_MAX );
bottomWeight = W_SUM - topWeight;
}
gbl.columnWeights = new double[]{leftWeight,xCompWeight, rightWeight};
gbl.rowWeights = new double[]{topWeight, yCompWeight, bottomWeight};
refresh();
}
/**
*
*/
private void refresh() {
revalidate();
getParent().repaint();
}
private void reSizeComp(int notches) {
width += notches*ZOOM_FACTOR ; height += notches *ZOOM_FACTOR ;
//respect min / max component size
width = (float) setValueInRange(width, component.getMinimumSize().getWidth(),
component.getMaximumSize().getWidth() );
height = (float) setValueInRange(height, component.getMinimumSize().getHeight(),
component.getMaximumSize().getHeight() );
component.setPreferredSize(new Dimension((int)width,(int)height));
refresh();
}
private double setValueInRange(double value, double min, double max) {
value = (value < min ) ? min : value;
value = (value > max ) ? max : value;
return value;
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Test Gridbag drag");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(400, 300));
frame.add(new GridbagDragDemo());
frame.pack();
frame.setVisible(true);
}
});
}
}
If the JPanel holds multiple components, it becomes a totally different ball game. With multiple components the functionality is similar to what you get using GUI builders like Eclipse' IDE Windowbuilder, where you can interactively move components.

How to Export JPanel with scrollable into pdf file

i have design a jpanel with so many swing components with scrollable capability. i want to export whole Jpanle into pdf file.but i am not able to export whole Jpanle.
I have use itext for pdf generation.
My problem is that i am not able to export whole jpanel into pdf. When i export half of Jpanel
components export.but half portion do not export.
this is my code.
public void PrintFrameToPDF(JPanel c, File file) {
try {
Document d = new Document();
PdfWriter writer = PdfWriter.getInstance(d, new FileOutputStream("F://newfile.pdf"));
d.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate template = cb.createTemplate(800, 1600);
Graphics2D g2d = template.createGraphics(800, 1600);
// g2d.translate(1.0, 1.0);
c.paintAll(g2d);
// c.addNotify();
// c.validate();
g2d.dispose();
cb.addTemplate(template, 0, 0);
d.close();
} catch (Exception e) {
//
}
}
plz help me .
tnx
Consider creating a java.awt.Image from the panel first (by painting the panel to an Image). You can then get an instance of com.itextpdf.text.Image using:
com.itextpdf.text.Image.getInstance(PdfWriter writer,
java.awt.Image awtImage,
float quality) -
Gets an instance of a com.itextpdf.textImage from a java.awt.Image. The image is added as a JPEG with a user defined quality.
Then you can scale the image with the com.itextpdf.text.Image API methods scaleToFit or scalePercent() (as used in the example below). More information on using images (in iText) can be found here
The following program create a panel of size 2000x2000 in which squares 20x20 (of 100px each) are drawn onto a panel. The panel is contained inside a scroll pane. It is then painted on to an image, where the image will be scaled and added to the pdf document and printed to pdf.
The below image just shows how the entire panel is drawn onto the image then another panel is created, using the previous panel image, to draw onto the the new panel. The new panel is then shown via a dialog.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfWriter;
/**
* This example requires iText. I retrieved it from Maven repository
*
* <dependency>
* <groupId>com.itextpdf</groupId>
* <artifactId>itextpdf</artifactId>
* <version>5.5.2</version>
* </dependency>
*
* The program can be run without iText if you comment out the entire
* method printToPDF (and iText imports), along with it's method call in
* the class constructor. The result will be the the image above.
*/
public class LargePanelToImageMCVE {
public LargePanelToImageMCVE() {
LargeImagePanel panel = new LargeImagePanel();
JFrame frame = new JFrame();
frame.add(new JScrollPane(panel));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
final java.awt.Image image = getImageFromPanel(panel);
/* This was just a text panel to make sure the full panel was
* drawn to the panel.
*/
JPanel newPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
/* Print Image to PDF */
String fileName = "D://newfile.pdf";
printToPDF(image, fileName);
/* This was just a test to show the newPanel drew the entire
* original panel (scaled)
*/
JOptionPane.showMessageDialog(null, newPanel);
}
public void printToPDF(java.awt.Image awtImage, String fileName) {
try {
Document d = new Document();
PdfWriter writer = PdfWriter.getInstance(d, new FileOutputStream(
fileName));
d.open();
Image iTextImage = Image.getInstance(writer, awtImage, 1);
iTextImage.setAbsolutePosition(50, 50);
iTextImage.scalePercent(25);
d.add(iTextImage);
d.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static java.awt.Image getImageFromPanel(Component component) {
BufferedImage image = new BufferedImage(component.getWidth(),
component.getHeight(), BufferedImage.TYPE_INT_RGB);
component.paint(image.getGraphics());
return image;
}
/**
* Demo panel that is 2000x2000 px with alternating squares
* to check all squares are drawn to image
*/
public class LargeImagePanel extends JPanel {
private static final int FULL_SIZE = 2000;
private static final int PER_ROW_COLUMN = 20;
private static final int SQUARE_SIZE = FULL_SIZE / PER_ROW_COLUMN;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < PER_ROW_COLUMN; row++) {
for (int col = 0; col < PER_ROW_COLUMN; col++) {
if ((row % 2) == (col % 2)) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(col * SQUARE_SIZE, row * SQUARE_SIZE,
SQUARE_SIZE, SQUARE_SIZE);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(FULL_SIZE, FULL_SIZE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new LargePanelToImageMCVE();
}
});
}
}

problems revalidating/repainting button panel

I've been googling for hours trying a million different subtle changes all to no avail, so I figure my best bet is to pick the brains of people more skilled than I.
I'm writing a class that loads a bunch of buttons from a database and the goal is to offer the user the ability to arrange the buttons to their liking, however, for some reason, I can't seem to get the frame to revalidate or repaint. The buttons will move around, but they will not rearrange as I have coded them to. The organization seems to be working correctly, ie the code involved in making the re arrangement when the mouse button is released, its just that the components will only stay where they are dragged and dropped, even though they are re ordered in their respective List.
The code is long, I didn't want to have to post the whole class as it may turn some people off but I don't know where I'm making the mistake so I think it would be in my best interest to post the whole thing. The main area of concern is mouseReleased(MouseEvent e) {...} and the repaint()/refresh() method, however, there could be something that I'm missing elsewhere.
tl;dr:
I'm basically just trying to perform a setBounds() after the user drags and drops the buttons in the order they want but the buttons stay in the same spot they are dragged and dropped, and won't revalidate() or repaint(). I can't even removeAll to clear the panel of components and reload.
Thank you in advanced. Here's my code:
public class AdminButtonEditor extends javax.swing.JFrame {
public AdminButtonEditor(OrderView parent) { ...
...
Component[] components = buttonsPanel.getComponents();
for (int i = 0; i < components.length; i++) {
Component c = components[i];
if (c instanceof JButton) {
JButton jb = (JButton) c;
jb.setFocusable(false);
buttons.add(new MyJButton(...));
}
}
for (int i = 0; i < buttons.size(); i++) {
buttons.get(i).addTo(editPanel);
buttons.get(i).orderIndex=modButtonList.get(i).menuModifier.getViewOrderValue();
buttons.get(i).idx=i;
}
EventHandler eh = new EventHandler();
addWindowListener(eh);
editPanel.addMouseMotionListener(eh);
editPanel.addMouseListener(eh);
contentPane.add(editPanel, BorderLayout.CENTER);
}
protected void refresh() {
if (!buttons.isEmpty() && buttons.get(0) != null) {
contentPane.remove(editPanel);
editPanel.removeAll();
for (int i = 0; i < buttons.size(); i++) {
MyJButton s = buttons.get(i);
s.addTo(editPanel);
}
contentPane.add(editPanel, BorderLayout.CENTER);
editPanel.repaint();
}
}
public void paint(Graphics g) {
refresh();
super.paint(g);
}
private int getSelectionIndex(int x, int y) {
int s=-1;
for (int i=buttons.size()-1; i>=0;i--){
if (buttons.get(i).contains(x, y)) {
s = i;
break;
}
}
return s;
}
private class EventHandler implements MouseInputListener,WindowListener, ActionListener {
private int selectionIndex, startX, startY, lastX, lastY;
private MyJButton selected;
private boolean moving=false;
....
....
public void mouseReleased(MouseEvent e) {
if (moving){
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
moving=false;
int dropX=e.getX();
int dropY=e.getY();
int row = dropY/selected.height;
int col = dropX/selected.width;
int idx=(row*3+col)-1;
int oldIdx=buttons.indexOf(selected);
insertIntoList(idx,oldIdx);
}
if (selected!=null){
selected.unHighLight();
selected=null;
}
Collections.sort(buttons);
for (int i=0;i<buttons.size();i++){
//modButtonList.get(buttons.get(i).idx).menuModifier.setViewOrderValue(buttons.get(i).orderIndex);
}
editPanel.validate();
repaint();
}
private void insertIntoList(int idx, int oldIdx) {
MyJButton temp = buttons.get(idx);
int tempid=buttons.get(idx).idx;
buttons.set(idx, new MyJButton(selected.text,selected.x,selected.y,selected.width,selected.height,selected.idx));
buttons.get(idx).orderIndex=temp.orderIndex;
if (idx<oldIdx){
int id;
for (int i=oldIdx;i>idx+1;i--){
id=buttons.get(i).orderIndex;
buttons.set(i, new MyJButton(buttons.get(i-1).text,buttons.get(i-1).x,buttons.get(i-1).y,buttons.get(i-1).width,buttons.get(i-1).height,buttons.get(i-1).idx));
buttons.get(i).orderIndex=id;
}
id = buttons.get(idx+1).orderIndex;
buttons.set(idx+1,new MyJButton(temp.text,temp.x,temp.y,temp.width,temp.height,temp.idx));
buttons.get(idx+1).orderIndex=id;
} else if (idx>oldIdx) {
int id;
for (int i=oldIdx;i<idx-1;i++){
id=buttons.get(i).orderIndex;
buttons.set(i, new MyJButton(buttons.get(i+1).text,buttons.get(i+1).x,buttons.get(i+1).y,buttons.get(i+1).width,buttons.get(i+1).height,buttons.get(i+1).idx));
buttons.get(i).orderIndex=id;
}
id = buttons.get(idx-1).orderIndex;
buttons.set(idx-1,new MyJButton(temp.text,temp.x,temp.y,temp.width,temp.height,temp.idx));
buttons.get(idx-1).orderIndex=id;;
} else {
buttons.get(idx).x=buttons.get(idx).originx;
buttons.get(idx).y=buttons.get(idx).originy;
}
repaint();
}
public void mouseDragged(MouseEvent e) {
if (moving) {
Graphics g = editPanel.getGraphics();
g.setColor(Color.black);
g.drawLine(selected.getXPos(), 0, selected.getXPos(),editPanel.getWidth());
g.drawLine(0, selected.getYPos(), editPanel.getHeight(), selected.getYPos());
selected.moveBy(e.getX()-lastX, e.getY()-lastY);
g.setXORMode(Color.black);
g.drawLine(selected.getXPos(), 0, selected.getXPos(), editPanel.getWidth());
g.drawLine(0, selected.getYPos(), editPanel.getHeight(), selected.getYPos());
lastX=e.getX();
lastY=e.getY();
repaint();
}
}
....
}
private class MyJButton extends JButton implements Comparable {
private int orderIndex,idx;
private int x, y, width, height,originx,originy;
private String text;
public Border DEFAULT_BORDER;// new SoftBevelBorder(BevelBorder.RAISED);
public Border SELECT_BORDER = BorderFactory.createLineBorder(Color.RED, 3, true);
public MyJButton(String text, int x, int y, int width, int height) {
....
setFocusable(false);
}
public MyJButton(String text, int x, int y, int width, int height,int idx) {....}
public void addTo(JPanel p) {
setBounds(x, y, width, height);
p.add(this);
}
#Override
public boolean contains(int x, int y) {
int x1 = x, y1 = y;
if (x1 >= this.x && y1 >= this.y && x1 <= this.x + width && y1 <= this.y + height) {
return true;
} else {
return false;
}
}
#Override
public void setSize(int w, int h) {
width = w;
height = h;
}
....
public void moveBy(int dx, int dy) {
x += dx;
y += dy;
}
#Override
public void resize(int newWidth, int newHeight) {
this.width = newWidth;
this.height = newHeight;
setBounds(x, y, width, height);
}
public int compareTo(Object o) {
MyJButton mjb = (MyJButton)o;
return this.idx-mjb.idx;
}
}
}
+1 to GagandeepBalis comment.
Okay so I found this very cool and decided to look into it more.
I came up with some logic which will be needed for it to work, maybe not the best but...:
1) We need to make our JButtons draggable ( thank you #camickr and his DragLayout) :)
2) When a JButtons is dragged and than dropped i.e on mouseReleased(..) we should check if a our dragged buttons collide with any others
3) we check whether a JButton collides with another by getting the JButton image and counting how many opaque pixels of the JButton, we are dragging, are covering another button.
4) sort the number of collisions and find the highest, this will be used so we can see where to insert the JButton we dragged. i.e it will be inserted by component with the most collisions.
5) sort the ArrayList which holds the buttons to match the changes
6) remove all buttons and re-add them using the Array (and thus they will be re-ordered).
Here is an example (Most code takes place in overridden ComponentMover mouseReleased(..) method):
Before dragging anything:
after dragging button 4 over button 1 and letting go of mouse button:
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DragButtons {
ArrayList<JButton> buttons = new ArrayList<>();
public DragButtons() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DragButtons();
}
});
}
private void initComponents() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new GridLayout(2, 2));
ComponentMover cm = new ComponentMover() {
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
HashMap<Integer, JButton> collisions = new HashMap<>();
JButton draggedButton = (JButton) e.getSource();
for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
if (btn != draggedButton) {//dont chck button we were dragging
int col = checkPerPixelCollision(draggedButton, btn);
System.out.println("Button " + btn.getText());
System.out.println(col);
collisions.put(col, btn);
}
}
//lets get the button which had most collisions
int maxCollisions = 0;
JButton intersectingButton = null;
for (Map.Entry<Integer, JButton> entry : collisions.entrySet()) {
Integer collisionCount = entry.getKey();
JButton button = entry.getValue();
if (collisionCount > maxCollisions) {
maxCollisions = collisionCount;
intersectingButton = button;
}
}
boolean reLayout = false;
if (maxCollisions > 0) {//check if there was any
System.out.println("Button " + draggedButton.getText() + " is intersecting more of Button " + intersectingButton.getText());
System.out.println("Collisions: " + maxCollisions);
reLayout = true;
} else {
System.out.println("No change made");
reLayout = false;
}
ArrayList<JButton> tmpButtons = (ArrayList<JButton>) buttons.clone();//create clone of buttons
if (reLayout) {//a button as moved and panel needs to be layed out
buttons.clear();//clear old buttons
for (JButton b : tmpButtons) {//re-order jbuttons
if (b == intersectingButton) {
buttons.add(draggedButton);
} else if (b == draggedButton) {
buttons.add(intersectingButton);
} else {
buttons.add(b);
}
}
panel.removeAll();//remove all buttons
for (JButton btn : buttons) {//iterate through all buttons and get the number of collsions of each
panel.add(btn);//re-add buttons according to arraylist
}
panel.revalidate();
panel.repaint();
//re-order the Array of buttons to fit
//remove all button and re add them using sorted array
}
}
};
for (int i = 0; i < 4; i++) {
JButton b = new JButton(String.valueOf(i + 1));
buttons.add(b);
panel.add(b);
cm.registerComponent(b);
}
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public HashSet<String> getMask(JButton e) {
HashSet<String> mask = new HashSet<>();
int pixel, a;
BufferedImage bi = null;
try {
bi = componentToImage(e, e.getBounds()); //gets the current image being shown
} catch (IOException ex) {
Logger.getLogger(DragButtons.class.getName()).log(Level.SEVERE, null, ex);
}
for (int i = 0; i < bi.getWidth(); i++) { // for every (x,y) component in the given box,
for (int j = 0; j < bi.getHeight(); j++) {
pixel = bi.getRGB(i, j); // get the RGB value of the pixel
a = (pixel >> 24) & 0xff;
if (a != 0) { // if the alpha is not 0, it must be something other than transparent
mask.add((e.getX() + i) + "," + (e.getY() - j)); // add the absolute x and absolute y coordinates to our set
}
}
}
return mask; //return our set
}
public static BufferedImage componentToImage(Component component, Rectangle region) throws IOException {
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
Graphics g = img.getGraphics();
g.setColor(component.getForeground());
g.setFont(component.getFont());
component.paintAll(g);
ImageIO.write(img, "png", new File("c:/saved.png"));
return img;
}
// Returns true if there is a collision between object a and object b
public int checkPerPixelCollision(JButton b, JButton b2) {
// This method detects to see if the images overlap at all. If they do, collision is possible
int ax1 = (int) b2.getX();
int ay1 = (int) b2.getY();
int ax2 = ax1 + (int) b2.getWidth();
int ay2 = ay1 + (int) b2.getHeight();
int bx1 = (int) b.getX();
int by1 = (int) b.getY();
int bx2 = bx1 + (int) b.getWidth();
int by2 = by1 + (int) b.getHeight();
if (by2 < ay1 || ay2 < by1 || bx2 < ax1 || ax2 < bx1) {
return 0; // Collision is impossible.
} else { // Collision is possible.
// get the masks for both images
HashSet<String> maskPlayer1 = getMask(b2);
HashSet<String> maskPlayer2 = getMask(b);
maskPlayer1.retainAll(maskPlayer2); // Check to see if any pixels in maskPlayer2 are the same as those in maskPlayer1
if (maskPlayer1.size() > 0) { // if so, than there exists at least one pixel that is the same in both images, thus
return maskPlayer1.size();
}
}
return 0;
}
}
class ComponentMover extends MouseAdapter {
private Insets dragInsets = new Insets(0, 0, 0, 0);
private Dimension snapSize = new Dimension(1, 1);
private Insets edgeInsets = new Insets(0, 0, 0, 0);
private boolean changeCursor = true;
private boolean autoLayout = false;
private Class destinationClass;
private Component destinationComponent;
private Component destination;
private Component source;
private Point pressed;
private Point location;
private Cursor originalCursor;
private boolean autoscrolls;
private boolean potentialDrag;
/**
* Constructor for moving individual components. The components must be
* regisetered using the registerComponent() method.
*/
public ComponentMover() {
}
/**
* Constructor to specify a Class of Component that will be moved when drag
* events are generated on a registered child component. The events will be
* passed to the first ancestor of this specified class.
*
* #param destinationClass the Class of the ancestor component
* #param component the Components to be registered for forwarding drag
* events to the ancestor Component.
*/
public ComponentMover(Class destinationClass, Component... components) {
this.destinationClass = destinationClass;
registerComponent(components);
}
/**
* Constructor to specify a parent component that will be moved when drag
* events are generated on a registered child component.
*
* #param destinationComponent the component drage events should be
* forwareded to
* #param components the Components to be registered for forwarding drag
* events to the parent component to be moved
*/
public ComponentMover(Component destinationComponent, Component... components) {
this.destinationComponent = destinationComponent;
registerComponent(components);
}
/**
* Get the auto layout property
*
* #return the auto layout property
*/
public boolean isAutoLayout() {
return autoLayout;
}
/**
* Set the auto layout property
*
* #param autoLayout when true layout will be invoked on the parent
* container
*/
public void setAutoLayout(boolean autoLayout) {
this.autoLayout = autoLayout;
}
/**
* Get the change cursor property
*
* #return the change cursor property
*/
public boolean isChangeCursor() {
return changeCursor;
}
/**
* Set the change cursor property
*
* #param changeCursor when true the cursor will be changed to the
* Cursor.MOVE_CURSOR while the mouse is pressed
*/
public void setChangeCursor(boolean changeCursor) {
this.changeCursor = changeCursor;
}
/**
* Get the drag insets
*
* #return the drag insets
*/
public Insets getDragInsets() {
return dragInsets;
}
/**
* Set the drag insets. The insets specify an area where mouseDragged events
* should be ignored and therefore the component will not be moved. This
* will prevent these events from being confused with a MouseMotionListener
* that supports component resizing.
*
* #param dragInsets
*/
public void setDragInsets(Insets dragInsets) {
this.dragInsets = dragInsets;
}
/**
* Get the bounds insets
*
* #return the bounds insets
*/
public Insets getEdgeInsets() {
return edgeInsets;
}
/**
* Set the edge insets. The insets specify how close to each edge of the
* parent component that the child component can be moved. Positive values
* means the component must be contained within the parent. Negative values
* means the component can be moved outside the parent.
*
* #param edgeInsets
*/
public void setEdgeInsets(Insets edgeInsets) {
this.edgeInsets = edgeInsets;
}
/**
* Remove listeners from the specified component
*
* #param component the component the listeners are removed from
*/
public void deregisterComponent(Component... components) {
for (Component component : components) {
component.removeMouseListener(this);
}
}
/**
* Add the required listeners to the specified component
*
* #param component the component the listeners are added to
*/
public void registerComponent(Component... components) {
for (Component component : components) {
component.addMouseListener(this);
}
}
/**
* Get the snap size
*
* #return the snap size
*/
public Dimension getSnapSize() {
return snapSize;
}
/**
* Set the snap size. Forces the component to be snapped to the closest grid
* position. Snapping will occur when the mouse is dragged half way.
*/
public void setSnapSize(Dimension snapSize) {
if (snapSize.width < 1
|| snapSize.height < 1) {
throw new IllegalArgumentException("Snap sizes must be greater than 0");
}
this.snapSize = snapSize;
}
/**
* Setup the variables used to control the moving of the component:
*
* source - the source component of the mouse event destination - the
* component that will ultimately be moved pressed - the Point where the
* mouse was pressed in the destination component coordinates.
*/
#Override
public void mousePressed(MouseEvent e) {
source = e.getComponent();
int width = source.getSize().width - dragInsets.left - dragInsets.right;
int height = source.getSize().height - dragInsets.top - dragInsets.bottom;
Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width, height);
if (r.contains(e.getPoint())) {
setupForDragging(e);
}
}
private void setupForDragging(MouseEvent e) {
source.addMouseMotionListener(this);
potentialDrag = true;
// Determine the component that will ultimately be moved
if (destinationComponent != null) {
destination = destinationComponent;
} else if (destinationClass == null) {
destination = source;
} else // forward events to destination component
{
destination = SwingUtilities.getAncestorOfClass(destinationClass, source);
}
pressed = e.getLocationOnScreen();
location = destination.getLocation();
if (changeCursor) {
originalCursor = source.getCursor();
source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
// Making sure autoscrolls is false will allow for smoother dragging of
// individual components
if (destination instanceof JComponent) {
JComponent jc = (JComponent) destination;
autoscrolls = jc.getAutoscrolls();
jc.setAutoscrolls(false);
}
}
/**
* Move the component to its new location. The dragged Point must be in the
* destination coordinates.
*/
#Override
public void mouseDragged(MouseEvent e) {
Point dragged = e.getLocationOnScreen();
int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);
int locationX = location.x + dragX;
int locationY = location.y + dragY;
// Mouse dragged events are not generated for every pixel the mouse
// is moved. Adjust the location to make sure we are still on a
// snap value.
while (locationX < edgeInsets.left) {
locationX += snapSize.width;
}
while (locationY < edgeInsets.top) {
locationY += snapSize.height;
}
Dimension d = getBoundingSize(destination);
while (locationX + destination.getSize().width + edgeInsets.right > d.width) {
locationX -= snapSize.width;
}
while (locationY + destination.getSize().height + edgeInsets.bottom > d.height) {
locationY -= snapSize.height;
}
// Adjustments are finished, move the component
destination.setLocation(locationX, locationY);
}
/*
* Determine how far the mouse has moved from where dragging started
* (Assume drag direction is down and right for positive drag distance)
*/
private int getDragDistance(int larger, int smaller, int snapSize) {
int halfway = snapSize / 2;
int drag = larger - smaller;
drag += (drag < 0) ? -halfway : halfway;
drag = (drag / snapSize) * snapSize;
return drag;
}
/*
* Get the bounds of the parent of the dragged component.
*/
private Dimension getBoundingSize(Component source) {
if (source instanceof Window) {
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle bounds = env.getMaximumWindowBounds();
return new Dimension(bounds.width, bounds.height);
} else {
return source.getParent().getSize();
}
}
/**
* Restore the original state of the Component
*/
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (!potentialDrag) {
return;
}
source.removeMouseMotionListener(this);
potentialDrag = false;
if (changeCursor) {
source.setCursor(originalCursor);
}
if (destination instanceof JComponent) {
((JComponent) destination).setAutoscrolls(autoscrolls);
}
// Layout the components on the parent container
if (autoLayout) {
if (destination instanceof JComponent) {
((JComponent) destination).revalidate();
} else {
destination.revalidate();
}
destination.repaint();
}
}
}

Categories