Community
Participate
Working Groups
When you resize a table view (e.g. the CVS Resource History View), the columns aren't resized proportionally; only the visibility of the columns is affected. This is a problem in particular when the view opens as a fast view and the columns are all squished together, like what happens with the CVS Resource History View. Having to then manually stretch out the view and every column is annoying for people. A more complex solution would be to be able to specific a suggested initial size for a view, and the fast view would attempt to honour that width. I believe Nick discussed this with me once. However, the simpler answer for now might be that resize of the view could grow the columns proportionally. I assume all table views would appreciate this behaviour, as its generally unlikely that they would prefer the clipping that occurs now?
I agree this is the desired behaviour. However, if you try to adjust the width of TableColumns dynamically in response to Table resize events, you currently get major flicker, scrollbars flash on and off while resizing, and occasionally stick around after when not needed. This is why we never went this route for the Tasks view. Need SWT support for this. Workbench will be adding support to let you specify the preferred width of a fast view (as a fraction), which will reduce the impact of this problem. Moving to SWT for future table work.
What is the state of table resizing? I thought we fixed some of the problems already.
Because the scrollbars pop up before the resize callback is sent and the columns are resized based on the client area which does not include the scrollbars, there is flashing. Effectively the columns are resized so that the horizontal scrollbar is no longer required and then another callback is issued because the client area grows when the scrollbars disappear. Steve gave Nick a hack - see http://dev.eclipse.org/bugs/show_bug.cgi?id=4505 - which mostly fixed the problem but was untested on motif and still had one condition where a single flash occurs. Should we pick this up again and try to verify the hack?
Kevin? Nick?
It would be interesting, but not essential, for M6 to see if we can make this work. I would appreciate it if the SWT team could come up with an example that works on all platforms.
The following example shows a platform independant way to get the desired result. This example makes the first column use 1/3 of the space and the second column uses the rest but it could easily be modified to support many more columns with some weighting strategy. import org.eclipse.swt.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; public class TableResizing { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new GridLayout()); Button b = new Button(shell, SWT.PUSH); b.setText("Button"); final Composite comp = new Composite(shell, SWT.NONE); comp.setLayoutData(new GridData(GridData.FILL_BOTH)); final Table table = new Table(comp, SWT.BORDER | SWT.V_SCROLL); table.setHeaderVisible(true); table.setLinesVisible(true); final TableColumn column1 = new TableColumn(table, SWT.NONE); column1.setText("Column 1"); final TableColumn column2 = new TableColumn(table, SWT.NONE); column2.setText("Column 2"); for (int i = 0; i < 10; i++) { TableItem item = new TableItem(table, SWT.NONE); item.setText(new String[] {"item 0" + i, "item 1"+i}); } comp.addControlListener(new ControlAdapter() { public void controlResized(ControlEvent e) { Rectangle area = comp.getClientArea(); Point preferredSize = table.computeSize (SWT.DEFAULT, SWT.DEFAULT); int width = area.width - 2*table.getBorderWidth (); if (preferredSize.y > area.height) { // Subtract the scrollbar width from the total column width // if a vertical scrollbar will be required Point vBarSize = table.getVerticalBar ().getSize(); width -= vBarSize.x; } Point oldSize = table.getSize(); if (oldSize.x > area.width) { // table is getting smaller so make the columns // smaller first and then resize the table to // match the client area width column1.setWidth(width/3); column2.setWidth(width - column1.getWidth()); table.setSize(area.width, area.height); } else { // table is getting bigger so make the table // bigger first and then make the columns wider // to match the client area width table.setSize(area.width, area.height); column1.setWidth(width/3); column2.setWidth(width - column1.getWidth()); } } }); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }
Nice. It looks great. Another important aspect of this approach is that resizing the columns should not make the scrollbars disappear. A good approach is to resize the column to the left of the sash (but none further left), and shrink all the columns to the right of the sash proportionally. I had a lot of trouble trying to get this to work previously for many of the same reasons as the basic resizing: the OS would add the scrollbars before I had the chance to adjust the other columns so they wouldn't be necessary. Could a similar approach be used to do this?
*** Bug 4518 has been marked as a duplicate of this bug. ***
*** Bug 4505 has been marked as a duplicate of this bug. ***
*** Bug 2593 has been marked as a duplicate of this bug. ***
Nick, I am sending this back to you since I think we have provided an acceptable work around. It is up to you guys if you want to use it.
As mentioned above, resizing the columns is an important aspect of this. Can this be done without flicker as well?
Column resizing works as it always did. You need to manage the semantics of what this means under the impact of table resizing yourself.
The problem is that when resizing the control smaller, scrollbars appear before I have the chance to respond to the resize callback on the table. I suppose that if I do the same as above and resize the columns before resizing the table, I can avoid this. I will have to try. Please let me know whether you think this should work.
If you look carefully at the example you will see that it handles the growing smaller case by doing exactly what you suggest.
I have implemented a new ControlAdapter based on the code provided by Veronika and I have tried it out with a sample properties page that I whipped up. I would suggest that we add this adapter to org.eclipse.ui and deprecate the TableLayout so as to encourage people to move to it. I will release it once approved. Here is the suggested code: package org.eclipse.ui.propertiespagetest.properties; import java.util.ArrayList; import org.eclipse.jface.util.Assert; import org.eclipse.jface.viewers.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.*; /** * The TableResizeAdapter is a ControlAdapter used to set the size of * a table. It is defined on a Composite which is the parent of a table. * The Composites only child is the table. */ public class TableResizeAdapter extends ControlAdapter { private Table table; /** * Create a new instance of the receiver with the table to create * specified */ public TableResizeAdapter(Table tableChild) { table = tableChild; } /** * The list of column layout data (element type: * <code>ColumnLayoutData</code>). */ private ArrayList columns = new ArrayList(); /** * Adds a new column of data. * * @param data the column layout data */ public void addColumnData(ColumnLayoutData data) { columns.add(data); } /** * Sent when the size (width, height) of a control changes. * The default behavior is to do nothing. * * @param e an event containing information about the resize */ public void controlResized(ControlEvent e) { Rectangle area = table.getParent().getClientArea(); int width = area.width - 2 * table.getBorderWidth(); // XXX: Layout is being called with an invalid value the first time // it is being called on Linux. This method resets the // Layout to null so we make sure we run it only when // the value is OK. if (width <= 1) return; TableColumn[] tableColumns = table.getColumns(); int size = Math.min(columns.size(), tableColumns.length); int[] widths = new int[size]; int fixedWidth = 0; int numberOfWeightColumns = 0; int totalWeight = 0; // First calc space occupied by fixed columns for (int i = 0; i < size; i++) { ColumnLayoutData col = (ColumnLayoutData) columns.get (i); if (col instanceof ColumnPixelData) { int pixels = ((ColumnPixelData) col).width; widths[i] = pixels; fixedWidth += pixels; } else if (col instanceof ColumnWeightData) { ColumnWeightData cw = (ColumnWeightData) col; numberOfWeightColumns++; // first time, use the weight specified by the column data, otherwise use the actual width as the weight // int weight = firstTime ? cw.weight : tableColumns[i].getWidth(); int weight = cw.weight; totalWeight += weight; } else { Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$ } } // Do we have columns that have a weight if (numberOfWeightColumns > 0) { // Now distribute the rest to the columns with weight. int rest = width - fixedWidth; int totalDistributed = 0; for (int i = 0; i < size; ++i) { ColumnLayoutData col = (ColumnLayoutData) columns.get(i); if (col instanceof ColumnWeightData) { ColumnWeightData cw = (ColumnWeightData) col; // calculate weight as above // int weight = firstTime ? cw.weight : tableColumns[i].getWidth(); int weight = cw.weight; int pixels = totalWeight == 0 ? 0 : weight * rest / totalWeight; if (pixels < cw.minimumWidth) pixels = cw.minimumWidth; totalDistributed += pixels; widths[i] = pixels; } } // Distribute any remaining pixels to columns with weight. int diff = rest - totalDistributed; for (int i = 0; diff > 0; ++i) { if (i == size) i = 0; ColumnLayoutData col = (ColumnLayoutData) columns.get(i); if (col instanceof ColumnWeightData) { ++widths[i]; --diff; } } } for (int i = 0; i < size; i++) { tableColumns[i].setWidth(widths[i]); } } } I implemented it for the following properties page: package org.eclipse.ui.propertiespagetest.properties; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TableLayout; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.*; import org.eclipse.ui.dialogs.PropertyPage; public class SamplePropertyPage extends PropertyPage { /** * Constructor for SamplePropertyPage. */ public SamplePropertyPage() { super(); } private void addFirstSection(Composite parent) { Composite enclosingComposite = new Composite(parent, SWT.NONE); enclosingComposite.setLayoutData(new GridData (GridData.FILL_BOTH)); GridLayout layout = new GridLayout(); layout.marginWidth = 0; layout.marginHeight = 0; enclosingComposite.setLayout(layout); Table table = new Table(enclosingComposite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION); table.setHeaderVisible(true); table.setLinesVisible(true); GridData data = new GridData(GridData.FILL_BOTH); table.setLayoutData(data); table.setHeaderVisible(true); TableColumn column = new TableColumn(table, SWT.NULL); column.setText("Column 1"); column = new TableColumn(table, SWT.NULL); column.setText("Column 2"); TableResizeAdapter adapter = new TableResizeAdapter(table); adapter.addColumnData(new ColumnWeightData(50, 100, true)); adapter.addColumnData(new ColumnWeightData(50, 100, true)); enclosingComposite.addControlListener(adapter); } /** * @see PreferencePage#createContents(Composite) */ protected Control createContents(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); composite.setLayout(layout); GridData data = new GridData(GridData.FILL); data.grabExcessHorizontalSpace = true; composite.setLayoutData(data); addFirstSection(composite); return composite; } private Composite createDefaultComposite(Composite parent) { Composite composite = new Composite(parent, SWT.NULL); GridLayout layout = new GridLayout(); layout.numColumns = 2; composite.setLayout(layout); GridData data = new GridData(); data.verticalAlignment = GridData.FILL; data.horizontalAlignment = GridData.FILL; composite.setLayoutData(data); return composite; } public boolean performOk() { return true; } }
I don't believe TableResizeAdapter fixes the scrollbar flash problem. In "private void addFirstSection(Composite parent)" you set a layout on the enclosingComposite as well as adding the control listener. You should only add the control listener and in the control listener set the size of the table - note that it is important where you set the table size - before or after setting the column widths, depending on whether the size is increasing or decreasing because otherwise you will get scrollbars flashing. Having two mechanisms for managing the size/location of the table is slow and will cause scrollbars to flash. The layout code always runs before the control resize callback and therefore can not be used to fix this problem. enclosingComposite.setLayout(layout); ... enclosingComposite.addControlListener(adapter);
There are currently no plans to work on this feature
(In reply to comment #18) > There are currently no plans to work on this feature > Maybe a stupid question but wouldn't it be enough to replace last lines where you set the ColumnWidths using: -----------------8<----------------- Point oldSize = table.getSize(); if (!(oldSize.x > area.width)) { table.setSize(area.width, area.height); } table.setRedraw(false); for (int i = 0; i < size; i++) { tableColumns[i].setWidth(widths[i]); } table.setRedraw(true); if (oldSize.x > area.width) { table.setSize(area.width, area.height); } -----------------8<----------------- At least in my test case this removes the scrollbars flashing but I must admit that I haven't thought about the whole thing in detail.
The question for me is do you want them to grow proportionally or do you really just want to see on entry better? My usual situation is that I resize the description field to take up the white space at the end of the table. The other entries are fine for me.
(In reply to comment #20) > The question for me is do you want them to grow proportionally or do you really > just want to see on entry better? > > My usual situation is that I resize the description field to take up the white > space at the end of the table. The other entries are fine for me. > What I'm referring is the AdapterClass which could with my patch used to address bug #93611 or am I missunterstanding something. The thing you are referring to is that we should should add a possiblity to mark a column as the one occuping leaving space.
Oh. And what I just forgot to mention is that Veronika's example has one small problem, that when you resize the table slowly vertically the space needed for the scrollbars is removed some pixels before the scrollbar are really made visible.
As of now 'LATER' and 'REMIND' resolutions are no longer supported. Please reopen this bug if it is still valid for you.