I have the following,
GridLayout layout = new GridLayout(4, 0);
In the event that I have 5 items, this will create 2 columns, where the first contains 3 rows and the second contains 2 rows. This is not what I want, nor is this what I expected. I expected the first column to contain 4 rows and the second column to contain 1 row.
Why isn't this layout manager respecting the number of rows I want per column? Or better yet, how do I make this layout manager respect this?
The result seems expected: "Specifying the number of columns affects the layout only when the number of rows is set to zero."
You can get the desired effect using JList, as shown here.
private static final int N = 5;
...
list.setLayoutOrientation(JList.VERTICAL_WRAP);
list.setVisibleRowCount(N - 1);
Disclaimer: This is not provided as a concrete answer, but rather to prove a point of the helpfulness of a SSCCE...
GridLayout constructor is GridLayout(int rows,int cols) (The reason I mention it is as #AndrewThompson said in his answer seems like you might have mixed up the parameters of rows/cols for the LayoutManager). Thus 4,0 will give us 4 rows and a variable amount of columns.
When I add 4 labels I get 4 rows and 1 coloumn (as expected):
when you add 5 labels I get 3 rows and 2 coloumns each having 2 items except for the last which has 1:
IMO this is expected GridLayout must honor column/row count >0 (anything less than 0 and the LayoutManager calculates the amount), thus if we add more components than the rows allowed it creates a new coloumn >0 but also >1 as 0 and 1 perform the same. Thus it creates 2 coloums now when we fill a Grid thats 4x0 with 5 components, we expect the 2 components on each line ( for each coloums) and the remaining on the last row (not necessarily the last row depending on the amount of components i.e 8 would fill it to the last row as now its 4x2 but adding 9 components would cause a GridLayout of 4x3 - filling all coloumns of the row before going to the new row)
Please post an SSCCE which re-inacts the problem or else we are just guessing here is my example I made which shows different behavior than what you said/get:
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
GridLayout layout = new GridLayout(4, 0);
frame.setLayout(layout);
for (int i = 0; i < 5; i++) {
frame.add(new JLabel(String.valueOf(i + 1)));
}
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Create Swing components on EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
The GridLayout you specified has number of columns as 0. That means number of columns is to be decided by the layout. In which case it tries to compute number of columns required based on number of items.
If you added 4 components you would have got 4 rows with one component each. If you add 5 components two columns are required and they are filled with the components serially that means only 3 rows will be consumed.
So depending on your number of components you may see all specified rows utilized or not. For instance try with 7 components.
Related
so I want to make my Jscrollpane to show Pascals triangle. I have this:
labelPanel= new JPanel();
lRows = new JLabel[n];
for (int i=0;i<n;i++){
lRows[i]=new JLabel(Arrays.toString(tri.tri[i]));
labelPanel.add(lRows[i]);
}
But it's not what I want and I am not sure how to fix that, picture included. Any help?
By default, JPanel uses a flow layout. To get the vertical arrangement you are looking for, you should be able to do this by using a BoxLayout with a vertical orientation on your labelPanel, then add your JLabel rows.
labelPanel= new JPanel();
//set this up to order things vertically
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
lRows = new JLabel[n];
for (int i=0;i<n;i++){
lRows[i]=new JLabel(Arrays.toString(tri.tri[i]));
//to center your label, just set the X alignment
lRows[i].setAlignmentX(Component.CENTER_ALIGNMENT)
labelPanel.add(lRows[i]);
}
I also threw in a line to center the rows like your picture. Component comes from the java.awt package.
You can read up on the different layout managers available by default in the Java Tutorial
The easiest solution is to rotate the triangle to make it look like:
1 1 1 1 1 1 1
1 2 3 4 5 6
1 3 6 10 15
1 4 10 20
1 5 15
1 6
1
However, if you must print sth like this
I did it this way:
for (int i = 0; i<n; i++){
for (int j = 0; j<Triangle.trojkat[i].length; j++){
sb.append(Triangle.trojkat[i][j]);
len = String.valueOf(Triangle.trojkat[i][j]).length();
while (12-len>0){
sb.append(" ");
len++;
}
//sb.append(" ");
}
TriangleRes[i] = new JLabel(sb.toString(), JLabel.CENTER);
TriangleRes[i].setFont(new Font("Serif",Font.PLAIN,8));
sb = new StringBuilder();
}
Let me explain:
I decided, that I want my triangle print beautifuly for the size smaller that 35. Then I've checked, that the numbers in such a triangle come up to 10 digits. Then, when I added next number to the existing row, I checked it's length and while total length wasn't 12 yet, I add spaces. This lead to the triangle that you have attached on the picture.
If this is for Ph.D Macyna classes, just post a question on a group and I'll respond :)
Use a JTextArea
Give it a monospaced font, i.e., Font.MONOSPACED
Append your lines of text to the JTextArea, similar to how you'd do this in the console.
Put the JTextArea into a JScrollPane
VoilĂ . You're done.
If you need to use JLabels, then put them in a JPanel that uses GridLayout with enough columns to show your bottom row.
If you did this, you'd be putting empty JLabels in every other cell, so that the cells branch correctly.
so I want to make my Jscrollpane to show Pascals triangle. I have this:
labelPanel= new JPanel();
lRows = new JLabel[n];
for (int i=0;i<n;i++){
lRows[i]=new JLabel(Arrays.toString(tri.tri[i]));
labelPanel.add(lRows[i]);
}
But it's not what I want and I am not sure how to fix that, picture included. Any help?
By default, JPanel uses a flow layout. To get the vertical arrangement you are looking for, you should be able to do this by using a BoxLayout with a vertical orientation on your labelPanel, then add your JLabel rows.
labelPanel= new JPanel();
//set this up to order things vertically
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
lRows = new JLabel[n];
for (int i=0;i<n;i++){
lRows[i]=new JLabel(Arrays.toString(tri.tri[i]));
//to center your label, just set the X alignment
lRows[i].setAlignmentX(Component.CENTER_ALIGNMENT)
labelPanel.add(lRows[i]);
}
I also threw in a line to center the rows like your picture. Component comes from the java.awt package.
You can read up on the different layout managers available by default in the Java Tutorial
The easiest solution is to rotate the triangle to make it look like:
1 1 1 1 1 1 1
1 2 3 4 5 6
1 3 6 10 15
1 4 10 20
1 5 15
1 6
1
However, if you must print sth like this
I did it this way:
for (int i = 0; i<n; i++){
for (int j = 0; j<Triangle.trojkat[i].length; j++){
sb.append(Triangle.trojkat[i][j]);
len = String.valueOf(Triangle.trojkat[i][j]).length();
while (12-len>0){
sb.append(" ");
len++;
}
//sb.append(" ");
}
TriangleRes[i] = new JLabel(sb.toString(), JLabel.CENTER);
TriangleRes[i].setFont(new Font("Serif",Font.PLAIN,8));
sb = new StringBuilder();
}
Let me explain:
I decided, that I want my triangle print beautifuly for the size smaller that 35. Then I've checked, that the numbers in such a triangle come up to 10 digits. Then, when I added next number to the existing row, I checked it's length and while total length wasn't 12 yet, I add spaces. This lead to the triangle that you have attached on the picture.
If this is for Ph.D Macyna classes, just post a question on a group and I'll respond :)
Use a JTextArea
Give it a monospaced font, i.e., Font.MONOSPACED
Append your lines of text to the JTextArea, similar to how you'd do this in the console.
Put the JTextArea into a JScrollPane
VoilĂ . You're done.
If you need to use JLabels, then put them in a JPanel that uses GridLayout with enough columns to show your bottom row.
If you did this, you'd be putting empty JLabels in every other cell, so that the cells branch correctly.
What i want to achieve: I want to be able to add components to a scrollpane inbetween components already added. In other words, i somehow want to move the index up and plop some new components where the old ones used to be. I created a short program to illustrate my problem, it replace the components it doesnt add them. can someone help?
Why i want to achieve it (to answer the inevitable question related to this, this is long only read if interested): Ive got a scrollpane in which i need to display lots of components, approx 150000 JTables. This takes too much memory and processing time. So what ive done is to load the scrollpane with 150000 TextFields and only displaying 100 of the tables at a time. If you scroll to textfield 200 it loads the next 100 tables, replacing the previously created text fields with the tables. If you move to textfield 300 it loads the next 100 tables, and removes the first 100, again replacing it with textfields. My thinking here is that the textfields are going to be much less resource intensive than the tables, and so far this thinking seems to be correct. So this all seems to work pretty well (on my smaller test file - about 5000 records). The problem is that to create the 150000 textfields also takes lots of time. I thought of a solution for this. To not create a textfield for every table, but to rather create 1 textfield for every 100 tables. The idea is that when you scroll to textfield 2 (instead of 200), it loads the next 100 tables, replacing textfield nr 2 with tables nr 200 - 299. So somehow i need to move textfield 3 and all those below it down in order to insert all the tables. Phew, hope this makes sense
So looking at the example below what i effectively want to achieve is to replace say textfield 20 with 5 new textfields, but not repalce textfields 21 - 25.
import javax.swing.*;
import java.awt.*;
public class Example {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ExampleScreen ex = null;
ex = new ExampleScreen();
ex.setVisible(true);
}
});
}
private static class ExampleScreen extends JFrame{
GridBagConstraints gc = new GridBagConstraints();
JPanel panel = new JPanel(new GridBagLayout());
JScrollPane scrollPane = new JScrollPane(panel);
public ExampleScreen() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.add(scrollPane, BorderLayout.CENTER);
setupFields();
createExtraFieldsInbetween(20);
this.pack();
scrollPane.getVerticalScrollBar().setUnitIncrement(16);
scrollPane.getViewport().setScrollMode(JViewport.BLIT_SCROLL_MODE);
}
//after this happens i need to add components somewhere in the middle, like after textfield 20 for example
private void setupFields() {
gc.gridy = 0;
gc.gridx = 0;
for(int k = 0; k < 50; k++) {
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(1500,36));
textField.setText(new Integer(k).toString());
panel.add(textField, gc, k);
gc.gridy++;
}
}
//this is to create extra fields inbetween those already created
//this does not work, it overwrites the existing components, doesnt move them up
private void createExtraFieldsInbetween(int i) {
gc.gridy = i;
//create 5 extra
for(int k = i; k < i + 5; k++) {
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(1500,36));
textField.setText("Extra Field : " + new Integer(k).toString());
panel.add(textField, gc, k);
gc.gridy++;
}
}
}
}
Anytime I see a number like 150,000 I think the user can't be bothered to scroll through all those components so you need a better UI.
Anyway if you have a problem with a GridBagLayout, then don't use a GridBagLayout.
It looks to me like you are just displaying the components vertically so try a BoxLayout. Then you can just use the add(...) method to specify the index where you want to remove/add components.
I am updating/maintaining an existing graphing program. This is suppose to be a medium duty program (able to handle anything less than a million nodes + their transitions). In the GUI, there is a 'viewport' that visually shows the graph and there is a side panel that contains tabs that contain summaries on the nodes, transitions, etc...
The graphical part works phenominal and is quick but after running a profiler (YourKit) 96-99.8% of the time is spent creating the summary tab/table for the nodes. So for 10,000 nodes, it takes a second or two to generate the graph visually but minutes for it to populate the table!
A summary of the process is this: the tab gets notified that the model changed and gets the node list. If it needs more rows, it adds them, else it reuses or throws old ones away. Then after creating the rows and their cells, it fills them.
The population is one node per row, three cells (JPanel) per row (each contain some information). Each time a cell is created when a new row is added or the row is asked to check for updates, it calls the "positionPanel" method provided below. The layout manager is SpringLayout. According to the profiler, of the 90-odd percent to generate this table, 90-odd percent minus one is the "add(newPanel);" line.
Any suggestions on where the speed is being taken and how to improve it?
private void positionPanel(int row, int col) {
JPanel upPanel = this;
JPanel leftPanel = this;
String upSpring = SpringLayout.NORTH;
String leftSpring = SpringLayout.WEST;
if (row != 0) {
upPanel = cells.get(row - 1)[col];
upSpring = SpringLayout.SOUTH;
}
if (col != 0) {
leftPanel = cells.get(row)[col-1];
leftSpring = SpringLayout.EAST;
}
Cell newPanel = cells.get(row)[col];
//cells.get(row).set(col, newPanel);
add(newPanel);
layout.putConstraint(SpringLayout.NORTH, newPanel, cellSpacing, upSpring, upPanel);
layout.putConstraint(SpringLayout.WEST, newPanel, cellSpacing, leftSpring, leftPanel);
}
The suggestion to consider JTable hinges on it's use of the flyweight pattern to implement rendering. The benefit comes from rendering only visible/altered nodes, while ignoring others. JGraph uses a similar approach. The essential mechanism is outlined here. Note that the benefit accrues only to the view, but your profiling suggests it may be worthwhile.
Does GridLayout ever not honor the number of rows and columns you've specified if you don't fill it completely?
I'm creating a GridLayout with 3 rows and 4 columns. However, I'm only adding 9 components. It ends up showing me these 9 components in a 3x3 grid, rather than a 3x4 grid (with only 1 component on the third row (and two blanks)).
rather than a 3x4 grid (with only 1 component on the third row (and two blanks)).
Then you should be creating your GridLayout using:
setLayout(new GridLayout(0,4));
It tell the layout that you don't know how many rows you have, but you want 4 columns. So the columns will be filled up before moving to the next row.
No need for empty components.
Just fill empty cells with empty items (like a JLabel), eg:
class MyFrame extends JFrame
{
MyFrame()
{
setLayout(new GridLayout(3,4));
for (int i = 0; i < 9; ++i)
this.getContentPane().add(new JLabel(""+i));
for (int i = 0; i < 3; ++i)
getContentPane().add(new JLabel());
pack();
setVisible(true);
}
}
This layouts them as
0 1 2 3
4 5 6 7
9