Images in JTable cells off by one pixel?
Asked Answered
U

1

2

So, I'm able to load images into my JTable's cells now, but for some reason the graphics are all shifted to the right by one pixel, allowing me to see the JTable's background. Any ideas? Sorry if my formatting's off; still not entirely used to this markup.

public static void main(String[] args) {  

  final int rows = 16;  
  final int columns = 16;  
  final int dimTile = 32;

  JFrame frame = new JFrame("test");  
  JTable table = new JTable(rows, columns);  
  table.setIntercellSpacing(new Dimension(0, 0));  
  table.setShowGrid(false);
  table.setBackground(Color.cyan);  
  table.setTableHeader(null);  
  table.setRowHeight(dimTile);  
  table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);  
  table.setPreferredSize(new Dimension(rows * dimTile, columns * dimTile));  

  Tile tile = new Tile(0);  
  for(int i = 0; i < rows; i++) {  
     for(int j = 0; j < columns; j++) {  
        table.getColumnModel().getColumn(j).setCellRenderer(new MyRenderer());  
        table.setValueAy(tile, i, j);  
     }  
  }  

  JScrollPane scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);  
scrollPane.setBorder(BorderFactory.createEmptyBorder());  

  frame.getContentPane().add(scrollPane);  
  frame.setSize(512, 512);  
  frame.setVisible(true);  
  int adjustedSizeX = frame.getInsets().left + frame.getInsets().right + 512;  
  int adjustedSizeY = frame.getInsets().top + frame.getInsets().bottom + 512;  
  frame.setSize(adjustedSizeX, adjustedSizeY);  
  frame.pack();  

  ...  
}  


public class MyRenderer extends DefaultTableCellRenderer {  
  @Override  
  public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {  
     super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);  

      Tile tile = (Tile) value;  
      setIcon(tile.getIcon());  
      return this;  
   }  
}  


public class Tile {  
  ImageIcon icon;  

  public Tile(int graphic) {  
     icon = new ImageIcon(PATH/TO/"...test.png");  
  }  

  public ImageIcon getIcon() {  
     return icon;  
  }  
}  
Uranus answered 16/8, 2011 at 6:48 Comment(2)
Can not reproduce the problem by the code you have posted. Post some code which can reproduce your problem without any dependency.Unwise
This code, exactly as is and without anything else from my project, creates the problem. I created a new project using only this code (and sticking the main method in a Test class) to try it out. There is a visible one pixel gap between images, as the image in each cell has been shifted one pixel to the right (cutting off the rightmost pixel of the image). Change the table's background color to whatever stands out the best, in your opinion. I went with cyan, but whatever works.Uranus
P
2

Not entirely sure what you mean by "one pixel off" - but achieve zero intercell spacing without any visual artefacts you have to both zero the margins and turn off the grid lines:

table.setIntercellSpacing(new Dimension(0, 0)); 
table.setShowGrid(false)

Edit

Okay, looking closer, there are several issues with your code

  • you do the column sizing indirectly instead of directly (and yet another nice example why to never-ever do a component.setPreferredSize :-)
  • the renderer's border takes some size

to fix the first, configure each column's width, table layout will automagically configure its itself

    final int rows = 16;
    final int columns = 16;
    Tile tile = new Tile(0);
    int tileHeight = tile.getIcon().getIconHeight();
    int tileWidth = tile.getIcon().getIconWidth();

    JTable table = new JTable(rows, columns);
    // remove all margin
    table.setIntercellSpacing(new Dimension(0, 0));
    table.setShowGrid(false);
    table.setTableHeader(null);
    // set the rowHeight
    table.setRowHeight(tileHeight);
    // turn off auto-resize
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    // configure each column with renderer and prefWidth
    for (int j = 0; j < columns; j++) {
        TableColumn column = table.getColumnModel().getColumn(j);
        column.setCellRenderer(new MyRenderer());
        column.setPreferredWidth(tileWidth);
    }

for the second, null the border in each call:

public static class MyRenderer extends DefaultTableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table,
            Object value, boolean isSelected, boolean hasFocus, int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected,
                hasFocus, row, column);
        setBorder(null);
        Tile tile = (Tile) value;
        setIcon(tile.getIcon());
        return this;
    }
}
Puffin answered 16/8, 2011 at 10:37 Comment(2)
Sorry, somehow missed the table.setShowGrid(false) line when I was copying over. Edited to include it.Uranus
Awesome, thanks! This did exactly what I needed. Also, thanks for the heads-up about setPreferredSize(); nobody's ever told me this before, but a quick look at jGuru gave me decent overview of why it's a bad idea.Uranus

© 2022 - 2024 — McMap. All rights reserved.