2011-07-27 7 views
5

私はコンポジットに描画することを理解しています。ペイントリスナーを追加することはできますが、その結果、子どもの下に描画されます。もし私が子供たちの上を描きたいのであれば?複合材料の子要素をSWTに描画する方法は?

以下は線を描いていますが、線の上にsubcが描かれています。

Composite c = new Composite(shell, 0); 
c.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLUE)); 
c.setBounds(100, 100, 800, 600); 

c.addPaintListener(new PaintListener() { 
    public void paintControl(PaintEvent e) { 
     e.gc.drawLine(0, 0, 500, 1000); 
    } 
}); 

final Composite subc = new Composite(c, 0); 
subc.setLayout(null); 
subc.setBounds(10, 10, 600, 400); 

答えて

4

残念ながら、Bug#114749のように、これは実装された機能ではありません。

独自のカスタムソリューションをコーディングする必要があります(たとえば、影響を受ける各コンポジットの描画領域を計算し、それぞれに描画する必要があります)。

これはかなり古いバグですが、これが必須のものだと思うならアップアップは常に良いアイデアです。

4

あなたがCompositeにするだけでなく、すべて含まれている子どもたち(再帰的)にだけでなく、あなたのSWT.Paintリスナーを追加する必要があります:-)

解決するためにすべてのことは難しいことではありません。そのトリックは、各コントロールの座標を適切にマッピングすることです。

説明するために、私はいくつかのプロジェクトで使用するコードを添付しました。そして、はい、クラスがないことは知っていますが、おそらくこれからアイデアを得ることができます。

/******************************************************************************* 
* Copyright (c) 2007, 2011 The RCP Company and others. 
* All rights reserved. This program and the accompanying materials 
* are made available under the terms of the Eclipse Public License v1.0 
* which accompanies this distribution, and is available at 
* http://www.eclipse.org/legal/epl-v10.html 
* 
* Contributors: 
*  The RCP Company - initial API and implementation 
*******************************************************************************/ 
package com.rcpcompany.uibindings.utils; 

import org.eclipse.jface.fieldassist.ControlDecoration; 
import org.eclipse.swt.graphics.Color; 
import org.eclipse.swt.graphics.Point; 
import org.eclipse.swt.graphics.Rectangle; 
import org.eclipse.swt.widgets.Control; 
import org.eclipse.swt.widgets.Event; 

import com.rcpcompany.uibindings.IDisposable; 
import com.rcpcompany.uibindings.internal.utils.PaintDecorationManager; 

/** 
* Support for arbitrary decorations for {@link Control controls}. 
* <p> 
* <p> 
* Differs from {@link ControlDecoration} in a number of ways: 
* <ul> 
* <li>Support for cells in tables</li> 
* <li>Vastly more efficient when there are many decorations</li> 
* </ul> 
* 
* @author Tonny Madsen, The RCP Company 
*/ 
public interface IPaintDecoration { 
    /** 
    * Factory for {@link IPaintDecoration}. 
    */ 
    final class Factory { 
     private Factory() { 
     } 

     /** 
     * Adds a new decoration. 
     * <p> 
     * The decoration is only added if the control of the decoration is non-<code>null</code>. 
     * <p> 
     * If the decoration supports the {@link IDisposable} interface, it will be notified when 
     * the decoration is no longer in use - e.g. when the decoration is removed with 
     * {@link #removeDecoration(IPaintDecoration)} or if the control is disposed. 
     * 
     * @param decoration the new decoration 
     */ 
     public static void addDecoration(IPaintDecoration decoration) { 
      PaintDecorationManager.addDecoration(decoration); 
     } 

     public static IPaintDecoration paintRectangle(final Control c, Rectangle rect, final Color color) { 
      final Rectangle r; 
      if (rect == null) { 
       final Point s = c.getSize(); 
       r = new Rectangle(0, 0, s.x, s.y); 
      } else { 
       r = rect; 
      } 
      final IPaintDecoration pd = new IPaintDecoration() { 

       @Override 
       public void paint(Event event, Rectangle area) { 
        // LogUtils.debug(this, event.widget + ": clip=" + event.gc.getClipping() + 
        // " area=" + area); 
        final Color oldForeground = event.gc.getForeground(); 
        event.gc.setForeground(color); 
        event.gc.drawRectangle(area.x, area.y, area.width - 1, area.height - 1); 
        event.gc.setForeground(oldForeground); 
       } 

       @Override 
       public Control getControl() { 
        return c; 
       } 

       @Override 
       public Rectangle getArea() { 
        return r; 
       } 
      }; 
      addDecoration(pd); 

      return pd; 
     } 

     /** 
     * Removes an existing decoration. 
     * 
     * @param decoration the decoration to remove 
     */ 
     public static void removeDecoration(IPaintDecoration decoration) { 
      PaintDecorationManager.removeDecoration(decoration); 
     } 
    }; 

    /** 
    * The control of this decoration. 
    * <p> 
    * The control of a specific decoration may not change during the lifetime of the decoration. 
    * 
    * @return the control 
    */ 
    Control getControl(); 

    /** 
    * Returns the area of this decoration in relation to the control. 
    * 
    * @return the relative location 
    */ 
    Rectangle getArea(); 

    /** 
    * Paints the decoration. 
    * 
    * @param area TODO 
    */ 
    void paint(Event event, Rectangle area); 
} 

/******************************************************************************* 
* Copyright (c) 2007, 2011 The RCP Company and others. 
* All rights reserved. This program and the accompanying materials 
* are made available under the terms of the Eclipse Public License v1.0 
* which accompanies this distribution, and is available at 
* http://www.eclipse.org/legal/epl-v10.html 
* 
* Contributors: 
*  The RCP Company - initial API and implementation 
*******************************************************************************/ 
package com.rcpcompany.uibindings.internal.utils; 

import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Map; 
import java.util.Set; 

import org.eclipse.jface.util.Util; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.graphics.Rectangle; 
import org.eclipse.swt.widgets.Control; 
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 com.rcpcompany.uibindings.IDisposable; 
import com.rcpcompany.uibindings.internal.Activator; 
import com.rcpcompany.uibindings.utils.IPaintDecoration; 
import com.rcpcompany.utils.logging.LogUtils; 

/** 
* Simple manager that can draw arbitrary "stuff". 
* <p> 
* A manager exists for each {@link Shell} of the application and is automatically disposed with the 
* shell. 
* <p> 
* Each decoration of the manager is handled internally via an {@link DecorationData} object. 
* 
* @author Tonny Madsen, The RCP Company 
*/ 
public final class PaintDecorationManager implements IDisposable, Listener { 

    /** 
    * The shell of this manager. 
    */ 
    private final Shell myShell; 

    /** 
    * Cached platform flag for dealing with platform-specific issue: 
    * https://bugs.eclipse.org/bugs/show_bug.cgi?id=219326 : Shell with custom region and 
    * SWT.NO_TRIM still has border 
    */ 
    private static boolean MAC = Util.isMac(); 

    /** 
    * Constructs and returns a new manager. 
    * 
    * @param shell the shell of the manager 
    */ 
    private PaintDecorationManager(Shell shell) { 
     myShell = shell; 
     theManagers.put(getShell(), this); 
     hookControl(getShell()); 
    } 

    @Override 
    public void dispose() { 
     /* 
     * Unhook all controls. This is automatically remove all decorations. 
     */ 
     for (final Control c : myHookedControls.toArray(new Control[myHookedControls.size()])) { 
      unhookControl(c); 
     } 
     theManagers.remove(getShell()); 
    } 

    public static void addDecoration(IPaintDecoration decoration) { 
     final PaintDecorationManager mng = getManager(decoration); 
     if (mng != null) { 
      mng.addADecoration(decoration); 
     } 
    } 

    public static void removeDecoration(IPaintDecoration decoration) { 
     final PaintDecorationManager mng = getManager(decoration); 
     if (mng != null) { 
      mng.removeADecoration(decoration); 
     } 
    } 

    /** 
    * Mapping of all decorations of this manager to internal data for the same decoration. 
    */ 
    private final Map<IPaintDecoration, DecorationData> myDecorations = new HashMap<IPaintDecoration, DecorationData>(); 

    public void addADecoration(IPaintDecoration decoration) { 
     DecorationData dd = myDecorations.get(decoration); 
     if (dd == null) { 
      dd = new DecorationData(decoration); 
     } 
     dd.update(); 
    } 

    public void removeADecoration(IPaintDecoration decoration) { 
     if (Activator.getDefault().TRACE_CONTROL_DECORATIONS) { 
      LogUtils.debug(this, "control: " + decoration.getControl() + "@" + decoration.getControl().hashCode() + "/" 
        + decoration.getArea()); 
     } 
     final DecorationData dd = myDecorations.get(decoration); 
     if (dd == null) return; 
     dd.dispose(); 
    } 

    /** 
    * Map with all defined managers indexed by the shell. 
    */ 
    private static Map<Shell, PaintDecorationManager> theManagers = new HashMap<Shell, PaintDecorationManager>(); 

    /** 
    * Returns the shell of the manager. 
    * 
    * @return the shell 
    */ 
    private Shell getShell() { 
     return myShell; 
    } 

    /** 
    * Returns the manager for the specified decoration. 
    * <p> 
    * Creates a new manager if none exists 
    * 
    * @param decoration the decoration 
    * @return the manager for the shell of the decoration 
    */ 
    private static PaintDecorationManager getManager(IPaintDecoration decoration) { 
     final Control c = decoration.getControl(); 
     if (c == null) return null; 
     final Shell shell = c.getShell(); 
     PaintDecorationManager mng = theManagers.get(shell); 
     if (mng == null) { 
      mng = new PaintDecorationManager(shell); 
     } 

     return mng; 
    } 

    /** 
    * The hooked controls of this manager. 
    * <p> 
    * A control is hooked when first referred in a decoration or a parent... 
    * <p> 
    * It is not unhooked until the control or this manager is disposed. 
    */ 
    private final Set<Control> myHookedControls = new HashSet<Control>(); 

    /** 
    * Hooks the specified control into this manager. 
    * <p> 
    * Also hooks all parent controls. 
    * 
    * @param control the control 
    */ 
    public void hookControl(Control control) { 
     if (myHookedControls.contains(control)) return; 

     myHookedControls.add(control); 
     control.addListener(SWT.Dispose, this); 
     control.addListener(SWT.Paint, this); 

     if (control != getShell()) { 
      hookControl(control.getParent()); 
     } 
    } 

    /** 
    * Unhooks a specific control from the manager. 
    * 
    * @param control the control 
    */ 
    public void unhookControl(Control control) { 
     if (!myHookedControls.contains(control)) return; 
     myHookedControls.remove(control); 
     if (!control.isDisposed()) { 
      control.removeListener(SWT.Dispose, this); 
      control.removeListener(SWT.Paint, this); 
     } 
     for (final DecorationData dd : myDecorations.values() 
       .toArray(new DecorationData[myDecorations.values().size()])) { 
      if (dd.getControl() == control) { 
       dd.dispose(); 
      } 
     } 
    } 

    @Override 
    public void handleEvent(Event event) { 
     // LogUtils.debug(this, ToStringUtils.toString(event)); 
     switch (event.type) { 
     case SWT.Dispose: 
      handleDispose(event); 
      break; 
     case SWT.Paint: 
      handlePaint(event); 
      break; 
     default: 
      break; 
     } 
    } 

    /** 
    * Handles the dispose event. 
    * 
    * @param event the event 
    */ 
    private void handleDispose(Event event) { 
     if (event.widget == getShell()) { 
      dispose(); 
      return; 
     } 
     unhookControl((Control) event.widget); 
    } 

    /** 
    * Handles the paint event. 
    * 
    * @param event the event 
    */ 
    private void handlePaint(Event event) { 
     final Control c = (Control) event.widget; 
     final Display display = c.getDisplay(); 
     final Rectangle area = display.map(c, null, event.x, event.y, event.width, event.height); 
     for (final DecorationData dd : myDecorations.values()) { 
      if (dd.intersects(area)) { 
       dd.paint(event); 
      } 
     } 
    } 

    /** 
    * Manager internal decoration data for one decoration. 
    */ 
    protected class DecorationData implements IDisposable { 

     private final IPaintDecoration myDecoration; 

     /** 
     * The previous area painted by this decoration relative to the display. 
     */ 
     private Rectangle myPreviousArea = null; 

     /** 
     * Set to true when the decoration is disposed 
     */ 
     private boolean isDisposed = false; 

     /** 
     * Constructs and returns a new decoration data object 
     * 
     * @param decoration he base decoration 
     */ 
     protected DecorationData(IPaintDecoration decoration) { 
      myDecoration = decoration; 
      myDecorations.put(getDecoration(), this); 
      if (Activator.getDefault().TRACE_CONTROL_DECORATIONS) { 
       LogUtils.debug(this, "control: " + this); 
      } 

      getManager().hookControl(getDecoration().getControl()); 
     } 

     /** 
     * Returns the control of the decoration 
     * 
     * @return the control 
     */ 
     public Control getControl() { 
      return getDecoration().getControl(); 
     } 

     @Override 
     public void dispose() { 
      isDisposed = true; 
      update(); 
      myDecorations.remove(getDecoration()); 
      if (Activator.getDefault().TRACE_CONTROL_DECORATIONS) { 
       LogUtils.debug(this, "control: " + this); 
      } 
     } 

     /** 
     * Returns the manager of this decoration 
     * 
     * @return the manager 
     */ 
     public PaintDecorationManager getManager() { 
      return PaintDecorationManager.this; 
     } 

     /** 
     * Returns the decoration itself 
     * 
     * @return the decoration 
     */ 
     public IPaintDecoration getDecoration() { 
      return myDecoration; 
     } 

     /** 
     * Updates this decoration 
     */ 
     public void update() { 
      if (Activator.getDefault().TRACE_CONTROL_DECORATIONS) { 
       LogUtils.debug(this, "control: " + this); 
      } 
      /* 
      * Calculate new area 
      */ 
      final Rectangle newArea = getDecorationRectangle(getShell()); 
      /* 
      * Compare with last area and image 
      */ 
      if ((newArea == null ? myPreviousArea == null : newArea.equals(myPreviousArea))) { 
       if (Activator.getDefault().TRACE_CONTROL_DECORATIONS_VERBOSE) { 
        LogUtils.debug(this, "-- return"); 
       } 
       return; 
      } 
      Rectangle r = null; 
      if (myPreviousArea != null) { 
       r = myPreviousArea; 
       if (newArea != null) { 
        r.add(newArea); 
       } 
      } else { 
       r = newArea; 
      } 
      myPreviousArea = newArea; 
      if (r != null) { 
       // LogUtils.debug(this, "redraw: " + r); 
       getShell().redraw(r.x, r.y, r.width, r.height, true); 
       if (Activator.getDefault().TRACE_CONTROL_DECORATIONS_VERBOSE) { 
        LogUtils.debug(this, "redraw " + r); 
       } 
      } 
     } 

     /** 
     * Calculates the area taken by the image translated to a specified target control 
     * 
     * @param c the target control or null for the Display 
     * 
     * @return the {@link Rectangle} for the image or <code>null</code> if no image is specified 
     */ 
     private Rectangle getDecorationRectangle(Control c) { 
      final Control control = getDecoration().getControl(); 
      final Rectangle b = getDecoration().getArea(); 
      final Rectangle bounds = new Rectangle(b.x, b.y, b.width + 1, b.height + 1); 

      return getShell().getDisplay().map(control, c, bounds); 
     } 

     /** 
     * Paints this decoration. 
     * 
     * @param event the {@link SWT#Paint} event 
     */ 
     public void paint(Event event) { 
      if (Activator.getDefault().TRACE_CONTROL_DECORATIONS_VERBOSE) { 
       LogUtils.debug(this, "paint: " + event.widget); 
      } 
      // if (!shouldShowDecoration()) { 
      // return; 
      // } 
      final Rectangle rect = getDecorationRectangle((Control) event.widget); 
      if (Activator.getDefault().TRACE_CONTROL_DECORATIONS_VERBOSE) { 
       LogUtils.debug(this, "paint: " + event.widget + "/" + event.widget.hashCode() + ": rect=" + rect); 
      } 

      getDecoration().paint(event, rect); 
     } 

     /** 
     * Returns whether this decoration intersects with specified rectangle. 
     * 
     * @param eventArea the area to check 
     * @return <code>true</code> if the decoration is visible and the area intersects 
     */ 
     public boolean intersects(Rectangle eventArea) { 
      if (isDisposed) return false; 
      if (!getControl().isVisible()) return false; 
      final Rectangle area = getDecorationRectangle(null); 
      if (area == null) return false; 
      if (!area.intersects(eventArea)) return false; 

      return true; 
     } 

     @Override 
     public String toString() { 
      return getControl() + "@" + getControl().hashCode() + " " + getDecoration().getArea() + " area " 
        + getDecorationRectangle(null); 
     } 
    } 
} 
+0

私はこれ走っ:http://pastebin.com/MmN8jvPfをし、それがコンボボックスの上の正方形を示しませんでした。私はいくつかのバリエーションを試しましたが、どちらもしませんでした。 – mentics

+0

うーん...これらのウィジェットが構築されているため、 'CCombo'とおそらく' CTabFolder'に問題があります...今夜あなたのコードをテストします。 –

関連する問題