how does JFrame refresh itself? - java

this is my code
public class ComboBoxDemo extends JFrame {
ArrayList<Common.DescriptionPanel> cartoon = new ArrayList<Common.DescriptionPanel>();
ArrayList<ImageIcon> image = new ArrayList<ImageIcon>();
ArrayList<String> title = new ArrayList<String>();
ArrayList<String> description = new ArrayList<String>();
JComboBox combo = new JComboBox();
Common.DescriptionPanel panel = new Common.DescriptionPanel();
public static void main(String[] args) {
new Common.SetFrame(new ComboBoxDemo(), "Combo Box");
}
public ComboBoxDemo() {
addCartoon(new ImageIcon("c.jpg"), "Mario", "This is Mario");
addCartoon(new ImageIcon("d.jpg"), "Sonic", "This is Sonic");
addCartoon(new ImageIcon("e.jpg"), "Astro Boy", "This is Astro Boy");
for (int i = 0; i < cartoon.size(); i++) {
cartoon.get(i).setImage(image.get(i));
cartoon.get(i).setTitle(title.get(i));
cartoon.get(i).setDescription(description.get(i));
combo.addItem(title.get(i));
}
combo.setBackground(Color.white);
combo.setForeground(Color.blue);
combo.setSelectedItem(cartoon.get(0));
panel = cartoon.get(0);
add(combo, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel = cartoon.get(combo.getSelectedIndex());
pack();
System.out.println(panel.textArea.getText());
}
});
}
void addCartoon(ImageIcon image, String title, String description) {
cartoon.add(new Common.DescriptionPanel());
this.image.add(image);
this.title.add(title);
this.description.add(description);
}
}
and the code of DescriptionPanel is
public class DescriptionPanel extends JPanel {
private JLabel imageTitle = new JLabel();
public JTextArea textArea = new JTextArea();
public DescriptionPanel() {
imageTitle.setHorizontalAlignment(JLabel.CENTER);
imageTitle.setHorizontalTextPosition(JLabel.CENTER);
imageTitle.setVerticalTextPosition(JLabel.BOTTOM);
imageTitle.setFont(Common.SetFont.boldFont);
textArea.setLineWrap(true); //when one line doesn't fit, it will jump to next line automatically
/*
* The wrapStyleWord property is set to true (line 23) so that the line is wrapped
* on words rather than characters.
*/
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
textArea.setFont(Common.SetFont.boldFont);
textArea.setForeground(Color.blue);
JScrollPane scrollpane = new JScrollPane(textArea);
setLayout(new GridLayout(1, 2));
add(imageTitle);
add(scrollpane);
}
public void setImage(ImageIcon image) {
imageTitle.setIcon(image);
}
public void setTitle(String title) {
imageTitle.setText(title);
}
public void setDescription(String description) {
textArea.setText(description);
}
}
when I reselect the combobox, JFrame won't change at all,
so i replace the code
panel = cartoon.get(combo.getSelectedIndex());
to the code
panel.setTitle(title.get(combo.getSelectedIndex()));
panel.setDescription(description.get(combo.getSelectedIndex()));
panel.setImage(image.get(combo.getSelectedIndex()));
and it works.
so what is the difference of these two code?
In the first code, the panel apparently change, because when I print the textarea out, it is different from the initial panel, but JFrame doesn't change.
why the second code can work?

panel = cartoon.get(combo.getSelectedIndex());
This simply changes the reference of panel (what it's pointing to in memory) to what ever is stored within the current combobox position. It does not effect what panel was once referencing.
panel.setTitle(title.get(combo.getSelectedIndex()));
panel.setDescription(description.get(combo.getSelectedIndex()));
panel.setImage(image.get(combo.getSelectedIndex()));
Changes the properties of the current object that the variable panel is referencing.
Because you have previous added panel to the frame (add(panel, BorderLayout.CENTER);, it will effect the component that is on the screen.
You should NEVER maintain component based data within this type of component. Instead, your combobox should be filled with data, which it can use to renderer a desired result, based on the current needs of the UI and which you can use to effect some other view. This is the basic concept of the Model-View-Controller paradigm.

Related

How to find the text of anonymous jtextfield

So i am making a shop system with a gui. I have a menu item that when i press it opens another jframe to input the number of each item sold in a jtextfield, like this:
JPanel salesPanel = new JPanel();
setSize(new Dimension(520,270));
setResizable(false);
setLocation(200,200);
title = new JLabel("<html><u><b>Fill in the number of products sold.</b></u></html>");
salesPanel.setSize(new Dimension(230,30*sw.getProductList().size()));
salesPanel.setLayout(new GridLayout(sw.getProductList().size()+1,3));
...
sw.getProductList().forEach(n ->{
salesPanel.add(new JLabel(Integer.toString(n.getProductID())+":"));
salesPanel.add(new JLabel(Integer.toString(n.getQuantity())));
salesPanel.add(new JLabel(n.getName()));
salesPanel.add(new JTextField());
});
This is how it looks.
Note that sw is the object of the main class which has an ArrayList of the type product which contains the information of each product.
Is there any way that I can text from these JTextFields ? And if not what is another way that I can do this.
EDIT:
in the main ShopWindow class, I have an ArrayList
private ArrayList<Product> productList = new ArrayList<Product>();
class product:
public class Product {
private int productID;
private String name;
private double price;
private int quantity;
private boolean isPerishable;
private double totalProdValue;
...getters and setters for each field
This is a mock solution (only meant to show how to update qty label and clear fields using action listeners)
public class MockFrame {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel framePanel = new JPanel();
ProductPanel bananaPanel = new ProductPanel("268", "25", "Bananas");
ProductPanel sugarPanel = new ProductPanel("321", "200", "Sugar");
JPanel buttonPanel = new JPanel();
JButton update = new JButton("Update");
JButton cancel = new JButton("Cancel");
buttonPanel.setSize(400, 30);
update.setSize(50, 20);
cancel.setSize(50, 20);
buttonPanel.add(update);
buttonPanel.add(cancel);
update.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bananaPanel.setNewQty();
sugarPanel.setNewQty();
}
});
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bananaPanel.clearField();
sugarPanel.clearField();
}
});
frame.setSize(400, 400);
framePanel.setLayout(new BoxLayout(framePanel, BoxLayout.PAGE_AXIS));
framePanel.add(bananaPanel);
framePanel.add(sugarPanel);
framePanel.add(buttonPanel);
frame.add(framePanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static class ProductPanel extends JPanel {
private JLabel productId = new JLabel();
private JLabel qty = new JLabel();
private JLabel name = new JLabel();
private JTextField field = new JTextField();
public ProductPanel(String id, String amount, String itemName) {
this.setSize(400, 30);
this.field.setSize(100, 20);
this.field.setColumns(5);
productId.setText(id);
qty.setText(amount);
name.setText(itemName);
this.add(productId);
this.add(qty);
this.add(name);
this.add(field);
}
public void clearField() {
field.setText("");
}
public void setNewQty() {
String newQty = field.getText();
if (newQty != null && !newQty.isBlank()) {
qty.setText(newQty);
}
}
}
}
Main points of this mocked solution:
Use a JPanel to encapsulate a product line item. This will make it easier if you need to remove and/or add product rows.
The product panel contains a method to update qty or clear the fields that will be invokable by the frame buttons (depending on which is clicked).
Simplicity of design - Creating a generic panel for the product eliminate repetitive code.
Obviously, you would have to modify this so that you use the proper layout manager or use absolute positioning to properly aligned components to your liking. Also, you would need to create a Panel for the table header and add the remaining of your products. Also, you may want to break this into public classes and even maybe create a separate class for your frame.
The action listeners could also have a "for-each" loop to update each ProductPanel instead of hard coding each panel individually. That should look something like this:
public void actionPerformed(ActionEvent e) {
JPanel panel = (JPanel)((JButton) e.getSource()).getParent().getParent();
Component[] components = panel.getComponents();
for (Component c : components) {
if (c instanceof ProductPanel) {
((ProductPanel)c).setNewQty();
}
}
}
});
Obviously, your solution will depend on how you decide to encapsulate your components in containers. For this mock, the product panels are inside the frame panel which contains the panels where the buttons were placed. Therefore, I need to get the "grandparent" container for the update and cancel buttons to take advantage of calling the appropriate methods to update and clear in a more dynamic way.
Lastly, you may want to do something more elegant for creating your product panels. For example, you may want to add some factory method to create your product panel instead of having hard-coded product panels like my mock solution. Anyway, I think I demonstrated the solution you were looking for.
UPDATE: If you don't follow Andrew Thompson's recommendation of not using text fields for numeric values, the panel's getNewQty method would need to validate the text obtained to make sure it contains a valid numeric value (which was his point). I would STRONGLY recommend you follow his advice.

using listeners with both list and button

Very new to Java, but I am slowly picking my way through things. So please be kind. I understand most things I've tried so far, and built a version of the following that uses console output, but now I'm trying to make a GUI. I tried the netbeans GUI maker, but it created so much new code that when I tried to pick through it, I got lost. I'm much better at learning by piecing new things together myself, not having an IDE generate a ton of code and then attempt to find where I want to work.
I am trying to build an window that has a list with three choices on the left side, a button in the middle that confirms your choice, and an answer output on the right. Once the button is pressed, the input from the list is read and is converted into a corresponding answer. As of right now, all I get is "We recommend... null" after selecting an option in the list. The button appears to do nothing at the moment.
I have used tutorials, hacked up others' code from online, and referenced a few books, but I'm stuck.
Here is what I have:
package diffguidegui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DiffGuideGUI extends JPanel implements ListSelectionListener {
private JList resultsTabList;
private DefaultListModel listModel;
private static final String recommendString = "Recommend a Option";
private JButton recommendButton;
private String recommendOutput;
final JLabel output = new JLabel("We recommend..." + recommendOutput);
//build list
public DiffGuideGUI () {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("A");
listModel.addElement("B");
//create the list and put it in the scroll pane
resultsTabList = new JList(listModel);
resultsTabList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
resultsTabList.setSelectedIndex(0);
//listener for user input
resultsTabList.addListSelectionListener(this);
resultsTabList.setVisibleRowCount(2);
JScrollPane listScrollPane = new JScrollPane(resultsTabList);
//build the button at the bottom to fire overall behavior
recommendButton = new JButton(recommendString);
recommendButton.setActionCommand(recommendString);
recommendButton.addActionListener(new RecommendListener());
//create a panel that uses Boxlayout for the button
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane.add(recommendButton);
//create a panel that uses Boxlayout for the label
JPanel outputPane = new JPanel();
outputPane.setLayout(new BoxLayout(outputPane, BoxLayout.LINE_AXIS));
outputPane.add(output);
add(listScrollPane, BorderLayout.WEST);
add(buttonPane, BorderLayout.CENTER);
add(outputPane, BorderLayout.EAST);
}
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
}
}
public void valueChanged(ListSelectionEvent e) {
if(e.getValueIsAdjusting() == false) {
if(resultsTabList.getSelectedIndex() == -1) {
recommendButton.setEnabled(false);
} else {
recommendButton.setEnabled(true);
}
}
}
//Create GUI and show it
private static void createAndShowGUI() {
JFrame frame = new JFrame("Recommend Window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create and set up content pane
JComponent newContentPane = new DiffGuideGUI();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
//display the window
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The button appears to do nothing at the moment.
It does something. It calculates the value for your recommendOutput varable. But you never output this value.
try the following:
//build listener class
class RecommendListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//build in logic for choice made here
String resultsTabChoice;
resultsTabChoice = (String)resultsTabList.getSelectedValue();
if( resultsTabChoice.equals("A")) {
recommendOutput = "One";}
else {recommendOutput = "Two";}
System.out.println(recommendOutput); // <-###################
}
}
This should print the value to stdout
To put the value into your label try this instead:
output.setText(recommendOutput);
where do you set the text for the JLabel? It says "We recommend NULL" because recommenedOutput is null when the object is created. I dont see
output.setText("We recommend "+value) anywhere. You probably need output.invalidate() also. Try putting setText(String text)/invalidate() in the RecommendListener.actionPerformed() method.
output.setText("We recommend A");
output.invalidate();

Putting multiple JPanels inside a JTabbed pane

I've looked around a while and also played around trying to add multiple panels to a JTabbedPane.
My question is: Is it possible to add the same Jpanel to multiple TabbedPanes. Everything way that I tried, it doesn't seem to work correctly. This is how it it works.
public MainGUI() {
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
getContentPane().add(tabbedPane, BorderLayout.CENTER);
JEditorPane instructionalEditorPane = new JEditorPane();
tabbedPane.addTab("Instructional", instructionalEditorPane);
JPanel codePanel = new JPanel();
JPanel drawPanel = new JPanel();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, codePanel, drawPanel);
splitPane.setResizeWeight(0.75);
tabbedPane.addTab("Code Panel", splitPane);
JEditorPane unifiedInstPane = new JEditorPane();
JPanel unifiedCodePanel = new JPanel();
JPanel unifiedDrawPanel = new JPanel();
JSplitPane unifiedSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, unifiedCodePanel, unifiedDrawPanel);
unifiedSplitPane.setResizeWeight(0.75);
JSplitPane unifiedPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT,unifiedInstPane, unifiedSplitPane);
unifiedPanel.setResizeWeight(0.40);
tabbedPane.addTab("Unified Tab", unifiedPanel);
}
What I would like to do is just add the instructionalEditorPane and the splitPane to multiple tabbedPanes but when I do I loose the original Individual tabbedPanes. If I have to I can do it this way but I would then have to write to both the unifiedInstPane & the instructionalEditorPane to keep them updated. I would also have to do this for the 2 splitPanes which have the codePanel and drawPanels embedded. This will make it harder to keep all the panels in sync.
Any suggestions?
"Is it possible to add the same Jpanel to multiple TabbedPanes." -- no. You can only add a component to one container at a time. Your JPanels should share models but use unique components. The model will likely be a non-GUI class of your creation.
For example, here's a very simplistic rendering of my recommendations:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
public class MainGui2 extends JPanel {
private static final int TAB_COUNT = 3;
private JTabbedPane tabbedPane = new JTabbedPane();
private PlainDocument doc = new PlainDocument();
private Action btnAction = new ButtonAction("Button");
public MainGui2() {
for (int i = 0; i < TAB_COUNT; i++) {
tabbedPane.add("Tab " + (i + 1), createPanel(doc, btnAction));
}
setLayout(new BorderLayout());
add(tabbedPane);
}
private JPanel createPanel(PlainDocument doc, Action action) {
JTextArea textArea = new JTextArea(doc);
textArea.setColumns(40);
textArea.setRows(20);
JPanel panel = new JPanel();
panel.add(new JScrollPane(textArea));
panel.add(new JButton(action));
return panel;
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String title) {
super(title);
}
#Override
public void actionPerformed(ActionEvent evt) {
try {
String text = "Button Pressed!\n";
doc.insertString(doc.getLength(), text, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainGui2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Better would be to create a formal model class that gets injected into each view, each tabbed pane's individual panes.
Edit
You state in comment:
Yes I can fix that by making calls to the instances but then I'm back to my original problem of having to make calls to each instance to affect a change in all the panel. Say for example I have a drawing panel and I need to call repaint(), I would have to make a call to 2 different instances to get both tabbedPanes to update. Is there any way around this?
Yes, the solution is to use an MVC, or model-view-control, structure. Your model holds your overall program logic, the views are what the user sees, and the control interacts between the two.
Consider having your model notify either the control or the views that its been changed, and then this stimulates a repaint an all observer views.

pass value from one jframe to other jframe?

i created two classes one class is just like form the other class is main class and having jmenu and jinternal frames i want to print the input from the form class on the jinternal frame but i cannot understand how i recall the jinternalframe in the form classes, please guide me in this regard or any hint or some piece of code or tutorial that can help me here is code of both the classes. Moreover both classes are working fine .
JTextArea text;
static int openFrameCount = 0;
public form(){
super("Insert Form");
Container panel=getContentPane();
JPanel cc = new JPanel();
cc.setLayout(new FlowLayout());
JButton b=new JButton("print");
b.setPreferredSize(new Dimension(140,50));
b.setBounds(1000,500,350,50);
cc.add(b);
.......................................................
JLabel label1=new JLabel(" Question"+(++openFrameCount));
cc.add(label1);
text=new JTextArea();
text.setLineWrap(true);
text.setWrapStyleWord(true);
text.setPreferredSize(new Dimension(750,50));
text.setBounds(80, 60,750,50);
cc.add(text);
JLabel symbol=new JLabel("Selection for Option?");
symbol.setBounds(200, 120,1000,100);
cc.add(symbol);
..................................................
JLabel op4=new JLabel("4th Option?");
JTextArea otext4=new JTextArea();
otext4.setLineWrap(true);
otext4.setWrapStyleWord(true);
otext4.setPreferredSize(new Dimension(750,50));
otext4.setBounds(10, 40,700,30);
cc.add( op4 ) ;
cc.add( otext4 ) ;
cc.revalidate();
validate();
............................................................
}
#Override
public void actionPerformed(ActionEvent ae) {
if ( e.getSource() == b1 ){
}
}
}
and the second class of jinternalframe is
public class Desktop1 extends JFrame
implements ActionListener {
Desktop p=new Desktop();
JDesktopPane desktop;
static int openFrameCount = 0;
public Desktop1() {
super("InternalFrameDemo");
//Make the big window be indented 50 pixels from each edge
//of the screen.
int inset = 50;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(inset, inset,
screenSize.width - inset*2,
screenSize.height - inset*2);
//Set up the GUI.
desktop = new JDesktopPane(); //a specialized layered pane
createFrame(); //create first "window"
setContentPane(desktop);
setJMenuBar(createMenuBar());
//Make dragging a little faster but perhaps uglier.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
//Set up the lone menu.
.................................................
return menuBar;
}
//React to menu selections.
public void actionPerformed(ActionEvent e) {
if ("new".equals(e.getActionCommand())) { //new
createFrame();
}
............................................
}
}
class MyInternalFrame extends JInternalFrame {
static final int xPosition = 30, yPosition = 30;
public MyInternalFrame() {
super("IFrame #" + (++openFrameCount), true, // resizable
true, // closable
true, // maximizable
true);// iconifiable
setSize(700, 700);
// Set the window's location.
setLocation(xPosition * openFrameCount, yPosition
* openFrameCount);
}
}
//Create a new internal frame.
protected void createFrame() {
Desktop1.MyInternalFrame frame = new Desktop1.MyInternalFrame();
JPanel panel=new JPanel();//to add scrollbar in jinternalpane insert jpanel
panel.setBackground(Color.white);//set background color of jinternal frame
JScrollPane scrollBar=new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
frame.add(scrollBar);
frame.setVisible(true);
desktop.add(frame);
try {
frame.setSelected(true);
frame.setMaximum(true);
} catch (java.beans.PropertyVetoException e) {}
}
public static void main(String[] args) {
Desktop1 d=new Desktop1();
d.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
d.setVisible(true);
}
}
i want to know hint about the work that come in this part of code to pass the value of form to internal frame when i click on print button
public void actionPerformed(ActionEvent ae) {
if ( e.getSource() == b1 ){
}
}
}
just call the constructor and pass the value
ClassName(parameter)
I guess you want to pass some text to your InternalFrame class on the button click from the main form.
Modify your createFrame() method to accept a String value
e.g-
protected void createFrame(String value){
//..your code
}
and when you call your InternalFrame class, pass this value to its constructor. e.g-
Desktop1.MyInternalFrame frame = new Desktop1.MyInternalFrame(value);
Parameterised constructor will solve your problem. Modify your InternalFrame constructor
e.g-
public MyInternalFrame(String value){
//..use this value
}

Multiple JLabel MouseListeners

I'm trying to add several JLabels to a JPanel along with mouse listeners using a loop. These JLabels are going to have mouse listeners so that they change their icon when clicked (Using label.setIcon()). However, I only want to have one "selected" at a time. So, I need them to know when another label is clicked so it knows to turn itself off before the new label gets selected. However, my problem is that because I'm adding these labels with a loop they all have the same MouseListener.
Can anyone teach me a simple way to accomplish this?
This is a short example, how you could implement it (please note, that I didn't use the icon, but change the label instead):
public class MouseListenerExample extends JFrame {
public static class MyMouseListener extends MouseAdapter {
private static final Collection<JLabel> labels = new ArrayList<JLabel>();
private final JFrame frame;
public MyMouseListener(JFrame frame, JLabel label) {
this.frame = frame;
labels.add(label);
}
#Override
public void mouseClicked(MouseEvent e) {
for (JLabel label : labels) {
String text = label.getText();
if (text.startsWith("X ")) {
label.setText(text.substring(2));
}
}
JLabel currentLabel = (JLabel) e.getComponent();
currentLabel.setText("X " + currentLabel.getText());
}
}
public MouseListenerExample() {
super("MouseListener Example");
Container c = getContentPane();
c.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
JLabel jLabel = new JLabel("Label " + i);
c.add(jLabel);
jLabel.addMouseListener(new MyMouseListener(this, jLabel));
}
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new MouseListenerExample();
}
}
The main idea is, that you create a new MouseListener for each label, but keep a list of labels outside of each listener's scope (in this example I just use a static variable, but you could also have a field containing the list of labels in the frame.

Categories