Is it possible to create a button that won't be seen until the user clicks another button?
My goal is for the button to be invisible by default rather than when its clicked on. Then become visible when another action is performed. The code below is my original attempt at creating this.
public void but_roll1ActionPerformed(java.awt.event.ActionEvent evt)
{
if (!bal_but.isEnabled() && !gamble_but.isEnabled()) {
but_roll1.setVisible(true);
but_roll1.setEnabled(true);
d1 = diceRoll();
die1_display.setText(String.valueOf(d1));
but_roll1.setEnabled(false);
} else {
but_roll1.setVisible(false);
}
}
Two better strategies:
Put the button in a CardLayout with a second blank panel till needed.
Make the button disabled until the first button is clicked.
I prefer the 2nd as the 'path of least surprise' for the user. YMMV.
Initial view
View after 'effect' button actioned
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class ButtonNotUsableTillAction {
private JComponent ui = null;
ButtonNotUsableTillAction() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout(1, 0, 4, 4));
ui.setBorder(new EmptyBorder(4,4,4,4));
// first demo, using card layout
JPanel cardDemoPanel = new JPanel(new GridLayout(1, 0, 2, 2));
cardDemoPanel.setBorder(new TitledBorder("Card Layout"));
ui.add(cardDemoPanel);
JButton actionCardButton = new JButton("Action");
cardDemoPanel.add(actionCardButton);
CardLayout cardLayout = new CardLayout();
JPanel cardLayoutPanel = new JPanel(cardLayout);
cardDemoPanel.add(cardLayoutPanel);
cardLayoutPanel.add(new JPanel(), "panel");
cardLayoutPanel.add(new JButton("Effect"), "button");
cardLayout.show(cardLayoutPanel, "panel");
ActionListener flipCardListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(cardLayoutPanel, "button");
}
};
actionCardButton.addActionListener(flipCardListener);
// first demo, using disabled / enabled
JPanel enabledDemoPanel = new JPanel(new GridLayout(1, 0, 2, 2));
enabledDemoPanel.setBorder(new TitledBorder("Enabled"));
ui.add(enabledDemoPanel);
JButton actionEnabledButton = new JButton("Action");
enabledDemoPanel.add(actionEnabledButton);
JButton effectButton = new JButton("Effect");
enabledDemoPanel.add(effectButton);
effectButton.setEnabled(false);
ActionListener enableComponentListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
effectButton.setEnabled(true);
}
};
actionEnabledButton.addActionListener(enableComponentListener);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
ButtonNotUsableTillAction o = new ButtonNotUsableTillAction();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
As #markspace mentioned, you need to revalidate the button's container after setting the button visible:
but_roll1.getParent().revalidate();
Related
I have a certain panel which contains a random number of items. This panel is added to the EAST of a JPanel which use BorderLayout.
I'd like to have them vertically centered.
How do i achieve this?
here is a code you can run
public class MainFrame {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new AlignDemo());
}
}
class AlignDemo implements Runnable {
#Override
public void run(){
try {
JFrame mainWindow = new JFrame();
mainWindow.getContentPane().add(initPanel());
mainWindow.pack();
mainWindow.setVisible(true);
} catch (Throwable th) {
JOptionPane.showMessageDialog(null,null,"General Error", JOptionPane.ERROR_MESSAGE);
}
}
private JPanel initPanel() {
FlowLayout layout = new FlowLayout(FlowLayout.LEFT);
layout.setHgap(15);
JPanel myContent = new JPanel();
myContent.setPreferredSize(new Dimension(400,200));
myContent.setBorder(BorderFactory.createLineBorder(Color.blue));
JButton button1 = new JButton("I'm a button");
JButton button2 = new JButton("I'm a button");
JButton button3 = new JButton("I'm a button");
myContent.add(button1,Component.CENTER_ALIGNMENT);
myContent.add(button2,Component.CENTER_ALIGNMENT);
myContent.add(button3,Component.CENTER_ALIGNMENT);
return myContent;
}
}
It can easily be achieved by combining layouts. A JPanel with FlowLayout (controls) to position the buttons relative to one another, placed as a single component into a JPanel with a GridBagLayout (ui).
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class CenteredButtons2 {
private JComponent ui = null;
CenteredButtons2() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridBagLayout()); // to center a single component
ui.setBorder(new EmptyBorder(4,4,4,4));
JPanel controls = new JPanel(new FlowLayout());
for (int ii=1; ii<4; ii++) {
controls.add(new JButton("Button " + ii));
}
controls.setBorder(new EmptyBorder(50, 90, 50, 90));
ui.add(controls);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
CenteredButtons2 o = new CenteredButtons2();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
I have the following problem:
I have a main application window (JFrame) that fills the whole screen.
When a button is clicked, a smaller window appears, to let the user input some Data. While the User does this, the main window should neither jump in front of it, nor allow interaction.
Solution to that: open a modal JDialog. Lets call that Dialog 1.
But when a button within this Dialog is clicked, a NEW window (yes/no-dialog) is supposed to pop up.. and, again, needs to act modal on the already modal JDialog Dialog 1. Trying to do that, the second Dialog keeps disappearing behind the first one.
I tried making Dialog 1 a JFrame but then, of course, I loose the "modal" bit. Forcing Dialog 1 to stay in from still keeps the main window's Button clickable.
What am I missing? How can I put a modal swing window OVER another modal swing window?
Edit:
minimal example of one not-really working version:
Main class for opening:
public class MainWin extends JFrame {
public MainWin(){
this.setSize(800,800);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia1(MainWin.this);
}
});
this.setVisible(true);
}
}
Main window:
public class MainWin extends JFrame {
public MainWin(){
this.setSize(800,800);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia1(MainWin.this);
}
});
this.setVisible(true);
}
}
First Dialog:
public class Dia1 extends JDialog {
public Dia1(final JFrame parent){
super(parent, true);
this.setSize(400, 400);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
this.setVisible(true);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Dia2(parent);
}
});
}
}
Second Dialog:
public class Dia2 extends JDialog {
public Dia2(JFrame parent){
super(parent, true);
this.setSize(200, 200);
JButton b = new JButton("click hehe");
this.getContentPane().add(b);
this.setVisible(true);
}
}
PS: I just realised: Dialog 2 is not hidden, as I suspected.. it is simply not there. Most likely because the parent window is blocked from the Modal Dialog?
Here is an MCVE of modality working as advertised.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class ModalOverModal {
private JComponent ui = null;
ModalOverModal() {
initUI();
}
public void initUI() {
if (ui!=null) return;
ui = new JPanel(new GridLayout());
ui.setBorder(new EmptyBorder(40,40,40,40));
final JButton b1 = new JButton("Open Modal Dialog");
b1.setMargin(new Insets(40, 200, 40, 200));
ui.add(b1);
final JButton b2 = new JButton("Open 2nd Modal Dialog");
ActionListener al1 = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b1, b2);
}
};
b1.addActionListener(al1);
ActionListener al2 = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b2, "Close Me!");
}
};
b2.addActionListener(al2);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ModalOverModal o = new ModalOverModal();
JFrame f = new JFrame("Modal over Modal");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
I would like to implement the cut method in java to provide the cut and paste functionality.I have already used StringSelection and getSystemClipboard() to provide the cut functionality(code below),but I wanna know how I can use java's inbuilt cut() method for it.
Code for cut functionality.
String t = qu.getText();
StringSelection s = new StringSelection(t);
this.getToolkit().getSystemClipboard().setContents(s, s);
qu.setText("");
I expected something like this to work but it didn't
qu.cut();
Thanks in advance.
If Swing just use the Actions available from the DefaultEditorKit:
new DefaultEditorKit.CutAction()
For example, a small program that uses default actions in a menu, a component-specific pop-up menu, and in buttons:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.text.*;
public class TestActions {
private String[] texts = {
"Hello", "Goodbye", "What the f***?", "Heck if I know", "Peace out man!"
};
private JTextArea textArea = new JTextArea(10, 30);
private Action[] textActions = { new DefaultEditorKit.CutAction(),
new DefaultEditorKit.CopyAction(), new DefaultEditorKit.PasteAction(), };
private JPanel mainPanel = new JPanel();
private JMenuBar menubar = new JMenuBar();
private JPopupMenu popup = new JPopupMenu();
private PopupListener popupListener = new PopupListener();
public TestActions() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
JMenu menu = new JMenu("Edit");
for (Action textAction : textActions) {
btnPanel.add(new JButton(textAction));
menu.add(new JMenuItem(textAction));
popup.add(new JMenuItem(textAction));
}
menubar.add(menu);
JPanel textFieldPanel = new JPanel(new GridLayout(0, 1, 5, 5));
for (String text: texts) {
JTextField textField = new JTextField(text, 15);
textField.addMouseListener(popupListener);
textFieldPanel.add(textField);
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
((JTextComponent)e.getSource()).selectAll();
}
});
}
textArea.addMouseListener(popupListener);
JScrollPane scrollPane = new JScrollPane(textArea);
JPanel textFieldPanelWrapper = new JPanel(new BorderLayout());
textFieldPanelWrapper.add(textFieldPanel, BorderLayout.NORTH);
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.setLayout(new BorderLayout(5, 5));
mainPanel.add(btnPanel, BorderLayout.NORTH);
mainPanel.add(scrollPane, BorderLayout.CENTER);
mainPanel.add(textFieldPanelWrapper, BorderLayout.EAST);
}
public JComponent getMainPanel() {
return mainPanel;
}
private JMenuBar getMenuBar() {
return menubar;
}
private class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
private static void createAndShowGui() {
TestActions testActions = new TestActions();
JFrame frame = new JFrame("Test Actions");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testActions.getMainPanel());
frame.setJMenuBar(testActions.getMenuBar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
It is because cut() method requires a selection in the text field. Try the following code:
qu.selectAll();
qu.cut();
I'm writing a program in Java where I'm using JTabbedPane. Each tab is associated with a different panel with labels, textfields and a button. I have used GridBagLayout in the panels.
I have added an actionlistener to the button, but when I click it nothing happens.
EDIT: I also have other buttons outside the JTabbedPane which works perfectly fine.
I can see that nothing is happening because I do this:
public void actionPerformed( ActionEvent e ) {
if ( e.getSource() == button ) {
System.out.println("blablabla");
}
and nothing is printed out.
Is there any common problems with using buttons and GridBagLayout/JTabbedPane?
EDIT with SSCCE
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class Hjelp extends JFrame {
private FlowLayout layout;
private JButton button1;
private JButton button2;
private JPanel menu, frontpage;
private JPanel present, previous, something;
public Hjelp() {
layout = new FlowLayout(FlowLayout.CENTER, 10, 20);
setLayout(layout);
setSize(900, 900);
setLocationRelativeTo(null);
setVisible(true);
setPanels();
something = something();
add(something, BorderLayout.CENTER);
something.setVisible(false);
button1 = new JButton("CLICK ME");
add(button1);
buttonListener();
}
private void buttonListener() {
Buttonlistener listener = new Buttonlistener();
button1.addActionListener(listener);
button2.addActionListener(listener);
}
private void setPanels() {
menu = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
frontpage = new JPanel();
previous = frontpage;
present = frontpage;
add(menu);
}
public void visiblePanel() {
previous.setVisible(false);
present.setVisible(true);
}
private JPanel something() {
visiblePanel();
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 1));
JTabbedPane tabbedPane = new JTabbedPane();
JComponent panel1 = tab();
tabbedPane.addTab("Click me", panel1);
tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
panel.add(tabbedPane);
return panel;
}
private JComponent tab() {
JPanel panel = new JPanel(false);
panel.setPreferredSize(new Dimension(870, 300));
panel.setLayout(new GridBagLayout());
GridBagConstraints cs = new GridBagConstraints();
cs.fill = GridBagConstraints.HORIZONTAL;
button2 = new JButton("Click me");
cs.gridx = 1;
cs.gridy = 6;
cs.gridwidth = 1;
panel.add(button2, cs);
return panel;
}
private class Buttonlistener implements ActionListener {
#Override
public void actionPerformed( ActionEvent e ) {
if ( e.getSource() == button1 ) {
present = something;
button1.setVisible(false);
something();
previous = something;
}
else if (e.getSource() == button2) {
System.out.println("Blablabla");
}
}
}
public static void main(String [] args) {
final Hjelp vindu = new Hjelp();
vindu.addWindowListener(
new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
} );
}
}
SOLVED
Solution
You don't need the getSource check at all—your listener is (hopefully) attached to just one button, so if it was invoked, that already means the button was clicked. Remove the check and unconditionally print your string. If you still don't see anything, then you have a problem.
You may not have attached a handler to the actual button, and therefore the event will never get called.
Part 1:
ButtonHandler handler = new ButtonHandler();
button.addActionListener( handler );
Part 2:
public class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event) {
}
}
ALSO: Java GUI can be finicky, rather than using "e.getSource() == button" you could try "button..isFocusOwner()"
I currently have a JComboBox which I'm using as an audio playlist - what I'd like to achieve is a little "remove" button on the right hand side of each item that I can use to remove it from the underlying model, where the circle is:
What would be the best way of achieving this?
I'd like the button to be the same for all items in the JComboBox.
Let me start by saying that this is an interesting question (+1 a while ago).
I had to quickly try and see for myself how difficult it is to achieve the wanted result with JComboBox. The conclusion I got (as #trashgod says in the comment above) was that this object was never designed to have other components or at least it feels like this to me.
Below is a sample that does something what you want. You could use it as a start, but to be honest you should forget about using the JComboBox for this problem.
For no means the sample below presents the right way of approaching the problem. It simply shows the result of my attempts of approaching the problem. The code below doesn't preserve good practice rules e.g. it mixes presentation with functionality (the renderer removes the elements). This is in fact just a hack not a real solution.
import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class ButtonCombo {
private JPanel getContent() throws MalformedURLException {
String[] ids = {"north", "west", "south", "east"};
JComboBox combo = new JComboBox(ids);
Icon removeIcon = new ImageIcon(new URL("http://filesharefreak.org/images/red_x.png"));
combo.setRenderer(new ButtonComboRenderer(removeIcon, combo));
JPanel panel = new JPanel();
panel.add(combo);
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.add(new ButtonCombo().getContent());
JButton button = new JButton("OKOKO");
panel.add(button);
f.setContentPane(panel);
f.setSize(300, 160);
f.setLocation(200, 200);
f.setVisible(true);
} catch (MalformedURLException ex) {
Logger.getLogger(ButtonCombo.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
class ButtonComboRenderer implements ListCellRenderer {
Icon icon;
JPanel panel;
JLabel label;
JButton button;
public ButtonComboRenderer(Icon removeIcon, final JComboBox combo) {
icon = removeIcon;
label = new JLabel();
button = new JButton(icon);
button.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
panel = new JPanel(new BorderLayout());
panel.add(label);
panel.add(button, BorderLayout.EAST);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (button.getX() < e.getX()) {
System.out.println("button contains the click remove the item");
combo.removeItem(label.getText());
}
}
});
}
//so we will install the mouse listener once
boolean isFirst = true;
#Override
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
if (isFirst) {
isFirst = false;
list.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
panel.dispatchEvent(e);
e.consume();
}
});
}
String text = (String) value;
label.setText(text);
if(text == null)
button.setIcon(null);
else if(button.getIcon() == null)
button.setIcon(icon);
panel.setBackground(isSelected ? Color.red : Color.white);
panel.setForeground(isSelected ? Color.white : Color.black);
return panel;
}
}
My final recommendation and the way I would do it is:
BUILD YOUR OWN COMPONENT. Make it extensible and modifiable by separating it from the trigger and presentation, where both use JComponents as they come as oppose to using a renderer. In this way you would be able to capture and serve events on the components rather than as in this case all events are captured by the JList used for rendering.
Below is a sample that should help you start. It is not the final solution but it presents lots of the important issues involved in making such component. You should use the presented functionality and wrap it all accordingly in a single component:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MockJComboBox {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JPanel popupContent = new JPanel(new GridLayout(0, 1));
popupContent.setBackground(Color.GREEN);
popupContent.add(new JLabel("Content of popupContent panel"));
popupContent.add(new JLabel("Content of popupContent panel"));
popupContent.add(new JLabel("Content of popupContent panel"));
popupContent.add(new JLabel("Content of popupContent panel"));
popupContent.add(new JLabel("Content of popupContent panel"));
popupContent.add(new JComboBox(new Object[]{"Content of popupContent panel"}));
final JButton popupCloseButton = new JButton("X");
popupContent.add(popupCloseButton);
final JScrollPane s = new JScrollPane(popupContent);
s.setPreferredSize(new Dimension(popupContent.getPreferredSize().width + s.getVerticalScrollBar().getPreferredSize().width
+ s.getBorder().getBorderInsets(s).left
+ s.getBorder().getBorderInsets(s).right, 100));
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200, 200));
final JButton popupOpenButton = new JButton();
panel.add(popupOpenButton);
final JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
final PopupFactory popupFactory = PopupFactory.getSharedInstance();
popupOpenButton.setAction(new AbstractAction("Open") {
private Popup popup;
private boolean isShown = false;
#Override
public void actionPerformed(ActionEvent e) {
if (isShown) {
popup.hide();
} else {
popup = popupFactory.getPopup(popupOpenButton, s,
popupOpenButton.getLocationOnScreen().x, popupOpenButton.getLocationOnScreen().y + popupOpenButton.getHeight());
popupCloseButton.setAction(new AbstractAction(popupCloseButton.getText()) {
#Override
public void actionPerformed(ActionEvent e) {
isShown = false;
popup.hide();
}
});
popup.show();
}
isShown = !isShown;
}
});
f.pack();
f.setVisible(true);
}
});
}
}