unable to set column width after jtable becomes visible
Asked Answered
G

1

5

I've read Oracle's API hundreds of times, read countless articles, both here and elsewhere, and i still cannot resize columns after the jtable becomes visible.

As you can deduce, i'm also trying to set the visibilty of the columns using jcheckboxes. Using addColumn and removeColumn, as other articles have noted, does not return columns to their original positions. I've previously used an additional class to hold column information eg the column itself, its identifier and original index. This became messy as well the problem of adding/removing data after a column's visibility has been changed. I noticed the data was not in its correct column. As a result, ive opted for setting the column's minWidth, preferredWidth and maxWidth.

Now to my problem, the below code does not adjust the column's width when setColumnVisible is set to true. In the words of julius summner miller, why is it so?

import java.awt.*;
import java.awt.event.*;

import java.util.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;

class run
{
    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                Viewer viewer = new Viewer();

                JFrame jframe = new JFrame();
                jframe.add(viewer);
                jframe.createBufferStrategy(1); // required for dual monitor issues
                jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                jframe.setLocation(50,100);
                jframe.pack();
                jframe.setVisible(true);
            }
        });
    }
}

class Viewer extends JPanel
{
    static final long serialVersionUID = 0;

    DefaultTableModel defaultTableModel;
    JTable jtable;
    JCheckBox jcheckBox[];

    public Viewer()
    {
        this.setLayout(new BorderLayout());

        JPanel jpanel = new JPanel(new BorderLayout());

        String columnNames[] = {"a","b","c","d","e"};

        Object tableData[][] = 
        {
            {"a1","b1","c1","d1","e1"},
            {"a2","b2","c2","d2","e2"},
            {"a3","b3","c3","d3","e3"}
        };

        defaultTableModel = new DefaultTableModel(tableData,columnNames);

        jtable = new JTable(defaultTableModel);

        JScrollPane jscrollPane = new JScrollPane(jtable);

        jpanel.add(jscrollPane,BorderLayout.CENTER);

        TableColumnModel tableColumnModel = jtable.getColumnModel();

        int columnCount = tableColumnModel.getColumnCount();

        jcheckBox = new JCheckBox[columnCount];

        JPanel visibility = new JPanel(new GridLayout(1,columnCount));

        for (int column = 0; column < columnCount; column++)
        {
            TableColumn tableColumn = tableColumnModel.getColumn(column);

            String identifier = (String)tableColumn.getIdentifier();

            jcheckBox[column] = new JCheckBox(identifier,true);
            jcheckBox[column].setName(identifier);
            jcheckBox[column].addActionListener(new ColumnListener());

            visibility.add(jcheckBox[column]);
        }

        jpanel.add(visibility,BorderLayout.SOUTH);

        this.add(jpanel,BorderLayout.CENTER);
    }

    public void setColumnVisible(String identifier, boolean setVisible)
    {
        TableColumn tableColumn = jtable.getColumn(identifier);

        int minWidth = 0;
        int preferredWidth = 0;
        int maxWidth = 0;

        if (setVisible)
        {
            minWidth = 100;
            preferredWidth = 100;
            maxWidth = 100;
        }

        tableColumn.setMinWidth(minWidth);
        tableColumn.setPreferredWidth(preferredWidth);
        tableColumn.setMaxWidth(maxWidth);

        //jtable.doLayout(); does not work
        //jtable.validate(); does not work
        //jtable.getTableHeader().resizeAndRepaint(); does not work
    }

    class ColumnListener implements ActionListener
    {
        public void actionPerformed(ActionEvent actionEvent)
        {
            JCheckBox checkBox = (JCheckBox)actionEvent.getSource();

            boolean setVisible = checkBox.isSelected();

            String identifier = checkBox.getName();

            setColumnVisible(identifier,setVisible);
        }
    }
}



Addendum doLayout(), validate() resizeAndRepaint() does not work, nor does setting setAutoResizeMode to off.

Note: As some of you mayve found out, resizing does in fact work AFTER all the columns are hidden. However, it still doesnt answer my question as to why column sizes are not adjusted when invoking setMin, setPreferred and setMax.

Note: Im writing a font viewer that can display multiple font famlies, styles and sizes simultaneously. I have a jtable that display installed fonts (column1 displays the font family, column2 displays the alphabet in coresponding font and column3 displays digits(0-9) in the corresponding font.

The example code ive provided will be used to display the aboveforementioned, giving the user the option of hiding either the alphabet or digits.

I also have 6 jlist's, 3 of which contain available font families, styles and sizes, and the other 3 contain user selections. I use another jtable to display user selections (column1 selected font family, column2 font style, column3 font size, column4 alphabet, column5 digits, column6 punctuation and column7 symbols.

The user will be allowed to select which columns are visible. As ive mentioned though, when the display table is updated, the data is not where its supposed to be. ie the user chooses to hide columns, digits and symbols and then selects a new fonts, styles and size to be displayed.

Globetrotter answered 21/9, 2014 at 0:57 Comment(12)
@AndrewThompson, i wouldve, but i didnt want people asking "where are you triggering visibility?" or "how are you trigger visibility"? i dont think the code is excessive.Globetrotter
@AndrewThompson, i dont want to get into a pedantic war, if you dont want to answer, please refrain from commenting.Globetrotter
On a site that gives free advice, both good and bad, you can't control directly what folks post in comments or answers, nor should you. About all any of us can or should do is to be thankful that some folks have taken the time and effort to consider our problem, up-vote good advice, down-vote bad advice, ignore comments that we don't really care about, and report abusive posts. In fact, feel free to ignore these suggestions if you'd like.Pervious
And for the record, I agree with @Andrew. I can't run your posted code without first creating an MCVE myself, but you're the one asking for help, so shouldn't the responsibility for creating this be on your shoulders? Hopefully you'll get help soon with or without the MCVE, but with it, you'll likely get help sooner, so up to you.Pervious
@HovercraftFullOfEels, i can see this is going to get ugly for no reason. firstly, i have no idea what MCVE means other than interpreting it verbatim, minimal complete verifiable example. am i supposed to take that to mean posting setMinWidth, setPreferredWidth and setMaxWidth?Globetrotter
No need for things to get ugly, rather just to take things one step at a time. The meaning of MCVE can be found in the link @Andrew provided in his first comment, or that I also provide here. Please read it over, since even if it doesn't help you with this question it is bound to help in future questions. The process of isolating your error to its smallest functional state is a useful debugging tool, not just for posting code here, but for helping you debug your own programs, because it exposes the bug.Pervious
You really shouldn't be setting the width to zero to hide a column. When the user uses the keyboard to tab from cell to cell the hidden column will still accept focus although the user has no indication that the column has focus. Instead you should be removing the TableColumn from the TableColumnModel. Maybe you can use the Table Column Manager instead.Topmast
@camickr, as i have pointed out, removing the table column not only adds complexity (not that that is my concern in this case), i want to know why my columns are not being resized after explicity setting min, preferred and max.Globetrotter
At this point perhaps functionality trumps perceived issues with complexity. But thanks for providing your MCVE. 1+ up-vote for that.Pervious
@HovercraftFullOfEels, ive used addColumn and removeColumn, but as you know, positions are not kept. This isnt a problem. The problem is when ive hidden a column and add data to the table, the data isnt in its correct column. It may help if it inform readers what the app is supposed to do.Globetrotter
For example.Emery
@trashgod, i already wrote working program using this technique. try adding and removing data from the table and let me know what happens ;-) i actually removed all the columns from the table's column model stored them in a hashmap<String,ColumnAttributes> where column attributes contained the tablecolumn, identifier and original index. after i stored the updates, i then add them back into the column model.Globetrotter
T
8

as i have pointed out, removing the table column not only adds complexity

I agree, and I gave you working code that manages this complexity. I see you didn't try the code even though it can be added to your program with a single line of code.

try adding and removing data from the table

That is not an issue. All a TableColumn does is map the data from the TableModel to the TableColumn. When you create a TableColumn, it is created with a default column value of 0. So yes, unless you manage this properly you will have a problem, which is why I gave you a link to working code.

my question as to why column sizes are not adjusted when invoking setMin, setPreferred and setMax.

The answer is that order of code execution is important. That is the preferred size must be in range of the min/max sizes, so you need to set the preferred size last:

    tableColumn.setMinWidth(minWidth);
    tableColumn.setMaxWidth(maxWidth);
    tableColumn.setPreferredWidth(preferredWidth);

Edit:

Simple example. You can call it an MCVE or a SSCCE.

import java.awt.*;
import javax.swing.table.*;

public class Main
{
    public static void main(String[] args)
    {
        TableColumn tc = new TableColumn();
        tc.setMinWidth(1);
        tc.setMaxWidth(10);
        tc.setPreferredWidth(15);
        System.out.println( tc.getPreferredWidth() );
    }
}

If this does not verify that the API is working correctly, then I don't know what will.

Topmast answered 21/9, 2014 at 2:44 Comment(10)
omg, lolololo........as simple as that. Is that mentioned anywhere in the API (ie order precendence)? i saw you code, and without trying to offend you, setXXXwidth is far simpler. the columns wont be adjustable, nor will they be tabbable. but thank you for clearing up something thats been driving me nuts for days.Globetrotter
@Globetrotter Is that mentioned anywhere in the API - yes, read the setPreferredWidth() API method. the columns wont be adjustable, nor will they be tabbable - that does simplify this requirement, but you never now what the future holds :)Topmast
it doesnt mention order of invocation precendence, all it says is "If preferredWidth exceeds the minimum or maximum width, it is adjusted to the appropriate limiting value.". one would resaonably assume that order of invocation was irrelevant.Globetrotter
@johnny, seriously, you can't imply that order is important from that description? if the max value is 0 at the time you set the preferred width, then you can't set it to 100 because it will be reset back to 0. So it implies you must set the max value before you set the preferred value. So one would reasonably assume order is important because editing is done at the time you attempt to change the preferred width. If that description was for the "getPreferredWidth" then I would agree with you because then you could store all 3 values and return the appropriate preferred value.Topmast
nope, if a have a class, lets call it Width and it has a three variables min, value, and max and if set max first, value second and finally min last, and if min is less than max and value is > min and less than max, value is value, does it matter when i call the method as to what the values are? what the above implies is, irrespective of the values you set, the order in which you invoke them takes precendce over what the values actually are which is ridiculous.Globetrotter
@johnny, I would not like to maintain your code. You don't understand the basic concept of min/max as range bounds. You can't set the value unless you know the range bounds. There are other examples in the JDK, for example a scrollbar. Once again you can't set the scrollbar to a value greater than the maximum value. It just does not make sense and the code prevents it. Or how about a JSpinner. Again the value must always be in the range of the spinner. I've done my best to explain a basic concept and am not about to spend any more time on the topic.Topmast
"If preferredWidth exceeds the minimum or maximum width, it is adjusted to the appropriate limiting value." which i take to mean, the lower value. eg min 1, max 10, value 15, will be adjusted to 1. i did not exceed either (min=100, max=100, preferred=100). would it make a difference if i set min to 100, max to 500 and preferred to 200? of course not. the order in which i set them will, which does not make sense. irrespective of when i set them, min will be 100, max will be 500 and preferred will be 200. i adhere to the api and yet its not respected.Globetrotter
Let us continue this discussion in chat.Globetrotter
@johnny, i adhere to the api - you are not adhering to the API. At the time you attempt to set the preferred size to 100, the max value was 0, so the preferred is set to 0. which i take to mean, the lower value eg min 1, max 10, value 15 Why would you think that? The appropriate limiting value is 10. Don't assume!!! This is extremely easy to test. See my edit that shows the 5 lines of code needed to demonstrate this.Topmast
@johnny, I think I see that your problem is with the word exceeds. You are interpreting this to mean "greater", which is not accurate. It means if the value exceeds the boundaries of the min/max range. When the value is less than the minimum it is set to the minimum. When the value is greater than the maximum it is set to the maximum.Topmast

© 2022 - 2024 — McMap. All rights reserved.