This is my first time creating a Gui and I'm stumped on how to create interactions.
I'm trying to implement a single selection mode when the combobox is on single, and multiple when it's placed on multiple. I placed them on the multi line comment.
Any ideas?
//Interactions
//When “Single” is selected then the JList changes so only one item
can be selected.
//When “Multiple” is selected, the JList changes so multiple items can
be selected
//When a country, or multiple countries, is selected the JLabel
changes to reflect the new selections
public class GuiTest {
public static String[] Countries = {"Africa", "Haiti", "USA", "Poland", "Russia", "Canada", "Mexico", "Cuba"};
public static String[] Selection = {"Single", "Multiple"};
JPanel p = new JPanel();
JButton b = new JButton("Testing");
JComboBox jc = new JComboBox(Selection);
JList jl = new JList(Countries);
private static void constructGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
frame.setTitle("Countries Selection");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add a JLabel that says Welcome
JLabel label = new JLabel("Selected Items:");
frame.add(label);
frame.pack();
JComboBox jc = new JComboBox(Selection);
frame.add(jc);
frame.pack();
frame.setVisible(true);
JList jl = new JList(Countries);
frame.add(jl);
frame.pack();
JComponent panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JLabel("Choose Selection Mode:"));
panel.add(jc);
frame.add(panel, BorderLayout.NORTH);
frame.add(jl, BorderLayout.WEST);
frame.add(label, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
constructGUI();
}
});
}
}
you should start adding the modes to the ComboBox:
comboBoxCategoria.addItem("Single",0);
comboBoxCategoria.addItem("Multiple",1);
then add a ActionListener to your ComboBox to modify the list selection mode
jc.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(jc.getSelectedItem().equals("Single")){
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}else{//must equals
jl.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
}
});
finally add a MouseListener on the list to detect changes on the list selections and change the JLabel to reflect the new selections
jl.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
label.setText(list.getSelectedValuesList().toString());
}
});
edit: you should also add a KeyListener to update the label since the selection can be changed via arrow keys
jl.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
label.setText(list.getSelectedValuesList().toString());
}
});
It would be something like this:
jc.addActionListener((evt) -> {
if ("Single".equals(jc.getSelectedItem())) {
jl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
int[] sel = jl.getSelectedIndices();
if (sel != null && sel.length > 1) {
jl.setSelectedIndex(sel[0]);
}
} else {
jl.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
});
jl.addListSelectionListener((evt) -> {
StringBuilder buf = new StringBuilder();
for (Object o: jl.getSelectedValuesList()) {
if (buf.length() > 0) {
buf.append(", ");
}
buf.append(o);
}
label.setText(buf.toString());
});
jc.setSelectedItem("Single");
Related
I have started working with JFrames and am creating a simple programme with 3 panels that are different colours and I was just wondering what would be the best way to switch between panels for my programme. The panels are to be changed when a JMenuItem with the colours name is selected. I was looking at cards and was wondering if they would be a good solution and if it would be possible to implement them into my programme? Any other suggestions would be greatly appreciated & apologies if I have done anything wrong ive only started on stack overflow and am quite a newcomer to Java :)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Colour extends JFrame
{
CardLayout card;
JPanel childPanel = new JPanel(), redPanel, bluePanel, greenPanel;
Container c;
public Colour(){
// Get Container
c=getContentPane();
//Create Menu and items
childPanel = new JPanel();
JMenuBar menuBar = new JMenuBar();
JMenu customer = new JMenu("Colour");
customer.setMnemonic(KeyEvent.VK_U);
JMenuItem blue = new JMenuItem("Blue");
JMenuItem red = new JMenuItem("Red");
JMenuItem green = new JMenuItem("Green");
customer.add(blue);
customer.add(red);
customer.add(green);
menuBar.add(customer);
this.setJMenuBar(menuBar);
//Adding panel to container
c.add(childPanel);
childPanel.setBackground(Color.PINK);
//Action Listeners for switching panels
blue.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
} );
red.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
} );
green.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
} );}
//Creating my different panels and adding them to childPanel
public void redC() {
redPanel = new JPanel();
redPanel.setBackground(Color.RED);
childPanel.add(redPanel, "Red");
}
public void blueC() {
bluePanel = new JPanel();
bluePanel.setBackground(Color.BLUE);
childPanel.add(bluePanel, "Blue");
}
public void greenC() {
greenPanel = new JPanel();
greenPanel.setBackground(Color.GREEN);
childPanel.add(greenPanel, "Green");
}
public static void main(String[] args) {
Colour cl=new Colour();
cl.setSize(400,400);
cl.setVisible(true);
cl.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
You are almost done with you code.
Here is the working code.
You need to revalidate the childPanel after adding/removing a panel so that it will be repainted:
//Action Listeners for switching panels
blue.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (childPanel.getComponentCount() >0)
childPanel.remove(0);
blueC();
childPanel.revalidate();
}
});
red.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (childPanel.getComponentCount() > 0)
childPanel.removeAll();
redC();
childPanel.revalidate();
}
});
green.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (childPanel.getComponentCount() > 0)
childPanel.remove(0);
greenC();
childPanel.revalidate();
}
});
I have a database with tables. I passed the name of the tables into the buttons. When you click, you need a table with fields and filling to appear. The problem is that I have a new table added every time I click on the button.
Can someone please say me how to do it? Thanks in advance!
public class App extends JPanel {
static List<FieldElement> fields = new ArrayList<>();
static List<Map<String, Object>> data = new ArrayList<>();
static JTable jTable = new JTable();
public static void createGUI() throws SQLException {
TableContent tableContent = new TableContent();
JFrame frame = new JFrame();
MetadataHelper databaseMetadata = new MetadataHelper();
List<ButtonElement> elements = databaseMetadata.showTables();
JPanel panel = new JPanel();
JPanel buttons = new JPanel(new GridLayout(0, 1));
for (ButtonElement buttonElements : elements) {
JButton jButton = new JButton(buttonElements.getTablesInMigrateSchema());
buttons.add(jButton);
jButton.addActionListener(new ActionListener() {
#SneakyThrows
#Override
public void actionPerformed(ActionEvent e) {
fields = tableContent.getDatabaseMetadata().showFields(buttonElements.getTablesInMigrateSchema());
data = tableContent.getDatabaseMetadata().selectAll(buttonElements.getTablesInMigrateSchema());
Object[][] objectRows = data.stream().map(m -> m.values().toArray()).toArray(Object[][]::new);
jTable = new JTable(objectRows, fields.toArray());
panel.add(new JScrollPane(jTable));
frame.revalidate();
frame.repaint();
}
});
}
panel.add(buttons, BorderLayout.EAST);
frame.add(panel);
frame.setTitle("SwingSandbox");
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#SneakyThrows
public void run() {
JFrame.setDefaultLookAndFeelDecorated(true);
createGUI();
}
});
}
}
One easy possibility is to store the JScrollPane in a variable (which holds your table that you want to remove):
static JTable jTable = new JTable();
static JScrollPane jScrollPane;
And then in your actionPerformed method:
public void actionPerformed(ActionEvent e) {
...
if (jScrollPane != null) {
panel.remove(jScrollPane);
}
jTable = new JTable(objectRows, fields.toArray());
jScrollPane = new JScrollPane(jTable);
panel.add(jScrollPane);
frame.revalidate();
frame.repaint();
}
In my form, when i press ENTER button in my keyboard, the okAction() method should be invoke (and invoke perfectly).
My problem is in focus state, When i fill the text fields and then press the ENTER button, the okAction() didn't invoked, because the focus is on the second text field (not on the panel).
How fix this problem?
public class T3 extends JFrame implements ActionListener {
JButton cancelBtn, okBtn;
JLabel fNameLbl, lNameLbl, tempBtn;
JTextField fNameTf, lNameTf;
public T3() {
add(createForm(), BorderLayout.NORTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 500);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new T3();
}
});
}
public JPanel createForm() {
JPanel panel = new JPanel();
panel.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "Button");
panel.getActionMap().put("Button", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
okAction();
}
});
okBtn = new JButton("Ok");
okBtn.addActionListener(this);
cancelBtn = new JButton("Cancel");
tempBtn = new JLabel();
fNameLbl = new JLabel("First Name");
lNameLbl = new JLabel("Last Name");
fNameTf = new JTextField(10);
fNameTf.setName("FnTF");
lNameTf = new JTextField(10);
lNameTf.setName("LnTF");
panel.add(fNameLbl);
panel.add(fNameTf);
panel.add(lNameLbl);
panel.add(lNameTf);
panel.add(okBtn);
panel.add(cancelBtn);
panel.add(tempBtn);
panel.setLayout(new SpringLayout());
SpringUtilities.makeCompactGrid(panel, 3, 2, 50, 10, 80, 60);
return panel;
}
private void okAction() {
if (fNameTf.getText().trim().length() != 0 && lNameTf.getText().trim().length() != 0) {
System.out.println("Data saved");
} else System.out.println("invalid data");
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == okBtn) {
okAction();
}
}
}
Declare a default button for your GUI's JRootPane:
public T3() {
//!! ..... etc...
setVisible(true);
getRootPane().setDefaultButton(okBtn);
}
In fact with a default button set, I don't see that you need to use key bindings.
I am making a battleship game and I'm trying to figure out a way to control buttons in a pane so that I can drag drop them and keep track of their indexes with a default list model.If I add string or ImageIcons it works fine but with buttons I get something different.
Here's my code:
public class ListModelExample extends JPanel {
JList list;
DefaultListModel model;
int counter = 15;
public ListModelExample() {
setLayout(new BorderLayout());
model = new DefaultListModel();
list = new JList(model);
JScrollPane pane = new JScrollPane(list);
JButton addButton = new JButton("Add Element");
JButton removeButton = new JButton("Remove Element");
final JButton button = new JButton("button");
for (int i = 0; i < 5; i++)
model.addElement(button);
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.addElement(button);
counter++;
}
});
removeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (model.getSize() > 0)
model.removeElementAt(0);
}
});
add(pane, BorderLayout.NORTH);
add(addButton, BorderLayout.WEST);
add(removeButton, BorderLayout.EAST);
}
public static void main(String s[]) {
JFrame frame = new JFrame("List Model Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new ListModelExample());
frame.setSize(260, 200);
frame.setVisible(true);
}
}
If I add Buttons I get this result:
So my question is: How is it possible to make buttons appear normally and not as text in a default list model?
this could be done only by Renderer, put only String value to the DefaultListModel
don't put any JComponents to the XxxModel
I'd be use JPanel with JButtons instead of JList as containers (required to change getScrollableBlockIncrement / getScrollableUnitIncrement for natural scrolling in compare with JList or JTable)
example about both a.m. ways
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.*;
public class ListButtons extends JFrame {
private static final long serialVersionUID = 1L;
public ListButtons() {
setLayout(new GridLayout(0, 2, 10, 10));
DefaultListModel model = new DefaultListModel();
model.addElement(createButtons("one"));
model.addElement(createButtons("two"));
model.addElement(createButtons("three"));
model.addElement(createButtons("four"));
model.addElement(createButtons("five"));
model.addElement(createButtons("six"));
model.addElement(createButtons("seven"));
model.addElement(createButtons("eight"));
model.addElement(createButtons("nine"));
model.addElement(createButtons("ten"));
model.addElement(createButtons("eleven"));
model.addElement(createButtons("twelwe"));
JList list = new JList(model);
list.setCellRenderer(new PanelRenderer());
JScrollPane scroll1 = new JScrollPane(list);
final JScrollBar scrollBar = scroll1.getVerticalScrollBar();
scrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("JScrollBar's current value = " + scrollBar.getValue());
}
});
add(scroll1);
JScrollPane scroll2 = new JScrollPane(createPanel());
add(scroll2);
final JScrollBar scrollBar1 = scroll2.getVerticalScrollBar();
scrollBar1.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("JScrollBar's current value = " + scrollBar1.getValue());
}
});
}
public static JPanel createPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1, 1, 1));
panel.add(createButtons("one"));
panel.add(createButtons("two"));
panel.add(createButtons("three"));
panel.add(createButtons("four"));
panel.add(createButtons("five"));
panel.add(createButtons("six"));
panel.add(createButtons("seven"));
panel.add(createButtons("eight"));
panel.add(createButtons("nine"));
panel.add(createButtons("ten"));
panel.add(createButtons("eleven"));
panel.add(createButtons("twelwe"));
return panel;
}
public static JButton createButtons(String text) {
JButton button = new JButton(text);
return button;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ListButtons frame = new ListButtons();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
//frame.pack();
frame.setSize(270, 200);
frame.setVisible(true);
}
});
}
class PanelRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JButton renderer = (JButton) value;
renderer.setBackground(isSelected ? Color.red : list.getBackground());
return renderer;
}
}
}
I'm having problems getting my JPanel to display properly. I want to use different extended JPanels to display what I want the user to do with this program (which is ultimately to display photographs). Below is the code for the only two classes that exist at this point. Unfortunately, I'm having problems just getting this to work right out of the gate with the first panel which was to present the user with the ability to select different graphic images.
What's happening is, I can't get my JPanel to display until I click the "Open" menu item in the File menu. Once that JOptionPane shows, so does my JPanel (NewAlbum).
class PhotoGallery {
static JPanel transientPanel = null;
static final JFrame mainFrame = new JFrame("Photo Gallery");
public static void main(String[] args) {
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
JMenuItem open = new JMenuItem("Open");
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(mainFrame, "Hello World");
}
});
fileMenu.add(open);
JMenuItem newAlbum = new JMenuItem("New Album");
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AssignToTransientPanel((JPanel) new NewAlbum());
Container content = mainFrame.getContentPane();
content.removeAll();
content.add(transientPanel);
content.validate();
content.repaint();
}
});
fileMenu.add(newAlbum);
JMenuItem exit = new JMenuItem("Exit");
exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
fileMenu.add(exit);
JMenuBar pgMenu = new JMenuBar();
pgMenu.add(fileMenu);
mainFrame.setJMenuBar(pgMenu);
mainFrame.setSize(640, 480);
mainFrame.setLocation(20, 45);
mainFrame.validate();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
public static void AssignToTransientPanel(JPanel jp) {
if(transientPanel != null)
mainFrame.remove(transientPanel);
transientPanel = jp;
}
}
}
class NewAlbum extends JPanel {
JButton selectImages = new JButton("Select Images");
JFileChooser jfc;
File[] selectedFiles;
public NewAlbum() {
selectImages.setLocation(25, 25);
add(selectImages);
selectImages.addActionListener(new ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent ae) {
jfc = new JFileChooser();
jfc.setMultiSelectionEnabled(true);
jfc.showOpenDialog(getParent());
selectedFiles = jfc.getSelectedFiles();
}
});
this.validate();
}
public int getHeight() {
return getParent().getSize().height - 20;
}
public int getWidth() {
return getParent().getSize().width - 20;
}
public Dimension getPreferredSize() {
return new Dimension(this.getWidth(), this.getHeight());
}
}
You have not added any components to the mainFrame's content pane in the main method. The only time a panel gets added is in this ActionListener:
open.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AssignToTransientPanel((JPanel) new NewAlbum());
Container content = mainFrame.getContentPane();
content.removeAll();
content.add(transientPanel);
content.validate();
content.repaint();
}
});
This is only getting called when "Open" is clicked as you have, I assume accidentally, added the ActionListener to the open JMenuItem rather than the newAlbum JMenuItem. To add content on startup you need to add something like this before the mainFrame.setVisible(true) line:
mainFrame.add(new NewAlbum());
BTW, the convention is for all methods in Java source code to start with a lower case letter. assignToTransientPanel would be a better name for your method.