I wan't to make my main JFrame become darken when the focus is on another window.
This is an example from the game Football Manager 2012. First the main window is selected and it looks like it should, then when it is loading, it turns darker and unselectable. I wan't to have this effects on my own application, but im not really sure how, not even sure what to google?
Im guessing its a JWindow that appears and the JFram becomes unselectable in the background. I'm planing to use it on a help-window in my application, that is a JWindow right now.
Andrew Thompson has the right idea, only it's easier to use the glass pane feature of your frame's JRootPane. Here's some working code: In your frame class, invoke
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
Then, to show the "curtain", invoke
getRootPane().getGlassPane().setVisible(true);
In the code above, change the alpha transparency value of 100 in order to find the suitable darkness.
..wan't the JFrame to go back to normal after the new window is closed. I tried setVisible(false) but it didn't work.
It works in this example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ShadowedFrame extends JFrame {
ShadowedFrame() {
super("Shadowed Frame");
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
JButton popDialog = new JButton("Block Frame");
popDialog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
getRootPane().getGlassPane().setVisible(true);
JOptionPane.showMessageDialog(ShadowedFrame.this, "Shady!");
getRootPane().getGlassPane().setVisible(false);
}
});
setContentPane(popDialog);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
setSize(350,180);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ShadowedFrame().setVisible(true);
}
});
}
}
(Untested, but..) Seems like a good task for a JLayeredPane. Create a JComponent that is set transparent and add that to the top level of the layered pane. In the paintComponent(Graphics) method of the component, set a semi-transparent color and fill the full area with it. In normal use (non-dimmed), call customComponent.setVisible(false).
Update
Or, as Ingo pointed out, use the glass pane.
I'm guessing its a JWindow that appears and the JFrame becomes unselectable in the background
It is more likely a modal JDialog. When a modal dialog is visible, the frame/window that is the owner becomes inaccessible (cannot be clicked on).
Related
I have the following program. It is supposed to print red text on a green ground. When the program opens, I only see the green background but not the red text on it. Once the window is resized and by this recalculated, the red text appears.
It works properly if I use a JPanel within the window and add a component there. If the colors are set in paintComponent then, everything works fine.
So where is the problem, if I draw on the JFrame directly. Am I missing a first "update" or something? It looks like there is some information missing on first draw of the window (the additional text) of which the program only becomes aware once the window is recalculated and redrawn.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class PaintAWT extends JFrame {
PaintAWT() {
this.setSize(600, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
// Set background color:
// If you don't paint the background, one can see the red text.
// If I use setBackground I only see a green window, until it is
// resized, then the red text appears on green ground
this.getContentPane().setBackground(new Color(0,255,0));
// Set color of text
g.setColor(new Color(255,0,0));
// Paint string
g.drawString("Test", 50, 50);
}
public static void main(String[] args) {
new PaintAWT();
}
}
You should NOT be setting properties of a component in a painting method. Painting methods are for painting only. Don't use setBackground().
You should be setting the background of the content pane when you create the frame.
Whenever you do custom painting you should also be overriding the getPreferredSize() method to return the size of the component.
You should also not be extending JFrame. You only extend a class when you add functionality to the class.
Start by reading the section from the Swing tutorial on Custom Painting fore more information and working examples. The examples will show you how to better structure your code to follow Swing conventions.
You should move setBackground to constructor. Setting of background in paint method is a bad approach.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class PaintAWT extends JFrame {
PaintAWT() {
this.setSize(600, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set background color:
// If you don't paint the background, one can see the red text.
// If I use setBackground I only see a green window, until it is
// resized, then the red text appears on green ground
this.getContentPane().setBackground(new Color(0,255,0));
this.setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
// Set color of text
g.setColor(new Color(255,0,0));
// Paint string
g.drawString("Test", 50, 50);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PaintAWT();
}
});
}
}
Searching stackoverflow for the answer to this question only led me to other questions asking how to accomplish transparency on one or the other, none that came up had the issue of transparency functioning on one, but not the other.
I'm sure by now you've been able to figure out the issue, but i'll explain in a little more depth... A friend and I are working on a java application and on running, a launcher is brought up. He uses a mac, and the JFrame was gotten to be transparent, however when I sync'd the project to my computer; A windows PC, The background of the JFrame was visible and the graphics on top flashed, kind of like a strobe light.
If anyone could provide any kind of insight it would be greatly appreciated, and if more information needs to be provided, I will try to go through program more deeply, and get more info.
private void setUpWindow(int width, int height) {
setIconImage(images.get(1));
setSize(width, height);
setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(new Color(0,255,0,0));
setLayout(new BorderLayout());
addMouseListener(this);
setResizable(false);
setLocationRelativeTo(null);
addComponents();
requestFocus();
setVisible(true);
}
private void addComponents() {
setContentPane(new BackPanel());
getContentPane().setBackground(Color.BLACK);
setLayout(new BorderLayout());
panel.setSize(screenSize);
add(panel);
}
Window size is 1000x600
public class BackPanel extends JPanel {
public BackPanel() {
setOpaque(false);
setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D overGraphics2D = (Graphics2D)g.create();
overGraphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
overGraphics2D.setColor(Color.BLACK);
overGraphics2D.fill(getBounds());
overGraphics2D.dispose();
}
}
public class DrawingPanel extends JPanel
{
public DrawingPanel()
{
setVisible(true);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
refreshTimer.schedule(new refreshTimer(), 1);
}
}
The referred refresh timer has a delay of '1' so that it is started when the launcher is drawn.
Also, ideas from this; how to set JFrame background transparent but JPanel or JLabel Background opaque? were used in setting up the transparency.
The referred refresh timer has a delay of '1' so that it is started when the launcher is drawn.
This is a problem with cross platform drawing because different operating systems have different "resolutions". You need to draw/call the method to draw inside that paintComponent() method. You also need to make the window full screen (or kinda fake full screen) by getting the screen size then setting the window full screen. Like this:
//in the constructor after declaring the frame undecorated
setSize(Toolkit.getDefaultToolkit().getScreenSize());
Hope that helps!
I am working on some application designed to be not 100% opaque, so it basically darkens the desktop of the user and my Swing interface is shown on top of this "dark veil".
It seems to me that, when some Swing components are being moved over that veil, my JFrame would need to be repainted for my moving components not to leave a trail behind them. The thing is that repainting the JFrame is too slow and my application wouldn't run smoothly anymore.
For your convenience, I created a SSCCE class that illustrates my issue, here it is:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class TransparentFrameSSCCE extends JFrame {
private static final Dimension SCREEN_DIMENSIONS = Toolkit.getDefaultToolkit().getScreenSize();
private final JPanel movingPanel;
private TransparentFrameSSCCE() {
super();
this.setUndecorated(true);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(TransparentFrameSSCCE.SCREEN_DIMENSIONS);
// This makes my JFrame transparent (its alpha component is set to 0)
this.setBackground(new Color(0, 0, 0, 0));
this.movingPanel = new JPanel();
this.movingPanel.setBounds(0, 0, 50, 50);
this.movingPanel.setBackground(Color.RED);
final JPanel contentPane = new JPanel();
// This makes my panel semi-transparent (its alpha component is set to 128)
contentPane.setBackground(new Color(0, 0, 0, 128));
contentPane.setLayout(null);
contentPane.add(this.movingPanel);
this.setContentPane(contentPane);
}
#Override
public void setVisible(final boolean isVisible) {
super.setVisible(isVisible);
new Thread(new Runnable() {
#Override
public void run() {
int x, y;
for(;;) {
x = TransparentFrameSSCCE.this.movingPanel.getLocation().x;
y = TransparentFrameSSCCE.this.movingPanel.getLocation().y;
TransparentFrameSSCCE.this.movingPanel.setLocation(x + 5, y);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public static void main(final String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TransparentFrameSSCCE().setVisible(true);
}
});
}
}
Would anyone know any other way to do so?
UPDATE: Following #MadProgrammer's directions about Swing components transparency behavior, this is how to deal with my "dark veil". It works perfectly. Many thanks to him :)
final JPanel contentPane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(0, 0, 0, 128));
g2d.fill(new Area(new Rectangle(new Point(0, 0), getSize())));
g2d.dispose();
}
};
contentPane.setOpaque(false); // Instead of: contentPane.setColor(new Color(0, 0, 0, 128)
Java components don't have a concept of transparency, they are either opaque or fully transparent (alright, the new transparency support for top level windows is an exception ;))
What you need to do is create a custom component that is fully transparent and the override it's paintComponent and fill the area of the component with your translucent color.
Also, don't modify the state of Swing components outside of the context of the Event Dispatching Thread, strange things begin to happen. A better solution might be to use a javax.swing.Timer
For example
Create rectangle with mouse drag, not draw
Java Swing: Transparent PNG permanently captures original background
How to make a transparent JFrame but keep everything else the same?
You may also want to take a look at Concurrency in Swing
Check out Backgrounds With Transparency for a simple explanation of the problem. Basically, you need to make sure your custom component paints the background.
Or instead of doing the custom painting you can take advantage of the AlphaContainer class which will do the painting for you:
//this.setContentPane( contentPane);
this.setContentPane( new AlphaContainer(contentPane) );
I have a transparent, editable JTextPane in a program I'm writing (to allow a background to show through), and everything works pretty well, except for the text caret.
The caret itself acts normally, but every time it's drawn, it breaks the transparency of the area right behind it, as seen in the image:
Is there any way to make the background of the caret transparent without repainting the whole frame? DefaultCaret doesn't have a setOpaque() method, so I'm not quite sure how to go about this.
Thanks!
EDIT: I can't answer my own question yet, but I ended up writing an SSCCE that works perfectly, so there is definitely something else wrong with my program. For future reference, this is the (working) code I wrote:
import java.awt.*;
import javax.swing.*;
class TransparentScrollPane extends JScrollPane {
public TransparentScrollPane(Component view) {
super(view);
this.setPreferredSize(new Dimension(540,480));
this.setOpaque(false);
this.viewport.setOpaque(false);
this.setBorder(null);
}
}
public class TextPaneExample extends JTextPane {
public TextPaneExample()
{
super();
this.setOpaque(false);
}
public void paintComponent(Graphics g)
{
g.setColor(new Color(255,255,255,128));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(640, 480);
JPanel panel = new JPanel();
panel.setBackground(new Color(255,128,255));
TextPaneExample textPane = new TextPaneExample();
TransparentScrollPane scroller = new
TransparentScrollPane(textPane);
textPane.setBackground(new Color(255,255,255,128));
frame.add(panel);
panel.add(scroller,BorderLayout.CENTER);
frame.setVisible(true);
}
}
See Backgrounds With Transparency for the problem and a couple of solutions.
Basically you can just use:
panel.add( new AlphaContainer(componentWithTransparency) );
For your first question you get one free answer :) Future questions should include a proper SSCCE that demonstrates the problem.
There appears to be a bug with the window translucency functionality in Java 7 (I believe the problem existed in Java 6 as well). If I open a translucent window and then minimize its parent window, both disappear as you would expect. But then when you restore the parent window the translucent window never reappears. However, it is still there and will consume input as if nothing was wrong.
Here is my SSCCE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BrokenTranslucentWindow extends JApplet //same problem exists using a JFrame
{
public BrokenTranslucentWindow()
{
JButton b = new JButton("Hello");
b.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JDialog d = new JDialog(Window.getWindows()[0])
{
#Override
public void paint(Graphics g)
{
g.fillOval(0, 0, getWidth(), getHeight());
}
};
d.setUndecorated(true);
d.setBackground(new Color(0, 0, 0, 0));
d.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
d.setSize(300, 300);
d.setLocationRelativeTo(null);
// d.setModal(true);
d.setVisible(true);
}
});
this.add(b);
}
}
You'll note that after you restore the parent window the translucent oval window will not be visible, but your cursor will still change to the hand cursor when you are over the area where the window should be.
I have submitted the bug to Oracle, but until it is fixed I could really use a better workaround.
My Question:
Does anybody have any ideas for a workaround that would prevent this from happening?
Fun Facts:
This causes big problems if the translucent window happened to be modal.
I'm focusing on per-pixel translucency, but the same applies to uniform translucency.
This problem presents with JFrames, Applets inside browsers, and Applets within the applet viewer.
I have found one undesirable workaround. I post it in hopes that it will get some creative juices going. The workaround is to turn off the translucency when the window is deactivated, and turn it back on when it is activated.
d.addWindowListener(new WindowAdapter()
{
public void windowActivated(WindowEvent e)
{
d.setBackground(new Color(0, 0, 0, 0));
}
public void windowDeactivated(WindowEvent e)
{
d.setBackground(Color.white);
}
});
This isn't ideal because when you click off of the window it becomes opaque. However, it does prevent the window from disappearing forever.