2011-07-27 26 views
5

Tôi hiểu để vẽ trên một Composite, bạn có thể thêm một người nghe sơn, nhưng điều đó dẫn đến việc vẽ theo trẻ em. Điều gì sẽ xảy ra nếu tôi muốn vượt qua đầu những đứa trẻ?Làm thế nào để vẽ các phần tử con của Composite trong SWT?

Sau đây vẽ một đường, nhưng biểu tượng con được vẽ trên nó.

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); 

Trả lời

4

Thật không may đây không phải là tính năng được triển khai, như bạn có thể thấy trong Bug#114749.

Bạn sẽ phải mã giải pháp tùy chỉnh của riêng mình (ví dụ: tính diện tích bản vẽ cho từng kết hợp bị ảnh hưởng và sau đó vẽ trên mỗi hình).

Lỗi khá cũ của nó, nhưng upvoting luôn luôn là một ý tưởng tốt nếu bạn nghĩ rằng đây là một "phải có".

4

Nó không phải là tất cả những gì khó khăn để giải quyết :-)

Bạn cần phải thêm SWT.Paint người nghe của bạn không chỉ đến Composite, mà còn cho tất cả các trẻ em chứa (đệ quy). Bí quyết là sau đó lập bản đồ tọa độ phù hợp cho mỗi điều khiển ...

Để minh họa, tôi đã đính kèm một số mã tôi sử dụng trong một số dự án. Và có, tôi biết rằng có những lớp học thiếu, nhưng bạn có thể có thể có được ý tưởng từ này.

/******************************************************************************* 
* 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

Tôi chạy này: http://pastebin.com/MmN8jvPf và nó không cho thấy hình vuông trên đầu trang của hộp combo. Tôi đã thử một vài biến thể và nó cũng vậy. – mentics

+0

Hmm ... Có vấn đề với 'CCombo' và có thể là' CTabFolder' do cách thức các công cụ này được xây dựng ... Tôi sẽ kiểm tra mã sau tối nay. –

Các vấn đề liên quan