Here is my code:
package trialruns;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TransparentFrame extends JFrame
{
JButton b1;
public TransparentFrame()
{
setTitle("Transparent Frame Demo");
setSize(400,400);
setLayout(new GridBagLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUndecorated(true);
setVisible(true);
setResizable(true);
setOpacity(0.4f);
}
public static void main(String args[])
{
new TransparentFrame();
}
}
The problem is if I setOpacity<1.0 i get an error :
The frame is decorated at java.awt.Frame.setOpacity(Frame.java:960)
And if I make do setUndecorated(true) then I cant resize the Jframe
I need to be able to resize a transparent JFrame
I also need to be able to access the folders under the transparent frame
I mean if the transparent window is sitting on the desktop and I want to open a particular folder placed under the window then I should be able to do so without the jframe getting minimized.
Is there any way to do this??
I searched online but couldn't find a suitable solution.
Resizing of the frame is handled by the frame itself. When you remove the Border decorations you lose the resizing functionality.
So, you need to manage the resizing of the frame yourself. Check out Component Resizer for a class that will allow you to resize any component.
The change to your code would be:
//setResizable(true); // not needed as this is the default anyway
setOpacity(0.4f);
new ComponentResizer( this );
But is it possible to keep the border opaque
Yes, but you will only get the Swing decorated Border, not the platform Border and decorations:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TransparentFrame2 extends JFrame
{
public TransparentFrame2()
{
setTitle("Transparent Frame Demo");
setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
setBackground( new Color(0, 0, 0, 0) );
setSize(400,400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String args[])
{
new TransparentFrame2();
}
}
Also it is still not possible to access the content behind the frame
Yes, but you need full transparency. If you don't use full transparency then the mouse event is passed to the frame, not the component underneath the frame.
If you what semi transparency then theoretically you could add a MouseListener to the frame to intercept the MouseEvent. Then you can make your frame invisible. Then you could use a Robot to generate a new MouseEvent which will now be dispatched to the screen. You would next to use the frames locationOnScreen(...) method to convert the mouse point from the frames coordinates. I have never tried this approach.
try this.. working for me..
import java.awt.*;
import static java.awt.GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT;
import javax.swing.*;
class TransparentFrame extends JFrame {
JButton b1;
public TransparentFrame() {
setTitle("Transparent Frame Demo");
setSize(400, 400);
setAlwaysOnTop(true);
setLayout(new GridBagLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
setResizable(true);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if (g instanceof Graphics2D) {
final int R = 255;
final int G = 255;
final int B = 255;
Paint p =
new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0),
0.0f, getHeight(), new Color(R, G, B, 0), true);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
};
setContentPane(panel);
JButton button = new JButton("Button");
setBackground(new Color(0,0,0,0));
panel.add(button);
}
public static void main(String args[]) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
boolean isPerPixelTranslucencySupported = gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
//If translucent windows aren't supported, exit.
if (!isPerPixelTranslucencySupported) {
System.err.println("PerPixel Translucency is not supported");
System.exit(0);
}
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TransparentFrame tw = new TransparentFrame();
tw.setVisible(true);
}
});
}
}
referenced from this
Related
The goal here is to use jlabels with an image icon that contains a BufferedImage. Those jlabels can then be easily moved around with the mouse without having to go searching a ton of different BufferedImages on the screen to find out which one is being clicked on.
This is easy to do in a standard JFrame. I've been searching around here for an hour trying to figure out how to implement this in a game loop where a paintComponent is overridden.
import javax.swing.*;
import java.awt.*;
public class Main {
public Main() {
}
public static void main(String[] args) {
JFrame window = new JFrame();
GamePanel gamePanel = new GamePanel();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(true);
window.setLayout(new FlowLayout());
window.setTitle("FX Test");
window.add(gamePanel);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
gamePanel.startGameThread();
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class GamePanel extends JPanel implements ActionListener {
private Timer gameLoopTimer;
public int screenWidthPixels = 640;
public int screenHeightPixels = 480;
private int counter;
private int x = 1;
private float alpha = 1;
private final int DELAY = 15;
private final int INITIAL_DELAY = 200;
public GamePanel() {
this.setPreferredSize(new Dimension(screenWidthPixels, screenHeightPixels));
this.setBackground(Color.black);
this.setDoubleBuffered(true);
this.setFocusable(true);
this.requestFocus();
counter = 0;
JButton testButton = new JButton("Button Test");
this.add(testButton);
JLabel label = new JLabel(new String("Label test"));
label.setVisible(true); // Doesn't seem to be needed.
this.add(label);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.drawString("Game Panel Testing: " + counter,128,129);
g2.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
update();
}
void startGameThread() {
gameLoopTimer = new Timer(DELAY,this);
gameLoopTimer.setInitialDelay(INITIAL_DELAY);
gameLoopTimer.start();
}
}
That code draws "Game Panel Testing: " and the incrementing counter, but no button and no label.
If I comment out the entire paintComponent I'm overriding, the button and label appear as expected.
What I can't wrap my head around is how to get the label and button to appear again once paintComponent is overridden. I thought the super.paintComponent(g) would take care of that automatically, but clearly I'm missing something here. How on earth can I add a bunch of JLabels to this game loop instead of having to manually handle moving of g2 drawn BufferedImages on mouse drag?
The jlabels are not drawn since you have overridden the paintComponent method.
The call to super is on the super class, so you have misunderstood how that call works.
If you put your in a class that inherits from your class with jlabels it will work.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.setSize(new Dimension(100, 100));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel panel = new TestPanel();
panel.setPreferredSize(new Dimension(50,50));
frame.add(panel);
frame.setVisible(true);
}
static class TestPanel extends JPanel implements ActionListener{
private static final long serialVersionUID = 8518959671689548069L;
public TestPanel() {
super();
Timer t = new Timer(1000, this);
t.setRepeats(true);
t.start();
}
int opacity = 10;
#Override
public void actionPerformed(ActionEvent e) {
if(opacity >= 250) {
opacity = 0;
}
else {
this.setBackground(new Color(255, 212, 100, opacity));
this.repaint();
opacity+=10;
System.out.println("opacity is " + opacity);
}
}
}
}
The rate the alpha changes is faster than it should be. After it reaches a certain point, the opacity drops, while the the opacity printed in the console is less than 250. Resizing the window "resets" it, making the alpha correct.
How do I make it actually draw the alpha correctly?
this.setBackground(new Color(255, 212, 100, opacity));
Swing does not support semi transparent backgrounds.
Swing expects a component to be either:
opaque - which implies the component will repaint the entire background with an opaque color first before doing custom painting, or
fully transparent - in which case Swing will first paint the background of the first opaque parent component before doing custom painting.
The setOpaque(...) method is used to control the opaque property of a component.
In either case this makes sure any painting artifacts are removed and custom painting can be done properly.
If you want to use tranparency, then you need to do custom painting yourself to make sure the background is cleared.
The custom painting for the panel would be:
JPanel panel = new JPanel()
{
protected void paintComponent(Graphics g)
{
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
panel.setOpaque(false); // background of parent will be painted first
Similar code would be required for every component that uses transparency.
Or, you can check out Background With Transparency for custom class that can be used on any component that will do the above work for you.
Why doesn't JPanel (panel) get drawn on the green background (the jpanel)? I want to be able to do this without extending j panel to...
Furthermore, for java games should i use keybindings or keylistener in java.
import javax.swing.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class Game {
JFrame window;
JPanel panel;
int charPosX = 0;
int charPosY = 0;
public Boolean createGui() {
window = new JFrame("Game");
window.setSize(1000,500);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
panel = new JPanel();
panel.setVisible(true);
panel.setLayout(null);;
panel.setBackground(new Color(65,130,92));
window.add(panel);
return true; //returns true if ran and will be ran by check status in Main.
}
public void paintComponent(Graphics g) {
panel.paintComponents(g);
g.setColor(Color.RED);
g.drawRect(100,10,30,40);
g.fillRect(10, 10, 20, 10);
}
}
Let's take your code for a second and add #Override to your paintComponent method...
public class Game {
//...
#Override
public void paintComponent(Graphics g) {
panel.paintComponents(g);
g.setColor(Color.RED);
g.drawRect(100, 10, 30, 40);
g.fillRect(10, 10, 20, 10);
}
}
And now we have a compiler error! This is because Game extends Object and does not have a paintComponent method. This means that there is no way that the method could be called by any part of the existing painting system, so, it never gets called.
Components make poor "game" entities, they have a lot of "plumbing" which doesn't make them very efficient for this kind of work, you're generally better off heading down a complete custom painting route
import javax.swing.*;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Game {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game().createGui();
}
});
}
JFrame window;
GamePanel panel;
int charPosX = 0;
int charPosY = 0;
public Boolean createGui() {
window = new JFrame("Game");
window.setSize(1000, 500);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new GamePanel();
panel.setBackground(new Color(65, 130, 92));
window.add(panel);
window.setVisible(true);
return true; //returns true if ran and will be ran by check status in Main.
}
public class GamePanel extends JPanel {
private Rectangle entity = new Rectangle(100, 10, 30, 40);
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
g2d.draw(entity);
g2d.setColor(Color.BLUE);
g2d.fill(entity);
g2d.dispose();
}
}
}
Also note, I called window.setVisible(true); only after I had added the panel to the window, this is because Swing is lazy when it comes to adding/removing components. If you want to add/remove components after the UI has been realized on the screen, you'll need to call revalidate and repaint on the container to trigger a layout and paint pass
Also, beware, there is a difference between paintComponent and paintComponents ;)
I would highly recommend having a look at Painting in AWT Swing and Performing Custom Painting to gain a better understanding of how painting works in Swing and how you can take advantage of it
I was wondering how you would get the color of the inset of a JTabbedPane. I cannot seem to get this color. Every attempt I make I get 236,236,236 which is the outside frame color, where the inside frame color is about 10 darker, 227,227,227 (using the built in apple color meter).
I am setting the look and feel using UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
You can see this in an image that I found on the internet. http://pagesofinterest.net/wordpress/wp-content/uploads/2009/06/Quaqua-Maven-Netbeans.jpg Where the words "Panel's Title" is the area that I am getting the lighter color that is not useful to me. Inside the round corners is the darker color I am trying to obtain. I tried getting the color of the content pane to no avail.
Thanks for all your help!
**EDIT:**Added code! As you see, I am trying to get the color of the area inside the rounded corners(if your on a mac) not the color of the frame or the tabs that say "1" "2". I have attached a photo and I am trying to get the background color of the portion that says "Here" Thanks!
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
public class main {
JFrame frame;
Container c1 = new Container();
Container c2 = new Container();
JTabbedPane top = new JTabbedPane();
static main GUI;
public void createGUI(){
frame = new JFrame();
Container c = frame.getContentPane();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.setFocusTraversalKeysEnabled(false);
top.setFocusable(false);
top.addTab("1", c1);
top.addTab("2", c2);
frame.setSize(315,450);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(true);
c.add(top);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {}
GUI = new main();
GUI.createGUI();
}
}
EDIT: camickr, Here is a screenshot of the UIManager Defaults. Unfortunately none of there colors in the are the correct color that the inset is.
You might be able to use UIMangaer Defaults to find the color.
You can override paintComponent() to use a GradientPaint in the tab's background, as shown below. A few notes,
Let the content adopt the preferred size of it contents, as shown here.
Construct the GUI in the event dispatch thread.
Use conventional Java names.
Addendum: the elements are not always in the same spot, so I do not know what place to get the color.
It sounds like you want to match a color used internally by the TabbedPaneUI delegate. One approach would be as follows:
Render a BufferedImage of the component, as shown here.
Determine the coordinates of a Point in top relative to the top of c1.
Point p = SwingUtilities.convertPoint(c1, 0, -1, top);
Obtain the color using getRGB(), as shown here; use Zoom to verify the result.
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/a/16625260/230513 */
public class Main {
JFrame frame;
Container c1 = new GradientPanel();
Container c2 = new GradientPanel();
JTabbedPane top = new JTabbedPane();
private static class GradientPanel extends JPanel {
public GradientPanel() {
this.add(new JLabel("Here"));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
GradientPaint p = new GradientPaint(0, 0, Color.white,
getWidth(), getHeight(), Color.gray);
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
}
public void createGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
top = new JTabbedPane(JTabbedPane.TOP);
top.addTab("1", c1);
top.addTab("2", c2);
frame.add(top);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main().createGUI();
}
});
}
}
import javax.swing.JFrame;
import javax.swing.JTextField;
import com.sun.awt.AWTUtilities;
#SuppressWarnings("serial")
public class TranslucentIssueTest extends JFrame
{
public static void main(String[] args)
{
(new TranslucentIssueTest()).setVisible(true);
}
public TranslucentIssueTest()
{
super();
setUndecorated(true);
setLayout(null);
setSize(300, 300);
AWTUtilities.setWindowOpaque(this, false);
JTextField box = new JTextField();
box.setBounds(30, 150, 100, 25);
add(box);
}
}
The code above creates a textfield on transparent frame.
But when I typed some Chinese characters into the box using an input method, transparent effect was removed automatically. Is there anything wrong with my code?
Thanks in advance.
I ran into what appears to be the same issue and thought I'd post my solution for anyone who finds this question while searching. The problem seems to be due to a bug in the DirectDraw pipeline in Swing. I'm using an older version of Java 7 (update 5), so it's possible that this has been fixed in one of the later releases.
The problem doesn't seem to be with the IME specifically, but rather with the rendering calls that get made by the text field while the IME is active.
The simplest way to work around the problem is to just disable DirectDraw rendering by making the following call before any GUI code is run:
System.setProperty("sun.java2d.noddraw", "true");
If you'd rather not disable DirectDraw rendering entirely, you can work around the specific JTextField issue by overriding its paintComponent method to write to a buffer as in the example below.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class Test {
public static class JTextField2 extends JTextField {
private static final long serialVersionUID = 1L;
private BufferedImage buffer = null;
#Override public void paintComponent(Graphics g) {
Component window = this.getTopLevelAncestor();
if (window instanceof Window && !((Window)window).isOpaque()) {
// This is a translucent window, so we need to draw to a buffer
// first to work around a bug in the DirectDraw rendering in Swing.
int w = this.getWidth();
int h = this.getHeight();
if (buffer == null || buffer.getWidth() != w || buffer.getHeight() != h) {
// Create a new buffer based on the current size.
GraphicsConfiguration gc = this.getGraphicsConfiguration();
buffer = gc.createCompatibleImage(w, h, BufferedImage.TRANSLUCENT);
}
// Use the super class's paintComponent implementation to draw to
// the buffer, then write that buffer to the original Graphics object.
Graphics bufferGraphics = buffer.createGraphics();
try {
super.paintComponent(bufferGraphics);
} finally {
bufferGraphics.dispose();
}
g.drawImage(buffer, 0, 0, w, h, 0, 0, w, h, null);
} else {
// This is not a translucent window, so we can call the super class
// implementation directly.
super.paintComponent(g);
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
final JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setBackground(new Color(96, 128, 160, 192));
JTextField textField = new JTextField2();
JButton exitButton = new JButton("Exit");
exitButton.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
frame.dispose();
}
});
frame.add(exitButton, BorderLayout.PAGE_START);
frame.add(textField, BorderLayout.PAGE_END);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}