After I asked a very vague question about this topic yesterday here (which I voted to close now), I was able to pinpoint the problem and create a MCVE which shows this behavior.
The scenario looks like this:
While some operation is ongoing in the background, a Modal "Wait" Dialog is provided in the foreground, also the JFrame is being set to be disabled, just to be sure. After the background task is finished, the Frame is enabled again and the dialog disposed.
The issue is, that after the JFrame is being enabled and a modal dialog is disposed, the JFrame suddenly moves to the background. With "background" meaning, it is moving behind the window that had focus before the JFrame. Why does this happen?
This code should replicate the issue:
private static JFrame frame;
private static JDialog dialog;
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
buildFrame();
buildDialog();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
protected static void buildDialog() {
dialog = new JDialog(frame);
dialog.getContentPane().add(new JLabel("This is the dialog"));
dialog.setLocationRelativeTo(frame);
javax.swing.Timer t = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
frame.setEnabled(true);
}
});
t.setRepeats(false);
t.start();
dialog.pack();
dialog.setVisible(true);
}
protected static void buildFrame() {
frame = new JFrame();
frame.setMinimumSize(new Dimension(400, 400));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JLabel("This is the Frame"));
frame.setEnabled(false);
frame.pack();
frame.setVisible(true);
}
Does anyone know why this happens and how this could be prevented?
The problem is the methods frame.setEnabled(). I don't know why, but it hides the frame. My suggestion is to remove it and use the modality concept: dialog.setModal(true) (it also makes the parent frame unavailable when the dialog is shown. To make the frame unavailable, you can place a glasspane over it. Here is the code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
/**
* <code>DialogFrameTest</code>.
*/
public class DialogFrameTest {
private static JFrame frame;
private static JDialog dialog;
private static Component oldGlassPane;
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
buildFrame();
buildDialog();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
protected static void buildDialog() {
dialog = new JDialog(frame);
dialog.getContentPane().add(new JTextField("This is the dialog"));
dialog.setLocationRelativeTo(frame);
dialog.setModal(true);
javax.swing.Timer t = new javax.swing.Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
frame.setGlassPane(oldGlassPane);
oldGlassPane.setVisible(false);
}
});
t.setRepeats(false);
t.start();
dialog.pack();
dialog.setVisible(true);
}
protected static void buildFrame() {
frame = new JFrame();
frame.setMinimumSize(new Dimension(400, 400));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new JTextField("This is the Frame"));
oldGlassPane = frame.getGlassPane();
frame.setGlassPane(new SplashGlassPane());
frame.getGlassPane().setVisible(true);
frame.pack();
frame.setVisible(true);
}
private static class SplashGlassPane extends JPanel implements FocusListener {
/** Holds the id of this panel. The creator of this object can submit this id to determine whether it's the owner of this object. */
private String typeId;
/**
* Creates new GlassPane.
*/
public SplashGlassPane() {
addMouseListener(new MouseAdapter() {});
addMouseMotionListener(new MouseAdapter() {});
addFocusListener(this);
setOpaque(false);
setFocusable(true);
setBackground(new Color(0, 0, 0, 100));
}
#Override
public final void setVisible(boolean v) {
// Make sure we grab the focus so that key events don't go astray.
if (v) {
requestFocus();
}
super.setVisible(v);
}
// Once we have focus, keep it if we're visible
#Override
public final void focusLost(FocusEvent fe) {
if (isVisible()) {
requestFocus();
}
}
/**
* {#inheritDoc}
*/
#Override
public final void paint(Graphics g) {
final Color old = g.getColor();
g.setColor(getBackground());
g.fillRect(0, 0, getSize().width, getSize().height);
g.setColor(old);
super.paint(g);
}
#Override
public void focusGained(FocusEvent fe) {
// nothing to do
}
}
}
Related
I have a button. I want to change the background after I click on it. My problem here is the button auto call paintComponent(). How can prevent this? I expect after clicking the button the button will be blue, but it will still be red.
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonDemo extends JButton implements ActionListener{
public ButtonDemo() {
this.setText("BUTTON TEXT");
this.addActionListener(this);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.RED);
}
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel contentPane = new JPanel();
frame.setContentPane(contentPane);
contentPane.add(new ButtonDemo());
frame.setSize(500, 500);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
this.setBackground(Color.BLUE);
}
}
My personal gut feeling is that JButton is probably not suited to your desired goal.
Essentially, you want to control when and how the "selected" state of the piece is changed.
Personally, I would have some kind of controller which monitored the mouse events in some way (probably having the piece component delegate the event back to the controller) and some kind of model which control when pieces become selected, this would then notify the controller of the state change and it would make appropriate updates to the UI.
But that's a long process to setup. Instead, I'm demonstrating a simple concept where a component can be selected with the mouse, but only the controller can de-select. In this example, this will allow only a single piece to be selected
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridLayout(5, 5));
ChangeListener listener = new ChangeListener() {
private PiecePane selectedPiece;
#Override
public void stateChanged(ChangeEvent e) {
if (!(e.getSource() instanceof PiecePane)) { return; }
PiecePane piece = (PiecePane) e.getSource();
// Want to ignore events from the selected piece, as this
// might interfer with the changing of the pieces
if (selectedPiece == piece) { return; }
if (selectedPiece != null) {
selectedPiece.setSelecetd(false);
selectedPiece = null;
}
selectedPiece = piece;
}
};
for (int index = 0; index < 5 * 5; index++) {
PiecePane pane = new PiecePane();
pane.addChangeListener(listener);
add(pane);
}
}
}
public class PiecePane extends JPanel {
private boolean selecetd;
private Color selectedBackground;
private Color normalBackground;
private MouseListener mouseListener;
public PiecePane() {
setBorder(new LineBorder(Color.DARK_GRAY));
mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
setSelecetd(true);
}
};
setNormalBackground(Color.BLUE);
setSelectedBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
#Override
public void addNotify() {
super.addNotify();
addMouseListener(mouseListener);
}
#Override
public void removeNotify() {
super.removeNotify();
removeMouseListener(mouseListener);
}
public void addChangeListener(ChangeListener listener) {
listenerList.add(ChangeListener.class, listener);
}
public void removeChangeListener(ChangeListener listener) {
listenerList.remove(ChangeListener.class, listener);
}
protected void fireSelectionChanged() {
ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class);
if (listeners.length == 0) {
return;
}
ChangeEvent evt = new ChangeEvent(this);
for (int index = listeners.length - 1; index >= 0; index--) {
listeners[index].stateChanged(evt);
}
}
public boolean isSelected() {
return selecetd;
}
public void setSelecetd(boolean selecetd) {
if (selecetd == this.selecetd) { return; }
this.selecetd = selecetd;
updateSelectedState();
fireSelectionChanged();
}
public Color getSelectedBackground() {
return selectedBackground;
}
public void setSelectedBackground(Color selectedBackground) {
this.selectedBackground = selectedBackground;
updateSelectedState();
}
public Color getNormalBackground() {
return normalBackground;
}
public void setNormalBackground(Color normalBackground) {
this.normalBackground = normalBackground;
updateSelectedState();
}
protected void updateSelectedState() {
if (isSelected()) {
setBackground(getSelectedBackground());
} else {
setBackground(getNormalBackground());
}
}
}
}
I created a toggle button.
You set the primary color and the alternate color in the class constructor.
When you call the switchColors method, the JButton background changes from the primary color to the alternate color. When you call the switchColors method again, the JButton background changes from the alternate color to the primary color.
In the following example, I put the switchColors method in the actionListener so you can see the color change. Each time you left-click on the JButton, the background color changes.
You would call the switchColors method when you want the JButton background to change from blue to red, and again when you want the JButton background to change from red to blue. It's under your control.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ButtonDemo extends JButton
implements ActionListener {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Button Demo");
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
frame.setContentPane(contentPane);
contentPane.add(new ButtonDemo(Color.BLUE,
Color.RED));
frame.setSize(300, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
private boolean primaryBackground;
private Color primaryColor;
private Color alternateColor;
public ButtonDemo(Color primaryColor,
Color alternateColor) {
this.primaryColor = primaryColor;
this.alternateColor = alternateColor;
this.primaryBackground = true;
this.setText("BUTTON TEXT");
this.setBackground(primaryColor);
this.addActionListener(this);
}
public void switchColors() {
primaryBackground = !primaryBackground;
Color color = primaryBackground ? primaryColor :
alternateColor;
this.setBackground(color);
}
#Override
public void actionPerformed(ActionEvent e) {
switchColors();
}
}
If you want to change the background for a short while you can do it with swing Timer:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ButtonDemo extends JButton implements ActionListener{
private static final int DELAY = 600; //milliseconds
private final Timer timer;
public ButtonDemo() {
this.setText("BUTTON TEXT");
this.addActionListener(this);
Color defaultCloor = getBackground();
timer = new Timer(DELAY, e-> setBackground(defaultCloor));
timer.setRepeats(false);
}
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel contentPane = new JPanel();
frame.setContentPane(contentPane);
contentPane.add(new ButtonDemo());
frame.setSize(300, 200);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
timer.stop();
this.setBackground(Color.RED);
timer.start();
}
}
What I'm trying to do is to create a desktop application using Swing. I need to add a background image to my frame and also add some buttons on some specific locations which should NOT have their content area filled. So, here is what I've done so far;
public class MainGUI extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainGUI window = new MainGUI();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainGUI() {
setUndecorated(true);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initialize();
}
private void initialize() {
JPanel mainPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
g.drawImage(new ImageIcon(ImageIO.read(new File("a.png"))).getImage(), 0, 0, null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
mainPanel.setLayout(new BorderLayout());
JButton btn1 = new JButton();
btn1 .setAlignmentX(Component.CENTER_ALIGNMENT);
btn1 .setContentAreaFilled(false);
btn1 .setBorder(new EmptyBorder(0, 0, 0, 0));
btn1 .setIcon(new ImageIcon("btn1.png"));
JPanel rightButtonPanel = new JPanel();
rightButtonPanel.setLayout(new BoxLayout(rightButtonPanel, BoxLayout.Y_AXIS));
rightButtonPanel.add(btn1);
mainPanel.add(rightButtonPanel, BorderLayout.EAST);
this.setContentPane(mainPanel);
}
}
When I do this, setContentAreaFilled(false) feature does not work. I suppose it's related to the painting but I'm not sure. Can anyone help me with this please?
So I took your code and modified it.
Primarily:
Added btn1.setOpaque(false);
And added rightButtonPanel.setBackground(Color.GREEN);
Example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class MainGUI extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainGUI window = new MainGUI();
window.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainGUI() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initialize();
pack();
}
private void initialize() {
JPanel mainPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
};
mainPanel.setBackground(Color.RED);
mainPanel.setLayout(new BorderLayout());
JButton btn1 = new JButton();
btn1.setAlignmentX(Component.CENTER_ALIGNMENT);
btn1.setContentAreaFilled(false);
btn1.setOpaque(false);
btn1.setBorder(new EmptyBorder(0, 0, 0, 0));
btn1.setText("This is a test");
JPanel rightButtonPanel = new JPanel();
rightButtonPanel.setBackground(Color.GREEN);
rightButtonPanel.setLayout(new BoxLayout(rightButtonPanel, BoxLayout.Y_AXIS));
rightButtonPanel.add(btn1);
mainPanel.add(rightButtonPanel, BorderLayout.EAST);
this.setContentPane(mainPanel);
}
}
This produced
So, it's not the buttons (at least at this point) which are at fault.
So, I changed rightButtonPanel.setBackground(Color.GREEN); to rightButtonPanel.setOpaque(false); and it produced
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class TheSize extends JFrame implements ActionListener, KeyListener {
static String inText="";
JPanel pane=new JPanel();
JLabel word0=new JLabel("I would like my grid to be 2^",JLabel.RIGHT);
JLabel word1=new JLabel("* 2^ "+inText,JLabel.RIGHT);
JButton finish=new JButton("I'm done");
JTextField size=new JTextField("",3);
public TheSize(){
super("size");
System.out.println("hi");
setLookAndFeel();
setSize(550,100);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
FlowLayout box=new FlowLayout();
setLayout(box);
pane.add(word0);
pane.add(size);
pane.add(word1);
pane.add(finish);
finish.addActionListener(this);
add(pane);
setVisible(true);
pack();
size. addKeyListener(this);
setFocusable(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc) {
// ignore error
}
}
public void actionPerformed(ActionEvent e) {
}
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent e) {
inText=size.getText();
pane.revalidate();
pane.repaint();
}
public static void main(String[] args){
new TheSize();
}
}
a couple of things
I made sure the KeyListener is working, and it is not working as in no output, it didn't give me any error.
What should happen:
It should pop a frame which says I would like my grid to be 2^__(user input Textfield)____* 2^(what is in the textfield). (Button for I'm done).
however, (what is in the textfield) remains empty after I type something into the text field. I checked whether the program heard my keystrokes using System.out.println();, and it is working, so the revalidate(); and repaint() commands must not be(I also tested it out by putting a System.out.println(); in my constructor. Thanks in advance
Never use a KeyListener on a JTextField. Get rid of the KeyListener and the JTextField should likely accept text just fine. Instead, if you want to register user input, use a DocumentListener if you just want the text but won't filter it, or a DocumentFilter if you need to filter the text before it is displayed. This sort of question has been asked many times on this site.
Also note that your JLabel will never change, even if you do use a DocumentListener since you call setText(...) on your word1 JLabel but never re-call this method. Just changing the String that the inText String variable refers to of course will not magically change the JLabel's displayed text.
Note, that I'm not sure what you mean by the replicate() command as I've not heard of this method. Do you mean revalidate() if so, please clarify.
For example:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
// Avoid extending JFrames if at all possible.
// and only extend other components if needed.
#SuppressWarnings("serial")
public class TheSize2 extends JPanel {
private static final String FORMAT = "* 2^ %s";
private static final int PREF_W = 550;
private static final int PREF_H = 100;
private String inText = "";
private JLabel word0 = new JLabel("I would like my grid to be 2^", JLabel.RIGHT);
private JLabel word1 = new JLabel(String.format(FORMAT, inText), JLabel.RIGHT);
private JButton finish = new JButton("I'm done");
private JTextField size = new JTextField("", 3);
public TheSize2() {
finish.setAction(new FinishAction("I'm Done"));
size.getDocument().addDocumentListener(new SizeListener());
add(word0);
add(size);
add(word1);
add(finish);
}
#Override // make JPanel bigger
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
int prefW = Math.max(superSz.width, PREF_W);
int prefH = Math.max(superSz.height, PREF_H);
return new Dimension(prefW, prefH);
}
private class SizeListener implements DocumentListener {
private void textUpdated(DocumentEvent e) {
try {
inText = e.getDocument().getText(0, e.getDocument().getLength());
word1.setText(String.format(FORMAT, inText));
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
#Override
public void changedUpdate(DocumentEvent e) {
textUpdated(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
textUpdated(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
textUpdated(e);
}
}
private class FinishAction extends AbstractAction {
public FinishAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Component comp = (Component) e.getSource();
if (comp == null) {
return;
}
Window win = SwingUtilities.getWindowAncestor(comp);
if (win == null) {
return;
}
win.dispose();
}
}
private static void createAndShowGui() {
TheSize2 theSize2 = new TheSize2();
JFrame frame = new JFrame("The Size");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(theSize2);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I found the solution with the help of Hovercraft Full Of Eels, all I missed was to re setSize. It is not the best solution, but it is simple enough for me to understand.
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class TheSize extends JFrame implements ActionListener, KeyListener {
static String inText="";
JPanel pane=new JPanel();
JLabel word0=new JLabel("I would like my grid to be 2^",JLabel.RIGHT);
JLabel word1=new JLabel("* 2^ "+inText,JLabel.RIGHT);
JButton finish=new JButton("I'm done");
JTextField size=new JTextField("",3);
public TheSize(){
super("size");
setLookAndFeel();
setSize(550,100);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
FlowLayout box=new FlowLayout();
setLayout(box);
pane.add(word0);
pane.add(size);
pane.add(word1);
pane.add(finish);
finish.addActionListener(this);
add(pane);
setVisible(true);
pack();
size.addKeyListener(this);
setFocusable(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc) {
// ignore error
}
}
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args){
new TheSize();
}
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
inText=size.getText();
word1.setText("* 2^ "+inText);
pane.revalidate();
pane.repaint();
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
I want to display a normal JButton as disabled, without setting it to setEnabled(false)!
I just want to show that this button is not enabled, but if the user pushs the button it should call the actionlistener as normal.
So what I did is:
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SwingTests {
private static void createWindow() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
MyButton button = new MyButton("Press");
button.setEnabled(false);
panel.add(button);
frame.add(panel);
frame.setSize(200, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createWindow();
}
});
}
}
class MyButton extends JButton {
private boolean enabled = false;
public MyButton(String text) {
super(text);
super.setEnabled(true);
}
#Override
protected void paintBorder(Graphics g) {
if (isEnabled())
super.paintBorder(g);
else
; // paint disabled button
}
#Override
protected void paintComponent(Graphics g) {
if (isEnabled())
super.paintComponent(g);
else
; // paint disabled button
}
#Override
public void setEnabled(boolean b) {
enabled = b;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
I "just" need to know what to write in paintComponent(g) and paintBorder(g).
if it is disabled and a user pushs the button i display an alarm why this button is disabled!
If it looks disabled I am probably not going to push it in the first place. You could achieve this type of effect using tool tips.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
public class TestGUI {
public TestGUI() {
JFrame frame = new JFrame();
final JButton button = new JButton("Press Me");
final JToggleButton enable = new JToggleButton("Enable / Disable");
enable.setSelected(true);
button.setToolTipText("Enabled");
enable.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if (enable.isSelected()) {
button.setEnabled(true);
button.setToolTipText("Enabled");
} else {
button.setEnabled(false);
button.setToolTipText("Not Enabled");
}
}
});
frame.add(button, BorderLayout.CENTER);
frame.add(enable, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TestGUI();
}
});
}
}
if it is disabled and a user pushs the button i display an alarm why this button is disabled!
Add a MouseListener to the button when it is disabled. Then you can handle the mouseClicked() event to display your "alarm".
I want to make JDialog-based window inactive, so all controls apeared disabled (in grey color). setEnabled(false) just makes impossible to click any control, even close window. But nothing turns gray. Help please.
EDIT: Here is sample code.
import javax.swing.JButton;
import javax.swing.JDialog;
public class Analyzer extends JDialog{
public Analyzer() {
JButton but = new JButton("test");
setLayout(null);
but.setBounds(10,10,100,100);
add(but);
setSize( 200, 200);
setVisible(true);
setEnabled(false);
}
public static void main(String[] args) {
new Analyzer();
}
}
The two ways I know to do this, one where you disable the components of a dialog recursively, and the second where you disable the entire dialog (including ability to drag the dialog):
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DisableEg extends JPanel {
public static final String DISABLE_DIALOG_COMPONENTS = "Disable Dialog Components";
public static final String ENABLE_DIALOG_COMPONENTS = "Enable Dialog Components";
public static final String DISABLE_DIALOG = "Disable Dialog";
public static final String ENABLE_DIALOG = "Enable Dialog";
private static final int LOC_SHIFT = 150;
private Analyzer analyzer;
public DisableEg(JFrame frame) {
analyzer = new Analyzer(frame);
analyzer.pack();
analyzer.setLocationRelativeTo(frame);
Point location = analyzer.getLocation();
location = new Point(location.x - LOC_SHIFT, location.y - LOC_SHIFT);
analyzer.setLocation(location);
analyzer.setVisible(true);
add(new JButton(new AbstractAction(DISABLE_DIALOG_COMPONENTS) {
#Override
public void actionPerformed(ActionEvent evt) {
AbstractButton btn = (AbstractButton) evt.getSource();
if (btn.getText().equals(DISABLE_DIALOG_COMPONENTS)) {
btn.setText(ENABLE_DIALOG_COMPONENTS);
analyzer.setComponentEnabled(false);
} else {
btn.setText(DISABLE_DIALOG_COMPONENTS);
analyzer.setComponentEnabled(true);
}
}
}));
add(new JButton(new AbstractAction(DISABLE_DIALOG) {
#Override
public void actionPerformed(ActionEvent evt) {
AbstractButton btn = (AbstractButton) evt.getSource();
if (btn.getText().equals(DISABLE_DIALOG)) {
btn.setText(ENABLE_DIALOG);
analyzer.setEnabled(false);
} else {
btn.setText(DISABLE_DIALOG);
analyzer.setEnabled(true);
}
}
}));
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Disable Example");
DisableEg mainPanel = new DisableEg(frame);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class Analyzer extends JDialog {
public Analyzer(JFrame frame) {
super(frame, "Analyzer Dialog", false);
JButton but = new JButton("test");
setLayout(new FlowLayout());
add(but);
setPreferredSize(new Dimension(200, 200));
}
public void setComponentEnabled(boolean enabled) {
setComponentEnabled(enabled, getContentPane());
// !! if you have menus to disable, you may need instead
// setComponentEnabled(enabled, this); // !!
}
private void setComponentEnabled(boolean enabled, Component component) {
component.setEnabled(enabled);
if (component instanceof Container) {
Component[] components = ((Container) component).getComponents();
if (components != null && components.length > 0) {
for (Component heldComponent : components) {
setComponentEnabled(enabled, heldComponent);
}
}
}
}
}
The typical way to do this is to use a glassPane, but Java 7 introduced JLayer that should do the trick too.