SWT How to print contents of a scrolledComposite?

2019-08-04 09:43发布

问题:

Does anyone know how I would print the contents of a scrolled composite?

Whenver I print onto a GC it will only copy the currently viewable area of the scrolled composite. What I want is to be able to copy the entire contents of the scrolled composite.

For instance, the code below makes a huge button, inside of a little window. Whenver I print the gc below, it only will output the small viewable area of the scrolled composite. Is it possible to print everything in the scrolled composite?

Shell shell = new Shell(getDisplay());
shell.setLayout(new FillLayout());
shell.setSize(200, 200);
shell.setLocation(20, 20);


ScrolledComposite sc = new ScrolledComposite(shell, SWT.H_SCROLL| SWT.V_SCROLL);
sc.setMinSize(availWidth, availHeight + 30);

Button b = new Button(sc, SWT.PUSH);
b.setText("Button");
b.setSize(availWidth, availHeight);
sc.setContent(b);

Image image = new Image(getDisplay(), availWidth, availHeight);
GC imageGC = new GC(image);
sc.print(imageGC);

回答1:

Note >>>

See @CryptDemon comments below. Though the solution is known to work on Windows 7 and with eclipse 3.7.x release.


Yes it is possible. The problem you are facing is due the way Windows paint events are generated (I am assuming Windows OS because I only have that !!) for a scrolling window.

At any given moment (as per your code) the visible size of your scrolled composite is less than the actual size. Now when you call print() on your scrolled composite then only a part of that (which is at that moment is available/visible) gets printed. Like this:

The solution is to create a fixed Composite inside your scrolled composite and call print on that.

Code:

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Scrolled 
{
    public static void main(String[] args)
    {
        final Display display = new Display();

        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        shell.setSize(200, 200);
        shell.setLocation(20, 20);

        final ScrolledComposite sc = new ScrolledComposite(shell, SWT.BORDER  | SWT.V_SCROLL | SWT.H_SCROLL);
        sc.setLayout(new GridLayout(1,true));

        final Composite innerComposite = new Composite(sc, SWT.NONE);
        innerComposite.setSize(400, 400);
        innerComposite.setLayout(new GridLayout(1, true));

        for(int i = 0; i < 10; i++)
        {
                Button b = new Button(innerComposite, SWT.PUSH);
                b.setText("Text");
                b.addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) 
                    {
                        Image image = new Image(display, innerComposite.getBounds().width, innerComposite.getBounds().height);
                        ImageLoader loader = new ImageLoader();

                        GC gc = new GC(image);
                        sc.print(gc);
                        gc.dispose();

                        loader.data = new ImageData[]{image.getImageData()};
                        loader.save("c:/temp/out.png", SWT.IMAGE_PNG);
                    }
                });
        }

        sc.setMinSize(innerComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
        sc.setContent(innerComposite);
        sc.setExpandHorizontal(true);
        sc.setExpandVertical(true);


        shell.open();
        while (!shell.isDisposed()) {
                if (!display.readAndDispatch())
                        display.sleep();
        }
        display.dispose();
    }
}

Output:



回答2:

SWT(GTK3 seems fix this bug), however in our project we intend to keep using SWT(GTK2), our solution is to create a temp shell and reparent contronl to temp shell

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Scrolled {
    public static void main(String[] args) {
        final Display display = new Display();

        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        shell.setSize(200, 200);
        shell.setLocation(20, 20);

        final ScrolledComposite sc = new ScrolledComposite(shell, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
        sc.setLayout(new GridLayout(1, true));

        final Composite innerComposite = new Composite(sc, SWT.NONE);
        innerComposite.setSize(400, 400);
        innerComposite.setLayout(new GridLayout(1, true));

        for (int i = 0; i < 10; i++) {
            Button b = new Button(innerComposite, SWT.PUSH);
            b.setText("Text");
            b.addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    Image image = new Image(display, innerComposite.getBounds().width,
                            innerComposite.getBounds().height);
                    ImageLoader loader = new ImageLoader();

                    GC gc = new GC(image);

                    // Create a temp shell and reparent it+
                    Shell newShell = new Shell(shell);
                    newShell.setLayout(new FillLayout());
                    Composite oldParent = sc.getParent();
                    oldParent.setRedraw(false);
                    sc.setParent(newShell);
                    newShell.open();
                    sc.print(gc);
                    sc.setParent(oldParent);
                    oldParent.setRedraw(true);

                    gc.dispose();
                    newShell.dispose();

                    loader.data = new ImageData[] { image.getImageData() };
                    loader.save("./out.png", SWT.IMAGE_PNG);
                }
            });
        }

        sc.setMinSize(innerComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
        sc.setContent(innerComposite);
        sc.setExpandHorizontal(true);
        sc.setExpandVertical(true);

        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
}