Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Standard Widget Toolkit (SWT) » Why is composites like Table not intended to be subclassed?
Why is composites like Table not intended to be subclassed? [message #464974] Fri, 02 December 2005 12:22 Go to next message
Robert BjervÃ¥s is currently offline Robert BjervÃ¥sFriend
Messages: 4
Registered: July 2009
Junior Member
Hi,

I'm working with an application intended for use with a touch screen. Each
time a row in a table is "picked" should it be selected or deselected
depending on the previous state, but all other rows should be as is. This is
the behavior if CTRL is pressed at the same time as the row is "picked". So
what we want to do is to handle every select event as if CTRL is pressed.
After some elaboration is our conclusion that the best way to a achieve such
behavior is to subclass Table and override all methods handling selection
and deselection. You can see our first implementation at the end of the
mail. It's not tested that much so it may contain errors. Anyway the reason
for this mail and my question is why is Table (and other composites) not
intended to be subclassed?

"IMPORTANT: This class is <em>not</em> intended to be subclassed."

I can't see the reason and this seams to be the best (and probably only)
solution to our issue.

Sincerely

/Robert

package my.viewer;

import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.SWT;
import java.util.List;
import java.util.ArrayList;

/**
* MultiSelectTable implement a table acting as if CTRL is pressed each time
* a row is selected in the table making it easier to work with a touch
screen.
*/
public class MultiSelectTable extends Table {

public final static int COLOR_NORMAL_BACKGROUND =
SWT.COLOR_LIST_BACKGROUND;
public final static int COLOR_NORMAL_TEXT = SWT.COLOR_LIST_FOREGROUND;
public final static int COLOR_SELECTED_BACKGROUND =
SWT.COLOR_LIST_SELECTION;
public final static int COLOR_SELCTED_TEXT =
SWT.COLOR_LIST_SELECTION_TEXT;

public MultiSelectTable(Composite composite, int i) {
super(composite, i);
}
public void deselect(int index) {
if (index>=0 && index<getItemCount())
deselectTableItem(getItem(index));
}
public void deselect(TableItem tableItem) {
deselectTableItem(tableItem);
}
publi c void deselect(int start, int end) {
for(int i=start;i<=end;i++) {
deselect(i);
}
}
public void deselect(int[] indices) {
for (int i = 0; i < indices.length; i++) {
int index = indices[i];
deselect(index);
}
}
public void deselectAll() {
TableItem[] tableItems =this.getItems();
for (int i = 0; i < tableItems.length; i++) {
TableItem tableItem = tableItems[i];
if
(tableItem.getBackground().equals(this.getDisplay().getSyste mColor(COLOR_SELECTED_BACKGROUND)))
deselectTableItem(tableItem);
}
super.deselectAll();
}
public TableItem[] getSelection() {
TableItem[] allTableItems =this.getItems();
ArrayList tableItems=new ArrayList();
int cnt=0;
for (int i = 0; i < allTableItems.length; i++) {
TableItem tableItem = allTableItems[i];
if (isSelected(tableItem))
tableItems.add(tableItem);
}
return (TableItem[]) tableItems.toArray(new TableItem[0]);
}
public int getSelectionCount() {
TableItem[] tableItems =this.getItems();
int cnt=0;
for (int i = 0; i < tableItems.length; i++) {
TableItem tableItem = tableItems[i];
if (isSelected(tableItem))
cnt++;
}
return cnt;
}
public int[] getSelectionIndices() {
return super.getSelectionIndices();
}
public int getSelectionIndex() {
return super.getSelectionIndex();
}
public void selectAll() {
TableItem[] tableItems = getItems();
select(tableItems);
}
public void select(TableItem[] tableItems) {
for (int i = 0; i < tableItems.length; i++) {
TableItem tableItem = tableItems[i];
selectTableItem(tableItem);
}
}
public void select(int index) {
if (index>=0 && index<getItemCount())
selectTableItem(getItem(index));
}
public void select(TableItem tableItem) {
selectTableItem(tableItem);
}
public void select(int start, int end) {
for(int i=start;i<=end;i++){
select(i);
}
}
public void select(int [] indices) {
for (int i = 0; i < indices.length; i++) {
int index = indices[i];
select(index);
}
}
public boolean isSelected(int i) {
return isSelected(getItem(i));
}
public void setSelection(int index) {
deselectAll();
select(index);
}
public void setSelection(int start, int end) {
deselectAll();
select(start,end);
}
public void setSelection(int[] indices) {
deselectAll();
select(indices);
}
public void setSelection(TableItem[] tableItems) {
deselectAll();
select(tableItems);
}
public void showSelection() {
TableItem tableItem= getFirstSelectedItem();
if (tableItem!=null)
showItem(tableItem);
}
private TableItem getFirstSelectedItem(){
TableItem firstItem=null;
TableItem[] tableItems =this.getItems();
int cnt=0;
for (int i = 0; i < tableItems.length; i++) {
TableItem tableItem = tableItems[i];
if (isSelected(tableItem)){
firstItem=tableItem;
break;
}
}
return firstItem;
}
public boolean isSelected(TableItem tableItem){
return
tableItem.getBackground().equals(this.getDisplay().getSystem Color(COLOR_SELECTED_BACKGROUND));
}
private void selectTableItem(TableItem tableItem){
tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_SELECTED_BACKGROUND));
tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_SELCTED_TEXT));
super.deselectAll();
}
private void deselectTableItem(TableItem tableItem){
tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_BACKGROUND));
tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_TEXT));
super.deselectAll();
}
// To shortcircuit the check done in the super class
protected void checkSubclass () {
}
}
Re: Why is composites like Table not intended to be subclassed? [message #464998 is a reply to message #464974] Fri, 02 December 2005 16:12 Go to previous messageGo to next message
Jeremy Dowdall is currently offline Jeremy DowdallFriend
Messages: 48
Registered: July 2009
Member
to answer your question bluntly - I have no idea :)

but I did run into the same problem with my own application and rigged
up the following hack that may be helpful until someone can offer better
insight. basically I just keep track of the selection with a mouse
listener:


private Table table;
private List selection = new ArrayList();

table.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
if(e.button == 1) {
TableItem newItem = viewer.getTable().getItem(new Point(e.x,e.y));
if(selection.contains(newItem)) {
selection.remove(newItem);
} else {
selection.add(newItem);
}
viewer.getTable().setSelection((TableItem[])
selection.toArray(new TableItem[selection.size()]));
}
}
});


naturally, I'd love to hear better ways of doing this, but I needed
something running!

Robert Bjervås wrote:
> Hi,
>
> I'm working with an application intended for use with a touch screen. Each
> time a row in a table is "picked" should it be selected or deselected
> depending on the previous state, but all other rows should be as is. This is
> the behavior if CTRL is pressed at the same time as the row is "picked". So
> what we want to do is to handle every select event as if CTRL is pressed.
> After some elaboration is our conclusion that the best way to a achieve such
> behavior is to subclass Table and override all methods handling selection
> and deselection. You can see our first implementation at the end of the
> mail. It's not tested that much so it may contain errors. Anyway the reason
> for this mail and my question is why is Table (and other composites) not
> intended to be subclassed?
>
> "IMPORTANT: This class is <em>not</em> intended to be subclassed."
>
> I can't see the reason and this seams to be the best (and probably only)
> solution to our issue.
>
> Sincerely
>
> /Robert
>
> package my.viewer;
>
> import org.eclipse.swt.widgets.Table;
> import org.eclipse.swt.widgets.Composite;
> import org.eclipse.swt.widgets.TableItem;
> import org.eclipse.swt.SWT;
> import java.util.List;
> import java.util.ArrayList;
>
> /**
> * MultiSelectTable implement a table acting as if CTRL is pressed each time
> * a row is selected in the table making it easier to work with a touch
> screen.
> */
> public class MultiSelectTable extends Table {
>
> public final static int COLOR_NORMAL_BACKGROUND =
> SWT.COLOR_LIST_BACKGROUND;
> public final static int COLOR_NORMAL_TEXT = SWT.COLOR_LIST_FOREGROUND;
> public final static int COLOR_SELECTED_BACKGROUND =
> SWT.COLOR_LIST_SELECTION;
> public final static int COLOR_SELCTED_TEXT =
> SWT.COLOR_LIST_SELECTION_TEXT;
>
> public MultiSelectTable(Composite composite, int i) {
> super(composite, i);
> }
> public void deselect(int index) {
> if (index>=0 && index<getItemCount())
> deselectTableItem(getItem(index));
> }
> public void deselect(TableItem tableItem) {
> deselectTableItem(tableItem);
> }
> publi c void deselect(int start, int end) {
> for(int i=start;i<=end;i++) {
> deselect(i);
> }
> }
> public void deselect(int[] indices) {
> for (int i = 0; i < indices.length; i++) {
> int index = indices[i];
> deselect(index);
> }
> }
> public void deselectAll() {
> TableItem[] tableItems =this.getItems();
> for (int i = 0; i < tableItems.length; i++) {
> TableItem tableItem = tableItems[i];
> if
> (tableItem.getBackground().equals(this.getDisplay().getSyste mColor(COLOR_SELECTED_BACKGROUND)))
> deselectTableItem(tableItem);
> }
> super.deselectAll();
> }
> public TableItem[] getSelection() {
> TableItem[] allTableItems =this.getItems();
> ArrayList tableItems=new ArrayList();
> int cnt=0;
> for (int i = 0; i < allTableItems.length; i++) {
> TableItem tableItem = allTableItems[i];
> if (isSelected(tableItem))
> tableItems.add(tableItem);
> }
> return (TableItem[]) tableItems.toArray(new TableItem[0]);
> }
> public int getSelectionCount() {
> TableItem[] tableItems =this.getItems();
> int cnt=0;
> for (int i = 0; i < tableItems.length; i++) {
> TableItem tableItem = tableItems[i];
> if (isSelected(tableItem))
> cnt++;
> }
> return cnt;
> }
> public int[] getSelectionIndices() {
> return super.getSelectionIndices();
> }
> public int getSelectionIndex() {
> return super.getSelectionIndex();
> }
> public void selectAll() {
> TableItem[] tableItems = getItems();
> select(tableItems);
> }
> public void select(TableItem[] tableItems) {
> for (int i = 0; i < tableItems.length; i++) {
> TableItem tableItem = tableItems[i];
> selectTableItem(tableItem);
> }
> }
> public void select(int index) {
> if (index>=0 && index<getItemCount())
> selectTableItem(getItem(index));
> }
> public void select(TableItem tableItem) {
> selectTableItem(tableItem);
> }
> public void select(int start, int end) {
> for(int i=start;i<=end;i++){
> select(i);
> }
> }
> public void select(int [] indices) {
> for (int i = 0; i < indices.length; i++) {
> int index = indices[i];
> select(index);
> }
> }
> public boolean isSelected(int i) {
> return isSelected(getItem(i));
> }
> public void setSelection(int index) {
> deselectAll();
> select(index);
> }
> public void setSelection(int start, int end) {
> deselectAll();
> select(start,end);
> }
> public void setSelection(int[] indices) {
> deselectAll();
> select(indices);
> }
> public void setSelection(TableItem[] tableItems) {
> deselectAll();
> select(tableItems);
> }
> public void showSelection() {
> TableItem tableItem= getFirstSelectedItem();
> if (tableItem!=null)
> showItem(tableItem);
> }
> private TableItem getFirstSelectedItem(){
> TableItem firstItem=null;
> TableItem[] tableItems =this.getItems();
> int cnt=0;
> for (int i = 0; i < tableItems.length; i++) {
> TableItem tableItem = tableItems[i];
> if (isSelected(tableItem)){
> firstItem=tableItem;
> break;
> }
> }
> return firstItem;
> }
> public boolean isSelected(TableItem tableItem){
> return
> tableItem.getBackground().equals(this.getDisplay().getSystem Color(COLOR_SELECTED_BACKGROUND));
> }
> private void selectTableItem(TableItem tableItem){
> tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_SELECTED_BACKGROUND));
> tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_SELCTED_TEXT));
> super.deselectAll();
> }
> private void deselectTableItem(TableItem tableItem){
> tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_BACKGROUND));
> tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_TEXT));
> super.deselectAll();
> }
> // To shortcircuit the check done in the super class
> protected void checkSubclass () {
> }
> }
>
>
>
>
Re: Why is composites like Table not intended to be subclassed? [message #465008 is a reply to message #464974] Fri, 02 December 2005 17:17 Go to previous messageGo to next message
Alex Blewitt is currently offline Alex BlewittFriend
Messages: 946
Registered: July 2009
Senior Member
I believe that the reason most SWT widgets have that warning is because most of the classes are pseduo-final. That is, they've been developed without any consideration for subclassing, and thus anyone who does subclass may have to change the subclass for each release (especially the internal ones). However, rather than making it final (which would prevent anyone subclassing, whether they had a legitimate need to or not -- such as yourself), a strongly worded comment indicates that if you do subclass it, it's up to you to fix it when they change the superclass without telling you.

It's mentioned briefly in the API Rules of engagement:

http://help.eclipse.org/help30/index.jsp?topic=/org.eclipse. platform.doc.isv/reference/misc/api-usage-rules.html

There are also some classes which call 'checkSubclass()' and throw an error if this.getClass() doesn't match the expected value. You might have to override this method if you are subclassing Widgets.

http://help.eclipse.org/help31/nftopic/org.eclipse.platform. doc.isv/reference/api/org/eclipse/swt/widgets/Widget.html

http://help.eclipse.org/help31/nftopic/org.eclipse.platform. doc.isv/reference/api/org/eclipse/swt/widgets/Widget.html#ch eckSubclass()

"Checks that this class can be subclassed.

The SWT class library is intended to be subclassed only at specific, controlled points (most notably, Composite and Canvas when implementing new widgets). This method enforces this rule unless it is overridden.

IMPORTANT: By providing an implementation of this method that allows a subclass of a class which does not normally allow subclassing to be created, the implementer agrees to be fully responsible for the fact that any such subclass will likely fail between SWT releases and will be strongly platform specific. No support is provided for user-written classes which are implemented in this fashion.

The ability to subclass outside of the allowed SWT classes is intended purely to enable those not on the SWT development team to implement patches in order to get around specific limitations in advance of when those limitations can be addressed by the team. Subclassing should not be attempted without an intimate and detailed understanding of the hierarchy. "

Alex.
Re: Why is composites like Table not intended to be subclassed? [message #465009 is a reply to message #464998] Fri, 02 December 2005 17:19 Go to previous messageGo to next message
Stefan Langer is currently offline Stefan LangerFriend
Messages: 236
Registered: July 2009
Senior Member
http://www.eclipse.org/swt/faq.php#subclassing

Jeremy Dowdall wrote:
> to answer your question bluntly - I have no idea :)
>
> but I did run into the same problem with my own application and rigged
> up the following hack that may be helpful until someone can offer better
> insight. basically I just keep track of the selection with a mouse
> listener:
>
>
> private Table table;
> private List selection = new ArrayList();
>
> table.addMouseListener(new MouseAdapter() {
> public void mouseDown(MouseEvent e) {
> if(e.button == 1) {
> TableItem newItem = viewer.getTable().getItem(new Point(e.x,e.y));
> if(selection.contains(newItem)) {
> selection.remove(newItem);
> } else {
> selection.add(newItem);
> }
> viewer.getTable().setSelection((TableItem[]) selection.toArray(new
> TableItem[selection.size()]));
> }
> }
> });
>
>
> naturally, I'd love to hear better ways of doing this, but I needed
> something running!
>
> Robert Bjervås wrote:
>
>> Hi,
>>
>> I'm working with an application intended for use with a touch screen.
>> Each time a row in a table is "picked" should it be selected or
>> deselected depending on the previous state, but all other rows should
>> be as is. This is the behavior if CTRL is pressed at the same time as
>> the row is "picked". So what we want to do is to handle every select
>> event as if CTRL is pressed. After some elaboration is our conclusion
>> that the best way to a achieve such behavior is to subclass Table and
>> override all methods handling selection and deselection. You can see
>> our first implementation at the end of the mail. It's not tested that
>> much so it may contain errors. Anyway the reason for this mail and my
>> question is why is Table (and other composites) not intended to be
>> subclassed?
>>
>> "IMPORTANT: This class is <em>not</em> intended to be subclassed."
>>
>> I can't see the reason and this seams to be the best (and probably
>> only) solution to our issue.
>>
>> Sincerely
>>
>> /Robert
>>
>> package my.viewer;
>>
>> import org.eclipse.swt.widgets.Table;
>> import org.eclipse.swt.widgets.Composite;
>> import org.eclipse.swt.widgets.TableItem;
>> import org.eclipse.swt.SWT;
>> import java.util.List;
>> import java.util.ArrayList;
>>
>> /**
>> * MultiSelectTable implement a table acting as if CTRL is pressed
>> each time
>> * a row is selected in the table making it easier to work with a
>> touch screen.
>> */
>> public class MultiSelectTable extends Table {
>>
>> public final static int COLOR_NORMAL_BACKGROUND =
>> SWT.COLOR_LIST_BACKGROUND;
>> public final static int COLOR_NORMAL_TEXT = SWT.COLOR_LIST_FOREGROUND;
>> public final static int COLOR_SELECTED_BACKGROUND =
>> SWT.COLOR_LIST_SELECTION;
>> public final static int COLOR_SELCTED_TEXT =
>> SWT.COLOR_LIST_SELECTION_TEXT;
>>
>> public MultiSelectTable(Composite composite, int i) {
>> super(composite, i);
>> }
>> public void deselect(int index) {
>> if (index>=0 && index<getItemCount())
>> deselectTableItem(getItem(index));
>> }
>> public void deselect(TableItem tableItem) {
>> deselectTableItem(tableItem);
>> }
>> publi c void deselect(int start, int end) {
>> for(int i=start;i<=end;i++) {
>> deselect(i);
>> }
>> }
>> public void deselect(int[] indices) {
>> for (int i = 0; i < indices.length; i++) {
>> int index = indices[i];
>> deselect(index);
>> }
>> }
>> public void deselectAll() {
>> TableItem[] tableItems =this.getItems();
>> for (int i = 0; i < tableItems.length; i++) {
>> TableItem tableItem = tableItems[i];
>> if
>> (tableItem.getBackground().equals(this.getDisplay().getSyste mColor(COLOR_SELECTED_BACKGROUND)))
>>
>> deselectTableItem(tableItem);
>> }
>> super.deselectAll();
>> }
>> public TableItem[] getSelection() {
>> TableItem[] allTableItems =this.getItems();
>> ArrayList tableItems=new ArrayList();
>> int cnt=0;
>> for (int i = 0; i < allTableItems.length; i++) {
>> TableItem tableItem = allTableItems[i];
>> if (isSelected(tableItem))
>> tableItems.add(tableItem);
>> }
>> return (TableItem[]) tableItems.toArray(new TableItem[0]);
>> }
>> public int getSelectionCount() {
>> TableItem[] tableItems =this.getItems();
>> int cnt=0;
>> for (int i = 0; i < tableItems.length; i++) {
>> TableItem tableItem = tableItems[i];
>> if (isSelected(tableItem))
>> cnt++;
>> }
>> return cnt;
>> }
>> public int[] getSelectionIndices() {
>> return super.getSelectionIndices();
>> }
>> public int getSelectionIndex() {
>> return super.getSelectionIndex();
>> }
>> public void selectAll() {
>> TableItem[] tableItems = getItems();
>> select(tableItems);
>> }
>> public void select(TableItem[] tableItems) {
>> for (int i = 0; i < tableItems.length; i++) {
>> TableItem tableItem = tableItems[i];
>> selectTableItem(tableItem);
>> }
>> }
>> public void select(int index) {
>> if (index>=0 && index<getItemCount())
>> selectTableItem(getItem(index));
>> }
>> public void select(TableItem tableItem) {
>> selectTableItem(tableItem);
>> }
>> public void select(int start, int end) {
>> for(int i=start;i<=end;i++){
>> select(i);
>> }
>> }
>> public void select(int [] indices) {
>> for (int i = 0; i < indices.length; i++) {
>> int index = indices[i];
>> select(index);
>> }
>> }
>> public boolean isSelected(int i) {
>> return isSelected(getItem(i));
>> }
>> public void setSelection(int index) {
>> deselectAll();
>> select(index);
>> }
>> public void setSelection(int start, int end) {
>> deselectAll();
>> select(start,end);
>> }
>> public void setSelection(int[] indices) {
>> deselectAll();
>> select(indices);
>> }
>> public void setSelection(TableItem[] tableItems) {
>> deselectAll();
>> select(tableItems);
>> }
>> public void showSelection() {
>> TableItem tableItem= getFirstSelectedItem();
>> if (tableItem!=null)
>> showItem(tableItem);
>> }
>> private TableItem getFirstSelectedItem(){
>> TableItem firstItem=null;
>> TableItem[] tableItems =this.getItems();
>> int cnt=0;
>> for (int i = 0; i < tableItems.length; i++) {
>> TableItem tableItem = tableItems[i];
>> if (isSelected(tableItem)){
>> firstItem=tableItem;
>> break;
>> }
>> }
>> return firstItem;
>> }
>> public boolean isSelected(TableItem tableItem){
>> return
>> tableItem.getBackground().equals(this.getDisplay().getSystem Color(COLOR_SELECTED_BACKGROUND));
>>
>> }
>> private void selectTableItem(TableItem tableItem){
>>
>> tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_SELECTED_BACKGROUND));
>>
>>
>> tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_SELCTED_TEXT));
>>
>> super.deselectAll();
>> }
>> private void deselectTableItem(TableItem tableItem){
>>
>> tableItem.setBackground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_BACKGROUND));
>>
>>
>> tableItem.setForeground(tableItem.getDisplay().getSystemColo r(COLOR_NORMAL_TEXT));
>>
>> super.deselectAll();
>> }
>> // To shortcircuit the check done in the super class
>> protected void checkSubclass () {
>> }
>> }
>>
>>
>>
>>
Re: Why is composites like Table not intended to be subclassed? [message #465103 is a reply to message #464974] Tue, 06 December 2005 08:33 Go to previous messageGo to next message
Robert BjervÃ¥s is currently offline Robert BjervÃ¥sFriend
Messages: 4
Registered: July 2009
Junior Member
Thanks Jeremy, Stefan and Alex,

Your help has been most valuable. There is clearly a lot of reasons for not
subclassing. Unfortunately is it probably the only practical solution since
we must cover all possible situations. It is not enough to listen only on
mouse clicks as in your solution Jeremy.

/Robert
Re: Why is composites like Table not intended to be subclassed? [message #465105 is a reply to message #465103] Tue, 06 December 2005 09:00 Go to previous message
Stefan Langer is currently offline Stefan LangerFriend
Messages: 236
Registered: July 2009
Senior Member
If subclassing is the only solution then it is ok to do so.
You just have to live with the fact that this can break behaviour if the
underlying component changes.

Stefan

Robert Bjervås wrote:
> Thanks Jeremy, Stefan and Alex,
>
> Your help has been most valuable. There is clearly a lot of reasons for not
> subclassing. Unfortunately is it probably the only practical solution since
> we must cover all possible situations. It is not enough to listen only on
> mouse clicks as in your solution Jeremy.
>
> /Robert
>
>
Previous Topic:Problem with TableTreeViewer and CheckboxTreeViewer -- HELP NEEDED!
Next Topic:[SWT][Draw2D] refresh problem
Goto Forum:
  


Current Time: Sun Dec 08 09:20:03 GMT 2024

Powered by FUDForum. Page generated in 0.03728 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top