So I'm working on making a database system built on top of a Java Swing GUI... I have one button that works to add a person/thing to a vector (in this case the database):
// Database
Vector<String> db = new Vector<String>();
Here is the button's actionlistener to add:
new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
This part all seems to be working fine, however, when I go to print out the vector on a JTextArea using a string buffer, there are odd spacing issues in the text on the JTextArea
Here is the StringBuffer and section where I print the vector onto the JTextArea:
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
// printDB is the JTextArea
printDB.setText(dbb.toString());
add(printDB);
Screenshot of spacing issues:
Screenshot
Any Ideas on what might be causing this? The spacing seems to be linear as well (1space, 2spaces, 3spaces...)
Link to full project if needed (Sorry for bad code in general lol i'm just beginning): Full Code
Sorry if linear isn't the right word btw I couldn't think of another way to describe it
Code:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import java.util.Vector.*;
import javax.swing.*;
public class Database extends JFrame implements ActionListener, EventListener {
// Database
Vector<String> db = new Vector<String>();
// Main Menu Buttons:
JButton addStudent = new JButton("Add Student");
JButton deleteStudent = new JButton("Delete Button");
JButton deleteAll = new JButton("Delete All Students");
JButton printAll = new JButton("Print Database");
JTextArea welcome = new JTextArea("Welcome!");
// Add Student Menu:
JTextField student = new JTextField();
JButton submit = new JButton("Add Student");
// Print Students
JTextArea printDB = new JTextArea();
JButton returnMenu = new JButton("Return to Menu");
public Database() {
super("DatabaseGUI");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setResizable(false);
welcome.setBackground(this.getForeground());
add(welcome);
welcome.setSize(60, 15);
welcome.setLocation(386, 300);
add(addStudent);
addStudent.setSize(150, 50);
addStudent.setLocation(25, 100);
add(deleteStudent);
deleteStudent.setSize(150, 50);
deleteStudent.setLocation(625, 100);
add(deleteAll);
deleteAll.setLocation(225, 100);
deleteAll.setSize(150, 50);
add(printAll);
printAll.setLocation(425, 100);
printAll.setSize(150, 50);
addStudent.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
add(student);
add(submit);
submit.setVisible(true);
submit.setSize(150, 30);
submit.setLocation(425, 250);
student.setVisible(true);
student.setSize(150, 30);
student.setLocation(275, 250);
submit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newStudent = student.getText();
db.addElement(newStudent);
student.setText(null);
student.setVisible(false);
submit.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
printAll.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
welcome.setVisible(false);
addStudent.setVisible(false);
deleteStudent.setVisible(false);
deleteAll.setVisible(false);
printAll.setVisible(false);
StringBuffer dbb = new StringBuffer();
for (int i = 0; i < db.size(); i++) {
dbb.append(db.get(i) + '\n');
}
printDB.setText(dbb.toString());
add(printDB);
printDB.setSize(300, 400);
printDB.setEditable(false);
printDB.setLocation(100, 100);
printDB.setVisible(true);
add(returnMenu);
returnMenu.setVisible(true);
returnMenu.setSize(200, 30);
returnMenu.setLocation(500, 400);
returnMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
returnMenu.setVisible(false);
printDB.setVisible(false);
welcome.setVisible(true);
addStudent.setVisible(true);
deleteStudent.setVisible(true);
deleteAll.setVisible(true);
printAll.setVisible(true);
}
});
}
});
setVisible(true);
}
public static void main(String[] args) {
Database student = new Database();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You're adding an ActionListener to the submit button repeatedly within the addStudent ActionListener, meaning as addStudent is pressed, more and more ActionListeners will be added to submit and this is not what you want.
Suggestions:
Add an ActionListener just once to your JButtons and not within other event listeners which may be called multiple times. Consider adding all ActionListeners within your class constructor.
Side recs:
Don't use absolute positioning and null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
Learn how to use and then use CardLayout to allow you to cleanly and easily swap your views.
For example,
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Database2 extends JPanel {
// constants for the cards
public static final String WELCOME = "welcome";
public static final String ADD_STUDENT = "add student";
public static final String DISPLAY_DATA = "display data";
private JTextArea displayTextArea = new JTextArea(15, 20);
private JTextField addStudentField = new JTextField(10);
private CardLayout cardLayout = new CardLayout();
private List<String> db = new ArrayList<>();
public Database2() {
// prepare JTextArea
displayTextArea.setWrapStyleWord(true);
displayTextArea.setLineWrap(true);
displayTextArea.setFocusable(false);
// set layout as CardLayout and add all JPanels with constants
setLayout(cardLayout);
add(createWelcomePanel(), WELCOME);
add(createAddStudentPanel(), ADD_STUDENT);
add(createDisplayDataPanel(), DISPLAY_DATA);
}
private JPanel createWelcomePanel() {
ShowStudentPanelAction showStudentAction = new ShowStudentPanelAction("Add Student");
DisplayDataAction displayDataAction = new DisplayDataAction("Display Data");
JButton addStudentButton = new JButton(showStudentAction);
JButton displayDataButton = new JButton(displayDataAction);
JPanel topPanel = new JPanel(new GridLayout(1, 0, 5, 0));
topPanel.add(addStudentButton);
topPanel.add(displayDataButton);
topPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
JLabel welcomeLabel = new JLabel("Welcome", SwingConstants.CENTER);
// make JLabel text bigger
welcomeLabel.setFont(welcomeLabel.getFont().deriveFont(Font.BOLD, 42f));
// and give it a border 30 points wide
int ebGap = 30;
welcomeLabel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap,
ebGap, ebGap));
JPanel welcomePanel = new JPanel(new BorderLayout());
ebGap = 4;
welcomePanel.setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
welcomePanel.add(topPanel, BorderLayout.PAGE_START);
welcomePanel.add(welcomeLabel, BorderLayout.CENTER);
return welcomePanel;
}
private JPanel createAddStudentPanel() {
AddStudentAction addStudentAction = new AddStudentAction("Add Student");
addStudentField.setAction(addStudentAction);
JPanel addStudentPanel = new JPanel();
addStudentPanel.add(addStudentField);
addStudentPanel.add(new JButton(addStudentAction));
return addStudentPanel;
}
private JPanel createDisplayDataPanel() {
JPanel displayDataPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane(displayTextArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
displayDataPanel.add(scrollPane);
displayDataPanel.add(new JButton(new ReturnToWelcomeAction("Return")));
return displayDataPanel;
}
private class ShowStudentPanelAction extends AbstractAction {
public ShowStudentPanelAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, ADD_STUDENT);
addStudentField.requestFocusInWindow();
addStudentField.selectAll();
}
}
private class DisplayDataAction extends AbstractAction {
public DisplayDataAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
StringBuilder sb = new StringBuilder();
for (String studentName : db) {
sb.append(studentName + "\n");
}
displayTextArea.setText(sb.toString());
cardLayout.show(Database2.this, DISPLAY_DATA);
}
}
private class AddStudentAction extends AbstractAction {
public AddStudentAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
String studentText = addStudentField.getText();
db.add(studentText);
cardLayout.show(Database2.this, WELCOME);
}
}
private class ReturnToWelcomeAction extends AbstractAction {
public ReturnToWelcomeAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(Database2.this, WELCOME);
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Window window = SwingUtilities.getWindowAncestor(Database2.this);
if (window != null) {
window.dispose();
}
}
}
private static void createAndShowGui() {
Database2 mainPanel = new Database2();
JFrame frame = new JFrame("Database2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I am trying to create a GUI and in that GUI I have different JLabels with a value. I want to be able to click on a JLabel to edit it in my JTextfield (only have 1) and after I press enter it should leave Editing the JLabel. At the moment if I try to edit a JLabel it will change but when I click on the next one the old one will also still change.
This is my code:
public class GUI {
JFrame frame;
int n1=1;
int n2=1;
int n3=1;
GUI(){
frame=new JFrame();//creating instance of JFrame
JLabel l1=new JLabel(Integer.toString(n1));
JLabel l2=new JLabel(Integer.toString(n2));
JLabel l3=new JLabel(Integer.toString(n3));
JTextField t=new JTextField();
l1.setBounds(40,50,100, 40);
l2.setBounds(40,100,100, 40);
l3.setBounds(40,150,100, 40);
t.setBounds(20,200,100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
l1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l1.setText(t.getText());
n1=parseInt(t.getText());
}
});
}
});
l2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
l2.setText(t.getText());
n2=parseInt(t.getText());
}
});
}
});
frame.setSize(400,500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
public static void main(String[] args) {
new GUI();
}
}
Thanks in advance.
Don't add action listeners for each click. Clicking on a label should record the state of your UI -- that that label is now being edited, and set up the value in the JTextField. Then enter should transfer the value to the JLabel which was recorded as selected.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();//creating instance of JFrame
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
l1.setBounds(40, 50, 100, 40);
l2.setBounds(40, 100, 100, 40);
l3.setBounds(40, 150, 100, 40);
t.setBounds(20, 200, 100, 40);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.setSize(400, 500);//400 width and 500 height
frame.setLayout(null);//using no layout managers
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
Figuring out how to set n1, n2, ... is left as an exercise, as is how to indicate in the UI that no label is selected (hint: should you allow input in the JTextField when no label has been selected?)
As #kleopatra says, using no layout manager is not good practice, as if your panel is resized (perhaps your program will be run on a mobile device, for instance) your components may become hidden, See this discussion.
Here's your code using GridLayout, a simple layout manager.
Points to note:
I've removed the absolute positioning and sizing of the components and the frame.
The frame is now resizable, so you can see what the layout manager does as the size changes.
The JFrame is packed before displaying it.
To get a layout which does exactly what you want you can look at GridBagLayout, and also think about nesting containers with simple layout managers.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GUI {
JLabel currentEditLabel = null;
JFrame frame;
int n1 = 1;
int n2 = 1;
int n3 = 1;
GUI() {
frame = new JFrame();
JLabel l1 = new JLabel(Integer.toString(n1));
JLabel l2 = new JLabel(Integer.toString(n2));
JLabel l3 = new JLabel(Integer.toString(n3));
JTextField t = new JTextField();
GridLayout layout = new GridLayout(4, 1, 10, 10);
frame.setLayout(layout);
frame.add(l1);
frame.add(l2);
frame.add(l3);
frame.add(t);
frame.setResizable(true);
t.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (currentEditLabel != null) {
currentEditLabel.setText(t.getText());
currentEditLabel = null;
}
}
});
addMouseListener(l1, t);
addMouseListener(l2, t);
addMouseListener(l3, t);
frame.pack();
frame.setVisible(true);//making the frame visible
}
private void addMouseListener(JLabel label, JTextField t) {
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
currentEditLabel = (JLabel) e.getComponent();
t.setText(currentEditLabel.getText());
}
});
}
public static void main(String[] args) {
new GUI();
}
}
I'm having trouble with the functionality of dispose for my checkerboard (called Checkers) . For each checkerboard that I have, i want to be able to remove it by using dispose before calling another instance of my interface. Here is my progress so far:
Checkers class:
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int i;
public int score;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel pane3 = new JPanel();
private JButton btn1 = new JButton("Play A Game");
private JButton btn2 = new JButton("Exit");
private JButton btn3 = new JButton("Easy");
private JButton btn4 = new JButton("Intermediate");
private JButton btn5 = new JButton("Difficult");
private JLabel lbl1 = new JLabel ("score: " + score);
private JLabel gameLost = new JLabel("You lose! You got: " + score + " points");
private MyPanel [] panel = new MyPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color col3 = Color.GREEN;
private Color tempColor;
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
setBackground(Color.BLACK);
setBoard();
}
public void setBoard()
// roates colors on the checkbaord
{
for (int i = 0; i < panel.length; i++) {
panel[i] = new MyPanel(this);
pane.add(panel[i]);
if (i % COLS == 0) {
tempColor = col1;
col1 = col2;
col2 = tempColor;}
if (i % 2 == 0) {
panel[i].setBackground(col1);}
else {
panel[i].setBackground(col2);}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.white);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.add(lbl1);
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
public void incrementScore(){
score++;
lbl1.setText("Score: " + Integer.toString(score));
}
//This is the method for resetting via dispose - only works once.
public void restartBoard(){
this.dispose();
new Checkers();
}
}
And also the MyPanel class
public class MyPanel extends JPanel implements MouseListener {
private final Checkers checkers;
public MyPanel(Checkers checkers) {
this.checkers = checkers;
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
setBackground(Color.BLACK);
checkers.incrementScore();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
EXPECTED RESULT - What i'd like to do is be able to close the current version of interface by using the dispose method, and then opening a new instance of said interface.
ACTUAL RESULT - When opening an interface, then calling dispose method, it will work once. once you try to remove the 2nd interface when creating a 3rd interface, dispose will not function, and I cant see why this is.
Any help is welcome.
For what it's worth, this is an MCVE that shows your likely problem:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static void createAndShowGui() {
Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
restartButton.addActionListener(event -> checkers.restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
public void restartBoard(){
this.dispose();
new Checkers();
}
}
The restart button refers to the original Checkers instance and so will not close any new instances created. The solution would be to get the restart method out of Checkers, create a Checkers field, and make sure the restart method refers to the visible Checkers instance:
import java.awt.Dimension;
import javax.swing.*;
public class CheckersTest {
private static Checkers checkers = new Checkers(); // holds reference
private static void restartBoard() {
if (checkers != null) {
checkers.dispose();
checkers = new Checkers(); // assign to reference field
}
}
private static void createAndShowGui() {
// !! Checkers checkers = new Checkers();
JButton restartButton = new JButton("Restart");
// !! restartButton.addActionListener(event -> checkers.restartBoard());
restartButton.addActionListener(event -> restartBoard());
JPanel restartPanel = new JPanel();
restartPanel.setPreferredSize(new Dimension(400, 400));
restartPanel.add(restartButton);
JFrame frame = new JFrame("Checkers Test");
frame.add(restartPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Checkers extends JFrame {
public Checkers() {
setPreferredSize(new Dimension(200, 200));
pack();
setLocationByPlatform(true);
setVisible(true);
}
}
Notes:
Again a much better design is not to swap JFrames but rather JPanel views
Note that the MCVE has code that reproduces the problem but avoids code not related to the problem. So it shows the restartBoard method, it compiles, but avoids game code since this is not relevant to the problem.
I am dynamically adding items to my JPanel through an ArrayList<Items>. Basically the items object looks like that:
public class Item {
private JComponent component;
private String functionality;
public Item(JComponent component, String functionality) {
super();
this.component = component;
this.functionality = functionality;
}
public JComponent getComponent() {
return component;
}
public void setComponent(JComponent component) {
this.component = component;
}
public String getFunctionality() {
return functionality;
}
public void setFunctionality(String functionality) {
this.functionality = functionality;
}
}
Here I am adding my buttons dynamically: (try the example out if you want)
public class minimumExample extends JFrame {
private JButton addItem;
private JComboBox itemBox;
private String[] itemSelect = { "test1", "test2" };
private JPanel addUpperPane;
private JPanel addLowerPane;
private ArrayList<Item> displayedItems = new ArrayList<Item>();
private JButton upButton;
private JButton downButton;
private JButton deleteButton;
public void createControlPane() {
addUpperPane = new JPanel();
addLowerPane = new JPanel(new GridLayout(0, 1));
addItem = new JButton("Add item");
upButton = new JButton("Up");
downButton = new JButton("Down");
deleteButton = new JButton("Delete");
itemBox = new JComboBox(itemSelect);
addItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(itemBox.getSelectedItem().toString().equals("test1")) {
displayedItems.add(new Item( new ButtonComp().butt(), "test1"));
validate();
repaint();
}
if(itemBox.getSelectedItem().toString().equals("test2")) {
displayedItems.add(new Item( new LabelComp().label(), "test2"));
validate();
repaint();
}
for (int i = 0; i < displayedItems.size(); i++) {
addLowerPane.add(displayedItems.get(i).getComponent());
validate();
repaint();
}
}
});
addUpperPane.add(itemBox, BorderLayout.EAST);
addUpperPane.add(addItem, BorderLayout.WEST);
addUpperPane.add(new JLabel(" | "), BorderLayout.WEST);
addUpperPane.add(upButton, BorderLayout.WEST);
addUpperPane.add(downButton, BorderLayout.WEST);
addUpperPane.add(deleteButton, BorderLayout.WEST);
addUpperPane.add(new JSeparator(JSeparator.HORIZONTAL));
//put everything together
add(addUpperPane, BorderLayout.NORTH);
add(addLowerPane, BorderLayout.SOUTH);
repaint();
}
private void makeLayout() {
setTitle("Test App");
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 500));
createControlPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
/**
* starts the GUI
*/
public void start() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
makeLayout();
}
});
}
public static void main(String[] args) throws IOException {
minimumExample ex = new minimumExample();
ex.start();
}
public class ButtonComp extends Component {
public JPanel butt() {
JPanel panel = new JPanel();
JButton button = new JButton("Test1");
JCheckBox check = new JCheckBox();
panel.add(button);
panel.add(check);
return panel;
}
}
public class LabelComp extends Component {
public JPanel label() {
JPanel panel = new JPanel();
JLabel label = new JLabel("Test2");
JCheckBox check = new JCheckBox();
panel.add(label);
panel.add(check);
return panel;
}
}
}
The program basically looks like that:
My problem is that the buttons Up, Down and Delete do not work, because I do not know how to get the selected element from the pane to delete it from the list where all components are in. Any recommendations on how to make this work?
I really appreciate your answer!
UPDATE
I changed my code your specifications #cghislai but it does not work. Try it out yourself:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
public class minimumExample extends JFrame {
private JButton addItem;
private JComboBox itemBox;
private String[] itemSelect = { "test1", "test2" };
private JPanel addUpperPane;
private JPanel addLowerPane;
private List<CheckableItem> displayedItems = new ArrayList<CheckableItem>();
private JButton upButton;
private JButton downButton;
private JButton deleteButton;
public void createControlPane() {
addUpperPane = new JPanel();
addLowerPane = new JPanel(new GridLayout(0, 1));
addItem = new JButton("Add item");
upButton = new JButton("Up");
downButton = new JButton("Down");
deleteButton = new JButton("Delete");
itemBox = new JComboBox(itemSelect);
addItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(itemBox.getSelectedItem().toString().equals("test1")) {
ButtonComp butt = new ButtonComp();
butt.init();
displayedItems.add(butt);
validate();
repaint();
}
if(itemBox.getSelectedItem().toString().equals("test2")) {
// displayedItems.add(new CopyOfItem( new LabelComp(), "test2"));
validate();
repaint();
}
for (int i = 0; i < displayedItems.size(); i++) {
addLowerPane.add(displayedItems.get(i).getComponent());
validate();
repaint();
}
}
});
deleteButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Iterator<CheckableItem> it = displayedItems.iterator();
while (it.hasNext()) {
CheckableItem next = it.next();
if (next.isSelected()) {
addLowerPane.remove(next.getComponent());
it.remove();
continue;
}
}
}
});
addUpperPane.add(itemBox, BorderLayout.EAST);
addUpperPane.add(addItem, BorderLayout.WEST);
addUpperPane.add(new JLabel(" | "), BorderLayout.WEST);
addUpperPane.add(upButton, BorderLayout.WEST);
addUpperPane.add(downButton, BorderLayout.WEST);
addUpperPane.add(deleteButton, BorderLayout.WEST);
addUpperPane.add(new JSeparator(JSeparator.HORIZONTAL));
//put everything together
add(addUpperPane, BorderLayout.NORTH);
add(addLowerPane, BorderLayout.SOUTH);
repaint();
}
private void makeLayout() {
setTitle("Test App");
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 500));
createControlPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
/**
* starts the GUI
*/
public void start() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
makeLayout();
}
});
}
public static void main(String[] args) throws IOException {
minimumExample ex = new minimumExample();
ex.start();
}
public abstract class CheckableItem {
protected JCheckBox check;
public boolean isSelected() {
return check.isSelected();
}
public abstract Component getComponent();
}
public class ButtonComp extends CheckableItem {
JPanel panel = new JPanel();
public void init() {
JButton button = new JButton("Test1");
check = new JCheckBox();
panel.add(button);
panel.add(check);
}
#Override
public Component getComponent() {
return panel;
}
}
public class LabelComp extends JPanel {
public void label() {
// JPanel panel = new JPanel();
JLabel label = new JLabel("Test2");
JCheckBox check = new JCheckBox();
add(label);
add(check);
}
}
}
You need to traverse all your items, check if the item checkbox is selected, if this is the case, remove your item from the panel. I would make an abstract CheckableItem class with a getter to the JCheckbox and the Component. Then, for each of you item, if the checkbox is selected, remove the component from the parent.
public abstract class CheckableItem {
protected JCheckbox checkbox;
public boolean isSelected() {
return checkbox.isSelected();
}
public abstract Component getComponent();
}
public class ButtonComp extends CheckableItem {
private Panel panel;
public void init() {
checkbox = new JCheckbox;
panel = new JPanel();
panel.add(new JButton());
panel.add(checkbox);
}
public Component getComponent() {
return panel;
}
}
Then to keep track of your items:
private List<CheckableItem> items = new ArrayList<>();
// ...
ButtonComp comp = new ButtonComp();
comp.init();
items.add(comp);
Then to remove all checked:
Iterator<CheckbleItem> it = items.iterator();
while (it.hasNext()) {
CheckableItem next = it.next();
if (next.isSelected()) {
mainPanel.remove(next.getComponent());
it.remove();
continue;
}
}
Why don't you just have your ButtomComp and LabelComp extend from JPanel? This would solve a lot of your problems I think. For example :
public class ButtonComp extends JPanel {
JButton button;
JCheckBox check = new JCheckBox();
public ButtonComp() {
button = new JButton("Test1");
this.add(button);
this.add(check);
}
}
Then all you would need to do is iterate over your items and look at the checkbox in the components :
for (int i = 0; i < displayedItems.size(); i++) {
if (displayedItems.get(i).check.isSelected()) {
displayedItems.remove(i);
}
}
Note: haven't tested this code. But you should get the idea.
I have created 2 classes that are working together to show pictures by clicking different buttons. In my EventEvent class I tried to make it so that when you press the "Picture 1" button, the variable ImageIcon xpic gets the value of ImageIcon vpic (which holds an image), after xpic has the same value as vpic my frame is supposed to somehow refresh so that xpic's new value applies and gets then shows the picture.
Why doesn't my image show up even though the button press repaints the JPanel the image is in?
Main class:
import java.awt.*;
import javax.swing.*;
public class EventMain extends JFrame{
EventEvent obje = new EventEvent(this);
// Build Buttons
JButton picB1;
JButton picB2;
JButton picB3;
JButton picB4;
JButton picB5;
//Build Panels
JPanel row0;
//Build Pictures
ImageIcon xpic;
ImageIcon vpic;
public EventMain(){
super("Buttons");
setLookAndFeel();
setSize(470, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridLayout layout1 = new GridLayout(3,4);
setLayout(layout1);
picB1 = new JButton("Picture 1");
picB2 = new JButton("Picture 2");
picB3 = new JButton("Picture 3");
picB4 = new JButton("Picture 4");
picB5 = new JButton("Picture 5");
vpic = new ImageIcon(getClass().getResource("Images/vanessa.png"));
// Set up Row 0
row0 = new JPanel();
JLabel statement = new JLabel("Choose a picture: ", JLabel.LEFT);
JLabel picture = new JLabel(xpic);
// Set up Row 1
JPanel row1 = new JPanel();
// Set up Row 2
JPanel row2 = new JPanel();
//Listeners
picB1.addActionListener(obje);
FlowLayout grid0 = new FlowLayout (FlowLayout.CENTER);
row0.setLayout(grid0);
row0.add(statement);
row0.add(picture);
add(row0);
FlowLayout grid1 = new FlowLayout(FlowLayout.CENTER);
row1.setLayout(grid1);
row1.add(picB1);
row1.add(picB2);
add(row1);
FlowLayout grid2 = new FlowLayout(FlowLayout.CENTER);
row2.setLayout(grid2);
row2.add(picB3);
row2.add(picB4);
row2.add(picB5);
add(row2);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.NimbusLookAndFeel");
} catch (Exception exc) {
}
}
public static void main(String[] args) {
EventMain con = new EventMain();
}
}
Class containing events:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventEvent implements ActionListener {
EventMain gui;
public EventEvent(EventMain in){
gui = in;
}
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals("Picture 1")){
gui.xpic = gui.vpic;
gui.row0.repaint();
}
}
}
You're confusing variables with objects. Just because you change the object associated with the xpic variable, don't assume that this will change the object (the Icon) held by the JLabel. There is no magic in Java, and changing the object that a variable refers to will have no effect on the prior object.
In other words, this:
gui.xpic = gui.vpic;
gui.row0.repaint();
will have no effect on the icon that the picture JLabel is displaying
To swap icons, you must call setIcon(...) on the JLabel. Period. You will need to make the picture JLabel a field, not a local variable, and give your GUI class a public method that allows outside classes to change the state of the JLabel's icon.
Also, you should not manipulate object fields directly. Instead give your gui public methods that your event object can call.
Edit
For example:
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyGui extends JPanel {
public static final String IMAGE_PATH = "https://duke.kenai.com/cards/.Midsize/CardFaces.png.png";
private static final int ROWS = 4;
private static final int COLS = 13;
private BufferedImage largeImg;
private List<ImageIcon> iconList = new ArrayList<>();
private JLabel pictureLabel = new JLabel();
private JButton swapPictureBtn = new JButton(new SwapPictureAction(this, "Swap Picture"));
private int iconIndex = 0;
public MyGui() throws IOException {
add(pictureLabel);
add(swapPictureBtn);
URL imgUrl = new URL(IMAGE_PATH);
largeImg = ImageIO.read(imgUrl);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
int x = (j * largeImg.getWidth()) / COLS;
int y = (i * largeImg.getHeight()) / ROWS;
int w = largeImg.getWidth() / COLS;
int h = largeImg.getHeight() / ROWS;
iconList.add(new ImageIcon(largeImg.getSubimage(x, y, w, h)));
}
}
pictureLabel.setIcon(iconList.get(iconIndex));
}
public void swapPicture() {
iconIndex++;
iconIndex %= iconList.size();
pictureLabel.setIcon(iconList.get(iconIndex));
}
private static void createAndShowGui() {
MyGui mainPanel;
try {
mainPanel = new MyGui();
JFrame frame = new JFrame("MyGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class SwapPictureAction extends AbstractAction {
private MyGui myGui;
public SwapPictureAction(MyGui myGui, String name) {
super(name);
this.myGui = myGui;
}
#Override
public void actionPerformed(ActionEvent e) {
myGui.swapPicture();
}
}
See the createAction() method below and how it creates an AbstractAction. See also the tutorial related to using actions with buttons. http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
import javax.swing.*;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import java.awt.*;
import java.awt.event.ActionEvent;
public class EventMain {
private static final ImageIcon PICTURE_1 = new ImageIcon(EventMain.class.getResource("images/v1.png"));
private static final ImageIcon PICTURE_2 = new ImageIcon(EventMain.class.getResource("images/v2.png"));
private JFrame frame;
EventMain create() {
setLookAndFeel();
frame = createFrame();
frame.getContentPane().add(createContent());
return this;
}
void show() {
frame.setSize(470, 300);
frame.setVisible(true);
}
private JFrame createFrame() {
JFrame frame = new JFrame("Buttons");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}
private Component createContent() {
final JLabel picture = new JLabel();
JButton picB1 = new JButton(createAction("Picture 1", picture, PICTURE_1));
JButton picB2 = new JButton(createAction("Picture 2", picture, PICTURE_2));
JButton picB3 = new JButton(createAction("Picture 3", picture, PICTURE_1));
JButton picB4 = new JButton(createAction("Picture 4", picture, PICTURE_2));
JButton picB5 = new JButton(createAction("Picture 5", picture, PICTURE_1));
JLabel statement = new JLabel("Choose a picture: ", JLabel.LEFT);
// Create rows 1, 2, 3
JPanel panel = new JPanel(new GridLayout(3, 4));
panel.add(createRow(statement, picture));
panel.add(createRow(picB1, picB2));
panel.add(createRow(picB3, picB4, picB5));
return panel;
}
/**
* Create an action for the button. http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
*/
private Action createAction(String label, final JLabel picture, final Icon icon) {
AbstractAction action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
picture.setIcon(icon);
}
};
action.putValue(Action.NAME, label);
return action;
}
private Component createRow(Component... componentsToAdd) {
JPanel row = new JPanel(new FlowLayout(FlowLayout.CENTER));
for (Component component : componentsToAdd) {
row.add(component);
}
return row;
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(new NimbusLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new EventMain().create().show();
}
});
}
}
I have a JFrame which contains 2 JPanel subclass and 2 JLabel in BorderLayout. One of the JPanel contains JButtons and the other is used for displaying graphics. The JLabels are in north and south, the button JPanel in the west and the display JPanel in center.
The display JPanel requires constant refresh, so i invoke its repaint() method via the action event generated by swing timer. I also override its paintComponent() method to do my drawings.
Instead of displaying what i have drawn, the "content of the JFrame" is being drawn onto the display JPanel. I am aware that i can simply "clear" the display JPanel by using g.fillRect() or super.paintComponent() before doing my drawings.
I am just curious why this happens.
i'm using jdk 1.6u27. below is my code:
package test;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Main {
public static void main(String[] args) {
Simulation sim = new Simulation();
}
}
class Simulation extends JFrame {
public JLabel state;
private JLabel id;
private ButtonPanel control;
private Display display;
public Simulation() {
id = new JLabel("Test");
state = new JLabel("Test");
control = new ButtonPanel();
display = new Display(this);
this.setLayout(new BorderLayout());
this.add(id, BorderLayout.NORTH);
this.add(control, BorderLayout.WEST);
this.add(display, BorderLayout.CENTER);
this.add(state, BorderLayout.SOUTH);
this.setSize(500, 600);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public ButtonPanel getControl() {
return this.control;
}
}
class ButtonPanel extends JPanel implements ActionListener {
public JButton b[] = new JButton[8];
public boolean bp[] = new boolean[8];
public ButtonPanel() {
this.setLayout(new GridLayout(8, 1));
for (int i = 0; i < b.length; i++) {
b[i] = new JButton(""+i);
b[i].addActionListener(this);
bp[i] = false;
this.add(b[i]);
}
}
public void actionPerformed(ActionEvent e) {
//do something
}
}
class Display extends JPanel implements ActionListener {
private Timer tm;
private int yco;
private Simulation sim;
public Display(Simulation sim) {
tm = new Timer(100, this);
tm.start();
yco = 0;
this.sim = sim;
}
#Override
public void paintComponent(Graphics g) {
//draw something
g.drawLine(0, yco, 100, 100);
}
public void actionPerformed(ActionEvent e) {
yco ++;
this.repaint();
}
}
Without super.paintComponent(g), the result depends on your platform's default for the opacity property of the JPanel UI delegate, PanelUI. Mine happens to be true, but you can experiment on your platform, as suggested below.
Addendum: "If you do not honor the opaque property you will likely see visual artifacts."—paintComponent(). The artifact you observe will vary by platform, but it is not atypical. In effect, you are breaking the promise to draw every pixel, and you see whatever is left over in some buffer.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Simulation sim = new Simulation();
}
});
}
}
class Simulation extends JFrame {
public JCheckBox state;
private JLabel id;
private ButtonPanel control;
private Display display;
public Simulation() {
id = new JLabel("Test");
state = new JCheckBox("Opaque");
control = new ButtonPanel();
display = new Display(this);
this.setLayout(new BorderLayout());
this.add(id, BorderLayout.NORTH);
this.add(control, BorderLayout.WEST);
this.add(display, BorderLayout.CENTER);
this.add(state, BorderLayout.SOUTH);
state.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
display.setOpaque(e.getStateChange() == ItemEvent.SELECTED);
}
});
state.setSelected(true);
this.pack();
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public ButtonPanel getControl() {
return this.control;
}
}
class ButtonPanel extends JPanel {
private static final int N = 8;
private List<JToggleButton> list = new ArrayList<JToggleButton>(N);
public ButtonPanel() {
this.setLayout(new GridLayout(0, 1));
for (int i = 0; i < N; i++) {
final JToggleButton b = new JToggleButton(String.valueOf(i));
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//System.out.println(b.isSelected());
}
});
list.add(b);
this.add(b);
}
}
}
class Display extends JPanel {
private Simulation sim;
private Timer tm;
private int yco;
public Display(Simulation sim) {
this.setPreferredSize(new Dimension(320, 320));
this.setOpaque(true);
this.sim = sim;
tm = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
yco++;
repaint();
}
});
tm.start();
}
#Override
public void paintComponent(Graphics g) {
//super.paintComponent(g);
g.drawLine(0, yco, getWidth() / 2, getHeight() / 2);
}
}