Keep JTable Stationary in JScrollPane When Resizing Columns - java

I have a JTable inside a JScrollPane. The user scrolls to the right. I then enlarge by x pixels a column to the left of where the user is looking. This causes the table to appear to scroll left. How do I adjust the JScrollPane, JScrollBar or JViewport to keep the table stationary? In other words, how do I keep the same visible portion of the table on the screen?
I tried adjusting the horizontal JScrollBar's value by x. I also tried adjusting the JViewport's view position by x. The problem is that the table ends up scrolling to the right.
Here is the code that shows the problem without any of my attempts to keep the table stationary.
package oracle.psr.ndr.guiclient.util.table;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public final class StableColumnResizing extends JFrame
{
private static final long serialVersionUID = 738732002168497075L;
private final TableColumnModel m_model;
private final JScrollBar m_bar;
private int m_colIndex;
public static void main(String args[])
{
SwingUtilities.invokeLater(StableColumnResizing::create);
}
private static void create()
{
StableColumnResizing frame;
Timer timer;
frame = new StableColumnResizing();
frame.setVisible(true);
SwingUtilities.invokeLater(frame::moveRight);
timer = new Timer(1000, frame::adjust);
timer.start();
}
private StableColumnResizing()
{
JScrollPane pane;
JTable table;
Object rowData[][], columnNames[];
columnNames = new Object[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
rowData = new Object[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29}};
table = new JTable(rowData, columnNames);
m_model = table.getColumnModel();
pane = new JScrollPane();
m_bar = pane.getHorizontalScrollBar();
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
pane.setViewportView(table);
add(pane, BorderLayout.CENTER);
setSize(1024, 768);
setLocationByPlatform(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void moveRight()
{
m_bar.setValue(m_bar.getMaximum() / 3);
}
private void adjust(#SuppressWarnings("unused") ActionEvent event)
{
TableColumn column;
int count;
count = m_model.getColumnCount();
if (m_colIndex >= count)
return;
column = m_model.getColumn(m_colIndex);
column.setPreferredWidth(200);
m_colIndex++;
}
}

At the request of others, I created some simple code to show the problem. With that simple code, it became easy to create the solution.
The solution adds a new method getX() and adds more code to adjust(). getX() computes the left-most position of the column before making any column size changes. This value is stored in the local variable x.
The solution also captures the JScrollBar.getValue() before making any column size changes. This value is stored in the local variable value.
After the column size is changed, then compare x < value. This is true if the left-most position of the column is off the left side of the view. If true, then add the difference in column width to value and call JScrollBar.setValue(). Thus, columns off the left side of the view will cause the scroll bar to be shifted enough to keep the visible columns in view. Columns to the right will simply be adjusted.
Becareful of TableColumn.getMaxWidth(). The width of the column will honor this when setting the width of the column. The code to handle getMaxWidth() is below even though it has no impact to the UI since the original post does nothing not call TableColumn.setMaxWidth().
private void adjust(#SuppressWarnings("unused") ActionEvent event)
{
TableColumn column;
int count, old, next, value, x, max;
count = m_model.getColumnCount();
if (m_colIndex >= count)
return;
x = getX(m_colIndex);
value = m_bar.getValue();
column = m_model.getColumn(m_colIndex);
old = column.getPreferredWidth();
max = column.getMaxWidth();
next = 200;
column.setPreferredWidth(next);
m_colIndex++;
if (x < value)
m_bar.setValue(value + Math.min(next, max) - old);
}
private int getX(int colIndex)
{
TableColumn column;
int result;
result = 0;
while (--colIndex >= 0)
{
column = m_model.getColumn(colIndex);
result += column.getPreferredWidth();
}
return(result);
}

Related

Trying to draw a vertical linear gradient using a map of colors, but only the first 9 colors are used: why?

(nota: a Minimal, Complete, and Verifiable example is provided at the end of this question)
Summary
Context, Aim & Problem
What I have already tried
Pertinent sources explained
Expected results, Actual results & Question
Minimal, Complete, and Verifiable example
Context, Aim & Problem
I am trying to animate some pixels to generate a fire animation in Java. Each pixel is colored so that a vertical linear gradient, from white to yellow, yellow to red, and red to black, is drawn. This gradient goes from bottom to top of the canvas.
At the beginning of the execution, all pixels are black, except the white line which is defined by the coordinate y = height - 1, height being the height of the canvas. This white line is used to init the gradient ("white to yellow, yellow to ..., etc.").
The problem is that the gradient begins correctly, but it stops when the 9th color is used. Then only this color is used to fill my gradient and I don't know why.
What I have already tried
I have a map of RGB values which defines a gradient.
The idea to know which color to apply to a pixel called "A" is to retrieve the RGB of the pixel just below it, then get the ID of this RGB among all the RGB of my map. Then, I get the RGB under this ID + 1 in this same map and apply it to the pixel A.
So:
I checked the function that returns the ID of the RGB, given this RGB: it seems to be OK since I don't have thrown any exception
I checked if the buffered image I use is correctly updated. In other words: if the fact that a pixel has been colored really has the consequence to determine the color of the pixel above : it's OK too
Pertinent sources explained
Calling methods to draw the gradient
The idea is to set all pixels in black, except the bottom line which is white. Then, I iterate on each canvas' pixel and give it the color of its below direct vertical neighbor. More precisely, I give it the color whose ID = the ID of this neighbor pixel's color + 1, within my map of colors.
Colors colors = new FireColors(new ArrayList<>());
gui.colorize(colors.getColorAtIndex(34), -1, -1); // Setting black anywhere
gui.colorize(colors.getColorAtIndex(0), -1, height - 1); // Setting white, in a lower line
try {
for(int y = height - 2; y >= 0; y--) {
for(int x = 0; x < width; x++) {
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
How I color pixels
I'm just iterating over the canvas.
void colorize(Color color, int x_parameter, int y_parameter) {
for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
buffered_image.setRGB(x, y, color.getRGB());
}
}
panel.repaint();
}
How do I find the index of the color of a pixel, within the list of colors?
int getIndexOfColor(int rgb) throws Exception {
for (int x = 0; x < colors.size(); x++) {
if(colors.get(x).getRGB() == rgb) {
return x;
}
}
throw new Exception("Color not found in the list!");
}
Expected results, Actual results & Question
I expect to have several vertical gradients (each from bottom to top). "Several" because my canvas' height is greater than the number of the colors of my gradients and because I use a modulo to choose the color to apply.
The actual results are: I get a gradient that begins from white to yellow, there are only 9 colors and that's all. No orange, no red, no black. Indeed: https://imgur.com/oQFJ52k
My question is: since the good ID is retrieved, and the good neighbor chosen for a given pixel, why is my gradient blocked to the 9th color? In other words: why, from a precise moment, aren't the good colors chosen?
Minimal, Complete, and Verifiable example
Launcher.java
import java.util.ArrayList;
public class Launcher {
public static void main(String args[]) {
int width = 150, height = 150;
Gui gui = new Gui(width, height);
gui.setUp("DOOM-like fire");
gui.setVisible(true);
Colors colors = new FireColors(new ArrayList<>());
gui.colorize(colors.getColorAtIndex(34), -1, -1); // Setting black anywhere
gui.colorize(colors.getColorAtIndex(0), -1, height - 1); // Setting white, in a lower line
try {
for(int y = height - 2; y >= 0; y--) {
for(int x = 0; x < width; x++) {
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
gui.colorize(colors.getColorAtIndex(index_of_color_to_apply), x, y);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
Gui.java
import java.awt.*;
import javax.swing.*;
import java.awt.image.BufferedImage;
class Gui extends JFrame {
private JPanel panel;
private BufferedImage buffered_image;
Gui(int width, int height) {
buffered_image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
panel = new JPanel() {
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics.drawImage(buffered_image, 0, 0, null);
}
};
}
void setUp(String title) {
setTitle(title);
setLayout(null);
setSize(buffered_image.getWidth(), buffered_image.getHeight());
setContentPane(panel);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
void colorize(Color color, int x_parameter, int y_parameter) {
for(int y = (y_parameter == -1 ? 0 : y_parameter); y <= (y_parameter == -1 ? this.getHeight() - 1 : y_parameter); y++) {
for(int x = (x_parameter == -1 ? 0 : x_parameter); x <= (x_parameter== -1 ? this.getWidth() - 1 : x_parameter); x++) {
buffered_image.setRGB(x, y, color.getRGB());
}
}
panel.repaint();
}
int getRGBAtCoordinates(int x, int y) {
return buffered_image.getRGB(x, y);
}
}
Colors.java
import java.awt.Color;
import java.util.List;
abstract class Colors {
List<Color> colors;
Color getColorAtIndex(int index) {
return colors.get(index);
}
int getIndexOfColor(int rgb) throws Exception {
for (int x = 0; x < colors.size(); x++) {
if(colors.get(x).getRGB() == rgb) {
return x;
}
}
throw new Exception("Color not found in the list!");
}
int getSize() {
return colors.size();
}
}
FireColors.java
import java.awt.Color;
import java.util.List;
class FireColors extends Colors {
FireColors(List<Color> colors) {
this.colors = colors;
this.colors.add(new Color(255, 255, 255));
this.colors.add(new Color(239, 239, 199));
this.colors.add(new Color(223, 223, 159));
this.colors.add(new Color(207, 207, 111));
this.colors.add(new Color(183, 183, 55));
this.colors.add(new Color(183, 183, 47));
this.colors.add(new Color(183, 175, 47));
this.colors.add(new Color(191, 175, 47));
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 159, 31));
this.colors.add(new Color(191, 159, 31));
this.colors.add(new Color(199, 151, 31));
this.colors.add(new Color(199, 143, 23));
this.colors.add(new Color(199, 135, 23));
this.colors.add(new Color(207, 135, 23));
this.colors.add(new Color(207, 127, 15));
this.colors.add(new Color(207, 119, 15));
this.colors.add(new Color(207, 111, 15));
this.colors.add(new Color(215, 103, 15));
this.colors.add(new Color(215, 95, 7));
this.colors.add(new Color(223, 87, 7));
this.colors.add(new Color(223, 87, 7));
this.colors.add(new Color(223, 79, 7));
this.colors.add(new Color(199, 71, 7));
this.colors.add(new Color(191, 71, 7));
this.colors.add(new Color(175, 63, 7));
this.colors.add(new Color(159, 47, 7));
this.colors.add(new Color(143, 39, 7));
this.colors.add(new Color(119, 31, 7));
this.colors.add(new Color(103, 31, 7));
this.colors.add(new Color(87, 23, 7));
this.colors.add(new Color(71, 15, 7));
this.colors.add(new Color(47, 15, 7));
this.colors.add(new Color(7, 7, 7));
}
}
Your problem is that FireColors contains duplicate colors:
// FireColors, lines 20 and 21:
this.colors.add(new Color(191, 167, 39));
this.colors.add(new Color(191, 167, 39));
// more duplicate colors found later on!
The problem is together with your color selection algorithm:
// Launcher lines 20 to 22:
int below_pixel_rgb = gui.getRGBAtCoordinates(x, y + 1);
int index_of_found_color = colors.getIndexOfColor(below_pixel_rgb);
int index_of_color_to_apply = (index_of_found_color + 1) % colors.getSize();
For the 8th line, it reads the color from the line below it, finds its index (7), adds one and colors that line with the color #8.
For the 9th line, it reads the color from the line below it, finds its index (8), adds one and colors that line with the color #9 (which is the same as color #8)
For the 10th line, it reads the color from the line below it, finds its index (8, because getIndexOfColor() returns the first found index, which is 8, not 9!), adds one and colors that line with the color #9 (which is the same as color #8)
To fix it, you should either redesign your color choosing algorithm or make your FireColor colors unique.

Generate list of int to populate ComboBox in JavaFX

I'm trying to avoid hardcoding a whole bunch of numbers into my JavaFX ComboBox, but I don't know any other way to do it. Currently I'm doing this:
length_comboBox.getItems().addAll(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30);
However my aim is to make a call to a method that will generate a list of numbers to some specified upper limit (say 50). I've tried the following but it just adds one last i, instead of all 50:
length_comboBox.getItems().addAll(generator(50));
public static int generator(int limit) {
int i;
for (i = 1; i < limit; i++)
System.out.println(i);
return i;
}
ComboBox cBox = new ComboBox();
cBox.getItems().addAll(generator());
... example ...
private Integer[] generator() {
int size = (int) (Math.random() * 100);
Integer[] result = new Integer[size];
for (int i = 0; i < result.length; i++) {
result[i] = (int) (Math.random() * 50);
}
return result;
}
You can use the one-liner
IntStream.rangeClosed(1,50).boxed().forEach(length_comboBox.getItems()::add);
or, if you want to fire fewer change events to the combo box (in practice it will make very little difference):
length_comboBox.getItems().setAll(
IntStream.rangeClosed(1,50).boxed().collect(Collectors.toList())
);

Unable to remove JLabel from JPanel

I have a chessboard with 64 JPanels representing each square on the board. The pieces are represented using JLabels which are placed on the JPanels. I am trying to remove all the JLabels off the board. I am confused why this doesn't work:
private void removePieces()
{
for(int i = 0; i < 64; i ++)
{
Component c = chessBoard.getComponent(i);
if(c instanceof JLabel)
{
Container parent = c.getParent();
parent.remove((JLabel)c);
parent.revalidate();
parent.repaint();
}
}
}
chessboard is the big JPanel with the 64 JPanels inside it. After some debugging it looks like the if loop is never being entered. I don't understand why it wouldn't enter the if loop if one of the components is a JLabel?
Looks like your trying to remove your JPanels from your chessboard if they are JLabels (which obviously makes no sense, and is why the if code is never firing). Instead you want to remove the chessBoard's components' JLabel component. Example below.
private void removePieces() {
for(int i = 0; i < 64; i ++) {
if(chessBoard.getComponent(i) instanceof JPanel) {
JPanel c = (JPanel)chessBoard.getComponent(i);
c.removeAll();
c.revalidate();
c.repaint();
}
}
}
I am using removeAll() because I am presuming your JPanels have no other components in them other than the potential JLabels.
Why remove the labels, rather than simply set the icon to null or text to ""?
E.G. using text for the pieces.
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.border.LineBorder;
class ChessBoard2 {
static ChessMoveMouseListener cmml = new ChessMoveMouseListener();
/** Unicode strings for chess pieces & empty string for blank squares. */
static String[][] pieces = {
{"\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659"},
{"\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F"},
{""}
};
static int[] order = new int[]{2, 4, 3, 0, 1, 3, 4, 2};
static int[] pawns = new int[]{5, 5, 5, 5, 5, 5, 5, 5};
static int[] blank = new int[]{0, 0, 0, 0, 0, 0, 0, 0};
static int white = 0;
static int black = 1;
static int space = 2;
public static JLabel getColoredLabel(String string, int color) {
JLabel l = new JLabel(string);
l.setFont(l.getFont().deriveFont(50f));
Color c = (color % 2 == 0 ? Color.WHITE : Color.LIGHT_GRAY);
l.setBackground(c);
l.setOpaque(true);
l.addMouseListener(cmml);
return l;
}
public static void addRowToContainer(
Container c,
int[] order,
int row,
int count) {
for (int ii : order) {
c.add(getColoredLabel(pieces[row][ii], count++));
}
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel chessboard = new JPanel(new GridLayout(0, 8, 1, 1));
chessboard.setBackground(Color.BLACK);
chessboard.setBorder(new LineBorder(Color.BLACK));
int count = 0;
// black pieces..
addRowToContainer(chessboard, order, black, count);
addRowToContainer(chessboard, pawns, black, ++count);
// middle squares..
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
// white pieces..
addRowToContainer(chessboard, pawns, white, ++count);
addRowToContainer(chessboard, order, white, ++count);
JOptionPane.showMessageDialog(null, chessboard,
"Click two squares to move from/to",
JOptionPane.INFORMATION_MESSAGE);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
class ChessMoveMouseListener extends MouseAdapter {
String s = null;
#Override
public void mouseClicked(MouseEvent e) {
JLabel l = (JLabel) e.getSource();
if (s == null) {
if (l.getText().trim().length() > 0) {
s = l.getText();
l.setText("");
}
} else {
l.setText(s);
s = null;
}
}
}
Think, when you're doing:
Component c = chessBoard.getComponent(i);
you're getting one of the JPanels, that contains your JLabels. And of course they are not instances of JLabel.
So you need to get JLabel from that JPanel and then remove it.

Passing parameters from method to main

I can't seem to figure out what my parameters should be for my method "public static int[][] sellSeatByPrice". I need to prompt the user for a price (of a seat), then figure out if that price is taken (if it = 0) and if not, assign it the value 0.
Below is my code, help please!
import java.util.Scanner;
/**
* Write a description of class A10_TheaterSeating here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class A10_TheaterSeating
{
public static void main(String args[])
{
System.out.println("***Welcome to the Ticket Choice App!***");
System.out.println();
int[][] theaterSeats = //set values in seating chart array
{
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
{10, 10, 20, 20, 20, 20, 20, 20, 10, 10},
{10, 10, 20, 20, 20, 20, 20, 20, 10, 10},
{10, 10, 20, 20, 20, 20, 20, 20, 10, 10},
{20, 20, 30, 30, 40, 40, 30, 30, 20, 20},
{20, 30, 30, 40, 50, 50, 40, 30, 30, 20},
{30, 40, 50, 50, 50, 50, 50, 50, 40, 30}
};
int[][] seats = theaterSeats;
printArray(seats); //print the seating chart
System.out.println();
//Defining variables
String str = "";
String input = "";
while (!input.equalsIgnoreCase("Q"))
{
System.out.print("Select 'S' to pick a seat, 'P' choose a price or 'Q' to quit: ");
Scanner in = new Scanner(System.in);
input = in.next();
if (input.equalsIgnoreCase("S"))
{
System.out.print("Enter row and seat number desired: ");
int row = in.nextInt();
int seat = in.nextInt();
System.out.println();
sellSeatByNumber(seats, row, seat);
printArray(seats);
System.out.println();
}
else if (input.equalsIgnoreCase("P"))
{
System.out.print("Enter price of seat desired: ");
int price = in.nextInt();
System.out.println();
sellSeatByPrice(seats, row, seat, price);
printArray(seats);
System.out.println();
}
}
System.out.println();
System.out.println("Thank you for choosing the ticket choice app.");
System.out.println();
}
public static void printArray(int[][] currSeat)
{
final int ROWS = 9;
final int COLUMNS = 10;
for(int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
System.out.print(currSeat[i][j] + "\t");
}
System.out.println();
}
}
public static int[][] sellSeatByNumber(int[][] seats, int row, int seat)
{
if (row <= 0 || row > 9)
{
if (seat <= 0 || seat > 10)
{
System.out.print("Please enter a valid row and seat: ");
}
}
if (seats[row][seat] == 0)
{
System.out.print("That seat is taken. Please select another seat: ");
}
else
{
seats[seats.length - row][seat - 1] = 0;
}
return seats;
}
public static int[][] sellSeatByPrice(int[][] seats, int row, int seat, int price)
{
if (seats[row][seat] = price)
{
seats[seats.length - row][seat - 1] = 0;
}
return seats;
}
}
Your parameters seem fine - the internal logic and syntax is incorrect.
Since you're using static methods, and passing along the seat matrix, that is okay - but you have to check that the values being passed in are inside the bounds of your matrix - or you will get exceptions on them.
For instance, you don't check the bounds in sellSeatByPrice(). You really should do that, or a bogus row/seat combination could blow your program up.
It's also the case that the comparison given is incorrect:
if (seats[row][seat] = price)
should really be
if (seats[row][seat] == price)
as = is assignment, and == is primitive comparison.
Furthermore, in sellSeatByNumber(), you can still run into issues since an out of bounds row/seat combo will still blow up. You do check the bounds - kudos - but you don't return anything if they're outside of those bounds. In all reality, an IllegalArgumentException should be raised if they're stepping out of bounds, or you can return the matrix unmodified (which may be more straightforward).

TableColumn setPreferredWidth not working

I have a JTable with a number of columns. I want a particular column to resize. What I was hoping was by using setPreferredWidth, the column would resize to that size, or the size of the contents such that no truncation occurred and let the rest of the columns take the remaining space, but instead, all of the columns, including the one I resized, equally split all of the space of the table; as if setPreferredWidth did nothing at all. In effect, I want to be able to set the width of a column and have it shrink to that size without truncating content (have I stressed that too much yet?) in such a way that all columns that have not been resized fill the remaining space. Using setMaxWidth truncates content (did I mention I didn't like that?) How do I resize/shrink a column without it truncating and without it doing absolutely nothing? Here is the offending code:
for (int i = 0, x = 0; i < table.getColumnModel().getColumnCount(); i++)
if ((x = model.getColumnWidth(i)) > -1)
table.getColumnModel().getColumn(i).setPreferredWidth(x);
The table is in a JPanel (MyListPanel - BorderLayout) which is in another JPanel (GridBagLayout) added with:
new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(2, 0, 0, 2), 0, 0))
EDIT: This is the constructor for my subclass of JPanel:
public MyListPanel(boolean showHeader, String title, ColData...columns) {
super(new BorderLayout());
model = new MyListTableModel(columns);
table = new JTable(model);
table.addFocusListener(this);
add(table);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
setTitle(title);
if (showHeader)
add(table.getTableHeader(), BorderLayout.NORTH);
for (int i = 0, x = 0; i < table.getColumnModel().getColumnCount(); i++)
if ((x = model.getColumnWidth(i)) > -1)
table.getColumnModel().getColumn(i).setPreferredWidth(x);
setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
}
And MyListTableModel.ColData:
public static class ColData {
private int index;
private String title;
private int width;
public ColData(int _index, String _title, int _width) { index = _index; title = _title; width = _width; }
}
Include :
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
I had a similar problem despite trying the two other answers here. In my case, some times the width would get set correctly while other times, it would not. I found the problem was caused because I was trying to set the column widths immediately after changing my table model. I found setting the column widths inside of SwingUtilities.invokeLater() did the trick. I.E.
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
int width = 100;
for (int column = 1; column < table.getColumnCount(); column++) {
columnModel.getColumn(column).setPreferredWidth(width);
}
}
}
I know this is a bit late so is mostly for future readers, but I had the same problem and solved it by setting both the column's preferred width and maximum width to the same value.
I had the same issue and reading #Jay Askren answer, the opposite worked for me. I had to set the width in the method where the table was being created.
public class Example{
//..stuff
private JTable myTable;
public Example{
//..stuff
myTable = AnotherClass.getTable();
myTable .getColumnModel().getColumn(0).setPreferredWidth(100);//not here
}
}
public class AnotherClass{
public static JTable getTable(){
JTable table= new JTable();
table.setModel(anyModel);
table.getColumnModel().getColumn(0).setPreferredWidth(100);//Here!
return table
}
}
Set all three of setMinWidth, setMaxWidth and setPreferredWidth, where minimum_width <= preferred_width <= maximum_width.
int[] minColSizes = { 15, 55, 75, 50, 50, 50 };
int[] preferredColSizes = { 25, 75, 125, 100, 100, 100 };
int[] maxSizes = { 50, 100, 200, 200, 200, 200 };
for ( int index = 0; index < preferredColSizes.length; index++ )
{
myTable.getColumnModel().getColumn(index).setMinWidth ( minColSizes[index] );
myTable.getColumnModel().getColumn(index).setMaxWidth ( preferredColSizes[index] + 100 );
myTable.getColumnModel().getColumn(index).setPreferredWidth ( maxSizes[index] );
}

Categories

Resources