简体   繁体   中英

Get the current titlebar and border size of my window and manipulate screenshot image

I am experimenting with Java and GUI manipulation and I have a custom dialog created from a jPanel imaginatively called DLog , which appears on request to collect user input. This works fine, but of course my dialog is not modal, which leaves the rest of the controls visible and accessible to the user while the dialog is open. Not good at all!

To overcome this I have a separate jPanel called DLogCover which sizes with the window but which is invisible until required. When the custom dialog is shown a screenshot of my window is taken and shown as an image in a label on the DLogCover , which appears beneath my custom dialog, but above everything else (On the MODAL_LAYER of a jLayeredPanel - the custom dialog appears on the POPUP_LAYER ). This works exactly as planned although there are two niggling points which I hope you may be able to help with.

Firstly the screenshot of course includes the title bar and left border of the window. I have taken this into account using arbitrary numbers which work for me right now, but of course this will be different on every OS because I use the system Look and feel and these sizes might be incorrect.

Question : Is there any way to make sure that my screenshot is only of the inner content of my window (or any way to always get the correct sizes for the title bar and borders of the window, regardless of OS)?

Secondly, while my screenshot works fine it is simply an image of the window, and I would like to have it slightly faded or blurred in order to make it appear that there is in fact something covering the controls.

Question : Is there any way to manipulate an image to give this appearance?

Here is the code I am using to capture the image and display it (before showing the custom dialog):

DLOGCover.setVisible(true);
Point pos = this.getLocationOnScreen();
Dimension dim = this.getSize();
//Arbitrary sizes! These need to be discovered and set correctly!
int xLoc = pos.x +1 ;
int yLoc = pos.y + 11;

try
{
    Robot robot = new Robot();
    Rectangle captureSize = new Rectangle(xLoc, yLoc, dim.width, dim.height);
    BufferedImage bImage = robot.createScreenCapture(captureSize);
    Image imgwork = (Image)bImage;
    ImageIcon labelimg = new ImageIcon(imgwork);
    imageLabel.setIcon(labelimg);
}
catch(AWTException e)
{
    System.err.println("Ouch!");
}
//... show the custom dialog

Many thanks for any help you can give, and as before, the reason I am doing things this way is because I am trying to learn Java so I am experimenting, and currently it is with this!

Many thanks for any help you can give, and of course I am open to suggestions about alternative methods for achieving the same thing.

Some Answers

Id like to add this information so that any others who come looking can find the it.

Thanks to Andrew Thompson's code (many thanks to nIcE cOw for the link) I can now get a screenshot of just my window contents, negating the need to try and work out titlebar and border sizes:

public static BufferedImage getScreenShot(Component component)
{

    BufferedImage image = new BufferedImage(
      component.getWidth(),
      component.getHeight(),
      BufferedImage.TYPE_INT_RGB
      );
    // call the Component's paint method, using
    // the Graphics object of the image.
    component.paint( image.getGraphics() );
    return image;
}

This is called when I open my custom dialog and I am then able to modify the image to darken and blur it a little then display it in a jLabel which exists on my custom DLogCover (which is just a jPanel and a jLabel for the image):

//get the screenshot
BufferedImage bufferedImage = getScreenShot( this.getContentPane() );

//blur and darken the image slightly
Kernel myKernel = new Kernel(3, 3,new float[] {1f/9f, 1f/9f, 1f/9f,1f/9f, 1f/9f, 1f/9f,1f/9f, 1f/9f, 1f/9f});
BufferedImageOp myOp1 = new ConvolveOp(myKernel);
bufferedImage = myOp1.filter(bufferedImage, null);
RescaleOp myOp2 = new RescaleOp(.6f, 0, null);
bufferedImage = myOp2.filter(bufferedImage, null);

//prepare the image to be shown in a `jLabel`
Image Conv1 = (Image)bufferedImage;
ImageIcon Conv2 = new ImageIcon(Conv1);
myLabel.setIcon(Conv2);

I then need to prevent mouse and key events from interacting with the controls on the main window, which are still accessible at the moment, even though they are hidden by the image. I am trying to do this with the following code, but this seems to block only the mouse events:

myLabel.addMouseListener(new MouseAdapter() {});
myLabel.addMouseMotionListener(new MouseMotionAdapter() {});
myLabel.addKeyListener(new KeyAdapter() {});

Iv tried various controls in place of the jLabel but with the same effect: The mouse is blocked but the keys are not. This is something of a problem because one of the main elements in the app is a jTextPane which absolutely must not be allowed to accept extraneous key inputs.

For simplicity at the moment I am turning the editable property on and off as required to prevent accidental typing into the text pane, but this is very much a workaround hack because at some point I might have keyboard accelerators assigned and I don't want them being activated by accident when the custom dialog is open.

If anyone has any further suggestions to prevent any keyboard events reaching the underlying controls while the custom dialog is open Id very much like to hear them.

regards

MVK

I'd highly recommend you take a look at the JXLayer project. It does exactly what you are asking.

Also, take a look at JHLabs-Filters at http://www.jhlabs.com/ip/filters/index.html .

If you're still hell bent, you could grab the size of the content pane and subtract that from the height of the main frame. This should (generally) give you the result you want.

You will need to do something like

Point pos = ((JComponent)frame.getContentPane()).getLocationOnScreen();
Point fPos = frame.getLocation();

This will allow you to calculate the offset of the content pane within the frame, from there you can make your adjustments.

Personally, I'd just look into JXLayer.

Shane

UPDATE:

Okay, the hard way. So you've got a capture of the screen. You will want to trim out the frame's border as I've suggest above.

Using JHLabs-Filters, you can blur the image as follows

GaussianFilter gf = new GaussianFilter(10);
imgBG = gf.filter(imgBG, null);

To accomplish the mouse event handler, you are going to want to use a "glass pane". This is simply a component you can lay over the top of the frame, attach a mouse listener (and key listener) to it and they should "consume" the events for you.

Lookup JFrame.getGlassPane(). Basically, you want add the component you are using to paint the background (and place the dialog on) to this (don't forget to make it visible).

This might help you in this area http://www.java2s.com/Code/Java/Swing-JFC/Showhowaglasspanecanbeusedtoblockmouseandkeyevents.htm

Hope that helps Shane

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM