# Screenshot mit SWT



## tbo007 (20. Feb 2007)

Hallo, ich bin am verzweifeln. 

Ich bin Betreuer für eine Eclipse RCP App. Ein Nutzer hat sich jetzt eine Screenshot Funktion gewünscht.  
Folgendermaßen habe ich das implementiert ( Auszug): 
	
	
	
	





```
GC screenGC = new GC(shell); // shell ist das aktuelle Fenster
      
      Rectangle shellSize = shell.getBounds();
      screenshot = new Image(shell.getDisplay(), shellSize);
      screenGC.copyArea(screenshot, 0, 0);
      screenGC.dispose();
```

Das Image enthält aber nur das Fenster ohne Menubar, dafür aber mit Windows Taskleiste.

Wenn ich statt shell.getBounds() shellgetClientArea() mache habe ich logischerweise das "nackte" Fenster ohne Menubar und Taskleiste.

Wie kriege ich einen Shell Screenshot mit Menubar ohne Taskleiste, halt nur die Shell?

Ich habe bald keine Idee mehr, wie ich meinem Chef erklären kann, warum so eine läpsche Geschichte so lange dauert. 

Vielen Dank im Voraus


----------



## marwestermann (20. Feb 2007)

hi,

schick mir mal eine mail an MarWestermann@gmx.de. Ich schick dir dann was zurück, was dir sicherlich weiterhelfen kann.

Gruß mw


----------



## AlArenal (20. Feb 2007)

Streng geheime Sourcecodes?


----------



## marwestermann (20. Feb 2007)

nein eigendlich nicht.. 

entnommen aus dem Buch RichClientEntwicklung mit Eclipse 3.2

Das ist zwar eigendlich zum Drucken der Widgets gedacht, sollte sich aber auch für eine Hardcopy implementieren lassen:


```
private static class PrinterFonts extends HashMap<FontData, Font> {
		private Printer printer;

		/**
		 * Konstruktor
		 * 
		 * @param printer –
		 *            Drucker
		 */
		PrinterFonts(Printer printer) {
			super();
			this.printer = printer;
		}

		/**
		 * Liefert einen Druckerfont
		 * 
		 * @param data –
		 *            Fontdaten, für welche ein Font benötigt wird
		 * @return – Font
		 */
		Font getFont(FontData data) {
			Font font = get(data);
			if (font == null) {
				font = new Font(printer, data);
				put(data, font);
			}
			return font;
		}

		/**
		 * Entsorgt alle Fonts
		 */
		void dispose() {
			for (Font font : values())
				font.dispose();
		}
	}

	@SuppressWarnings("serial")
	/**
	 * Repositorium für Farben
	 */
	private static class PrinterColors extends HashMap<RGB, Color> {

		private Printer printer;

		/**
		 * Konstruktor
		 * 
		 * @param printer -
		 *            Drucker
		 */
		PrinterColors(Printer printer) {
			super();
			this.printer = printer;
		}

		/**
		 * Liefert eine Druckerfarbe
		 * 
		 * @param rgb -
		 *            RGB-Wert
		 * @return - Druckerfarbe
		 */
		Color getColor(RGB rgb) {
			Color color = get(rgb);
			if (color == null) {
				color = new Color(printer, rgb);
				put(rgb, color);
			}
			return color;
		}

		/**
		 * Entsorgt alle Farben
		 */
		void dispose() {
			for (Color color : values())
				color.dispose();
		}
	}

	private PrinterFonts printerFonts;

	private PrinterColors printerColors;

	/**
	 * Druckt ein Control-Element
	 * 
	 * @param control –
	 *            das zu druckende Element
	 * @param printer –
	 *            der Drucker
	 * @param marginX –
	 *            Abstand von der linken Kante in Zoll
	 * @param marginY –
	 *            Abstand von der Oberkante in Zoll
	 * @param borders –
	 *            true, wenn Umrahmungen gewünscht sind
	 * @param fill –
	 *            true, wenn Flächen ausgefüllt werden sollen
	 */
	public void print(Control control, Printer printer, float marginX,
			float marginY, boolean borders, boolean fill) {
		// Grafikkontext und Repositorien anfertigen
		GC gc = new GC(printer);
		printerFonts = new PrinterFonts(printer);
		printerColors = new PrinterColors(printer);
		// Druckerauflösung ermitteln
		Point dpi = printer.getDPI();
		// drucken
		print(control, gc, dpi, (int) (dpi.x * marginX),
				(int) (dpi.y * marginY), borders, fill);
		// Aufräumen
		printerColors.dispose();
		printerFonts.dispose();
		gc.dispose();
	}

	/**
	 * Druckt ein Widget mitsamt seiner Kindelemente
	 * 
	 * @param w –
	 *            das zu druckende Widget
	 * @param gc –
	 *            der grafische Kontext
	 * @param dpi –
	 *            Druckerauflösung
	 * @param offX –
	 *            X-Offset in Pixel
	 * @param offY –
	 *            Y-Offset in Pixel
	 * @param borders –
	 *            true, wenn Umrahmungen gewünscht sind
	 * @param fill –
	 *            true, wenn Flächen ausgefüllt werden sollen
	 */
	private void print(Widget w, GC gc, Point dpi, int offX, int offY,
			boolean borders, boolean fill) {
		// Das Widget ausdrucken
		Rectangle printBounds = null;
		if (w instanceof Control)
			printBounds = printControl((Control) w, gc, dpi, offX, offY,
					borders, fill);
		else if (w instanceof TreeItem) {
			TreeItem item = (TreeItem) w;
			printBounds = printItem(item, gc, dpi, offX, offY, fill);
		} else if (w instanceof TableItem) {
			TableItem item = (TableItem) w;
			printItem(item, gc, dpi, offX, offY, fill);
		}
		// Die Kindelemente ausdrucken
		if (printBounds != null) {
			if (w instanceof TreeItem) {
				TreeItem item = (TreeItem) w;
				for (TreeItem child : item.getItems()) {
					print(child, gc, dpi, printBounds.x, printBounds.y,
							borders, fill);
				}
			} else {
				Rectangle oldClip = gc.getClipping();
				gc.setClipping(printBounds.x, printBounds.y, printBounds.width,
						printBounds.height);
				if (w instanceof Tree) {
					gc.setClipping(printBounds.x, printBounds.y,
							printBounds.width, printBounds.height);
					Tree tree = (Tree) w;
					for (TreeItem child : tree.getItems()) {
						print(child, gc, dpi, printBounds.x, printBounds.y,
								borders, fill);
					}
				} else if (w instanceof Table) {
					Table table = (Table) w;
					for (TableItem child : table.getItems()) {
						print(child, gc, dpi, printBounds.x, printBounds.y,
								borders, fill);
					}
				} else if (w instanceof Composite) {
					gc.setClipping(printBounds.x, printBounds.y,
							printBounds.width, printBounds.height);
					Composite composite = (Composite) w;
					for (Control child : composite.getChildren()) {
						print(child, gc, dpi, printBounds.x, printBounds.y,
								borders, fill);
					}
				}
				gc.setClipping(oldClip);
			}
		}
	}

	/**
	 * Druckt ein TableItem
	 * 
	 * @param item –
	 *            das zu druckende TableItem
	 * @param gc –
	 *            der grafische Kontext
	 * @param dpi –
	 *            Druckerauflösung
	 * @param offX –
	 *            X-Offset in Pixel
	 * @param offY –
	 *            Y-Offset in Pixel
	 * @param fill –
	 *            true, wenn Flächen ausgefüllt werden sollen
	 */
	private void printItem(TableItem item, GC gc, Point dpi, int offX,
			int offY, boolean fill) {
		int columns = Math.max(1, item.getParent().getColumnCount());
		for (int i = 0; i < columns; i++) {
			// Umrandung und Ausfüllen
			Rectangle printBounds = renderArea(item.getDisplay(), gc, offX,
					offY, dpi, item.getBounds(i), null, (fill) ? item
							.getBackground() : null);
			// Text
			printText(gc, item.getText(), printBounds, item.getFont(), item
					.getForeground(), false);
		}
	}

	/**
	 * Druckt ein TreeItem
	 * 
	 * @param item –
	 *            das zu druckende TreeItem
	 * @param gc –
	 *            der grafische Kontext
	 * @param dpi –
	 *            Druckerauflösung
	 * @param offX –
	 *            X-Offset in Pixel
	 * @param offY –
	 *            Y-Offset in Pixel
	 * @param fill –
	 *            true, wenn Flächen ausgefüllt werden sollen
	 * @return -Druckbereich des Widgets
	 */
	private Rectangle printItem(TreeItem item, GC gc, Point dpi, int offX,
			int offY, boolean fill) {
		int columns = Math.max(1, item.getParent().getColumnCount());
		Rectangle printBounds = null;
		for (int i = 0; i < columns; i++) {
			// Umrandung und Ausfüllen
			Rectangle bounds = renderArea(item.getDisplay(), gc, offX, offY,
					dpi, item.getBounds(), null, (fill) ? item.getBackground()
							: null);
			if (printBounds == null)
				printBounds = bounds;
			// Text
			printText(gc, item.getText(), bounds, item.getFont(), item
					.getForeground(), false);
		}
		return printBounds;
	}

	/**
	 * Druckt ein Control-Element
	 * 
	 * @param control –
	 *            das zu druckende Control-Element
	 * @param gc –
	 *            der grafische Kontext
	 * @param dpi –
	 *            Druckerauflösung
	 * @param offX –
	 *            X-Offset in Pixel
	 * @param offY –
	 *            Y-Offset in Pixel
	 * @param borders –
	 *            true, wenn Umrahmungen gewünscht sind
	 * @param fill –
	 *            true, wenn Flächen ausgefüllt werden sollen
	 * @return -Druckbereich des Widgets
	 */
	private Rectangle printControl(Control control, GC gc, Point dpi, int offX,
			int offY, boolean borders, boolean fill) {
		if (!control.isVisible())
			return null;
		// Umrandung und Ausfüllen
		Display display = control.getDisplay();
		Rectangle printBounds = renderArea(display, gc, offX, offY, dpi,
				control.getBounds(),
				(borders && hasBorder(control)) ? getColors().getColor(
						FormColors.BORDER) : display
						.getSystemColor(SWT.COLOR_WHITE), (fill) ? control
						.getBackground() : null);
		// Text – ExpandableComposites replizieren den Text in einem
		// Kindelement; wir verhindern den doppelten Ausdruck
		if (!(control instanceof ExpandableComposite)) {
			// Per Java-Reflection
			Class<? extends Control> clazz = control.getClass();
			try {
				Method m = clazz.getMethod("getText", (Class[]) null);
				String text = (String) m.invoke(control, (Object[]) null);
				printText(gc, text, printBounds, control.getFont(), control
						.getForeground(), (control.getStyle() & SWT.WRAP) != 0);
			} catch (Exception e) {
			}
		}
		return printBounds;
	}

	/**
	 * Druckt den Widget-Text
	 * 
	 * @param gc –
	 *            der grafische Kontext
	 * @param text –
	 *            Text
	 * @param bounds –
	 *            Druckbereich
	 * @param font –
	 *            Display-Font
	 * @param color –
	 *            Display-Farbe
	 * @param wrap –
	 *            true, wenn Text umgebrochen werden soll
	 */
	private void printText(GC gc, String text, Rectangle bounds, Font font,
			Color color, boolean wrap) {
		Rectangle oldClip = gc.getClipping();
		gc.setClipping(bounds);
		text = text.trim();
		if (text != null && text.length() > 0) {
			gc.setForeground(printerColors.getColor(color.getRGB()));
			gc.setFont(printerFonts.getFont(font.getFontData()[0]));
			Point extent = gc.textExtent(text);
			if (extent.x <= bounds.width || !wrap)
				gc.drawText(text, bounds.x, bounds.y, true);
			else {
				int ty = 0;
				while (true) {
					int wordBreak = -1;
					boolean whiteSpace = false;
					for (int i = 0; i < text.length(); i++) {
						char c = text.charAt(i);
						if (Character.isWhitespace(c)) {
							if (!whiteSpace) {
								wordBreak = i;
								whiteSpace = true;
							}
							if (c == '\n')
								break;
						} else
							whiteSpace = false;
						if (gc.textExtent(text.substring(0, i)).x > bounds.width) {
							if (wordBreak < 0)
								wordBreak = i;
							break;
						}
					}
					if (wordBreak < 0) {
						gc.drawText(text, bounds.x, bounds.y + ty, true);
						break;
					}
					gc.drawText(text.substring(0, wordBreak), bounds.x,
							bounds.y + ty, true);
					text = text.substring(wordBreak).trim();
					ty += gc.getFontMetrics().getHeight();
					if (ty > bounds.height)
						break;
				}
			}
		}
		gc.setClipping(oldClip);
	}

	/**
	 * Umrahmungen und Füllungen
	 * 
	 * @param display –
	 *            die Display-Instanz
	 * @param gc –
	 *            der grafische Kontext
	 * @param offX –
	 *            X-Offset in Pixeln
	 * @param offY –
	 *            Y-Offset in Pixeln
	 * @param dpi –
	 *            Druckerauflösung
	 * @param bounds –
	 *            zu füllender/umrahmender Bereich
	 * @param borderColor –
	 *            Rahmenfarbe oder null
	 * @param fillColor –
	 *            Füllfarbe oder null
	 * @return – der Druckbereich des Widgets
	 */
	private Rectangle renderArea(Display display, GC gc, int offX, int offY,
			Point dpi, Rectangle bounds, Color borderColor, Color fillColor) {
		// Bildschirmauflösung ermitteln
		Point screenDPI = display.getDPI();
		// Positionen umrechnen
		int x = offX + bounds.x * dpi.x / screenDPI.x;
		int y = offY + bounds.y * dpi.y / screenDPI.y;
		int width = bounds.width * dpi.x / screenDPI.x;
		int height = bounds.height * dpi.y / screenDPI.y;
		// Bereich füllen
		if (fillColor != null) {
			gc.setBackground(printerColors.getColor(fillColor.getRGB()));
			gc.fillRectangle(x, y, width, height);
		}
		// Bereich umrahmen
		if (borderColor != null) {
			gc.setForeground(printerColors.getColor(borderColor.getRGB()));
			int pixX = dpi.x / screenDPI.x;
			int pixY = dpi.y / screenDPI.y;
			gc.drawRectangle(x - pixX, y - pixY, width + pixX, height + pixY);
		}
		// Anfangsposition zurückgeben
		return new Rectangle(x, y, width, height);
	}

	/**
	 * Ermittelt, ob eine Umrahmung gezeichnet werden soll
	 * 
	 * @param c –
	 *            das Control-Element
	 * @return – true, wenn das Element eine Umrahmung hat
	 */
	public boolean hasBorder(Control c) {
		boolean inactiveBorder = false;
		boolean textBorder = false;
		if (c.getEnabled() == false && !(c instanceof CCombo))
			return false;
		if ((c.getStyle() & SWT.BORDER) != 0)
			return true;
		if (c instanceof Hyperlink)
			return false;
		Object flag = c.getData(KEY_DRAW_BORDER);
		if (flag != null) {
			if (flag.equals(Boolean.FALSE))
				return false;
			if (flag.equals(TREE_BORDER))
				inactiveBorder = true;
			else if (flag.equals(TEXT_BORDER))
				textBorder = true;
		}
		if (getBorderStyle() == SWT.BORDER) {
			if (!inactiveBorder && !textBorder)
				return false;
			if (c instanceof Text || c instanceof Table || c instanceof Tree)
				return false;
		}
		if (!inactiveBorder
				&& (c instanceof Text || c instanceof CCombo || textBorder))
			return true;
		if (inactiveBorder || c instanceof Table || c instanceof Tree)
			return true;
		return false;
	}
```

Gruß mw


----------



## tbo007 (20. Feb 2007)

Hi danke, werde ich mir morgen auf der Schaffe mal durchlesen und probieren


----------



## tbo007 (21. Feb 2007)

Hilft mir leider nicht, da dadurch mein Problem nicht gelöst wird, dass die Menubar nicht mitgedruckt wird. Trotzdem Danke und hat einer noch eine andere Idee?

Ich hatte auch mal ausprobiert einen Screenshot vom Display zu machen und dann den Bereich der Shell auszuschneiden, allerdings führt das zu Problemen, wenn das Bild maximiert (Windows) wird oder wenn eine Ecke der Shell nicht auf dem Monitor zu sehen ist.


----------

