I want to show the dialogs JColorChooser and JFileChooser programmatically from
a method called when I submit a buttons.
After the button is clicked the method is invoked but the dialogs won't display.
I have a JFrame with a null layout (absolute positioning) and, e.g., the following code:
public class _TEST_ extends JFrame
{
private JColorChooser color_chooser;
private JFileChooser file_chooser;
public _TEST_()
{
super("_TEST_");
setLayout(null);
final JButton b = new JButton("Color chooser");
final JButton b2 = new JButton("File chooser");
ActionListener al = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == b)
{
createJColorChooser();
}
else if (e.getSource() == b2)
{
createJFileChooser();
}
}
};
b.addActionListener(al);
b2.addActionListener(al);
b.setBounds(1, 1, 160, 20);
b2.setBounds(1, 30, 160, 20);
add(b);
add(b2);
}
public void createJColorChooser()
{
color_chooser = new JColorChooser();
color_chooser.setBounds(1, 70, 225, 50);
add(color_chooser);
repaint();
}
public void createJFileChooser()
{
file_chooser = new JFileChooser();
file_chooser.setBounds(330, 70, 225, 50);
add(file_chooser);
repaint();
}
public static void main(String args[])
{
_TEST_ window = new _TEST_();
window.setSize(800, 600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setLocationRelativeTo(null);
}
}
what's wrong?
If you are adding to a frame that has already been made visible, you need to revalidate the frame:
frame.validate();
From the JavaDocs for frame.add(...):
Note: If a component has been added to a container that has been displayed, validate must
be called on that container to display the new component.
If you want to make the color chooser show in a separate dialog (the usual approach), do this:
final Color color = JColorChooser.showDialog(null, "Choose a color", Color.BLUE);
For JFileChooser here is a typical approach:
JFileChooser ch = new JFileChooser();
ch.showOpenDialog(null);
The JavaDocs for these two dialogs have good working examples.
(See the comments in #Steve McLeod's answer for context.)
JColorChooser and JFileChooser are not regular JComponents. You can add them to a container but you don't see anything because JColorChooser's UI doesn't paint, and JFileChooser doesn't even have a UI.
As in Steve's answer, you can use JColorChooser#showDialog and JFileCHooser#showOpenDialog to get modal dialog, which is the right way to use them.
If you really want, you can call JColorChooser#createDialog then grab its content pane (you could do this for any top-level container):
public void createJColorChooser()
{
...
add(JColorChooser.createDialog(this, "", false, color_chooser, null, null).getContentPane());
...
}
And you could override JFileChooser to publicize its createDialog, but please, please don't do that. File chooser should always be modal dialogs.
Generally I add components to a specific panel and not the frame directly so I would use:
panel.add( someComponent );
panel.revalidate();
panel.repaint(); // sometimes required
But in this case you can just use the validate() method:
color_chooser.setSize( color_chooser.getPreferredSize() );
add(color_chooser);
validate();
repaint();
file_chooser.setSize( file_chooser.getPreferredSize() );
add(file_chooser);
validate();
repaint();
Edit: of course you should also use the preferred size of the component so that the entire component is visible. Now all you need to do is add all the code to respond when a user makes a selection. That is a lot of work, which is why it is better to use the dialog version of each class.
Related
I want to change appearance of Button on JOptionPane.ShowMessageDialog.
I have managed to change Button caption with
UIManager.put("OptionPane.okButtonText", "Text I want");
Now, my next goal is to make Button work same as buttons in rest of my app. That is, when hovering mouse over it, it changes background and font color.
On rest of my buttons I added mouse listener like this one:
//setting change color on hover
private final MouseListener mouseAction = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
JButton rollOver = (JButton)e.getSource();
if (rollOver.isEnabled()) {
rollOver.setBackground(new Color(163, 184, 204));
rollOver.setForeground(Color.WHITE);
rollOver.setFont(b);
}
};
#Override
public void mouseExited(MouseEvent e) {
JButton rollOver = (JButton)e.getSource();
if (rollOver.isEnabled()) {
rollOver.setBackground(new Color(230, 230, 230));
rollOver.setForeground(Color.BLACK);
rollOver.setFont(f);
}
};
};
Previously in code I have Font varibles set:
Font f = new Font("System", Font.PLAIN, 12);
Font b = new Font("System", Font.BOLD, 12);
I could make new dialogs from scratch and implent this behaviour but that would be overkill.
Is there some way to access Button on JOptionPane and add mouse listener
to it?
UIManager.put("OptionPane.okButtonText", "Text I want");
The above will change the text for all "Ok" buttons on all JOptionPanes that you create.
If you want to change the text on an individual button on a specific JOptionPane then
read the section from the Swing tutorial on Customizing Button Text.
Is there some way to access Button on JOptionPane and add mouse listener to it?
When you use the static showXXX(...) methods a modal JDialog is created so you don't have access to the dialog or its components until the dialog is closed which is too late.
So instead you need to manually create the JOptionPane and add it to a JDialog. The basics of doing this can be found by reading the JOptionPane API and looking at the section titled "Direct Use".
Once you have created the JOptionPane (and before you make the dialog visible) you can then search the option pane for the buttons and add a MouseListener to each button. To help you with this you can use the Swing Utils class. It will do a recursive search of the option pane and return the buttons to you in a List. You can then iterate through the List and add the MouseListener.
The basic code using this helper class would be:
JOptionPane optionPane = new JOptionPane(
"Are you sure you want to exit the application",
JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_CANCEL_OPTION);
List<JButton> buttons = SwingUtils.getDescendantsOfType(JButton.class, optionPane, true);
for (JButton button: buttons)
{
System.out.println( button.getText() );
}
If you want to see the same effect inside all OptionPanels, I think the override BasicOptionPaneUI is a good solution
This is a minimal example
public class MyOptionPaneUI extends BasicOptionPaneUI {
#SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"})
public static ComponentUI createUI(JComponent c) {
return new MyOptionPaneUI();
}
private static final MyMouseListener m = new MyMouseListener();
#Override
public void update(Graphics g, JComponent c) {
super.update(g, c);
}
#Override
protected void installListeners() {
JButton button = (JButton) getButtons()[0];
button.addMouseListener(m);
super.installListeners();
}
#Override
protected void uninstallListeners() {
JButton button = (JButton) getButtons()[0];
button.removeMouseListener(m);
super.uninstallListeners();
}
public static class MyMouseListener extends MouseAdapter{
#Override
public void mouseEntered(MouseEvent e) {
JButton rollOver = (JButton)e.getSource();
if (rollOver.isEnabled()) {
rollOver.setBackground(new Color(163, 184, 204));
rollOver.setForeground(Color.WHITE);
}
};
#Override
public void mouseExited(MouseEvent e) {
JButton rollOver = (JButton)e.getSource();
if (rollOver.isEnabled()) {
rollOver.setBackground(new Color(230, 230, 230));
rollOver.setForeground(Color.BLACK);
}
};
}
}
inside your frame your main class you can add this code for load the class inside the UIDefoult
static{
UIManager.put("OptionPaneUI", MyOptionPaneUI.getClass().getCanonicalName());
}
Because getButtons()[0], because I see this code inside the BasicOptionPaneUI
else if (type == JOptionPane.OK_CANCEL_OPTION) {
defaultOptions = new ButtonFactory[2];
defaultOptions[0] = new ButtonFactory(
UIManager.getString("OptionPane.okButtonText",l),
getMnemonic("OptionPane.okButtonMnemonic", l),
(Icon)DefaultLookup.get(optionPane, this,
"OptionPane.okIcon"), minimumWidth);
defaultOptions[1] = new ButtonFactory(
UIManager.getString("OptionPane.cancelButtonText",l),
getMnemonic("OptionPane.cancelButtonMnemonic", l),
(Icon)DefaultLookup.get(optionPane, this,
"OptionPane.cancelIcon"), minimumWidth);
} else {
defaultOptions = new ButtonFactory[1];
defaultOptions[0] = new ButtonFactory(
UIManager.getString("OptionPane.okButtonText",l),
getMnemonic("OptionPane.okButtonMnemonic", l),
(Icon)DefaultLookup.get(optionPane, this,
"OptionPane.okIcon"), minimumWidth);
}
inside the method protected Object[] getButtons()
If you want the effect mouse hover on the button I'm working on this library and have the solution for the mouse over.
If you have a possibility to personalize the DefaoultButton inside the library with this constant
UIManager.put("Button[Default].background", new Color(163, 184, 204));
UIManager.put("Button[Default].foreground", Color.WHITE);
UIManager.put("Button[Default].mouseHoverColor", new Color(230, 230, 230));
ps: this is only information if you need to add the mouse hover inside the you project
I have a JFrame which creates a JInternalFrame which in turn creates JInternalFrames inside itself. The 'outer' JIF has an 'Add Frames' button with a checkbox menu so each 'inner' JIF type can only be created once. There may be up to 6 'inner' JIFs (code example restricted to 2, FRAME A & B).
Creating the inner JIFs works fine, BUT when user deselects a checkbox, how do I find the right inner JIF to close?
And if user closes an inner JIF, how do I link that back to unchecking the right checkbox?
Methods I've tried end up closing ALL the inner JIFs, or if I try to search the list of open JIFs and match their title to the checkbox field, compiler says the info is not available at this time.
Simplified code for the Outer & Inner JIF creation is as shown. Don't tell me I need a layout manager - the JIFs have to be user-movable and resizeable without restraint.
class OUTJIF extends JInternalFrame {
OUTJIF() {
JInternalFrame outerJIF = new JInternalFrame("Outer JInternalFrame", true, true, true, true);
outerJIF.setBounds(50, 50, 600, 400);
outerJIF.getContentPane().setLayout(null);
JButton btnAddFrames = new JButton("Add Frames");
btnAddFrames.setBounds(10, 11, 125, 23);
outerJIF.getContentPane().add(btnAddFrames);
JPopupMenu popMenu = new JPopupMenu();
JCheckBoxMenuItem boxFrameA = new JCheckBoxMenuItem("Frame A");
JCheckBoxMenuItem boxFrameB = new JCheckBoxMenuItem("Frame B");
popMenu.add(boxFrameA);
popMenu.add(boxFrameB);
btnAddFrames.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
popMenu.show(e.getComponent(), e.getX(), e.getY());
}
});
Demo.mainPane.add(outerJIF); // add to invoking JFrame
outerJIF.setVisible(true);
// Class for internal JIF
class intJIF extends JInternalFrame {
intJIF(String intType, int x, int y, int h, int w) {
JInternalFrame innerJIF = new JInternalFrame(intType, true, true, true, true) ;
innerJIF.setBounds(new Rectangle(x, y, h, w));
outerJIF.getContentPane().add(innerJIF);
innerJIF.setVisible(true);
// ISSUE #2 - IF USER CLOSES ONE OF THESE, HOW TO CHANGE CHECKBOX MENU?
}
};
// LISTENERS FOR outerJIF MENU ITEMS
ActionListener listFrameA = new ActionListener() {
public void actionPerformed(ActionEvent event) {
AbstractButton boxFrameA = (AbstractButton) event.getSource();
boolean selected = boxFrameA.getModel().isSelected();
if (selected) { new intJIF("Inner Frame A", 0, 100, 250, 250); }
else { // ISSUE #1 - HOW TO FIND THE RIGHT INTERNAL JIF TO CLOSE?
}
} };
boxFrameA.addActionListener(listFrameA);
ActionListener listFrameB = new ActionListener() {
public void actionPerformed(ActionEvent event) {
AbstractButton boxFrameB = (AbstractButton) event.getSource();
boolean selected = boxFrameB.getModel().isSelected();
if (selected) { new intJIF("Inner Frame B", 50, 50, 250, 250); }
else { // ISSUE #1 - HOW TO FIND THE RIGHT INTERNAL JIF TO CLOSE?
}
} };
boxFrameB.addActionListener(listFrameB);
}
}
I define GUI components as class members when I need to add listeners to them. So if I make the JInternalFrame and the JCheckBox class members, then in the ActionListener of the JCheckBox I can close the JInternalFrame. Similarly I can add an InternalFrameListener to the JInternalFrame and update the JCheckBox in the internalFrameClosing() method. It appears - from the code you posted - that you are unfamiliar with InternalFrameListener. If that is the case, then I suggest reading How to Write an Internal Frame Listener. If you would like more specific help, then for me, you need to post more of your code so that I can download it and run it.
My app has a JWindow that needs to be minimized when the custom minimizer button clicked.
Please reply if anyone knows how to minimize a JWindow. I have searched a lot but couldn't find any suitable method to minimize.
I know how to minimize a JFrame. So please don't bother answering regarding JFrame.
Thanks.
I know you don't want to hear this, but the terrible truth is that there is no big difference between undecorated jframes (with setstate methods) and jwindows... :)
JFrame f = new JFrame("Frame");
f.setUndecorated(true);
Due to the fact that a JWindow is not decorated with any control icons, no setState method is provided. One workaround is to allow your custom minimizer button to set the window visible as required:
public class JWindowTest extends JFrame {
JWindow window = new JWindow();
JButton maxMinButton = new JButton("Minimize Window");
public JWindowTest() {
setSize(300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
maxMinButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (window.isVisible()) {
maxMinButton.setText("Restore Window");
} else {
maxMinButton.setText("Minimize Window");
}
window.setVisible(!window.isVisible());
}
});
add(maxMinButton);
window.setBounds(30, 30, 300, 220);
window.setLocationRelativeTo(this);
window.add(new JLabel("Test JWindow", JLabel.CENTER));
window.setVisible(true);
}
public static void main(String[] args) {
new JWindowTest().setVisible(true);
}
}
Nimbus often looks great, but for certain color combinations the result is non-optimal. In my case, the background of a JPopupMenu does not fit, which is why I want to set it manually.
I'm on Java 7 and, interestingly, Nimbus fully ignores the setting of some properties in the UIManager (like PopupMenu.background). So my only option was to create a subclass of JPopupMenu that overrides paintComponent(...). I know, that's nasty, but at least it worked.
However, if you add a JMenu to another menu, it embeds it's own instance of JPopupMenu and I could not figure out how to replace it with my own subclass.
Even assigning an own PopupMenuUI to the embedded instance didn't bring any results. If inherited directly from JPopupMenu the overriden paint(...) method was called, but, not matter what I did, nothing was drawn. If inherited from javax.swing.plaf.synth.SynthPopupMenuUI paint isn't even called and the result is if I hadn't set an own PopupMenuUI at all.
So the simple question is: How do I adjust the background color of one JPopupMenu or (if that's easier) all of them on Java 7 using Nimbus as L&F?
Edit: Code example
Take a look at the following code and the result:
public static void main(final String[] args) {
try {
UIManager.setLookAndFeel(NimbusLookAndFeel.class.getCanonicalName());
UIManager.getLookAndFeelDefaults().put("PopupMenu.background", Color.GREEN);
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.RED);
UIManager.getLookAndFeelDefaults().put("List.background", Color.BLUE);
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200,200);
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
JList list = new JList();
panel.add(list);
frame.getContentPane().add(panel);
JPopupMenu menu = new JPopupMenu();
menu.add(new JMenuItem("A"));
menu.add(new JMenuItem("B"));
menu.add(new JMenuItem("C"));
frame.setVisible(true);
menu.show(frame, 50, 50);
}
I know, some say that you should use UIManager.put(key, value) or UIManager.getLookAndFeelDefautls().put(key,value) before setting the L&F, but for me this does not bring any results (meaning: no changes to the default colors at all). The code above at least brings:
Same thing (meaning nothing) happens if you use JPopupMenu.setBackground(...). This is because Nimbus uses an internal painter, which computes the color from Nimbus' primary colors and ignores the components' property. In this example, you can use the following as workaround:
JPopupMenu menu = new JPopupMenu() {
#Override
public void paintComponent(final Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0,0,getWidth(), getHeight());
}
};
Which brings
However, this workaround does not work if you insert a JMenu which itself wraps a JPopupMenu you can't override:
JMenu jmenu = new JMenu("D");
jmenu.add(new JMenuItem("E"));
menu.add(jmenu);
gives, as expected:
You can retrieve this JPopupMenu using JMenu.getPopupMenu() but you can't set it. Even overriding this method in an own subclass of JMenu does not bring any results, as JMenu seems to access it's enwrapped instance of JPopupMenu without using the getter.
One way to do it is to color the background of the individual JMenuItems and make them opaque:
JMenuItem a = new JMenuItem("A");
a.setOpaque(true);
a.setBackground(Color.GREEN);
Then give the menu itself a green border to fill the rest:
menu.setBorder(BorderFactory.createLineBorder(Color.GREEN));
There may be an easy/more straightforward way out there, but this worked for me.
there are a few mistakes in both answers
and above mentioned way to required to override most UIDeafaults that have got impact to the another JComponents and its Color(s)
Nimbus has own Painter, one example for that ...
from code
import com.sun.java.swing.Painter;
import java.awt.*;
import javax.swing.*;
public class MyPopupWithNimbus {
public MyPopupWithNimbus() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JList list = new JList();
panel.add(list);
frame.getContentPane().add(panel);
JPopupMenu menu = new JPopupMenu();
menu.add(new JMenuItem("A"));
menu.add(new JMenuItem("B"));
menu.add(new JMenuItem("C"));
JMenu jmenu = new JMenu("D");
jmenu.add(new JMenuItem("E"));
menu.add(jmenu);
frame.setVisible(true);
menu.show(frame, 50, 50);
}
public static void main(String[] args) {
try {
for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(laf.getName())) {
UIManager.setLookAndFeel(laf.getClassName());
UIManager.getLookAndFeelDefaults().put("PopupMenu[Enabled].backgroundPainter",
new FillPainter(new Color(127, 255, 191)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyPopupWithNimbus aa = new MyPopupWithNimbus();
}
});
}
}
class FillPainter implements Painter<JComponent> {
private final Color color;
FillPainter(Color c) {
color = c;
}
#Override
public void paint(Graphics2D g, JComponent object, int width, int height) {
g.setColor(color);
g.fillRect(0, 0, width - 1, height - 1);
}
}
not the whole story - but looks like setting the opacity of menu/items to true partly solves it (as #Derek Richard already did for a item created under full application control):
UIDefaults ui = UIManager.getLookAndFeelDefaults();
ui.put("PopupMenu.background", GREEN);
ui.put("Menu.background", GREEN);
ui.put("Menu.opaque", true);
ui.put("MenuItem.background", GREEN);
ui.put("MenuItem.opaque", true);
and so on, for all types of items like radioButton/checkBox.
This still leaves a upper/lower grey area - don't know which part is responsible for that drawing. Removing the margin helps at the price of looking squeezed
// this looks not so good, but without the margins above/below are still grey
ui.put("PopupMenu.contentMargins", null);
There's a list of property keys in the tutorial.
I am making an applet and as part of my applet, I want this to happen: When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
However, I cannot figure out how to add a new component to the applet after it has started. I made the problem simpler by ignoring the removal part (Which I know how to do) and just adding a simple JLabel instead, but even that won't add!
Here is my code so far:
// imports omitted
public class Class extends Applet implements ActionListener
{
Button okButton;
CheckboxGroup radioGroup;
Checkbox radio1;
Checkbox radio2;
Checkbox radio3;
JLabel j;
public void init()
{
setLayout(new FlowLayout());
okButton = new Button("OK");
j = new JLabel("hello");
radioGroup = new CheckboxGroup();
radio1 = new Checkbox("Red", radioGroup,false);
radio2 = new Checkbox("Blue", radioGroup,true);
radio3 = new Checkbox("Green", radioGroup,false);
add(okButton);
add(radio1);
add(radio2);
add(radio3);
okButton.addActionListener(this);
}
public void repaint(Graphics g)
{
if (radio1.getState()) add(j);
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) repaint();
}
}
What am I doing wrong?
You shouldn't override the repaint method, and certainly not add a component in this method. Just remove the radio buttons from the applet (using its remove method) and add the label in the applet in your actionPerformed method, the same way you add them in the init method.
You might have to call validate after.
Add components and then call validate() of your container. In this case yourApplet.validate(). This will trigger repainting and rearranging of all elements.
you could do something like
JFrame fr= new JFrame(); // global variables
JPanel panelToBeAdded = new JPanel();
JPanel initialPanel = new JPanel();
JTextField fieldToBeAdded = new JTextField();
panelToBeAdded.setPreferredSize( new Dimension(400,400));
initialPanel.setPreferredSize( new Dimension(400,400));
initialPanel.setVisible(true);
fr.add(initialPanel);
fr.setVisible(true);
fr.pack();
public void actionPerformed(ActionEvent ae) {
initialPanel.setVisible(false);
//radiobuttons.setVisible(false);---> hide the radio buttons
panelToBeAddedd.add(fieldToBeAddedd);
panelToBeAddedd.setVisible(true);
fr.add(panelToBeAddedd);
}
public void repaint( Graphics g ) {
// do something
}
What am I doing wrong?
Your repaint(Graphics) method is not the same method you are calling in your actionPerformed method.
Also, repaint is a pretty bad name for a method which is adding a new component.
public void swapComponents()
{
if (radio1.getState()) {
remove(radio1);
remove(radio2);
remove(radio3);
add(j);
validate();
}
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) {
swapComponents();
}
}
When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
Use a CardLayout, as shown here. It is perfect for situations like this.