I am trying to set up a multi-column SWT Tree
(via a JFace TreeViewer
) that allows its columns to be re-ordered by the user by dragging the column headers. However, the first column should remain fixed and unmoveable. I can use the setMoveable(true)
method on each TreeColumn
except the first to get real close, but that doesn't prevent the user dragging a different column to the left of it. Any ideas how to resolve this?
我正在尝试建立一个多列SWT树(通过JFace TreeViewer),它允许用户通过拖动列标题来重新排序其列。但是,第一列应该保持固定且不可移动。我可以在每个TreeColumn上使用setMoveable(true)方法,除了第一个要真正靠近它的方法,但是这并不能防止用户将另一列拖到它的左边。有什么办法解决这个问题吗?
Here's a simplified working snippet (without JFace) to illustrate the problem:
下面是一个简化的工作片段(没有JFace)来说明问题:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
public class TreeTableColumnMove {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new RowLayout(SWT.HORIZONTAL));
Tree tree = new Tree(shell, SWT.BORDER | SWT.CHECK);
tree.setLayoutData(new RowData(-1, 100));
tree.setHeaderVisible(true);
for (int i = 0; i < 5; i++) {
TreeColumn column = new TreeColumn(tree, SWT.CENTER);
column.setText("Col " + i);
column.setWidth(60);
if (i > 0) column.setMoveable(true);
}
TreeItem item = new TreeItem(tree, SWT.NONE);
item.setText(new String[] { "c0", "c1", "c2", "c3", "c4" });
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
2 个解决方案
#1
2
I don't know if it's possible to actually prevent it, but you can handle the result of the column moving, and react to it to achieve what you want.
我不知道是否有可能预防它,但你可以处理列移动的结果,并对其做出反应以实现你想要的。
Maybe something along these lines would be a good starting point? Essentially it listens for the first column being moved (not directly, but being shifted as a result of another column being moved to the left of it), and then re-shuffles the order so it is the first column visually again.
也许沿着这些线的一些东西会是一个很好的起点?本质上,它监听第一列被移动(不是直接移动,而是由于另一列移动到它的左边而被移动),然后重新洗牌,这样它就会再次出现在第一个列中。
Note that regardless of the visual order, the first column created will always be zero (and so on). The method tree.getColumnOrder() will be ordered visually, with the values being the created order indexes (so if you swap the 2nd and 3rd columns, the method will return [0, 2, 1, 3, 4])
注意,不管视觉顺序如何,创建的第一列始终为0(等等)。getcolumnorder()方法将被可视化地排序,其值为创建的顺序索引(因此如果您交换第2和第3列,方法将返回[0,2,1,3,4])
for (int i = 0; i < 5; i++) {
TreeColumn column = new TreeColumn(tree, SWT.CENTER);
column.setText("Col " + i);
column.setWidth(60);
if (i > 0) column.setMoveable(true);
// NEW CODE HERE
if (i == 0) {
column.addControlListener(new ControlAdapter() {
public void controlMoved(ControlEvent e) {
List<Integer> newOrder = new ArrayList<Integer>();
// add the first
newOrder.add(0);
// loop around all columns
for (int col : tree.getColumnOrder()) {
// if not the first that was added, add to list
if (col != 0) {
newOrder.add(col);
}
}
// convert list to array
int[] newOrderArray = new int[newOrder.size()];
for (int j = 0; j < newOrder.size(); j++) {
newOrderArray[j] = newOrder.get(j);
}
// update tree order
tree.setColumnOrder(newOrderArray);
}
});
}
}
#2
3
Here is my final solution based on danmec's answer:
这是我根据danmec的回答得出的最终解决方案:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
public class TreeTableColumnMove {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new RowLayout(SWT.HORIZONTAL));
final Tree tree = new Tree(shell, SWT.BORDER | SWT.CHECK);
tree.setLayoutData(new RowData(-1, 100));
tree.setHeaderVisible(true);
Listener moveListener = new Listener() {
public void handleEvent(Event e) {
int[] order = tree.getColumnOrder();
for(int i=0, col=0; i<order.length; i++) {
int tmp = order[i];
order[i] = col;
col = tmp;
if(col == 0)
if(i == 0) return;
else break;
}
tree.setColumnOrder(order);
}
};
for (int i = 0; i < 5; i++) {
TreeColumn column = new TreeColumn(tree, SWT.CENTER);
column.setText("Col " + i);
column.setWidth(60);
if (i == 0)
column.addListener(SWT.Move, moveListener);
else
column.setMoveable(true);
}
TreeItem item = new TreeItem(tree, SWT.NONE);
item.setText(new String[] { "c0", "c1", "c2", "c3", "c4" });
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
#1
2
I don't know if it's possible to actually prevent it, but you can handle the result of the column moving, and react to it to achieve what you want.
我不知道是否有可能预防它,但你可以处理列移动的结果,并对其做出反应以实现你想要的。
Maybe something along these lines would be a good starting point? Essentially it listens for the first column being moved (not directly, but being shifted as a result of another column being moved to the left of it), and then re-shuffles the order so it is the first column visually again.
也许沿着这些线的一些东西会是一个很好的起点?本质上,它监听第一列被移动(不是直接移动,而是由于另一列移动到它的左边而被移动),然后重新洗牌,这样它就会再次出现在第一个列中。
Note that regardless of the visual order, the first column created will always be zero (and so on). The method tree.getColumnOrder() will be ordered visually, with the values being the created order indexes (so if you swap the 2nd and 3rd columns, the method will return [0, 2, 1, 3, 4])
注意,不管视觉顺序如何,创建的第一列始终为0(等等)。getcolumnorder()方法将被可视化地排序,其值为创建的顺序索引(因此如果您交换第2和第3列,方法将返回[0,2,1,3,4])
for (int i = 0; i < 5; i++) {
TreeColumn column = new TreeColumn(tree, SWT.CENTER);
column.setText("Col " + i);
column.setWidth(60);
if (i > 0) column.setMoveable(true);
// NEW CODE HERE
if (i == 0) {
column.addControlListener(new ControlAdapter() {
public void controlMoved(ControlEvent e) {
List<Integer> newOrder = new ArrayList<Integer>();
// add the first
newOrder.add(0);
// loop around all columns
for (int col : tree.getColumnOrder()) {
// if not the first that was added, add to list
if (col != 0) {
newOrder.add(col);
}
}
// convert list to array
int[] newOrderArray = new int[newOrder.size()];
for (int j = 0; j < newOrder.size(); j++) {
newOrderArray[j] = newOrder.get(j);
}
// update tree order
tree.setColumnOrder(newOrderArray);
}
});
}
}
#2
3
Here is my final solution based on danmec's answer:
这是我根据danmec的回答得出的最终解决方案:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
public class TreeTableColumnMove {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new RowLayout(SWT.HORIZONTAL));
final Tree tree = new Tree(shell, SWT.BORDER | SWT.CHECK);
tree.setLayoutData(new RowData(-1, 100));
tree.setHeaderVisible(true);
Listener moveListener = new Listener() {
public void handleEvent(Event e) {
int[] order = tree.getColumnOrder();
for(int i=0, col=0; i<order.length; i++) {
int tmp = order[i];
order[i] = col;
col = tmp;
if(col == 0)
if(i == 0) return;
else break;
}
tree.setColumnOrder(order);
}
};
for (int i = 0; i < 5; i++) {
TreeColumn column = new TreeColumn(tree, SWT.CENTER);
column.setText("Col " + i);
column.setWidth(60);
if (i == 0)
column.addListener(SWT.Move, moveListener);
else
column.setMoveable(true);
}
TreeItem item = new TreeItem(tree, SWT.NONE);
item.setText(new String[] { "c0", "c1", "c2", "c3", "c4" });
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}