/* * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This source code is provided to illustrate the usage of a given feature * or technique and has been deliberately simplified. Additional steps * required for a production-quality application, such as security checks, * input validation and proper error handling, might not be present in * this sample code. */ package transparentruler; import java.awt.*; import java.awt.GraphicsDevice.WindowTranslucency; import static java.awt.GraphicsDevice.WindowTranslucency.*; import java.awt.event.ActionEvent; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Path2D.Float; import java.lang.reflect.InvocationTargetException; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; /** * This sample demonstrates shaped and translucent window feature. * @author Alexander Kouznetsov */ @SuppressWarnings("serial") public class Ruler extends JFrame { private static final Color BACKGROUND = Color.RED; private static final Color FOREGROUND = Color.WHITE; private static final int OPACITY = 180; private static final int W = 70; private static final int F_HEIGHT = 400; private static final int F_WIDTH = (int) (F_HEIGHT * 1.618 + 0.5); private static boolean translucencySupported; private static boolean transparencySupported; private static boolean checkTranslucencyMode(WindowTranslucency arg) { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); return gd.isWindowTranslucencySupported(arg); } public Shape buildShape() { int h = getHeight(); int w = getWidth(); float a = (float) Math.hypot(h, w); Float path = new java.awt.geom.Path2D.Float(); path.moveTo(0, 0); path.lineTo(w, 0); path.lineTo(0, h); path.closePath(); path.moveTo(W, W); path.lineTo(W, h - W * (a + h) / w); path.lineTo(w - W * (a + w) / h, W); path.closePath(); return path; } private final ComponentAdapter componentListener = new ComponentAdapter() { /** * Applies the shape to window. It is recommended to apply shape in * componentResized() method */ @Override public void componentResized(ComponentEvent e) { // We do apply shape only if PERPIXEL_TRANSPARENT is supported if (transparencySupported) { setShape(buildShape()); } } }; private final Action exitAction = new AbstractAction("Exit") { { putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X); } @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }; private final JPopupMenu jPopupMenu = new JPopupMenu(); { jPopupMenu.add(new JMenuItem(exitAction)); } /** * Implements mouse-related behavior: window dragging and popup menu * invocation */ private final MouseAdapter mouseListener = new MouseAdapter() { int x, y; @Override public void mousePressed(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { x = e.getX(); y = e.getY(); } } @Override public void mouseDragged(MouseEvent e) { if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0) { setLocation(e.getXOnScreen() - x, e.getYOnScreen() - y); } } @Override public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) { jPopupMenu.show(getContentPane(), e.getX(), e.getY()); } } }; /** * Implements keyboard navigation. Arrows move by 5 pixels, Ctrl + arrows * move by 50 pixels, Alt + arrows move by 1 pixel. * Esc exits the application. */ private final KeyAdapter keyboardListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { int step = e.isControlDown() ? 50 : e.isAltDown() ? 1 : 5; switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: setLocation(getX() - step, getY()); break; case KeyEvent.VK_RIGHT: setLocation(getX() + step, getY()); break; case KeyEvent.VK_UP: setLocation(getX(), getY() - step); break; case KeyEvent.VK_DOWN: setLocation(getX(), getY() + step); break; case KeyEvent.VK_ESCAPE: exitAction.actionPerformed(null); } } }; public Ruler() { setUndecorated(true); // Enables perpixel translucency setBackground(new Color(BACKGROUND.getRed(), BACKGROUND.getGreen(), BACKGROUND.getBlue(), OPACITY)); addMouseListener(mouseListener); addMouseMotionListener(mouseListener); addComponentListener(componentListener); addKeyListener(keyboardListener); setContentPane(new JPanel() { @Override protected void paintComponent(Graphics g) { Graphics2D gg = (Graphics2D) g.create(); int w = getWidth(); int h = getHeight(); int hh = gg.getFontMetrics().getAscent(); // This is an approach to apply shape when PERPIXEL_TRANSPARENT // isn't supported if (!transparencySupported) { gg.setBackground(new Color(0, 0, 0, 0)); gg.clearRect(0, 0, w, h); gg.clip(buildShape()); gg.setBackground(Ruler.this.getBackground()); gg.clearRect(0, 0, w, h); } gg.setColor(FOREGROUND); for (int x = 0; x < w * (h - 8) / h - 5; x += 5) { boolean hi = x % 50 == 0; gg.drawLine(x + 5, 0, x + 5, hi ? 20 : (x % 25 == 0 ? 13 : 8)); if (hi) { String number = Integer.toString(x); int ww = gg.getFontMetrics().stringWidth(number); gg.drawString(number, x + 5 - ww / 2, 20 + hh); } } gg.dispose(); } }); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(F_WIDTH, F_HEIGHT); setLocationByPlatform(true); } /** * @param args the command line arguments are ignored */ public static void main(String[] args) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { translucencySupported = checkTranslucencyMode(PERPIXEL_TRANSLUCENT); transparencySupported = checkTranslucencyMode(PERPIXEL_TRANSPARENT); if (!translucencySupported) { System.err.println("This application requires " + "'PERPIXEL_TRANSLUCENT' translucency mode to " + "be supported."); System.exit(-1); } Ruler ruler = new Ruler(); ruler.setVisible(true); } }); } }