The main idea is to draw a specific form, using Swing library(it will be used to generate an image, which will be transfered to a escpos printer, but thats another question). The form itself has a full width container at the top, which represents the label. The label has a custom font, font size and can have a linewrap, therefor i used JTextPane. JTextPane element, and all of the form, will have a fixed size of 500px.
As a test, the code looks like:
JFrame fr = getFrame();
JPanel root = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JPanel titleP = new JPanel(new BorderLayout());
titleP.setBorder(BorderFactory.createTitledBorder("titleP"));
c.fill = GridBagConstraints.BOTH;
c.gridy = 0;
c.gridx = 0;
c.gridwidth = 8;
c.weightx = 1.0f;
c.weighty = 1.0f;
JTextPane tp = new JTextPane();
JScrollPane sp = new JScrollPane(tp);
Font font = new Font("Arial",Font.BOLD, 37);
tp.setFont(font);
tp.setText("fdsfdsf sdf sdf sd fdsfsdf sdf sd fsd fdsf sdf sdf sdf sdf sdf sdf sdf ds");
tp.setOpaque(false);
titleP.add(sp);
root.add(titleP,c);
JPanel infoP = new JPanel();
infoP.setBorder(BorderFactory.createTitledBorder("infoP"));
c.gridwidth = 5;
c.gridy = 1;
c.gridx = 0;
//infoP.setPreferredSize(new Dimension(350,200));
root.add(infoP,c);
JPanel priceP = new JPanel();
priceP.setBorder(BorderFactory.createTitledBorder("priceP"));
c.gridx = 5;
c.gridwidth = 3;
root.add(priceP,c);
fr.setContentPane(root);
fr.pack();
int size1 = fr.getHeight();
int width = 120;
fr.setSize(width, 0);
size1 += tp.getHeight();
size1 += 25;
fr.setSize(width, size1);
fr.setVisible(true);
The question is, how do i calculate JTextPane's full size, in order to set its height to the container, which is holding it? The part where i hardcodedly try to give out a height correction, even worked, but then i added a font...
I wrote a detailed answer on a similar question. Check here
The idea is that getPreferredSize().height called on a JTextPane will return the height needed to display the current content given the current width. If the width is not set yet, it will return the height needed if the width of the JTP was the width of the longest line.
With the same logic, getPreferredSize().width will return the width of the longest line.
For those who maybe struck on the same problem(or just curious). Found a solution here: link
The idea came to be quite simple:
public int getContentHeight(int width, String content) {
JEditorPane dummyEditorPane = new JEditorPane();
dummyEditorPane.setSize(width, Short.MAX_VALUE);
dummyEditorPane.setText(content);
return dummyEditorPane.getPreferredSize().height;
}
Related
I am trying to position components on JPanel using GridBagLayout but the output I am getting is completely off from what I expect. Hope to get some clarity with brilliant-minded ppl in stackoverflow:).
Below I have provided a piece of code and screentshot of the program. My questions are:
Why the JLabel Choose measure system to convert is not on Y-axis = 1? As to my knowledge, c.gridy=1 is one pixel downward, but the label is stuck on the top leaving no space from the Frame title. And also, why is it positioned so weird, i.e., not really in the center, nor in the start?
Why is there such a big space between ComboBoxes From... and To..., but there is no space between ComboBox To... and TextField Enter value here...?
Here is the code:
JPanel container = new JPanel();
container.setLayout(new GridBagLayout());
getContentPane().add(container, BorderLayout.NORTH);
TitledBorder outputCenter;
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("Choose measure system to convert");
label.setFont(new Font("Times New Roman", Font.PLAIN, 20));
c.gridx = 0;
c.gridy = 1;
container.add(label, c);
fromList = new JComboBox<String>(convertFrom);
c.gridx = 0;
c.gridy = 2;
container.add(fromList, c);
toList = new JComboBox<String>(convertTo);
c.gridx = 1;
c.gridy = 2;
container.add(toList, c);
//Field where user enters the value to be converted
input = new JTextField("Enter value here...");
input.setPreferredSize(new Dimension(150,30));;
input.setEditable(true);
input.setBackground(Color.WHITE);
input.setBorder(BorderFactory.createLineBorder(Color.BLACK));
input.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
input.setText("");}});
c.gridx = 2;
c.gridy = 2;
container.add(input, c);
And here is the screentshot:
EDIT: If I change the code from:
label = new JLabel("Choose measure system to convert");
label.setFont(new Font("Times New Roman", Font.PLAIN, 20));
c.gridx = 0;
c.gridy = 1;
container.add(label, c);
label = new JLabel("Choose measure system to convert");
label.setFont(new Font("Times New Roman", Font.PLAIN, 20));
c.gridx = 1; // changed this line
c.gridy = 1;
container.add(label, c);
The outcome is like this:
This is very confusing me as why changing the position of one component effects everything?
GridBagConstraints sets up the frame into effectively a grid. The width and height of the cells in the grid are determined by the size of the data in the cell by default unless otherwise specified. So if you want to add some space in-between cells I suggest ipadx and ipady. You can also utilize anchor for adjusting your data in the cell. I also suggest weightx and weighty for adjusting the actual cell size.
So imagine something like this as your current set up:
EDIT: Example of what your new GBC looks like. The numbers are (gridx,gridy)
Why the JLabel Choose measure system to convert is not on Y-axis = 1? As to my knowledge, c.gridy=1 is one pixel downward
You're confusing yourself, c.gridy = 1 is not positioning it 1 pixel downward but rather on the next row, but as there's no previous row, then it takes the first row. For reference see: GridBagConstraints#gridy which says the following:
Specifies the cell at the top of the component's display area, where the topmost cell has gridy=0. The value RELATIVE specifies that the component be placed just below the component that was added to the container just before this component was added.
Next question:
And also, why is it positioned so weird, i.e., not really in the center, nor in the start?
It is centered in its own cell, if you want to center it on the JFrame, then you might need to create it on its own gridx = 1 and the rest of components on the other ones (0 and 2) or make it span 2 or more columns based on you want it to look like...
Why is there such a big space between ComboBoxes From... and To..., but there is no space between ComboBox To... and TextField Enter value here...?
It is because your program is giving it all the extra space because of the large text on the first cell...
You can have something like this:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class GridBagLayoutExample {
private JFrame frame;
private JPanel pane;
private JLabel label;
private JTextField field;
private JComboBox<String> box1;
private JComboBox<String> box2;
private GridBagConstraints gbc;
public static void main(String[] args) {
SwingUtilities.invokeLater(new GridBagLayoutExample()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
pane = new JPanel();
pane.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
label = new JLabel("Choose measure system to convert");
box1 = new JComboBox<>(new String[] {"From..."});
box2 = new JComboBox<>(new String[] {"To..."});
field = new JTextField(10);
gbc.insets = new Insets(5, 5, 5, 5); //We add extra space at top, left, bottom, right of each component
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 3; //We make our text to span 3 cells
pane.add(label, gbc);
gbc.gridy = 1;
gbc.gridwidth = 1; //We return the spanning to 1 single cell
pane.add(box1, gbc);
gbc.gridx = 1;
pane.add(box2, gbc);
gbc.gridx = 2;
pane.add(field, gbc);
frame.add(pane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Which produces the following output:
I would be grateful for any help/suggestion regarding my problem. I attached the image of my simple program which shows that the positioning of the components seems a bit off. My question is - why the ComboBox From... as well as TextField Enter value here... start so far off of the left corner? I've given gridx=0 so it positions the component on the very edge of the window, but components start some pixels off from the edge. How can I fix it?
Also, what do I need to do/consider to remove dependency of the rows on each other? I mean how to position components anywhere I want in one row without effecting the position of other components in another row. Thank you!
Piece of Code:
JPanel container = new JPanel();
container.setLayout(new GridBagLayout());
getContentPane().add(container, BorderLayout.NORTH);
TitledBorder outputCenter;
GridBagConstraints c = new GridBagConstraints();
label = new JLabel("Choose measure system to convert");
label.setFont(new Font("Times New Roman", Font.PLAIN, 20));
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
c.insets = new Insets(10, 0, 20, 0);
container.add(label, c);
fromList = new JComboBox<String>(convertFrom);
c.gridx = 0;
c.gridy = 1;
c.gridwidth =1;
c.ipadx = 20;
c.anchor = GridBagConstraints.LINE_START;
container.add(fromList, c);
toList = new JComboBox<String>(convertTo);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
c.ipadx = 20;
container.add(toList, c);
//Field where user enters the value to be converted
input = new JTextField("Enter value here...");
input.setPreferredSize(new Dimension(150,30));;
input.setEditable(true);
input.setBackground(Color.WHITE);
input.setBorder(BorderFactory.createLineBorder(Color.BLACK));
input.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
input.setText("");}});
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 1;
c.ipady = 20;
container.add(input, c);
//The area where the output/result is shown
output = new JTextArea(10,30);
output.setEditable(false);
output.setFont(new Font("Serif", Font.BOLD, 12));
output.setBackground(Color.WHITE);
outputCenter = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLACK), "Output");
outputCenter.setTitleJustification(TitledBorder.CENTER);
output.setBorder(outputCenter);
c.gridx = 1;
c.gridy = 2;
c.insets = new Insets(50,5,10,10);
c.gridwidth = 3;
container.add(output, c);
//Convert button
convert = new JButton("Convert");
c.gridx = 0;
c.gridy = 3;
c.ipadx = 50;
container.add(convert, c);
}
Output:
Remember, GridBagLayout is a "flexible grid" layout manager. It still relies on the concept of rows and columns, but each row and column has it's own size, based on the requirements of the components and the constraints applied to them.
This means, that you combo box is been aligned to the left position because of a combination of c.anchor = GridBagConstraints.LINE_START and the space requirements of the JTextField sharing the same column.
You "could" change c.anchor = GridBagConstraints.LINE_START to c.anchor = GridBagConstraints.LINE_END, while will (in your case) align the combo box to the right edge of the column, for example...
Another solution would be to use a combination of containers to reduce the overall complexity of the layout. For example, you could add both the combo boxes to their own container, managing the layout requirements for them in an isolated manner and then layout that container within the large scheme of things
I'm trying to set up a couple of labels and textfields in a table-like style.
Currently I'm using the GridLayout, which kind of works as I want it to. However, the TextFields and Button is expanding to the full size of the cell.
How can I make the TextFields and Button "normal" sized, and what Layout Manager would accomplish this the easiest way?
Here's the current code and a screenshot:
JPanel forms = new JPanel();
forms.setLayout(new GridLayout(3, 2));
JLabel lbl_navn = new JLabel("Virksomhedsnavn:");
JTextField txt_navn = new JTextField();
JLabel lbl_adresse = new JLabel("Adresse:");
JTextField txt_adresse = new JTextField();
forms.add(lbl_navn);
forms.add(txt_navn);
forms.add(lbl_adresse);
forms.add(txt_adresse);
forms.add(Box.createRigidArea(new Dimension(10, 10)));
forms.add(new JButton("Opret virksomhed"));
I suggest you use gridBagLayout:
http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
As an example:
JPanel forms = new JPanel();
forms.setLayout(new GridBagLayout());
JLabel lbl_navn = new JLabel("Virksomhedsnavn:");
JTextField txt_navn = new JTextField();
JLabel lbl_adresse = new JLabel("Adresse:");
JTextField txt_adresse = new JTextField();
//Setting grid bag constraints
GridBagConstraints c = new GridBagConstraints();
// Grid position coordinates
c.gridx = 0; c.gridy = 0;
//Align panel in top-left corner
c.anchor=GridBagConstraints.LINE_START;
forms.add(lbl_navn, c);
c.gridx = 1; c.ipadx = 195;
forms.add(txt_navn, c);
c.gridy = 1; c.gridx = 0; c.ipadx = 0;
forms.add(lbl_adresse, c);
c.gridx = 1; c.ipadx = 195;
forms.add(txt_adresse,c);
c.gridy = 2; c.gridx = 0; c.ipadx = 0;
forms.add(Box.createRigidArea(new Dimension(10, 10)),c);
c.anchor=GridBagConstraints.CENTER;
c.gridy = 2; c.gridx = 1;
forms.add(new JButton("Opret virksomhed"),c);
Hope this helps.
I think you can refer to this question where useful answers have been given:
JTextField Fixed Height
I read good things about Mig layout a while ago, I never used, but seems very powerful.
Check this Mig layout, may be a good solution for your problems.
UPDATE:
Mig layout is not a "standard" layout from sun/oracle.
GridBagLayout as mentioned, can accomplished your objectives(from experience). I personally when I want fixed sizes components I use to work with "null layouts".
See below a simple test code using a GridBagLayout (2 rows, 2 component on row 0, 1 component on row 1). Although I have specified weighty to be 0.01 for first row and 1 for second row, the ratio on the screen looks more like 0.3 vs. 0.7. It seems that the height of the first row is resized so that the whole textarea fits in it.
How can I reduce the height of the first row, so that the scroll bars of the JScrollPane will appear?
public class Test {
public static void main(String... args) {
String text = "text\n\n\n\n\n\n\n\ntext";
JFrame frame = new JFrame();
JTextArea area;
JScrollPane pane;
JPanel desktop = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.weightx = 0.25;
c.weighty = 0.05;
area = new JTextArea(text);
area.setBackground(Color.RED);
pane = new JScrollPane(area);
desktop.add(pane, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 0.75;
c.weighty = 0.05;
area = new JTextArea(text);
area.setBackground(Color.BLUE);
pane = new JScrollPane(area);
desktop.add(pane, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 1;
c.weightx = 0;
c.weighty = 1;
c.gridwidth = 2;
area = new JTextArea(text);
area.setBackground(Color.GREEN);
pane = new JScrollPane(area);
desktop.add(pane, c);
frame.setContentPane(desktop);
frame.setPreferredSize(new Dimension(800, 600));
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
Set the number of rows on the JTextArea so that the preferredSize of the textarea and scrollpane will adjust to that number of rows. In case there is an excessive number of rows in the text of the textarea, the scrollbar will appear.
weight - Specifies how to distribute extra vertical space. So if available space is bigger than sum of preferred sizes then extra pixes are distributed according to the weight values.
I have a JPanel like this:
GridBagConstraints constPanelInfo = new GridBagConstraints();
panelInfo = new JPanel(new GridBagLayout());
JLabel sensor1 = new JLabel("Sensor: ");
constPanelInfo.gridx = 0;
constPanelInfo.gridy = 0;
constPanelInfo.weightx = 0.0;
constPanelInfo.fill = GridBagConstraints.NONE;
panelInfo.add(sensor1, constPanelInfo);
constPanelInfo.gridx = 1;
constPanelInfo.gridy = 0;
constPanelInfo.weightx = 1.0;
constPanelInfo.fill = GridBagConstraints.HORIZONTAL;
campoSensor.setPreferredSize(new Dimension(100, campoSensor.getPreferredSize().height));
panelInfo.add(campoSensor, constPanelInfo);
where campoSensor is defined as:
private JTextField campoSensor = new JTextField();
...but the JTextField is not scaled to 100 px weight as I want: it stays the same size it had before writting the setPreferredSize method. Any idea here?
Hopefully this is what you're looking for... setting
constPanelInfo.weightx = 0;
for the sensor should keep it at the specified 100px. i.e If all the weights are zero, all the extra space appears between the grids of the cell and the left and right edges.
Remember that if the weigths are set and because of
constPanelInfo.fill = GridBagConstraints.HORIZONTAL;
The campoSensor is going to fill the full width of the cell regardless of the preferred size.
This width will probably be determined by the size of the JFrame that your panel is sitting in.
Try to set constPanelInfo.iPadX=100; instead of setting preferred size.