I have the following scenario: a JFrame which contains several JPanels that are selected using a CardLayout. One JPanel contains a pretty large JTable which I have wrapped in a JScrollPane and added the JScrollPane to the main JPanel:
package com.javaswingcomponents.demo;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.table.DefaultTableModel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class MyPanel extends JPanel {
private DefaultTableModel model = new DefaultTableModel();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setBounds(100, 100, 450, 535);
frame.getContentPane().add(new MyPanel());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyPanel() {
JTable table = new JTable(model);
JScrollPane scrollPaneParte = new JScrollPane(table);
scrollPaneParte.setPreferredSize(new Dimension(600, 600));
scrollPaneParte.setBounds(10, 92, 867, 92);
add(scrollPaneParte);
scrollPaneParte.setViewportView(table);
addColumns(model);
}
public void addColumns(DefaultTableModel model) {
for (int ii=0;ii<10;ii++)
model.addColumn("Field"+ii);
}
}
I initially thought the problem was the XY (null) layout used, but even changing to BorderLayout nothing happens, that is, the ScrollBar is not displayed and only a part of the JTable is shown.
Any idea how to solve this issue?
EDIT: I have included a full working example which reproduces the issue.
This variant works reliably. Note that the default layout of a panel is flow layout. If the GUI becomes too small for the components in the flow layout, they will be truncated as in your example. I'd tend to change the layout to grid layout, which fixes the problem, in one sense. But in this example, we follow best practices for setting sizes (and locations) and enforce the minimum size.
import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class MyPanel extends JPanel {
private DefaultTableModel model = new DefaultTableModel();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.getContentPane().add(new MyPanel());
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyPanel() {
addColumns(model);
JTable table = new JTable(model);
JScrollPane scrollPaneParte = new JScrollPane(table);
add(scrollPaneParte);
}
public void addColumns(DefaultTableModel model) {
for (int ii=0;ii<10;ii++)
model.addColumn("Field"+ii);
}
}
Related
In my code, currently each card is the size of my frame. How do I set different sizes of each of my panels in the layout. I tried making the frame different sizes by calling the run() method and changing the size of the frame, but it does not work. I'm hoping there is another way.
This is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class GameManager
{
JFrame frame;
JPanel cards,Title;
public GameManager()
{
cards = new JPanel(new CardLayout());
Title title = new Title();
cards.add(title,"title");
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, "title");
}
public static void main(String [] args)
{
GameManager gm = new GameManager();
gm.run();
}
public void run()
{
frame = new JFrame("Greek Olympics");
frame.setSize(1000,1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(cards);
frame.setVisible(true);
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, "title");
}
public class Title extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillRect(100,100,100,100);
}
}
}
How would I change the code so that if I wanted to add another panel with a different size?
How do I set different sizes of each of my panels in the layout
First, understand that CardLayout will use the preferredSize property of all the view's it's managing to determine the best resulting size that the container it's managing should use. This means that if you call pack on the frame (instead of setSize), it will be sized (automatically) to the largest component been managed (by the CardLayout)
How would I change the code so that if I wanted to add another panel with a different size?
Each component you add to the CardLayout should either be calculating it's size through one or more appropriate layout managers, or, in the case of custom components, be providing a sizing hint through the getPreferredSize method
public class Title extends JPanel
{
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillRect(100,100,100,100);
}
}
Then, instead of using setSize, use pack
public void run()
{
frame = new JFrame("Greek Olympics");
//frame.setSize(1000,1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(cards);
frame.pack();
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, "title");
frame.setVisible(true);
}
Example...
This is a basic example which sets up two panels, one with preferredSize of 200x200 and one with 400x400
When you run it, you will find the window will be at least 400x400 and both panels will be the same size
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CardLayout cardLayout = new CardLayout();
JPanel base = new JPanel(cardLayout);
base.add(makePanel(200, 200, Color.RED), "red");
base.add(makePanel(400, 400, Color.BLUE), "blue");
frame.add(base);
JButton blue = new JButton("Blue");
blue.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(base, "blue");
}
});
JButton red = new JButton("red");
red.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(base, "red");
}
});
JPanel buttons = new JPanel();
buttons.add(red);
buttons.add(blue);
frame.add(buttons, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public TestPane makePanel(int width, int height, Color background) {
TestPane pane = new TestPane(new Dimension(width, height));
pane.setBackground(background);
return pane;
}
public class TestPane extends JPanel {
private JLabel label;
private Dimension preferredSize;
public TestPane(Dimension size) {
label = new JLabel("...");
setLayout(new GridBagLayout());
add(label);
this.preferredSize = size;
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
#Override
public void invalidate() {
super.invalidate();
label.setText(getWidth() + "x" + getHeight());
}
}
}
I'm having a problem trying to change JPanels by using buttons. I have a JFrame with 2 panels, 1 of them is for the buttons, which i want them to always be showed. The other one is the one that i will be switching everytime i press one ot the buttons of the other panel. The problem is that everytime i press them nothing really ever displays, i keep my buttons but the other panel that i call does not appear.
Code for one of the buttons is as follows
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
ReparacaoPanel r = new ReparacaoPanel(this, this.jPanel1);
this.getContentPane().remove(this.jPanel1);
this.getContentPane().add(r);
//this.setContentPane(r);
this.visiblePanel.setVisible(false);
this.visiblePanel = r;
this.pack();
this.setVisible(true);
r.setLocation(200, 200);
this.getContentPane().revalidate();
this.repaint();
}
If i try to use "this.setContentPane(r);" (it sets the frame to only show the panel) the panel shows. But when i try to call it as i'm trying to do in the code above nothing is showed apart from the panel that has the buttons.
I have no idea what i'm doing wrong, it does not seem to be a problem with the JPanel that i'm trying to call as it shows if used alone.
Anyone can help me out?
Consider this working example for switching manually between panels. Which produces this output.
.........
Some tiny NumberPanel
Every new instance shows another number in the center.
import javax.swing.JPanel;
public class NumberPanel extends JPanel {
private static int counter = 0;
public NumberPanel() {
setLayout(new BorderLayout(0, 0));
JLabel lblNewLabel = new JLabel("" + counter++);
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(lblNewLabel);
}
}
Setting up a frame
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.SOUTH);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.getContentPane().remove(numberPanel);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
}
});
panel.add(btnNewButton);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
}
Testprogram
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestPanelSwitch {
private JFrame frame;
private NumberPanel numberPanel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestPanelSwitch window = new TestPanelSwitch();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public TestPanelSwitch() {
initialize();
}
private void initialize() {
// see above
}
}
Back to the Question
I think you only need to pack your frame, like in the anonymous ActionListener.
frame.getContentPane().remove(numberPanel);
numberPanel = new NumberPanel();
frame.getContentPane().add(numberPanel, BorderLayout.CENTER);
frame.pack();
EDIT
As leonidas mentioned it is also possible to revalidate the frame. This requires only to replace the upper call to pack by theese.
frame.invalidate();
frame.validate();
I know a lot of people asked this question, but i still can't resolve this problem.
I have a JPanel inside a JScrollPane. JPanel contains six panels that are loaded dynamically.
After the panels are loaded the system makes a vertical autoscroll to the middle of the panel.
I have to avoid this, so I tried with this:
panel.scrollRectToVisible(scrollPane.getBounds());
But it doesn't work.
My scrollPane has been created in this way
JScrollPane scrollPane= new JScrollPane();
scrollPane.setBounds(panel.getBounds());
scrollPane.setViewportView(panel);
Can you help me?
panel.scrollRectToVisible(scrollPane.getBounds()); should be panel.scrollRectToVisible(JPanelAddedOnRuntime.getBounds());
rest of code (posted here) coudn't be works,
for better help sooner post an SSCCE, short, runnable, compilable
EDIT
works, again you would need to re_read my above 3rd. point
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class ScrollTesting {
private JPanel panel = new JPanel();
private JScrollPane scrollPane = new JScrollPane(panel);
private Vector<JTextField> fieldsVector = new Vector<JTextField>();
private Dimension preferredSize = new Dimension(400, 40);
private Font font = new Font("Tahoma", 1, 28);
public ScrollTesting() {
panel.setLayout(new GridLayout(100, 1));
for (int i = 0; i < 100; i++) {
fieldsVector.addElement(new JTextField());
fieldsVector.lastElement().setPreferredSize(preferredSize);
fieldsVector.lastElement().setFont(font);
panel.add(fieldsVector.lastElement());
}
JFrame frame = new JFrame();
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JTextField tf = (JTextField) fieldsVector.lastElement();
panel.scrollRectToVisible(tf.getBounds());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ScrollTesting scrollTesting = new ScrollTesting();
}
});
}
}
When I edit text in a JTextField in my Swing application on OSX, the text gets garbled. It's most pronounced when I insert or delete characters but there are artifacts just when moving the cursor around. The data is fine, but the UI rendering is not.
What causes this and how can I fix it?
I'm using com.apple.laf.AquaLookAndFeel, as in this sample program. Type in some text and move the cursor around with the arrow keys to observe the weirdness.
import java.awt.*;
import javax.swing.*;
class TextFieldDisplay {
public static void main(String[] args) {
MainWindow app = new MainWindow();
}
}
class MainWindow extends JFrame {
public MainWindow() {
try {
UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel");
} catch(Exception e) {
System.out.println("AquaLookAndFeel is not supported on your platform.");
System.exit(1);
}
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
setMinimumSize(new Dimension(300, 100));
JPanel innerPanel = new JPanel();
JScrollPane scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(250, 20));
scrollPane.setViewportView(innerPanel);
JPanel mainPanel = new JPanel();
getContentPane().add(mainPanel);
mainPanel.add(innerPanel);
JTextField textField = new JTextField();
textField.setPreferredSize(new Dimension(250, 20));
innerPanel.add(textField);
pack();
}
}
I noticed as I was writing the SSCCE that the display issues seemed to crop up after I added the JScrollPane.
Not sure if it's relevant but I'm using Apple Java version 1.6.0_51 with a retina display.
Two things jump out at me.
Firstly, you're not initalisig your UI in the EDT, secondly, you're messing with the preferred and minimum sizes of your components.
You are not taking into consideration the font metrics when calculating the size of your components, which seems to be causing issues when it is rendering the content
Start by taking a look at Initial Threads.
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
class TextFieldDisplay {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
//UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println("AquaLookAndFeel is not supported on your platform.");
System.exit(1);
}
MainWindow app = new MainWindow();
}
});
}
}
class MainWindow extends JFrame {
public MainWindow() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
// setMinimumSize(new Dimension(300, 100));
JPanel innerPanel = new JPanel();
// JScrollPane scrollPane = new JScrollPane();
// scrollPane.setPreferredSize(new Dimension(250, 20));
// scrollPane.setViewportView(innerPanel);
JPanel mainPanel = new JPanel();
getContentPane().add(mainPanel);
mainPanel.add(innerPanel);
JTextField textField = new JTextField(20);
// textField.setPreferredSize(new Dimension(250, 20));
innerPanel.add(textField);
pack();
}
}
I would like the JTable to autoscroll to the bottom whenever I add a new column and show the last 10 rows. However, I have the option of scrolling to anywhere I want (mouse listener?). Do you know how to do that? Here's the code I have so far. It builds a JTable and adds a new row for every mouse click on the JButton.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class sampleGUI extends JFrame implements ActionListener {
private JButton incrementButton;
private JTable table;
private DefaultTableModel model;
private int count;
private JScrollPane scroll;
public sampleGUI() {
JFrame frame = new JFrame("sample frame");
frame.setLayout(new BorderLayout());
incrementButton = new JButton("Increase the count!");
model = new DefaultTableModel();
model.addColumn("column 1");
table = new JTable(model);
frame.add(incrementButton, BorderLayout.NORTH);
scroll = new JScrollPane(table)
frame.add(scroll, BorderLayout.CENTER);
count = 0;
incrementButton.addActionListener(this);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public synchronized void actionPerformed(ActionEvent e) {
if (e.getSource() == incrementButton) {
count++;
model.addRow(new Object[] { count });
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sampleGUI gui = new sampleGUI();
}
});
}
}
Thanks!
Required to change selection in JTable, add code line
table.changeSelection(table.getRowCount() - 1, 0, false, false);
to
public (synchronized) void actionPerformed(ActionEvent e) {
I would like the JTable to autoscroll to the bottom whenever I add a new column
I assume you mean scroll to the bottom when you add a new row?
model.addRow(new Object[] { count });
table.scrollRectToVisible(...);
You forget add JScrollPane to the table :
//...
frame.add(new JScrollPane(table), BorderLayout.CENTER);
//...
and don't forget
import javax.swing.JScrollPane;