I created a JScrollPane with a JTable on it. When the table's height is larger than the height of the scroll pane, a scroll bar appears. If minimize the JFrame although I didn't change the size of it, the scroll bar vanishes and the scroll pane extends downwards.
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class Main {
static String columns[] = {"Date", "Price", "URL", "Expired"};
static String data[][] = new String[8][4];
/*
* The data that should be provided to the JTable is
* replaced with some example data because the method
* of getting this data is complicated and doesn't
* change anything at the outcome.
*/
public static void main(String[] args) {
loadGui();
}
public static void loadGui() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
data[i][j] = "Example data " + i + " " + j;
}
}
JFrame mainFrame = new JFrame();
mainFrame.setSize(800, 300);
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
JTable table = new JTable(data, columns);;
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane pane = new JScrollPane(table);
pane.setViewportView(table);
pane.setSize(785, 100);
mainFrame.add(pane);
table.getTableHeader().setReorderingAllowed(false);
table.setDefaultEditor(Object.class, null);
table.setFocusable(false);
table.setRowSelectionAllowed(false);
}
}
I search for a way to stop the scroll pane to extend downwards and keeping it in its size.
You can use BorderLayout layout manager to make your scroll pane stick to the top
You can use setPreffered size to suggest to the layout manager what dimensions element should have if possible
Use setVisible when all components are already added
public class Main {
static String columns[] = {"Date", "Price", "URL", "Expired"};
static String data[][] = new String[8][4];
/*
* The data that should be provided to the JTable is
* replaced with some example data because the method
* of getting this data is complicated and doesn't
* change anything at the outcome.
*/
public static void main(String[] args) {
loadGui();
}
public static void loadGui() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
data[i][j] = "Example data " + i + " " + j;
}
}
JFrame mainFrame = new JFrame();
mainFrame.setSize(800, 300);
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//set our layour manager
mainFrame.setLayout(new BorderLayout());
JTable table = new JTable(data, columns);;
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.getTableHeader().setReorderingAllowed(false);
table.setDefaultEditor(Object.class, null);
table.setFocusable(false);
table.setRowSelectionAllowed(false);
JScrollPane pane = new JScrollPane(table);
pane.setViewportView(table);
// we would like to have its height at 100px, width does not matter thus 0
pane.setPreferredSize(new Dimension(0,100));
//using NORTH will "stick" the component to the top
mainFrame.add(pane,BorderLayout.NORTH);
//all the calculation will be done now. The same happens when you minimize/restore the frame.
mainFrame.setVisible(true);
}
}
Related
My task is to create checked board on JPAnel. For that purpose I'm trying to fill in parent JPanel with JPanels that has borders, but for some reason code doesnt give desired result and no error shown to do investigation why. Here is the code:
private static class GlassView extends JFrame {
private static int width = 600;
private static int height = 750;
public GlassView() {
this.setSize(width, height);
this.setVisible(true);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void workingFrame() {
int cols = 0;
int rows = 0;
String frameName = "Bot World";
WorkFrame workF = new WorkFrame(0, 0, frameName);
wfFrame = workF.newFrame();
wfFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
wfFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wfFrame.setVisible(true);
JSplitPane splitPane = new JSplitPane();
splitPane.setSize(width, height);
splitPane.setDividerSize(0);
splitPane.setDividerLocation(150);
splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
JPanel panelLeft = createLftPanel();
JPanel panelRight = createRightPanel();
splitPane.setLeftComponent(panelLeft);
splitPane.setRightComponent(panelRight);
wfFrame.add(splitPane);
}
}
Here is the code for the panelRight which needs to be cheked:
public static JPanel createRightPanel() {
JPanel panel = new JPanel();
int rows = 100;
int cols = 100;
panel.setLayout(new GridLayout(rows, cols));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
JPanel pane = new JPanel();
pane.add(new JTextField("both"));
pane.setBorder(BorderFactory.createLineBorder(Color.black));
panel.add(new JButton(""));
}
}
return panel;
}
Any help will be appreciated. Thank you
Ok, my (second) guess is that the frame isn't laid out again after the call to
wfFrame.setVisible(true);
For me the example below:
public class Framed {
public static void workingFrame() {
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.getContentPane().add(createRightPanel(10, 10));
frame.revalidate(); // <-- HERE
}
public static JPanel createRightPanel(int rows, int cols) {
JPanel panel = new JPanel(new GridLayout(rows, cols));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
JPanel pane = new JPanel();
pane.setBackground((i+j)%2==0?Color.black:Color.white);
panel.add(pane);
}
}
return panel;
}
public static void main(String... none) throws Exception {
workingFrame();
}
}
Shows a checker grid, but is you remove the call to
frame.revalidate(); // <-- HERE
Then the gird is not displayed (until you do something with the frame that causes it to lay out again). Better than calling revalidate() though may be to call setVisible only after all the components have been added.
I have a JPanel and I'm adding 25 JPanels to the inside in a grid. I want a border around each panel so you can clearly distinguish between each element. Padding would work as well. The way I'm adding panels to the board if I try to add a border it will apply it to the larger panel containing the elements instead.
public class LightsOutView
{
GridLayout experimentLayout = new GridLayout(5, 5);
// Creates layout of the GUI
public LightsOutView ()
{
JFrame frame = new JFrame();
frame.setTitle("Lights Out");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setContentPane(makeContents());
frame.setVisible(true);
}
/**
* Creates the blank game board. Returns the panel
*
* #return JPanel
*/
public JPanel makeContents ()
{
// Create a panel to hold the 5x5 grid
JPanel board = new JPanel(new GridLayout(5, 5));
board.setLayout(experimentLayout);
// Add the components to the panel
for (int i = 0; i < 25; i++)
{
board.add(new JPanel()).setBackground(Color.YELLOW);
}
// Return the panel
return board;
}
}
How do I add a border around each element. Will I need to change how I'm adding panels to the grid?
One way:
Change your GridLayout to something like:
GridLayout experimentLayout = new GridLayout(5, 5, gap, gap);
where gap is some small int value, say 1 to 3 (for pixels). Then give the background container a background color, and it will show through the gaps. You'll also want to give the background JPanel a line border with the same gap width.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class GridWithBorders extends JPanel {
private static final int SIDES = 6;
private static final int SIDE_LENGTH = 60;
private static final int GAP = 3;
private static final Color BG = Color.BLACK;
private static final Color CELL_COLOR = Color.GREEN.darker();
public GridWithBorders() {
setBackground(BG);
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new GridLayout(SIDES, SIDES, GAP, GAP));
Dimension prefSize = new Dimension(SIDE_LENGTH, SIDE_LENGTH);
for (int i = 0; i < SIDES; i++) {
for (int j = 0; j < SIDES; j++) {
JPanel cell = new JPanel();
cell.setBackground(CELL_COLOR);
cell.setPreferredSize(prefSize);
add(cell);
}
}
}
private static void createAndShowGui() {
GridWithBorders mainPanel = new GridWithBorders();
JFrame frame = new JFrame("GridWithBorders");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I need to update the text of different labels throughout the program.
Example: If my grid layout is (12,12) and I need to change the texts of a label at (2,5) how can I do this?
Maybe even a way to erase the label and add a new one at the same position.
Create a 2D array of JLabel
JLabel[][] labels = new JLabel[12][12];
// populate and add to container with GridLayout(12, 12)
...
// change property
JLabel label = labels[2][5];
label.setText(..)
"Maybe even a way to erase the label and add a new one at the same position."
No need, just change the properties of the existing one
UPDATE
See example here. Pay close attention to the method createButtonsPanel. Its where I access the label from the grid.
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestLabelGrid {
public TestLabelGrid() {
JLabel[][] labelGrid = createLabelGrid(6, 6);
JPanel labelPanel = createPanel(labelGrid);
JPanel buttonPanel = createButtonsPanel(labelGrid);
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(2, 1));
frame.add(labelPanel);
frame.add(buttonPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createPanel(JLabel[][] labels) {
int rows = labels.length;
int cols = labels[0].length;
JPanel panel = new JPanel(new GridLayout(rows, cols));
for (JLabel[] rowOfLabels: labels) {
for (JLabel label : rowOfLabels) {
panel.add(label);
}
}
return panel;
}
private JLabel[][] createLabelGrid(int rows, int cols) {
JLabel[][] labels = new JLabel[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
labels[i][j] = new JLabel("( " + i + " , " + j + " )");
}
}
return labels;
}
private JPanel createButtonsPanel(final JLabel[][] labels) {
int rows = labels.length;
int cols = labels[0].length;
JButton[][] buttons = new JButton[rows][cols];
JPanel panel = new JPanel(new GridLayout(rows, cols));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
String text = "( " + i + " , " + j + " )";
JButton button = new JButton(text);
buttons[i][j] = button;
final int jTemp = j;
final int iTemp = i;
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
JLabel label = labels[iTemp][jTemp];
label.setForeground(Color.BLUE);
}
});
panel.add(button);
}
}
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new TestLabelGrid();
}
});
}
}
You can save a reference to each of your Labels, or perhaps use container.getComponents(), but I am unsure if that method has any guarantee on the order of the components in the array.
To swap components, you can instead add a container at each of the locations of the GridLayout, and change what component the container at that position contains.
I've been trying for hours, different things and searching everywhere for a solution, but I can not get my table in addScoreCardUpper() to show up. I get an horizontal scrollbar, but no content, just 2 pixels worth of border.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
public class YahtzeeGUI extends JFrame{
/**
*
*/
private static final long serialVersionUID = 3255683022699487295L;
private JFrame frame;
private JPanel panel;
private JPanel dicePanel;
private JScrollPane scrollPane;
private JButton btnRoll;
private JButton[] btnDice = new JButton[5];
private JTable table;
private Yahtzee y = new Yahtzee();
public YahtzeeGUI(){
createWindow();
addButtonRoll();
addButtonDice();
addScoreCardUpper();
//addScoreCardLower();
frame.add(panel);
frame.setVisible(true);
}
public void createWindow(){
frame = new JFrame();
frame.setTitle("Yahtzee");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1000,700);
frame.setVisible(true);
panel = new JPanel(new BorderLayout());
dicePanel = new JPanel();
scrollPane = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
}
public void addButtonRoll(){
btnRoll = new JButton ("Roll the Dice");
btnRoll.addActionListener(new RollHandler());
dicePanel.add (btnRoll);
panel.add(dicePanel, BorderLayout.SOUTH);
}
public void addButtonDice(){
for (int i = 0; i < btnDice.length; i++){
btnDice[i] = new JButton(String.valueOf(y.dice[i].getFaceValue()));
btnDice[i].addActionListener(new HoldHandler());
dicePanel.add (btnDice[i]);
}
panel.add(dicePanel, BorderLayout.SOUTH);
}
public void addScoreCardUpper(){
String tableHeader[] = {"Upper Section", "How to score", "Score" };
String tableValues[][] = {
{"ONES", "Total of all Ones",""},
{"TWOS", "Total of all Twos",""},
{"THREES", "Total of all Threes",""},
{"FOURS", "Total of all Fours",""},
{"FIVES", "Total of all Fives",""},
{"SIXES", "Total of all Sixes",""},
{"TOTAL SCORE", "",""},
{"BONUS", "",""},
{"TOTAL + BONUS", "",""}
};
table = new JTable(tableValues, tableHeader);
table.setEnabled(false);
setColumnWidths();
scrollPane.add(table); // Here is the offender
panel.add(scrollPane, BorderLayout.EAST);
}
/*public void addScoreCardLower(){
String tableHeader[] = {"Lower S", "How to score", "Score" };
String tableValues[][] = {
{"ONES", "Total of all Ones",""},
{"TWOS", "Total of all Twos",""},
{"THREES", "Total of all Threes",""},
{"FOURS", "Total of all Fours",""},
{"FIVES", "Total of all Fives",""},
{"SIXES", "Total of all Sixes",""},
{"TOTAL SCORE", "",""},
{"BONUS", "",""},
{"TOTAL + BONUS", "",""}
};
table = new JTable(tableValues, tableHeader);
table.setEnabled(false);
setColumnWidths();
scoreSubPanel.add(table);
panel.add(scoreSubPanel, BorderLayout.WEST);
}*/
public void setColumnWidths(){
TableColumn a = table.getColumnModel().getColumn(0);
TableColumn b = table.getColumnModel().getColumn(1);
a.setPreferredWidth(100);
b.setPreferredWidth(100);
}
class RollHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
for(int i = 0; i < y.dice.length; i++){
if (y.dice[i].getHoldState() != true){
y.dice[i].roll();
btnDice[i].setText(String.valueOf(y.dice[i].getFaceValue()));
}
}
}
}
class HoldHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
for (int i = 0; i < btnDice.length; i++){
if (event.getSource()== btnDice[i]){ // Picks the pressed button after running through them all.
if (y.dice[i].getHoldState() == false){
y.dice[i].setHoldState(true);
} else if (y.dice[i].getHoldState() == true){
y.dice[i].setHoldState(false);
}
}
}
}
}
}
This is your problem:
scrollPane.add(table);
This does not add the JTable to the JScrollPane's viewport's view which is where you want it, but rather completely replaces the JScrollPane's viewport with the JTable, making the JScrollPane completely nonfunctional. Instead set the table as the JScrollPane's viewportview:
scrollPane.setViewportView(table);
Do either this or pass the table into the JScrollPane's constructor which does pretty much the same thing:
JScrollPane scrollPane = new JScrollPane(table,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
This is all well explained in the JScrollPane API, and you will want to give it a look for the important details.
Edit
Your code also calls setVisible(true) on the JFrame before adding all components which can lead to trouble. You'll want to avoid doing this.
Try any one
scrollPane = new JScrollPane(table);
or
scrollPane = new JScrollPane(table,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
or
scrollPane.getViewport().add(table);
I set up a small program that can create rows and columns at run time, its for a math class implementing sets, I already got the program to create the rows and columns but what I wanna do next is be able to get the values inside and then load another form of the same structure and get that forms values then add them and show them on a final form. Fairly new to the whole java thing, so if anyone could help it'd mean the world. Here's what I have so far..
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Matrice extends JFrame {
protected static final int PREF_W = 200;
protected static final int PREF_H = 200;
JPanel mainPanel = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
};
public JComponent getMainComponent() {
return mainPanel;
}
public Matrice(){
int rows, columns, end;
String RI, CI;
RI = JOptionPane.showInputDialog(null, "How many rows: ");
rows = Integer.parseInt(RI);
CI = JOptionPane.showInputDialog(null, "How many columns: ");
columns = Integer.parseInt(CI);
end = rows * columns;
JPanel holder = new JPanel(new GridLayout(rows, columns));
holder.setVisible(true);
for(int i = 0; i < end; i ++){
holder.add(new JTextField("output"));
}
JPanel set = new JPanel(new GridLayout(1, 0));
JTextField r = new JTextField("rows");
JTextField c = new JTextField("columns");
set.add(r);
set.add(c);
set.add(new JButton("Set"));
mainPanel.add(set, BorderLayout.SOUTH);
mainPanel.add(holder, BorderLayout.NORTH);
}
private static void createAndShowGui() {
Matrice test = new Matrice();
JFrame frame = new JFrame("Matrice");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(test.getMainComponent());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
never mind the buttons and the pre-set TextField
Simple answer to your question is that you need to define a array of TextField after getting the size:
TextField[][] inputFields = new TextField[rows][columns];
now add the TextFields
getContentPane().setLayout(new GridLayout(rows, columns));
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
inputFields[i][j] = new TextField("output");
holder.add(inputFields[i][j]);
}
}
There might be syntax errors above as I am directly typing it here.
To get the text out of a JTextField call .getText() on the object. so r.getText();
An elegant way to get a number out of the field is to use Integer.parseInt(String)
so your call would be Integer.parseInt(r.getText()) Note that this may throw
NumberFormatException so you will have to catch the exception and maybe reprompt the user to enter a valid number.