SWT Tree and TreeItem: Remove or change the drawin

2019-08-11 04:56发布

问题:

I'm working in SWT (no JFace), and I'm attempting to customize the behavior of a Tree that I'm using a sidebar.

The top-level items in the tree shouldn't be selectable; they're basically headers. Only the children of these items should be selectable. As a result, I would like the UI to behave in a way that indicates this; clicking on one of these top-level items should expand or collapse but shouldn't provide any sort of visual feedback outside of the indicator changing its state and the children's visibility changing.

The problem seems to be that on OS X, the expand/collapse indicator is a triangle (don't know if it's an image or a unicode character) that either points right or down, but is also colored based on the "selection" state. I've managed to override all of the relevant behavior for the top-level items except for the arrow changing color.

  • I've used an SWT.EraseItem listener to hook in to the background drawing so that the background doesn't change color. This works as expected.
  • I've used an SWT.PaintItem listener to make sure that the text in the top-level item doesn't change color. This works as expected, but doesn't seem to have any influence over the indicator; I've even tried not resetting the GC's foreground color, but the color of the indicator still changes:

Not Selected:

Selected

Some of the things that I've attempted to do, all of which have failed:

  • Just drawing a rectangle on top of indicator. The indicator seems to always be on top, no matter what I attach the PaintListener to.

  • Using a Listener on the Selection event type, checking to see if the event.item is one of the top-level items, and then fiddling with the event bits and redraw flags. This doesn't seem to work well at all; the behavior is completely unpredictable. The code looks something like this:

    sideBar.addListener(SWT.Selection, new Listener()
    {
        @Override
        public void handleEvent(Event event)
        {
            TreeItem eventItem = (TreeItem) event.item;
    
            if(sideBarRoots.contains(event.item))
            {
                event.detail = 0;
                event.type = 0;
                event.doit = false;
                sideBar.setRedraw(false);
            }
            else
            {
                sideBar.setRedraw(true);
                event.type = SWT.Selection;
                event.doit = true;
            }
        }
    });
    

    Since the redraw flag is just a hint, sometimes it gets set properly and others it doesn't. It can have either no effect, or can get locked in to a state where nothing redraws in the sidebar.

I'm aware that a lot of this behavior is highly coupled to the behavior of the underlying native widgets, but I was wondering if there was any way to get the behavior that I'm looking for without roll a custom widget from scratch?

回答1:

I think in a situation as yours you should ideally not allow selection on a tree header.

You can either cancel the selection event, by not allowing it to be clickable. But that might be a little kludgy implementation, especially for key navigation.

The safer approach, if possible with your data, would be to just move the selection whenever a tree parent node is selected. So it should work like this that if a parent node is selected, either by keyboard or mouse: you expand the node and move the selection to the first child.

This way you can avoid all the paint trickery to hide the selection state.