swt带复选的结构树,完美处理树中的勾选现象

时间:2021-03-04 22:21:59

1.先来看看项目截图:

swt带复选的结构树,完美处理树中的勾选现象

2.本项目是maven写的,下面是maven配置:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.pan</groupId>
    <artifactId>myui</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <swt.version>4.3</swt.version>
        <jface.version>3.3.0-I20070606-0010</jface.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.eclipse</groupId>
            <artifactId>jface</artifactId>
            <version>${jface.version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.swt.org.eclipse.swt.win32.win32.x86_64.4.3.swt</groupId>
            <artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
            <version>${swt.version}</version>
        </dependency>

    </dependencies>

</project>

3.界面代码TreeDialog.java 如下:

package org.pan.tree.ui;

import java.util.Arrays;

import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.pan.tree.domain.City;
import org.pan.tree.domain.ITreeNode;

public class TreeDialog {

    protected Shell shell;
    private CheckboxTreeViewer treeViewer;
    private Tree tree;

    /**
     * Launch the application.
     * 
     * @param args
     */
    public static void main(String[] args) {
        try {
            TreeDialog window = new TreeDialog();
            window.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Open the window.
     */
    public void open() {
        Display display = Display.getDefault();
        createContents();
        shell.open();
        shell.layout();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /**
     * Create contents of the window.
     */
    protected void createContents() {
        shell = new Shell();
        shell.setSize(450, 300);
        shell.setText("SWT Application");
        shell.setLayout(new FillLayout());

        SashForm sashForm = new SashForm(shell, SWT.NONE);

        Composite composite = new Composite(sashForm, SWT.NONE);
        composite.setLayout(new FillLayout());

        treeViewer = new CheckboxTreeViewer(composite, SWT.BORDER|SWT.CHECK);
        treeViewer.setLabelProvider(new TreeLabelProvider());
        treeViewer.setContentProvider(new TreeContentProvider());
        tree = treeViewer.getTree();
        
        initTree();
        
        Composite composite_1 = new Composite(sashForm, SWT.NONE);

        sashForm.setWeights(new int[] { 2, 3 });
        
        treeViewer.addCheckStateListener(new ICheckStateListener() {
            public void checkStateChanged(CheckStateChangedEvent arg0) {
                CheckboxTreeViewer checkboxTreeViewer = (CheckboxTreeViewer)arg0.getSource();
                boolean checked = arg0.getChecked();
                checkboxTreeViewer.setSubtreeChecked(arg0.getElement(), checked);
                
                TreeItem ti = (TreeItem)checkboxTreeViewer.testFindItem(arg0.getElement());
                tree.setSelection(ti);
                TreeItem parent = ti.getParentItem();
                if(parent == null){
                    return;
                }
                TreeItem[] items = parent.getItems();
                int checkItems = 0;
                for (TreeItem treeItem : items) {
                    if(treeItem.getChecked() && !treeItem.getGrayed()){
                        checkItems = checkItems + 1;
                    }
                }
                ti.setChecked(checked);
                if(checkItems == 0){
                    parent.setChecked(false);
                    return;
                }
                if(checkItems == items.length){
                    parent.setGrayed(false);
                    parent.setChecked(true);
                    return;
                }
                if(checkItems != items.length){
                    parent.setChecked(true);
                    parent.setGrayed(true);
                    return;
                }
            }
        });
    }

    public void initTree() {
        City city = new City("大中国");

        City city2 = new City("湖北");
        city.getChildren().add(city2);

        City city3 = new City("咸宁");
        city2.getChildren().add(city3);

        City city4 = new City("武汉");
        city2.getChildren().add(city4);

        City city5 = new City("湖南");
        city.getChildren().add(city5);

        treeViewer.setInput(Arrays.asList(city));

    }
}

4.treeviewer中用到的provider:
TreeLabelProvider.java:

package org.pan.tree.ui;

import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Image;
import org.pan.tree.domain.ITreeNode;

public class TreeLabelProvider extends LabelProvider implements ILabelProvider {

    public String getText(Object element) {
        ITreeNode node = (ITreeNode) element;
        return node.getName();
    }

    public Image getImage(Object element) {
        return null;
    }

}

TreeContentProvider.java

package org.pan.tree.ui;

import java.util.List;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.pan.tree.domain.ITreeNode;

public class TreeContentProvider implements ITreeContentProvider {

    public Object[] getElements(Object inputElement) {
        if (inputElement instanceof List) {
            List input = (List) inputElement;
            return input.toArray();
        }
        return new Object[0];
    }

    public Object[] getChildren(Object parentElement) {
        ITreeNode node = (ITreeNode) parentElement;
        List list = node.getChildren();
        if (list == null) {
            return new Object[0];
        }
        return list.toArray();
    }

    public boolean hasChildren(Object element) {
        ITreeNode node = (ITreeNode) element;
        List list = node.getChildren();
        return !(list == null || list.isEmpty());
    }

    // 以下三个函数根据需要填充
    public Object getParent(Object element) {
        return null;
    }

    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    }

    public void dispose() {
    }

}

5.填充对象为树结构,所以为树结构写了一下通用的接口,所有树型数据都必须实现这个接口:

ITreeNode.java:

package org.pan.tree.domain;

import java.util.List;

public interface ITreeNode {

    public String getName();
    
    public String setName(String name);
    
    public boolean getChecked();
    
    public void setChecked(boolean checked);
    
    public List getChildren();
    
    public void setChildren(List list);
    
}

以城市结构作为类子:

City.java:

package org.pan.tree.domain;

import java.util.ArrayList;
import java.util.List;

public class City implements ITreeNode {

    private String name;
    private boolean checked;
    private List<City> children = new ArrayList<City>();

    public City() {
    }

    public City(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public String setName(String name) {
        return this.name = name;
    }

    public boolean getChecked() {
        return checked;
    }

    public void setChecked(boolean checked) {
        this.checked = checked;
    }

    public List<City> getChildren() {
        return this.children;
    }

    public void setChildren(List list) {
        this.children.clear();
        this.children.addAll(children);
    }

    @Override
    public String toString() {
        return "City [name=" + name + "]";
    }

}

 

下面是最终的效果图:

swt带复选的结构树,完美处理树中的勾选现象

为在达下图中的选中效果,折腾了很久,在监听勾选的事件中,看似其中有一些比较重复的代码,但的确是缺一不可.因为勾选的项目不一定是我们当前选中的项目,导致子节点与父节点的显示有误 .好了,可以算是比较完美了.