Get layout constraints for a component in Java Swing - java

Below is a mock up of code that I've been working on.
public class Pane {
private final JPanel pane;
private JPanel namePanel;
private final JTextField panIdField;
public Pane() {
pane = new JPanel();
pane.setLayout(new MigLayout("", "[][grow]", "[][][][][]"));
namePanel = new JPanel();
pane.add(namePanel, "cell 1 1,growx");
panIdField = new JTextField();
pane.add(panIdField, "cell 1 2,growx");
panIdField.setColumns(10);
}
public void replaceNameField(JPanel newNamePanel) {
this.namePanel = newNamePanel;
// Object constraintsForNamePanel =
pane.remove(namePanel);
pane.add(newNamePanel, constraintsForNamePanel);
}
}
In Container there's method
public void add(Component comp, Object constraints)
Is there any way that we can programatically get the constraints that we set, like getConstraints(...) so that we can use it for later use?
In my code, I want to use it to replace a old component with a new one at the same place.
What do I have to do after
Object constraintsForNamePanel =
to get the constraints for namePanel.
Currently, I'm using
pane.add(newNamePanel, "cell 1 1,growx");
It is working but the problem is I'm using WindowsBuilder for UI and my UI is like to change when I add new components to the pane and I don't want to copy and paste the constraints.

Got the solution, I had to do following.
public void replaceNameField(JPanel newNamePanel) {
MigLayout layout = (MigLayout) pane.getLayout();
Object constraintsForNamePanel = layout.getComponentConstraints(this.namePanel);
pane.remove(this.namePanel);
this.namePanel = newNamePanel;
pane.add(newNamePanel, constraintsForNamePanel);
}

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.

Java.awt: Second TextArea is not shown

I'm trying to understand how Java.awt works (we need to create a GUI without GUI editor)
the following code does not show 2 TextAreas:
Frame fr = new Frame("Parser");
Panel buttons = new Panel();
Panel inputText = new Panel();
Panel outputText = new Panel();
String here = new String ("Insert code here...");
TextArea input = new TextArea(here, 9, 96, TextArea.SCROLLBARS_VERTICAL_ONLY);
TextArea output = new TextArea(here, 9,96,TextArea.SCROLLBARS_VERTICAL_ONLY);
public Window(){
fr.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
fr.dispose();
}
}
);
fr.setSize(700, 400);
fr.setLocation(200,100);
fr.setResizable(false);
fr.add(buttons);
fr.add(inputText);
fr.add(outputText);
buttons.setBounds(new Rectangle(0,0,700,60));
buttons.setBackground(new Color(200,200,200));
inputText.setBounds(new Rectangle(0,60,700,170));
inputText.setBackground(new Color(255,255,255));
inputText.add(input);
outputText.setBounds(new Rectangle(0,230,700,170));
outputText.setBackground(new Color(200,200,200));
outputText.add(output);
}
Obtained result:
Expected result:
Your code does not respect the layout managers that your containers are using. I believe that AWT Frames use a BorderLayout by default (edit: yes they do, per the Frame API. Suggestions:
In general avoid AWT for Swing which has much greater power and flexibility, although it too is showing its age, just less so than AWT.
Read up on and use layout managers in a smart way to do your heavy lifting for you. Here it looks like a BoxLayout could help you.
Avoid use of null layouts. While yes, that could offer you a quick and easy fix for your current code, it leads to the creation of very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.
Avoid setting bounds, sizes or locations of any components, and again let the components and their container's layout managers set the sizes for you.
The Layout Manager Tutorial
For example:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class MyWindow extends JPanel {
private static final int ROWS = 10;
private static final int COLS = 50;
private static final String[] BUTTON_NAMES = { "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday" };
private static final int GAP = 3;
private JTextArea inputTextArea = new JTextArea(ROWS, COLS);
private JTextArea outputTextArea = new JTextArea(ROWS, COLS);
public MyWindow() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
for (String btnName : BUTTON_NAMES) {
buttonPanel.add(new JButton(btnName));
}
outputTextArea.setFocusable(false);
outputTextArea.setEditable(false);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(buttonPanel);
add(putInTitledScrollPane(inputTextArea, "Input Text"));
add(putInTitledScrollPane(outputTextArea, "Output Text"));
}
private JPanel putInTitledScrollPane(JComponent component,
String title) {
JPanel wrapperPanel = new JPanel(new BorderLayout());
wrapperPanel.setBorder(BorderFactory.createTitledBorder(title));
wrapperPanel.add(new JScrollPane(component));
return wrapperPanel;
}
private static void createAndShowGui() {
MyWindow mainPanel = new MyWindow();
JFrame frame = new JFrame("MyWindow");
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();
}
});
}
}
Which displays as:
Use of layout managers gives you much greater ease when it comes to changing or enhancing your GUI. For example, since I'm setting my JTextArea's width with a COL constant, if I change the COL constant, the whole GUI widens, even the buttons and the button JPanel, since the layout managers are handling all the sizing. With your code, you'd have to manually change the width of every component added to the GUI, which is prone to bug creation.
Because you are manually laying out your components, you are needed to set layout to null (setLayout(null);)
so before adding any component add this line in your code.
fr.setLayout(null);
Now you will get this :

JTable Not Appearing

Whenever I set the panel's Layout to FlowLayout, the JTable appears, however my imageBackground and buttons are misplaced. And when I set the layout to null, the the table doesn't appear, but the buttons and imageBackground are where I wanted them to be. What am I'm going to do with this?
public class AssetPanel extends JPanel implements ActionListener{
private ArrayList<AssetDetails> assetList;
private Frame frame;
private Database db;
private JTable assetTable;
private JScrollPane scrollPane;
private JButton btnBack;
private JButton btnView;
public AssetPanel (Frame frame){
super();
this.frame = frame;
initialize();
}
public void initialize(){
setName("Assets");
setSize(700, 475);
setLayout(null);
setVisible(true);
db = new Database();
btnView = new JButton("View");
btnView.addActionListener(this);
btnView.setBounds(450, 400, 90, 20);
add(btnView);
btnBack = new JButton("Back");
btnBack.setFont(new Font("Tahoma", Font.BOLD, 12));
btnBack.setBounds(550, 400, 90, 20);
btnBack.addActionListener(this);
add(btnBack);
ImageIcon imageBackground = new ImageIcon(AssetPanel.class.getResource("/resources/assets.png"));
JLabel jlBackground = new JLabel(imageBackground);
jlBackground.setBounds(0,0, 700, 475);
add(jlBackground);
initializeTable();
}
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource() == btnBack){
frame.changePanel("Main Menu");
}
}
public void initializeTable(){
Object[][] assetData;
assetList = new ArrayList<>();
String[] columnNames = {"Asset Name", "Date Acquired", "Type", "Classification"};
assetList = db.getAssetTable();
assetData = new Object[assetList.size()][columnNames.length];
for(int i = 0; i < assetList.size(); i++){
assetData[i][0] = assetList.get(i).getAssetName();
assetData[i][1] = assetList.get(i).getDateAcquired();
assetData[i][2] = assetList.get(i).getType();
assetData[i][3] = assetList.get(i).getClassification();
}
assetTable = new JTable(assetData, columnNames);
assetTable.setPreferredScrollableViewportSize(new Dimension(400, 100));
assetTable.setLocation(150, 100);
assetTable.setFillsViewportHeight(true);
scrollPane = new JScrollPane(assetTable);
add(scrollPane);
}
}
Don't use a null layout or use the setBounds() method to position and size components.
however my imageBackground and buttons are misplaced
A background is a Container component. That is you create it as a component and paint an image as the background. Then you add other components to the background component. Now the image will appear in the background and the other components appear on top of it.
See the Background Panel to give an example of creating a background component.
On possible solution: I recommend switching to Mig Layout as a solution to all java layout problems. I now use it for the layout of every single container component in my apps. If you switch you'll probably be glad you did (will never again have problems like that listed in this question).
http://www.miglayout.com/
MigLayout may be included in the JDK in a future version of java.
null layouts mean you have to explicitly place all the components.
I recommend BoxLayout. it's really simple, and you can put in spacers to create space between objects, and glue to fill in all remaining space.
you can also nest the boxes, as well.
if you look at java sample code (and at the source for things);
they nest a lot of JPanels to get the complicated layouts.
Try adding this before trying the steps below if it does not work:
// Set your flow layout thus:
setLayout(new FlowLayout(FlowLayout.LEFT,5,5));
// Set your table Auto Resize Mode to OFF
assetTable.setAutoResizeMode(assetTable.AUTO_RESIZE_OFF);
EXTRA: Try if above tips does not help
Technically, your class should extend a JFrame.
Add a root layout to the class(i.e. the JFrame):
setLayout(new FlowLayout(FlowLayout.LEFT,5,5));
Create two panels; one should contain your label and buttons components.
The other should contain the JScrollPane that contains your table.
Both panels can have their Layout which determines how the components will be laid out.
You can use FlowLayout.
Then you can add both panels to the mother layout (JFrame).

Java GUI JScrollPane

I am a beginer at programing and i wanted to add a scroll panel to a JTextArea so i tried to research tutorials online. i followed the examples but its not working can someone plz tell me what i am doing wrong. thank you so much
public View(Model model) {
this.model = model;
setBounds(100,50, 800, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container c = getContentPane();
addDisplay(c);
addButtons(c);
addTxt(c);
}
private void addDisplay(Container c){
JPanel p = new JPanel();
addTxt2(p);
addTxt(p);
add(p, "North");
}
private void addTxt(JPanel p){
txt = new JTextArea(15, 35);
txt.setBackground(Color.BLACK);
txt.setForeground(Color.WHITE);
txt.setEditable(true);
JScrollPane scroll= new JScrollPane (txt);
p.add(scroll);
}
Always invoke revalidate and repaint after adding any components to a JPanel
p.add(scroll);
p.revalidate();
p.repaint();
From the use of setBounds, it appears that there is no layout manager in use. Don't use absolute positioning (null layout). By default, components have a size of 0 x 0 so will not appear unless their size is set. A layout manager should be used here instead.
Post an SSCCE for better help sooner
You have to set the bounds of your scroll setBounds(int, int, int, int)
and define the area of your JTextArea
Here's an example:
public class ScrollingTextArea extends JFrame {
JTextArea txt = new JTextArea();
JScrollPane scrolltxt = new JScrollPane(txt);
public ScrollingTextArea() {
setLayout(null);
scrolltxt.setBounds(3, 3, 300, 200);
add(scrolltxt);
}
public static void main(String[] args) {
ScrollingTextArea sta = new ScrollingTextArea();
sta.setSize(313,233);
sta.setTitle("Scrolling JTextArea with JScrollPane");
sta.show();
}
}
I've found it here

Creating a Form manually

I am trying to create a form manually with code rather than the designer, I have already created using the designer.
This is the manual code that I came up with so far but I am having problem aligning the label and textfield side by side
mport java.awt.*;
import javax.swing.*;
/**
*
* #author jackandjill
*/
public class summinup_copy extends JFrame
{
private JLabel lblTitle, lblOctal, lblDecimal, lblMessage ;
private JTextField txtOctal, txtDecimal;
private JButton calculate_btn;
public summinup_copy()
{
JPanel panel = (JPanel)this.getContentPane();
panel.setLayout(new BorderLayout());
JPanel panCentre = new JPanel();
panCentre.setLayout(new GridLayout(3,3));
lblTitle = new JLabel("Area of Triangle");
lblTitle.setFont(new Font("Arial", 1, 20));
lblTitle.setHorizontalAlignment(JLabel.CENTER);
lblOctal = new JLabel("Octal");
lblOctal.setHorizontalAlignment(JLabel.CENTER) ;
//lblDecimal = new JLabel("Decimal");
//
//lblDecimal.setHorizontalAlignment(JLabel.CENTER);
lblMessage = new JLabel("Result will be displayed here");
lblMessage.setForeground(Color.red);
lblMessage.setHorizontalAlignment(JLabel.CENTER);
txtOctal = new JTextField("0", 5);
txtOctal.setHorizontalAlignment(JLabel.CENTER);
//txtDecimal = new JTextField("0", 5);
//
//txtDecimal.setHorizontalAlignment(JLabel.CENTER);
calculate_btn = new JButton("Calculate Area");
//AHandlerClass aListener = new AHandlerClass() ;
//btnOtoD.addActionListener(aListener);
//btnDtoO.addActionListener(aListener);
panCentre.add(lblOctal);
//panCentre.add(lblDecimal);
panCentre.add(txtOctal);
//panCentre.add(txtDecimal);
panCentre.add(calculate_btn);
//panCentre.add(btnDtoO);
panel.add(lblTitle, BorderLayout.NORTH);
panel.add(lblMessage,BorderLayout.SOUTH);
panel.add(panCentre, BorderLayout.CENTER);
}
public static void main(String args[]) {
summinup_copy myGui = new summinup_copy();
myGui.setTitle("Bharath");
myGui.setSize(400, 200);
myGui.setVisible(true);
}
}
As you have already figured out, you have to use LayoutManagers when coding a Swing GUI by hand. Here are some links that can help you figure out which LayoutManager is appropriate for a given look:
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
In order to place a JLabel next to a JTextField or other component, I usually use GridLayout or GridBagLayout. I find that it takes a lot of trial and error trying to get components to look the way I want. Often you have to have layers of embedded JPanels to get it just right.

Categories