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.
Related
I have tried this code to draw a string on my frame using KeyListener interface such that whenever I hit a typeable key on keyboard, it should appear on frame but it doesn't work even though there are no errors.
Can someone tell what's the mistake?
Below is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class KeyevntFrame2 extends Frame {
Button b = new Button("ok");
Button b1 = new Button("hey");
char ch;
String s = "";
public KeyevntFrame2() {
setTitle("understand key events");
setSize(800, 600);
addKeyListener(new KeyHandler());
setFont(new Font("Arial", Font.PLAIN, 35));
setForeground(Color.BLACK);
add(b);
add(b1);
b.setBounds(200, 200, 100, 100);
b1.setBounds(200, 700, 100, 100);
setLayout(null);
b.addActionListener(new KeyHandler());
b1.addActionListener(new KeyHandler());
}
class KeyHandler implements KeyListener, ActionListener {
public void keyPressed(KeyEvent e) {
ch = e.getKeyChar();
s = s + ch;
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void paint(Graphics g) {
g.drawString(s, 300, 200);
g.setFont(new Font("Arial", Font.PLAIN, 35));
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b1, "thank you for using java");
}
}
public static void main(String a[]) {
KeyevntFrame2 f = new KeyevntFrame2();
f.setVisible(true);
}
}
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space. This advice is especially relevant to this GUI, given that the frame does not have enough height to display the second button.
Don't mix AWT (Frame) and Swing (JOptionPane) components in one GUI. Choose a GUI toolkit and stick with it.
Always use #Override notation when changing the behavior of existing methods or implementing the methods of an interface. Doing so would have warned you that neither the KeyListener nor ActionListener interfaces define a public void paint(Graphics) method!
Defining a combined KeyListener and ActionListener does not make much sense, and has confused you into thinking that calling Button.addActionListener(..) with the combined listener will also have the effect of adding it as a KeyListener. It won't.
new Font("Arial", Font.PLAIN, 35) for cross-platform robustness, that should be new Font(Font.SANS_SERIF, Font.PLAIN, 35) (e.g OS X will typically not have the Arial font installed, and users would prefer to see Helvetica in any case.)
It is not necessary to set the font of the frame, and also the font in the paint method. Just do it once in the frame.
Since the frame itself is not focusable, calling addKeyListener(..) will have no effect. Better to use Swing and implement key bindings in any case.
When custom painting, always call the super method first.
Swing and AWT GUIs should be started on the EDT.
"it doesn't work even though there are no errors." There are plenty of errors in the code seen above, it's just that they are neither compilation errors, nor run-time errors that throw exceptions. Plenty can still go wrong with code even if the compiler or virtual machine does not identify them. This is why 'cut & paste' coding sans understanding what the code does, never works. Hit the tutorials and read the Java docs.
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.
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).
I have a problem with java Xor method:
public class Okno extends JFrame {
public static void main(String[] args) {
Okno okno = new Okno();
}
Window()
{
this.setSize(300,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton button= new JButton("Circle");
button.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g = (Graphics2D)Window.this.getGraphics();
g.setXORMode(Color.red);
g.setStroke(new BasicStroke(10));
g.drawOval(100, 100, 100, 100);
}
});
this.add("South",button);
this.setVisible(true);
}
It paints circle after second click on button. On Graphic from Image it works fine...
If the code works the second time, odds are good you are calling the code incorrectly. For example, you may be requesting a paint callback and then improperly invalidating the screen area, which means that while the view has changed, the is no event to start the repainting routines.
On the second button click, the paint will then detect the first button click's action, which was to change what is drawn.
Swing painting has changed slightly over the years. You might be stuck with an old tutorial or text. Take a look at the latest online offerings to get a good idea of how it should be done.
I am building a Java Swing application that needs to support both an embedded browser and ActiveX. The easy way to do this seemed to be to use JDICplus, which just embeds IE in your application. That would have covered both requirements.
I also need to overlay some buttons on top of this browser view so the user can navigate between views. To do that, I have a JLayeredPane to which I add views, and at a higher layer, buttons. This works in my pure Java views. However, on my Internet view, the Internet draws on top of the buttons. In other words, it doesn't seem to respect the JLayeredPane. I'm guessing this is because it is a native component and not a Java component.
To be sure, I put the Internet pane into a JInternalFrame, and the buttons in the other, and put both of the internal frames into a JDesktopPane. When I drag the button frame on top of the Internet frame, the Internet frame jumps to the foreground and covers the other frame. It's as if the embedded IE steals the focus and puts itself in the forefront of my other windows.
My question is this: is there any way to draw Java components on top of these Windows/IE components reliably? Or, am I not going to get anywhere mixing Java with IE? Are there other options to meeting my requirement of an embedded browser and ActiveX support (which technically, could be a different view--in other words, I could have an Internet view and another view that just supports ActiveX). I'm open to suggestions. I have looked at other free browser components for Java, and as everyone will tell you, it's discouraging.
Check out Sun's article on mixing heavy and light components - since JDICPlus basically embeds IE into your app, it's a heavyweight component.
You may be able to place buttons over the browser window by using other heavyweight components (i.e. AWT Button), or do something like place the button into a JPopupMenu placed over the browser with setDefaultLightWeightPopupEnabled(false) set on it to make it heavyweight.
Edited
I wrote an example using JPopupMenu to display a JButton over a heavyweight component - JPopupMenu works, but it does have built in behavior to close the menu when the popup or components in the popup lose focus. I added a MouseMotionListener to the heavyweight component to show the popups when the mouse entered a bounding box near where the buttons should be. Not sure if this works for you as the buttons aren't always shown.
Including a code example and screenshot -
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
public class LightHeavy extends JFrame {
private Component heavyweightComponent;
private JPopupMenu backButton, forwardButton;
public LightHeavy() {
super("LightHeavy");
heavyweightComponent = buildHeavyweightComponent();
heavyweightComponent.setBackground(Color.ORANGE);
heavyweightComponent.setSize(640, 480);
getContentPane().add(heavyweightComponent, BorderLayout.CENTER);
ImageIcon backArrow = new ImageIcon("left_arrow_128.png");
backButton = buildPopup(backArrow);
ImageIcon forwardArrow = new ImageIcon("right_arrow_128.png");
forwardButton = buildPopup(forwardArrow);
heavyweightComponent.addMouseMotionListener(new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
Rectangle backHotSpot = new Rectangle(0, 0, 200, 200);
Rectangle forwardHotSpot = new Rectangle(heavyweightComponent.getWidth() - 200, 0, 200, 200);
if (backHotSpot.contains(e.getPoint())) {
backButton.show(heavyweightComponent, 0, 0);
} else if (forwardHotSpot.contains(e.getPoint())) {
forwardButton.show(heavyweightComponent,
heavyweightComponent.getWidth() - forwardButton.getWidth(), 0);
}
}
});
}
private Component buildHeavyweightComponent() {
return new Canvas() {
public void paint(Graphics og) {
super.paint(og);
Graphics2D g = (Graphics2D)og;
String big = "Heavyweight Component";
g.setFont(getFont().deriveFont(20F));
Rectangle2D bigBounds = g.getFontMetrics().getStringBounds(big, g);
g.drawString(big,
(this.getWidth() - (int)bigBounds.getWidth()) / 2,
(this.getHeight() - (int)bigBounds.getHeight()) / 2);
String little = "(assume this is JDICplus)";
g.setFont(getFont().deriveFont(10F));
Rectangle2D littleBounds = g.getFontMetrics().getStringBounds(little, g);
g.drawString(little,
(this.getWidth() - (int)littleBounds.getWidth()) / 2,
(this.getHeight() + (int)littleBounds.getHeight()) / 2);
}
};
}
private JPopupMenu buildPopup(Icon icon) {
JButton button = new JButton(icon);
JPopupMenu popup = new JPopupMenu();
popup.add(button);
popup.setBorderPainted(false);
popup.setLightWeightPopupEnabled(false);
return popup;
}
public static void main(String[] args) {
JFrame f = new LightHeavy();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Here's a screenshot with the JButton on the left showing - note that you also won't be able to do any cool transparency effects, as you're dealing with heavyweight components.