| Summary: | SWT Combo text alignment on resize wrong | ||
|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Balazs <b.lichtl> |
| Component: | SWT | Assignee: | Platform-SWT-Inbox <platform-swt-inbox> |
| Status: | CLOSED WONTFIX | QA Contact: | |
| Severity: | minor | ||
| Priority: | P3 | CC: | hirdhird, rheydenr, r_pattanaik |
| Version: | 3.7 | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows XP | ||
| Whiteboard: | stalebug | ||
I ran into this bug with SWT CCombo - exactly the same problem. The workaround from Balazs does not work, so I wrote my own. It could probably be done more efficiently, nevertheless following code works for resizing the column as well as for selecting longer item:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
GridLayout layout = new GridLayout();
shell.setLayout(layout);
Table table = new Table(shell, SWT.BORDER);
table.setLayout(new FillLayout());
table.setHeaderVisible(true);
TableColumn column = new TableColumn(table, SWT.NONE);
column.setWidth(150);
TableItem item = new TableItem(table, SWT.NONE);
TableEditor editor = new TableEditor(table);
final CCombo combo = new CCombo(table, SWT.DROP_DOWN | SWT.BORDER);
GridData data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
combo.setLayoutData(data);
String itemString = "BbbCDEFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaCc";
String itemString2 = "hello";
combo.add(itemString);
combo.add(itemString2);
combo.select(1);
combo.setData("selectionIndex", combo.getSelectionIndex());
combo.setEditable(false);
editor.grabHorizontal = true;
editor.setEditor(combo, item, 0);
combo.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(final Event e) {
//We need the original text, not the displayed substring which would return methods such as combo.getText() or combo.getItem(combo.getSelectionIndex())
combo.setData("selectionIndex", combo.getSelectionIndex());
String text = combo.getItem(combo.getSelectionIndex());
GC gc = new GC(combo);
//Exact dimensions of selected text
int textWidth = gc.stringExtent(text).x;
//reset text limit
combo.setTextLimit(text.length());
//In case the text is wider then the area on which it's displayed, we need to set a textLimit
//because part of the CCombo client area is occupied by a dropdown menu arrow, we use a magic constant
//(Unfortunately I don't know how to find out the exact width of the combo area on which the text is displayed)
int magicConst = 14;
int comboWidth = combo.getClientArea().width - magicConst;
if (textWidth > comboWidth) {
//find text limit - first we set it according to average char width of our text
int averageCharWidth = textWidth / text.length();
int tempLimit = comboWidth / averageCharWidth;
//then we fine-tune the limit - it must be as precise as possible
while (tempLimit > 0 && (comboWidth < gc.stringExtent(text.substring(0, tempLimit + 1)).x)) {
tempLimit--;
}
//textLimit must not be zero
if (tempLimit == 0) {
tempLimit++;
}
combo.setTextLimit(tempLimit);
}
combo.setText(text);
gc.dispose();
}
});
combo.addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(final Event e) {
//We need the original text, not the displayed substring which would return methods such as combo.getText() or combo.getItem(combo.getSelectionIndex())
String text = combo.getItem((int) combo.getData("selectionIndex"));
//reset text limit
combo.setTextLimit(text.length());
GC gc = new GC(combo);
//exact dimensions of selected text
int textWidth = gc.stringExtent(text).x;
int magicConst = 14;
int comboWidth = combo.getClientArea().width - magicConst;
//In case the text is wider then the area on which it's displayed, we need to set a textLimit
if (textWidth > comboWidth) {
//find text limit - first we set it according to average char width of our text
int averageCharWidth = textWidth / text.length();
int tempLimit = comboWidth / averageCharWidth;
//sometimes on resize it can happen that computed tempLimit is greater than text length
if (tempLimit >= text.length()) {
tempLimit = text.length() - 1;
}
//then we fine-tune the limit - it must be as precise as possible
while (tempLimit > 0 && (comboWidth < gc.stringExtent(text.substring(0, tempLimit + 1)).x)) {
tempLimit--;
}
//textLimit must not be zero
if (tempLimit == 0) {
tempLimit++;
}
combo.setTextLimit(tempLimit);
}
combo.setText(text);
gc.dispose();
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
I am not sure if this would be useful to anyone at this stage, but I am adding this just in case.
I actually implemented this to get around the bug. Then a colleague suggested to position the cursor to the beginning of the combo box. That seemed to work OK.
// Get a listener
public Listener getComboListener(final Combo combo) {
Listener comboListener = new Listener() {
@Override
public void handleEvent(final org.eclipse.swt.widgets.Event e)
{
combo.setSelection(new Point(0, 0));
}
};
return comboListener;
}
Then for the combo, add the lsitener for the following events
combo.addListener(SWT.Selection, getComboListener(combo));
combo.addListener(SWT.Resize, getComboListener(combo));
combo.addListener(SWT.FocusOut, getComboListener(combo));
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug. If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant. -- The automated Eclipse Genie. |
Build Identifier: On resising a combo to be smaller than the width of the item text, the right side of the selected text remains visible, not the left, which is not how it was in 3.1.1 and not what is wanted by users. The problem arose when migrating an SWT 3.1.1 application to 3.6.2. The different versions tested have the following sympthoms: 3.1.1: always the left part of the text is visible -> desired behaviour 3.4.1: at dialog open, the left part is visible, but the right side becomes visible on resizing 3.6.2 and 3.7: right side of the text is visible even at dialog open, it remains so at resize. This is the worst possible behaviour. We could not find any setting to influence this behaviour, the only workaround I have found is in the reproduce snippet commented out, but that is not a viable solution for our app, as the SWT code is generated and there are many (around 100) combo's affected. Reproducible: Always Steps to Reproduce: 1) compile and run this code: public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); GridLayout layout = new GridLayout(); shell.setLayout(layout); final Combo combo = new Combo(shell, SWT.DROP_DOWN | SWT.BORDER); GridData data = new GridData(); data.horizontalAlignment = GridData.FILL; data.grabExcessHorizontalSpace = true; combo.setLayoutData(data); String item = "BbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaCc"; combo.add(item); combo.setText(item); combo.setEnabled(false); //Uncomment the following lines and the text is drawn correctly // combo.addListener(SWT.Resize, new Listener() { // public void handleEvent(final Event argEvent) { // combo.setText(combo.getText()); // } // }); shell.pack(); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } 2) make the dialog smaller and you will see the effect described.