I have created a CellRenderer for my table.
It works fine if the image is with small size.
However , if it's a little large it shows me blank space
public class ImageRenderer extends DefaultTableCellRenderer {
JLabel lbl = new JLabel();
JButton bouton ;
List<Commentaire> liste;
ImageIcon icon ;
Commentaire commentaire;
// Increase the height of each row by 50% so we can see the whole
// image.
public ImageRenderer() {
liste= new CommentaireDAO().findCommentaire();
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
if (column==0){
int id = (int)value;
Client c = new ClientDAO().findClientById(id);
InputStream photo= c.getPhoto();
try {
if (photo != null) {
int size = photo.available();
byte[] imageBytes = new byte[size];
photo.read(imageBytes);
ImageIcon icon = new ImageIcon(imageBytes);
Image img = icon.getImage();
BufferedImage bi = new BufferedImage(img.getWidth(null),img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.drawImage(img, 0, 0, 50, 50, null);
ImageIcon newIcon = new ImageIcon(bi);
lbl.setSize(250,250);
lbl.setHorizontalAlignment(CENTER);
lbl.setIcon(newIcon);
}else{
System.out.println("photo null");
}
} catch (IOException ex) {
Logger.getLogger(OffreClientGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
Is there any method to resize the image to fit in the column ?
The code in a renderer should be very fast and efficient. You should not be doing processing to create the image every time the cell is rendered.
Instead you should be storing an ImageIcon in the TableModel. Then you override the getColumnClass(...) method of the TableModel to return Icon.class and the JTable will used the default table renderer for the Icon.
If you want to dynamically scale the Icon you can add a Stretch Icon to the TableModel.
Related
I hope someone can help me out. Iam trying to create a "countrycombobox" with icons in Java Swing. I found some stuff, but nothing did work for me. Maybe the problem is, that Iam still "new" to Java.
I just want it simple like this: http://www.zomex.com/libs/images/layout/whmcs-template-language-select-w-flags-eco.jpg
Just the flags in front of the countrys.
I would really appreciate a working example. I really wonder, that there is no standard option or a good code snippet(used Google a lot to find help here) for stuff like this.
I found a better example and wanna share my stuff with you. There is just one problem left, that I dont get it sized.
package view;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CountryComboBox extends JPanel {
ImageIcon[] images;
String[] imgStrings = {"de"};
/*
* Despite its use of EmptyBorder, this panel makes a fine content
* pane because the empty border just increases the panel's size
* and is "painted" on top of the panel's normal background. In
* other words, the JPanel fills its entire background if it's
* opaque (which it is by default); adding a border doesn't change
* that.
*/
public CountryComboBox() {
super(new BorderLayout());
//Load the images and create an array of indexes.
images = new ImageIcon[imgStrings.length];
Integer[] intArray = new Integer[imgStrings.length];
for (int i = 0; i < imgStrings.length; i++) {
intArray[i] = new Integer(i);
images[i] = createImageIcon("/res/" + imgStrings[i] + ".png");
if (images[i] != null) {
images[i].setDescription(imgStrings[i]);
}
}
//Create the combo box.
JComboBox imgList = new JComboBox(intArray);
ComboBoxRenderer renderer= new ComboBoxRenderer();
imgList.setRenderer(renderer);
imgList.setMaximumRowCount(3);
//Lay out the demo.
add(imgList, BorderLayout.PAGE_START);
//setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
}
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = CountryComboBox.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
class ComboBoxRenderer extends JLabel
implements ListCellRenderer {
private Font uhOhFont;
public ComboBoxRenderer() {
setOpaque(true);
setHorizontalAlignment(CENTER);
setVerticalAlignment(CENTER);
}
/*
* This method finds the image and text corresponding
* to the selected value and returns the label, set up
* to display the text and image.
*/
#Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
//Get the selected index. (The index param isn't
//always valid, so just use the value.)
int selectedIndex = ((Integer)value).intValue();
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
//Set the icon and text. If icon was null, say so.
ImageIcon icon = images[selectedIndex];
String img = imgStrings[selectedIndex];
setIcon(icon);
if (icon != null) {
setText(img);
setFont(list.getFont());
} else {
setUhOhText(img + " (no image available)",
list.getFont());
}
return this;
}
//Set the font and text when no image was found.
protected void setUhOhText(String uhOhText, Font normalFont) {
if (uhOhFont == null) { //lazily create this font
uhOhFont = normalFont.deriveFont(Font.ITALIC);
}
setFont(uhOhFont);
setText(uhOhText);
}
}
}
I call it in a JPanel with absolute layout:
JComponent newContentPane = new CountryComboBox();
newContentPane.setOpaque(true); //content panes must be opaque
newContentPane.setBounds(10, 75, 50, 26);
contentPane.add(newContentPane);
setBounds isnt working, just to get the right position. I cant size it with this.
Best regards
Acanis
I'm trying to create this basic photo editing app via java swing. I have my code to work somewhat for when 1 picture is imported; I have 3 views - photo view which displays the photo only, thumbnail view which should display thumbnails of the pictures and split view which should be a combination of photo in BorderLayout.CENTER and thumbnail in BorderLayout.SOUTH. I've put in images and code excerpts as to why this isn't working the way it should. I can't upload any images but hopefully the excerpts provide much detail.
Split View Related Excerpts:
public void changeMode(boolean p, boolean b, boolean s){
/*
* Photo View will display a single PhotoComponent2 in a large area.
*/
isPhoto = p;
if (isPhoto){
//have a child JPanel set as CENTER component of BorderLayout of the JScrollPane (scroll)
childPhoto = new JPanel();
childPhoto.add(displayPhotos.get(getCurrentPhoto()), BorderLayout.CENTER);
System.out.println("in lc photo view class");
}
/*
* Browser View will hold all the images.
*/
isBrowse = b;
if(isBrowse){
//have a child JPanel set as CENTER component of BorderLayout to hold grid of thumbnails within
// JScrollPanel (scroll)
this.removeAll();
childBrowse = new JPanel();
tc2 = new ThumbnailComponent(displayPhotos.get(getCurrentPhoto()));
childBrowse.setLayout(new WrapLayout());
childBrowse.add(tc2);
// for(int i = 0; i < displayThumbs.size(); i++){
// childBrowse.add(displayThumbs.get(i));
// System.out.println(displayThumbs.get(i));
// }
System.out.println("in lc browser view class");
}
/*
* Split View is a combination of Photo and Browser View in that the top half
* is Photo View and the bottom half is Browser View.
*/
isSplit = s;
if(isSplit){
//have a child JPanel in CENTER to hold PhotoComponent plus a child JPanel in SOUTH to hold thumbnails
containsAll = new JPanel();
containsAll.setLayout(new BorderLayout());
containsAll.add(childPhoto, BorderLayout.CENTER);
containsAll.add(childBrowse, BorderLayout.SOUTH);
System.out.println("in lc split view class");
}
}
This is basically all of my problems right now. Currently the thumbnails that are being created are based on the current image. If I go to photo view and and change the image being displayed with my forward/backward buttons and then go back to browser view I get the thumbnail of the respective image. However, I want to be able to create thumbnails for all images being imported and then display it. I tried the for loop (which I've commented out) and that didn't help either. The other code associated with this are my main class that creates the JFrame and the buttons,etc., the photoComponent that has my paintComponent method I use in my thumbnails and lightComponent classes.
MyPhotos3:
view = new JMenu("View");
mbar.add(view);
pv = new JRadioButton("Photo Viewer");
pv.addActionListener(new ActionListener(){ //change status
public void actionPerformed(ActionEvent e){
sbar.setText("Status: By clicking this, you'll be able to view your photos one at a time");
boolean p = true;
boolean b = false;
boolean s = false;
lc.changeMode(p,b,s);
scroll.add(lc.childPhoto);
scroll.setViewportView(lc.childPhoto);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
b = new JRadioButton("Browser");
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){ //change status
sbar.setText("Status: By clicking this, you'll be able to view all your photos as thumbnails");
boolean p = false;
boolean b = true;
boolean s = false;
lc.changeMode(p,b,s);
scroll.setViewportView(lc.childBrowse);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
sm = new JRadioButton("Split Mode");
sm.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){ //change status
sbar.setText("Status: By clicking this, you'll be able to view a single photo with a film strip dimensional view");
boolean p = false;
boolean b = false;
boolean s = true;
lc.changeMode(p,b,s);
scroll.setViewportView(lc.containsAll);
scroll.getViewport().setBackground(Color.BLUE);
scroll.revalidate();
scroll.repaint();
}
});
PhotoComponent:
public PhotoComponent2(boolean f, Image img){
isFlip = f;
init = img;
x = init.getWidth(null);
y = init.getHeight(null);
setPreferredSize(new Dimension (x,y));
bi = new BufferedImage(init.getWidth(null),init.getHeight(null),BufferedImage.TYPE_INT_ARGB);
newIcon = new ImageIcon(bi);
img1 = new JLabel("", newIcon, JLabel.CENTER);
image = img1;
this.add(img1);
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocus(true);
//System.out.println("In constructor");
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(init, 0, 0, null);
this.addMouseListener(this);
this.addMouseMotionListener(this);
//System.out.println("In paintComponent");
Thumbnails:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.JComponent;
public class ThumbnailComponent extends JComponent{
/**
* ThumbnailComponent class is a way to create smaller versions of each photo passed in.
*
* #author Puja Sheth
* #version 1.0 10/16/2014
*/
private static final long serialVersionUID = 1L;
PhotoComponent2 pc;
Image img;
double x;
double y;
int newX;
int newY;
public ThumbnailComponent(PhotoComponent2 input){
pc = input;
img = pc.init;
x = (img.getWidth(null))/(.5);
y = (img.getHeight(null))/(.5);
newX = (int)x;
newY = (int)y;
setPreferredSize(new Dimension (newX,newY));
// add(input);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics gCopy = g.create();
Graphics2D g2d = (Graphics2D)gCopy;
g2d.scale(.5,.5);
pc.paintComponent(g2d);
}
}
Any help would be greatly appreciated!!!!
Won't solve your problem, but a few general comments about your code:
scroll.add(lc.childPhoto);
scroll.setViewportView(lc.childPhoto);
scroll.revalidate();
scroll.repaint();
You should never add a component to a scrollpane. The only line of code you need is:
scroll.setViewportView(lc.childPhoto);
The scrollpane will automatically revalidate() and repaint() itself when the viewport view is changed.
super.paintComponent(g);
g.drawImage(init, 0, 0, null);
this.addMouseListener(this);
this.addMouseMotionListener(this);
Never add listener to a component is a painting method. Painting methods are for painting only. A listener has nothing to do with painting. Also, the painting methods are invoked whenever Swing determines the component needs to be repainted so you will be adding multiple listeners to the component.
I`ve got a mysterious problem with my custom JTable and a custom TableRenderer.
In 95%-99,99% it works perfectly, but sometimes the renderer just stops doing his job, and leaves a portion of the table (which is inside a JScrollPane) blank.
The problem case looks like that:
In all other cases, and after a slight resize of the window, the Table look like that:
Now both columns has a TextAreaCellRenderer associated to, which works as follows:
public class TextAreaCellRenderer extends JTextArea implements TableCellRenderer {
private final Color evenColor = new Color(252, 248, 202);
public TextAreaCellRenderer() {
super();
setLineWrap(true);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
#Override
public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
setBackground((row % 2 == 0) ? evenColor : getBackground());
}
setWrapStyleWord(true);
setFont(table.getFont());
setText((value == null) ? "" : value.toString());
return this;
}
}
I also have to override the doLayout method of the JTable to be able to calculate the hight of a cell depending on the content. The custom table looks like that:
public class MediaMetaDataTable extends JTable {
#Override
public void doLayout() {
TableColumn col = getColumnModel().getColumn(1);
for (int row = 0; row < getRowCount(); row++) {
Component c = prepareRenderer(col.getCellRenderer(), row, 1);
if (c instanceof JTextArea) {
JTextArea a = (JTextArea) c;
int h = getPreferredHeight(a) + getIntercellSpacing().height;
if (getRowHeight(row) != h) {
setRowHeight(row, h);
}
}
}
super.doLayout();
}
private int getPreferredHeight(final JTextComponent c) {
Insets insets = c.getInsets();
View view = c.getUI().getRootView(c).getView(0);
int preferredHeight = (int) view.getPreferredSpan(View.Y_AXIS);
return preferredHeight + insets.top + insets.bottom;
}
}
The table is instantiated once with the following parameters:
metaTable = new MediaMetaDataTable();
metaTable.setModel(new MediaMetaDataTableModel());
metaTable.setEnabled(false);
metaTable.setShowGrid(false);
metaTable.setTableHeader(null);
metaTable.getColumnModel().getColumn(0).setCellRenderer(new TextAreaCellRenderer());
metaTable.getColumnModel().getColumn(1).setCellRenderer(new TextAreaCellRenderer());
metaTable.setPreferredScrollableViewportSize(new Dimension(-1, -1));
metaTable.setShowHorizontalLines(false);
metaTable.setShowVerticalLines(false);
Each time the data to show changes i update table by replacing the underlying models data:
List<MediaMetaData> metaInformation = mediaSearchHit.getMetaInformation();
if (metaInformation != null) {
((MediaMetaDataTableModel) metaTable.getModel()).replaceMetaInfos(metaInformation);
}
On update the model itself fires a table data changed event:
public class MediaMetaDataTableModel extends AbstractTableModel {
private List<MediaMetaData> metaInfos = new LinkedList<MediaMetaData>();
public static final int COL_INDEX_NAME = 0;
public static final int COL_INDEX_VALUE = 1;
public void replaceMetaInfos(final List<MediaMetaData> metaInfos) {
this.metaInfos = null;
this.metaInfos = metaInfos;
fireTableDataChanged();
}
...
Now does anybody has a idea, what causes the described rendering problem?
Thanks for any advices.
I also have to override the doLayout method of the JTable to be able
to calculate the hight of a cell depending on the content.
To achieve this goal there's no need to override doLayout() method. I think the simplest way to do this is by adding the text area used to render the cell content into a JPanel with BorderLayout and set the row height based on the panel's preferred size. This way the layout manager will do the trick for you and all the cell's content will be visible:
#Override
public Component getTableCellRendererComponent(...) {
...
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(this);
table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
return contentPane;
}
As #mKorbel pointed out, there's no need to make the renderer extend from JTextArea: a single variable will work. Keeping this in mind take a look to this implementation based on your work:
class TextAreaRenderer implements TableCellRenderer {
private JTextArea renderer;
private final Color evenColor = new Color(252, 248, 202);
public TextAreaRenderer() {
renderer = new JTextArea();
renderer.setLineWrap(true);
renderer.setWrapStyleWord(true);
renderer.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (isSelected) {
renderer.setForeground(table.getSelectionForeground());
renderer.setBackground(table.getSelectionBackground());
} else {
renderer.setForeground(table.getForeground());
renderer.setBackground((row % 2 == 0) ? evenColor : table.getBackground());
}
renderer.setFont(table.getFont());
renderer.setText((value == null) ? "" : value.toString());
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(renderer);
table.setRowHeight(row, contentPane.getPreferredSize().height); // sets row's height
return contentPane;
}
}
Screenshot
If I had to guess I would say it could be a concurency problem. Are you doing everything in the GUI-Thread? If yes, it can't be a concurency problem. Otherwhise try to call everything with Thread.InvokeLater() in an inital debug step, if you don't encounter the error anymore after a long time of testing, you know the cause of the problem.
In a second step you would then check exactly where it is necessary to make the calls with invokelater() and where not (because you shouldn't do that all the time, because it leads to very poor performance.
As I said, just a wild guess... It can of youre just be another bug. Are you using Java7? There are millions of Bugs in Swing with java 7 code (just all the code that from oracle came).
I'm working on a program that will read a folder of images into a JList, and the picture that is selected in the JList will be drawn into a JPanel. I have two classes: ImageViewerPanel, which creates the panel to display the selected picture. I then have ImageViewerUI which will draw the JList, and the ImageViewerPanel will be added into the ImageViewerUI class. Here is the relevant code from the ImageViewerPanel class.
public ImageViewerPanel() {
initComponents();
}
public void setImage(BufferedImage image) {
this.image = image;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (scaled == false) {
g.drawImage(image, 0, 0, null);
}else if(scaled == true) {
g.drawImage(image, 0, 0, 80, 80, null);
}
Here is the code from the ImageViewerUI class that is to refresh the panel with the image:
ImageViewerPanel imagePanel = new ImageViewerPanel();
BufferedImage displayedImage;
BufferedImage originalImage;
public ImageViewerUI() {
initComponents();
loadListWithImageFilenames();
updateImagePanel();
updateThumbnailImagePanel();
}
public final void updateImagePanel() {
try {
String currFile = (String) ("Images/" + imageList.getSelectedValue());
displayedImage = ImageIO.read(new File(currFile));
imagePanel.setImage(displayedImage);
} catch (IOException ex) {
Logger.getLogger(ImageViewerUI.class.getName()).log(Level.SEVERE, null, ex);
}
public final void updateThumbnailImagePanel() {
try {
String currFile = (String) ("Images/" + imageList.getSelectedValue());
originalImage = ImageIO.read(new File(currFile));
imagePanel.setScaled(true);
imagePanel.setImage(originalImage);
imageViewerPanel1.add(imagePanel);
imagePanel.repaint();
} catch (IOException ex) {
Logger.getLogger(ImageViewerUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
The issue I am having is that the image is not being displayed in the panel. Anyone know why?
imageViewerPanel1.add(imagePanel);
imagePanel.repaint();
When you add components to a visible GUI the code should be:
imageViewerPanel1.add(imagePanel);
//imagePanel.repaint();
imageViewerPanel1.revalidate();
imageViewerPanel1.repaint();
All components are created with a size of (0, 0) so there is nothing to paint. The revalidate() invokes the layout manager which in turn gives a size to the compoenent.
As mentioned above you will also need to override the getPreferredSize() method of you imagePanel so the layout manager can determine the proper size of the panel.
I am trying to resize a picture and save it however the picture I am saving is not resized.
Here is the code I am trying use.
if(CC_Files.fileExists(path)){
if(path.contains(".jpg") || path.contains(".png") || path.contains(".gif") ){
Image image = (Image) SWTResourceManager
.getImage(path);
ImageData imgData = image.getImageData();
imgData.scaledTo(150, 150);
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] {imgData};
imageLoader.save(Variables.getStrResources() + "\\Pics\\" + a.getHerd_id() + ".jpg",SWT.IMAGE_JPEG);
}
}
Your problem is that you do not read the JavaDoc where is wrriten
ImageData#scaledTo(int width, int height) - Returns a copy of the receiver which has been stretched or shrunk to the specified size.
So the solution is:
imgData = imgData.scaledTo(150, 150);
Documentation
Java SWT Image Resize is proper Working
ImageLoader class are used to load images from, and save images to, a file or stream
imageLoader.save(result, SWT.IMAGE_COPY)
FileDialog class allow the user to navigate the file system and select or enter a file name.
Button btnOpen = new Button(parent, SWT.NONE);
btnOpen.setBounds(200, 55, 68, 23);
btnOpen.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
FileDialog dialog = new FileDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT.OPEN);
String result = dialog.open();
if(result!=null)
{
Image image=SWTResourceManager.getImage(result);
//ImageData class are device-independent descriptions of images
ImageData imgData = image.getImageData();
imgData=imgData.scaledTo(200, 200);
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] {imgData};
imageLoader.save(result, SWT.IMAGE_COPY);
System.out.println("Width: "+imgData.width+".....Height: "+imgData.height);
lbl_image_text.setBounds(25,88,imgData.width+10,imgData.height+10);
lbl_image_text.setImage(SWTResourceManager.getImage(result));
}
}
});
btnOpen.setText("open");
CLabel lbl_image_text = new CLabel(parent, SWT.Resize);
Image size set to Label Dynamically
Button btnOpen = new Button(parent, SWT.NONE);
btnOpen.setBounds(200, 55, 68, 23);
btnOpen.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
FileDialog dialog = new FileDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT.OPEN);
String result = dialog.open();
if(result!=null)
{
Image image=SWTResourceManager.getImage(result);
//get Image width and height
lbl_image_text.setBounds(25,88,image.getBounds().width+10,image.getBounds().height+10);
lbl_image_text.setImage(SWTResourceManager.getImage(result));
}
}
});
btnOpen.setText("open");
CLabel lbl_image_text = new CLabel(parent, SWT.Resize);
Call this method from the SWT.addListener(SWT.Close, new CustomShellCloseListener()). Tha parameters required to pass are LabelImage(Do not Use Label.getImage() ,pass the direct path),label.getBounds.width ,label.getBounds.height
protected Image resize(Image imageFromSource, int width, int height) {
if(width>0 && height>0){
Image scaledImage = new Image(shellCCMPFMatrixBomCompare.getDisplay(), width, height);
GC gc = new GC(scaledImage); //Graphics Capabilities(GC instance) in SWT used to draw an Image, graphics, display
gc.setAntialias(SWT.ON); // Anti aliasing is used for making the low resolution image to redraw and make into a good resolution Image
gc.setInterpolation(SWT.HIGH); //Interpolation is based in the Graphics, it may not work properly in some systems
gc.drawImage(imageFromSource, 0, 0,
imageFromSource.getBounds().width, imageFromSource.getBounds().height,
0, 0, width, height);
/*drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight)
Copies a rectangular area from the source image into a (potentially different sized) rectangular area in the receiver.*/
gc.dispose();
return scaledImage;
}
else return imageFromSource;
}