I've got this list of JPanels and I'd like to save them without displaying them
make Jpanel -> Save it(without displaying it)
I tried using BufferedImage and painting it but the image returned is always black, the method I used for that is "save" and is displayed in the code below.
I'd like to know how to do fix this problem.
EDIT:
#camickr thanks to your suggestion and this thread
Why does the JTable header not appear in the image?
I was able to fix the problem, here is the fixed code:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class Solution extends JFrame
{
int i;
ArrayList <Individual> AKA;
Container jgraph;
JButton gauche;
JButton droite;
JMenuBar barre;
JMenu fichier;
JMenuItem enregistrer;
JPanel jpgenerale ;
Solution current;
Component middle;
public Solution(ArrayList <Individual> graph) throws HeadlessException
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
barre = new JMenuBar();
fichier = new JMenu("Fichier");
enregistrer = new JMenuItem("Enregistrer");
enregistrer.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK));
fichier.add(enregistrer);
barre.add(fichier);
AKA = graph;
current = this;
gauche = new JButton("Gauche");
droite = new JButton("Droite");
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_END;
c.gridx = 1;
c.gridy = 2;
gauche.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(java.awt.event.ActionEvent e)
{
i = (AKA.size() + (i - 1)) % AKA.size();
jpgenerale.removeAll();
jpgenerale.validate();
jpgenerale.add(AKA.get(i).chopper.getContentPane());
jpgenerale.revalidate();
jpgenerale.repaint();
}
});
getContentPane().add(gauche, c);
c.gridx = 3;
c.gridy = 2;
droite.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(java.awt.event.ActionEvent e)
{
i = (i+1)% AKA.size();
jpgenerale.removeAll();
jpgenerale.validate();
jpgenerale.add(AKA.get(i).chopper.getContentPane());
jpgenerale.revalidate();
jpgenerale.repaint();
}
});
getContentPane().add(droite, c);
jpgenerale = new JPanel();
c.anchor = GridBagConstraints.CENTER;
jpgenerale.setLayout(new BoxLayout(jpgenerale,BoxLayout.LINE_AXIS));
jpgenerale.setPreferredSize(new Dimension(400, 400));
jpgenerale.add(AKA.get(0).chopper.getContentPane());
c.ipady = 40;
c.gridx = 2;
c.gridy = 1;
getContentPane().add(jpgenerale,c);
setTitle("AGPM");// le titre on va change plutard
setSize(600,600);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
middle = AKA.get(0).chopper.getContentPane();
scan(middle);
middle = AKA.get(1).chopper.getContentPane();
scan(middle);
}
private static void scan(Component pan1)
{
JPanel temp = new JPanel();
temp.setBackground(Color.WHITE);//so that the image and JPanel background are unified
temp.setPreferredSize(new Dimension(400, 400));
temp.add(pan1);
BufferedImage bi = ScreenImage.createImage(temp);
try {
ScreenImage.writeImage(bi, "image.png");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
I edited the thread's title so that it's clearer, if you have any suggestion they're welcomed.
Thanks again everyone:)
If the component hasn't been added to the visible frame, then the size of the component is (0, 0) so there is nothing to paint. Also, the components haven't been positioned on the panel since the layout manager hasn't been invoked.
So you first need to:
set the size of the component equal to the preferred size
invoke doLayout() on the component
Or, you can check out Screen Image which does the above for you and can be used to create an image of any component.
Related
I want to make list of JButtons (with fixed dimensions, one beneath another) inside JScrollPane, using Swing. My idea was to make JPanel with GridBagLayout and add buttons in their suiting rows, and then create JScrollPane with that JPanel. That looks fine when number of buttons is large, but when the number of buttons is 2 or 3, I can't manage to align buttons one right below the other.
Also later I will add option to add new button (thus the + sign).
Works fine with 10 buttons
I get this empty space between button 0 and button 1 when it's just 2 buttons (this is the problem)
The code (creates upper east panel)
private JPanel createLayerPanel() {
JPanel layerPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
// Label ------------------------------------------------
JLabel layersLabel = new JLabel("Buttons");
layersLabel.setHorizontalAlignment(SwingConstants.CENTER);
layersLabel.setFont(DEFAULT_FONT);
//layersLabel.setBorder(new LineBorder(Color.red, 3));
layersLabel.setBackground(new Color(0x22222));
layersLabel.setForeground(new Color(0xFFFFFF));
layersLabel.setOpaque(true);
c.gridx = c.gridy = 0;
c.ipadx = 180;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
layerPanel.add(layersLabel, c);
// Button ------------------------------------------------
JButton newLayerBtn = new JButton("+");
newLayerBtn.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 18));
newLayerBtn.setBackground(new Color(0x222222));
newLayerBtn.setForeground(Color.white);
newLayerBtn.setFocusable(false);
c.gridx = 1;
c.gridy = 0;
c.ipadx = 0;
c.weightx = 0;
layerPanel.add(newLayerBtn, c);
// ScrollPane ------------------------------------------------
//------------------------------------------------------------
//------------------------------------------------------------
JPanel layerListPanel = new JPanel(new GridBagLayout());
layerListPanel.setBackground(Color.BLACK);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
gbc.weighty = 1;
gbc.ipady = 40;
gbc.gridx = 0;
gbc.anchor = GridBagConstraints.NORTH;
for (gbc.gridy = 0; gbc.gridy < 10; gbc.gridy++) {
JButton btn = new JButton("Button " + gbc.gridy);
layerListPanel.add(btn, gbc);
}
JScrollPane js = new JScrollPane(layerListPanel);
js.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
// ...
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 2;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
layerPanel.add(js, c);
return layerPanel;
}
Do you absolutely need a GridBagLayout?
I just made a demo using a simple Box.
And please have a look at How to write an SSCCE.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class YY extends JFrame {
static String[] args;
public YY() {
setSize(160, 200);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
int icnt= args.length==0 ? 5 : Integer.parseInt(args[0]);
Box box= Box.createVerticalBox();
for (int i=1; i<=icnt; i++) {
JButton btn= new JButton("Button "+i);
btn.setMaximumSize(new Dimension(150, 30));
box.add(btn);
}
JScrollPane scroll= new JScrollPane(box);
scroll.setPreferredSize(new Dimension(150, 100));
add(scroll);
setVisible(true);
}
public static void main(String... args) {
YY.args= args;
EventQueue.invokeLater(YY::new);
}
}
The below code initially displays a JFrame that contains a single JButton that displays the text Add. Each time you click the button a new JButton appears above it. The text on each newly created button is a three digit number with leading zeros that is incremented each time the Add button is clicked. And whenever a new button is added, the JFrame increases in height in order to display the newly added button.
import java.awt.BorderLayout;
import java.awt.EventQueue;
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.JPanel;
import javax.swing.WindowConstants;
public class GridBttn implements ActionListener, Runnable {
private int counter;
private JFrame frame;
private JPanel gridPanel;
#Override
public void run() {
showGui();
}
#Override
public void actionPerformed(ActionEvent event) {
addButtonToGridPanel();
}
private void addButtonToGridPanel() {
JButton button = new JButton(String.format("%03d", counter++));
gridPanel.add(button);
frame.pack();
}
private JButton createButton(String text) {
JButton button = new JButton(text);
button.addActionListener(this);
return button;
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(createButton("Add"));
return buttonsPanel;
}
private JPanel createGridPanel() {
gridPanel = new JPanel(new GridLayout(0, 1));
return gridPanel;
}
private void showGui() {
frame = new JFrame("Grid");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createGridPanel(), BorderLayout.CENTER);
frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new GridBttn());
}
}
Note the parameters to GridLayout constructor. Zero rows and one column. This means that whenever a Component is added to the JPanel it will be placed directly beneath the last Component added. In other words all the components added will appear in a single column. Also note that I call method pack() (of class JFrame) after adding a new button. This causes the JFrame to recalculate its size in order to display all the buttons.
EDIT
Due to OP's comment slightly modified above code so as to be more suitable to his requirements.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;
public class GridBttn implements ActionListener, Runnable {
private int counter;
private JFrame frame;
private JPanel gridPanel;
private JPanel gridPanel2;
#Override
public void run() {
showGui();
}
#Override
public void actionPerformed(ActionEvent event) {
addButtonToGridPanel();
}
private void addButtonToGridPanel() {
JButton button = new JButton(String.format("%03d", counter++));
gridPanel2.add(button);
frame.pack();
}
private JButton createButton(String text) {
JButton button = new JButton(text);
button.addActionListener(this);
return button;
}
private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(createButton("Add"));
return buttonsPanel;
}
private JPanel createMainPanel() {
gridPanel = new JPanel();
gridPanel.setPreferredSize(new Dimension(400, 300));
return gridPanel;
}
private JScrollPane createScrollPane() {
gridPanel2 = new JPanel();
BoxLayout layout = new BoxLayout(gridPanel2, BoxLayout.PAGE_AXIS);
gridPanel2.setLayout(layout);
JScrollPane scrollPane = new JScrollPane(gridPanel2,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(70, 0));
return scrollPane;
}
private void showGui() {
frame = new JFrame("Grid");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createScrollPane(), BorderLayout.LINE_END);
frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new GridBttn());
}
}
I've seen two other posts on stackoverflow about this and in both, the solutions use setConstraints(myComponent, anotherConstraint) which doesn't even come up as an available method when I try to use it in java.
want to change an Inset in a gridbag layout dynamically
Change the component weight dynamically in GridBagLayout
How else could I change the weightx of a component after a button press?
The actual problem is that I have two components at the bottom of the screen and I need to set one of the components to be the max width of the screen after a button press.
I couldn't get setConstraints() to work..
Then it seems the code was wrong. From the fact the RHS of the red panel neatly aligns with the LHS of the Articuno label I suspect that the grid bag cell containing the red panel does not span more than one column, and currently entirely fills that column.
There could be other reasons, but short a minimal reproducible example I won't speculate further.
Here is a simplified example showing how to do it. Note that it was necessary to call revalidate() before the changes could be seen.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.image.BufferedImage;
public class FullWidthToggle {
private JComponent ui = null;
FullWidthToggle() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
GridBagConstraints gbc = new GridBagConstraints();
GridBagLayout gbl = new GridBagLayout();
ui = new JPanel(gbl);
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
BufferedImage image = new BufferedImage(
160, 20, BufferedImage.TYPE_INT_RGB);
gbc.insets = new Insets(5, 5, 5, 5);
ui.add(new JLabel(new ImageIcon(image)), gbc);
final JCheckBox checkBox = new JCheckBox("Full Width");
gbc.gridx = 1;
gbc.anchor = GridBagConstraints.LINE_START;
ui.add(checkBox, gbc);
final JLabel label = new JLabel("Am I full width?");
label.setBorder(new LineBorder(Color.RED, 2));
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 2;
ui.add(label, gbc);
ActionListener actionListener = (ActionEvent e) -> {
if (checkBox.isSelected()) {
gbc.fill = GridBagConstraints.HORIZONTAL;
} else {
gbc.fill = GridBagConstraints.NONE;
}
gbl.setConstraints(label, gbc);
ui.revalidate(); // <- important!
};
checkBox.addActionListener(actionListener);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
FullWidthToggle o = new FullWidthToggle();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
I'm trying to create a GUI for a personal project. I have a file chooser, a console area, a text field (with label), a button panel(2 buttons) and finally a "drop zone" area.
The GUI is divided vertically in half with the console on the right.
On the UpperLeft I have FileChooser positioned at BorderLayout.CENTER, followed by the ButtonPanel at BorderLayout.SOUTH.
Below that is the "drop zone"
It currently looks something like this:
_________________
| file | console|
| chooser| |
| buttons| |
|--------| |
| drop | |
| zone | |
|________|________|
I want to add a new text field between the file chooser and the button panel, but when I change file chooser to NORTH, jtextfield to CENTER and buttons to SOUTH, the file chooser is weirdly small and the jtextfield is much to large. I think this is just due to the inherent properties of BorderLayout, but I am not sure. Should I use a different Layout and what kind of changes would I make?
I've included the code I'm working with below. Thank you for any help in advance!
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.*;
import java.util.*;
import java.nio.*;
public class ConsolidatorDemo extends JPanel implements ActionListener {
JFileChooser fc;
JButton clear;
JButton ok;
JTextArea console;
JList<File> dropZone;
DefaultListModel listModel;
JSplitPane childSplitPane, parentSplitPane;
PrintStream ps;
JTextField wordCount;
JLabel lblCount;
public ConsolidatorDemo() {
super(new BorderLayout());
fc = new JFileChooser();;
fc.setMultiSelectionEnabled(true);
fc.setDragEnabled(true);
fc.setControlButtonsAreShown(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
JPanel fcPanel = new JPanel(new BorderLayout());
fcPanel.add(fc, BorderLayout.CENTER);
clear = new JButton("Clear All");
clear.addActionListener(this);
JPanel buttonPanel = new JPanel(new BorderLayout());
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
buttonPanel.add(clear, BorderLayout.LINE_END);
ok = new JButton("OK");
ok.addActionListener(this);
buttonPanel.add(ok, BorderLayout.WEST);
JPanel sizePanel = new JPanel(new BorderLayout());
sizePanel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
wordCount = new JTextField();
sizePanel.add(wordCount, BorderLayout.LINE_END);
// lblCount = new JLabel("Word Counter");
// buttonPanel.add(lblCount, BorderLayout.CENTER);
JPanel leftUpperPanel = new JPanel(new BorderLayout());
leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
leftUpperPanel.add(fcPanel, BorderLayout.NORTH);
leftUpperPanel.add(sizePanel, BorderLayout.CENTER);
leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);
JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
listModel = new DefaultListModel();
dropZone = new JList(listModel);
dropZone.setCellRenderer(new FileCellRenderer());
dropZone.setTransferHandler(new ListTransferHandler(dropZone));
dropZone.setDragEnabled(true);
dropZone.setDropMode(javax.swing.DropMode.INSERT);
dropZone.setBorder(new TitledBorder("Selected files/folders"));
leftLowerPanel.setViewportView(new JScrollPane(dropZone));
childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
leftUpperPanel, leftLowerPanel);
childSplitPane.setDividerLocation(400);
childSplitPane.setPreferredSize(new Dimension(480, 650));
console = new JTextArea();
console.setColumns(40);
console.setLineWrap(true);
console.setBorder(new TitledBorder("Console"));
parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
childSplitPane, console);
parentSplitPane.setDividerLocation(480);
parentSplitPane.setPreferredSize(new Dimension(800, 650));
add(parentSplitPane, BorderLayout.CENTER);
this.redirectSystemStreams();
}
private void updateTextArea(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
console.append(text);
}
});
}
private void redirectSystemStreams() {
OutputStream out = new OutputStream() {
#Override
public void write(int b) throws IOException {
updateTextArea(String.valueOf((char) b));
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
updateTextArea(new String(b, off, len));
}
#Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
};
System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
}
public void setDefaultButton() {
getRootPane().setDefaultButton(ok);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clear) {
listModel.clear();
}
if(e.getSource() == ok){
try{
if(dropZone.isSelectionEmpty() == true){
int start = 0;
int end = dropZone.getModel().getSize() - 1;
if (end >= 0) {
dropZone.setSelectionInterval(start, end);
}
}
List<File> list = dropZone.getSelectedValuesList();
for (File file : list) {
//StringEditing.editDocument(file, Integer.parseInt(wordCount.getText()));
}
}
catch(NumberFormatException nfe){
System.out.println("You did not input a number");
}
catch(Exception ef){
System.out.println("Something is wrong!");
}
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
try {
//UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}catch (Exception e){
e.printStackTrace();
}
//Create and set up the window.
JFrame frame = new JFrame("Consolidator!");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//Create and set up the menu bar and content pane.
ConsolidatorDemo demo = new ConsolidatorDemo();
demo.setOpaque(true); //content panes must be opaque
frame.setContentPane(demo);
//Display the window.
frame.pack();
frame.setVisible(true);
demo.setDefaultButton();
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
class FileCellRenderer extends DefaultListCellRenderer {
public Component getListCellRendererComponent(JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(
list,value,index,isSelected,cellHasFocus);
if (c instanceof JLabel && value instanceof File) {
JLabel l = (JLabel)c;
File f = (File)value;
l.setIcon(FileSystemView.getFileSystemView().getSystemIcon(f));
l.setText(f.getName());
l.setToolTipText(f.getAbsolutePath());
}
return c;
}
}
class ListTransferHandler extends TransferHandler {
private JList list;
ListTransferHandler(JList list) {
this.list = list;
}
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
// we only import FileList
if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
return false;
}
return true;
}
#Override
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
// Check for FileList flavor
if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
displayDropLocation("List doesn't accept a drop of this type.");
return false;
}
// Get the fileList that is being dropped.
Transferable t = info.getTransferable();
List<File> data;
try {
data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
}
catch (Exception e) { return false; }
DefaultListModel model = (DefaultListModel) list.getModel();
for (Object file : data) {
model.addElement((File)file);
}
return true;
}
private void displayDropLocation(String string) {
System.out.println(string);
}
}
I ended up using GridBagLayout using the various answers here, thank you for your help!
I've got a ton of extra/ unused stuff in this example, mostly because I was starting to implement the functions I needed when I figured I'd post an update here. Should still compile and run fine though.
One problem I have is that the GUI spawns with the button panel / drop zone divider sort of eating into each other. On top of that, there is a text field which has no width despite it working perfectly fine before I used the split panes. If anyone had any knowledge of how to get around these bugs I'd appreciate it!
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.*;
import java.util.*;
import java.nio.*;
public class TestGridBagLayout {
final static boolean shouldFill = true;
final static boolean shouldWeightX = true;
final static boolean RIGHT_TO_LEFT = false;
public static void addComponentsToPane(Container pane) {
if (RIGHT_TO_LEFT) {
pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
}
JButton clear;
JButton ok;
JLabel num;
JTextField input;
JSplitPane childSplitPane, parentSplitPane;
PrintStream ps;
JTextArea console;
JList<File> dropZone;
DefaultListModel listModel;
pane.setLayout(new GridBagLayout());
JPanel leftUpperPanel = new JPanel(new GridBagLayout());
leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
GridBagConstraints c = new GridBagConstraints();
if (shouldFill) {
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;
}
JFileChooser fc = new JFileChooser();;
fc.setMultiSelectionEnabled(true);
fc.setDragEnabled(true);
fc.setControlButtonsAreShown(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40; //make this component tall
c.weightx = 0.0;
c.gridwidth = 4;
c.gridx = 0;
c.gridy = 1;
leftUpperPanel.add(fc, c);
ok = new JButton("OK");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0; //reset to default
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0); //top padding
c.weightx = 0.5;
c.gridx = 0; //aligned with button 2
c.gridwidth = 1;
c.gridy = 2; //third row
leftUpperPanel.add(ok, c);
num = new JLabel("Word Count:");
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.PAGE_END;
c.insets = new Insets(10,0,0,0); //top padding
c.weightx = 0.25;
c.gridx = 1;
c.gridy = 2;
leftUpperPanel.add(num, c);
input = new JTextField("", 50);
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.PAGE_END;
c.insets = new Insets(10,0,0,0); //top padding
c.weightx = 0.25;
c.gridx = 2;
c.gridy = 2;
leftUpperPanel.add(input, c);
clear = new JButton("Clear All");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0;
c.anchor = GridBagConstraints.PAGE_END;
c.insets = new Insets(10,0,0,0); //top padding
c.weightx = 0.5;
c.gridx = 3;
c.gridy = 2;
leftUpperPanel.add(clear, c);
JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
listModel = new DefaultListModel();
dropZone = new JList(listModel);
dropZone.setCellRenderer(new FileCellRenderer());
dropZone.setTransferHandler(new ListTransferHandler(dropZone));
dropZone.setDragEnabled(true);
dropZone.setDropMode(javax.swing.DropMode.INSERT);
dropZone.setBorder(new TitledBorder("Selected files/folders"));
leftLowerPanel.setViewportView(new JScrollPane(dropZone));
childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
leftUpperPanel, leftLowerPanel);
childSplitPane.setDividerLocation(400);
childSplitPane.setPreferredSize(new Dimension(480, 650));
console = new JTextArea();
console.setColumns(40);
console.setLineWrap(true);
console.setBorder(new TitledBorder("Console"));
parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
childSplitPane, console);
parentSplitPane.setDividerLocation(480);
parentSplitPane.setPreferredSize(new Dimension(800, 650));
pane.add(parentSplitPane);
}
public static void initUI() {
JFrame frame = new JFrame("GridBagLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestGridBagLayout testMultiplePanels = new TestGridBagLayout();
testMultiplePanels.initUI();
}
});
}
}
You could start by using a GridLayout setup to display two columns and one row. This would start out as the primary display/container/panel for the vertical split. You would then need another JPanel, possibly with a GridLayout setup to display one column and two rows, this would display the file chooser and drop zone.
You would then add this panel and the text area to the primary panel.
You could also do this using a single GridBagLaout, but you might find using compound GridLayouts easier.
See How to Use GridLayout and How to Use GridBagLayout for more details
I would probably create a panel with BoxLayout with a y-axis orientation, and put my 'two halves' in that, and put it on the west end of the JFrame's default BoxLayout. Then I'd put the other panel in the center, assuming you want it to stretch and shrink in both directions as the user changes the window size.
For flexibility, you could use a JSplitPane having HORIZONTAL_SPLIT; put the console on the right and a nested JSplitPane having VERTICAL_SPLIT on the left to hold the fcPanel and dropZone.
I'm having some trouble trying to resize the components in my GUI when I resize the GUI. Right now, when I resize the GUI, the size of the components don't change, they keep to the static size I set them to. When I resize the GUI passed the minimum size needed to display them, they are no longer displayed. I want them to resize and maintain an aspect ratio when the GUI is resized.
Here's the code I have for the GUI:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.*;
import java.net.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.text.*;
import javax.swing.text.html.*;
public class DraftGUI implements MouseListener {
private JPanel jpPack;
private JPanel jpCards;
private JPanel jpInfo;
private JPanel jpChat;
private TextField tf;
private StyledDocument doc;
private JTextPane tp;
private JScrollPane sp;
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
e.getComponent().setVisible(false);
}
private Client client;
public GUI(Client client) throws IOException {
JFrame frame = new JFrame("Draft");
//set the size to fullscreen to start
frame.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
//set the content pane, we'll add everything to it and then add it to the frame
JPanel contentPane = new JPanel();
contentPane.setSize(Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
contentPane.setLayout(new GridBagLayout());
//creates some panels with some default values for now
JPanel jpCards = new JPanel(new BorderLayout());
jpCards.setOpaque(true); //ensures it paints every pixel
jpCards.setBackground(Color.BLUE);
JPanel jpInfo = new JPanel();
jpInfo.setOpaque(true);
jpInfo.setBackground(Color.GREEN);
JPanel jpPack = new JPanel(new GridBagLayout());
jpPack.setOpaque(true);
jpPack.setBackground(Color.RED);
//grab some info to make the JTextPane and make it scroll
this.client = client;
tf = new TextField();
doc = new DefaultStyledDocument();
tp = new JTextPane(doc);
tp.setEditable(false);
tf.addActionListener(this.client);
sp = new JScrollPane(tp);
//adding the quantities to the chat panel
JPanel jpChat = new JPanel();
jpChat.setLayout(new BorderLayout());
jpChat.add("North", tf);
jpChat.add("Center", sp);
//a new GridBagConstraints used to set the properties/location of the panels
GridBagConstraints c = new GridBagConstraints();
//adding some panels to the content pane
//set it to start from the top left of the quadrant if it's too small
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH; //set it to fill both vertically and horizontally
c.gridx = 0; //set it to quadrant x=0 and
c.gridy = 0; //set it to quadrant y=0
c.weightx = 0.7;
c.weighty = 0.3;
contentPane.add(jpCards, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 0.3;
c.weighty = 0.3;
contentPane.add(jpInfo, c);
c.gridx = 0;
c.gridy = 1;
c.weightx = 0.7;
c.weighty = 0.7;
contentPane.add(jpPack, c);
c.gridx = 1;
c.gridy = 1;
c.weightx = 0.3;
c.weighty = 0.7;
contentPane.add(jpChat, c);
//set some necessary values
frame.setContentPane(contentPane);
frame.setLocationByPlatform(true);
frame.setVisible(true);
//This code works for adding an Image
//need to learn how to specify a path not dependent on the specific users's machine
//this is not a high priority for now though
GridBagConstraints d = new GridBagConstraints();
d.gridx = 0;
d.gridy = 0;
ImageLabel imageLabel1 = new ImageLabel("path-to-file");
imageLabel1.setPreferredSize(new Dimension(223, 310));
jpPack.add(imageLabel1, d);
ImageLabel imageLabel2 = new ImageLabel("path-to-file");
imageLabel2.setPreferredSize(new Dimension(223, 310));
ImageLabel imageLabel3 = new ImageLabel("path-to-file");
imageLabel3.setPreferredSize(new Dimension(223, 310));
d.gridx = 1;
jpPack.add(imageLabel2, d);
d.gridy = 1;
jpPack.add(imageLabel3, d);
imageLabel1.addMouseListener(this);
imageLabel2.addMouseListener(this);
imageLabel3.addMouseListener(this);
//223, 310 are the aspect values for a card image, width, height
//these need to be maintained as the GUI size changes
}
}
class ImageLabel extends JLabel {
Image image;
ImageObserver imageObserver;
// constructor with filename
ImageLabel(String filename) {
ImageIcon icon = new ImageIcon(filename);
image = icon.getImage();
imageObserver = icon.getImageObserver();
}
// constructor with icon
ImageLabel(ImageIcon icon) {
image = icon.getImage();
imageObserver = icon.getImageObserver();
}
// overload setIcon method
void setIcon(ImageIcon icon) {
image = icon.getImage();
imageObserver = icon.getImageObserver();
}
// overload paint()
public void paint( Graphics g ) {
super.paint( g );
g.drawImage(image, 0 , 0 , getWidth() , getHeight() , imageObserver);
}
}
For some reason, there's no default resizing property for the frame's components, so when the frame resizes, the components don't do anything. I'm not sure what I'm doing wrong or missed, but clearly I left something out.
Also, if anyone knows, the ImageLabels are taking up extra space around them. The padding is set to 0 by default, so I'm not sure why it's creating like a border around them.
Thanks.
EDIT for Guillaume:
I know a main is necessary if I want to run it as a standalone, it's currently part of another application and gets called separately from within it. It was probably not the best decision to post it without a main for completeness, but whatever, it can't be that big of a problem.
Your code took out the portion where the picture was actually displayed. "path-to-file" was supposed to be replaced by an actual image file path, so you would display the image. It's hard to actually see the issue at hand when it's simply text in there.
When you have the image displayed correctly, and you try to resize the entire GUI, you will notice that the image doesn't shrink. It keeps to its preferred size and has issues when it becomes smaller than it. In my code, it stops displaying the picture completely when it can't display at least the preferred size. In your code, it cuts off part of the picture when it shrinks.
What I want is for it to actually resize the JLabel containing the picture, so that as the GUI resizes, so will the image. It's necessary that the image shrinks accordingly for my program. The user will eventually have functionality based on clicking the images, so displaying only some images or portions of them simply won't do.
Please try your code/my code again and reproduce the issue I'm having, testing with pictures, so that we can find a correct solution. Thanks.
JFrame.setVisible(true) should be the last line you call.
GridBagLayout can adapt the size of your components according to the frame size, as long as you use weightx/weighty and fill
UPDATE:
Forget about setting preferred size, this is just going down the path to GUI-problems
If you use LayoutManager's (and it is a very good idea), forget about calling setSize()/setBounds()/setLocation(), the LayoutManager's will override them anyway
You need to take care of the resizing of the image in order to maintain the original image ratio
If you use weightx/weighty, you should also use anchor and/or fill
Use frame.pack() to size properly your frame
Use setExtendedState() to maximize a frame
Btw, an SSCCE means that you make a runnable example for others, this includes changing local path to images to online URL's (see the example below).
With the following snippet, everything seems to work ok:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.TextField;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.StyledDocument;
public class DraftGUI implements MouseListener {
private static final String IMAGE_URL = "http://images.paramountbusinessjets.com/space/spaceshuttle.jpg";
private JPanel jpPack;
private JPanel jpCards;
private JPanel jpInfo;
private JPanel jpChat;
private TextField tf;
private StyledDocument doc;
private JTextPane tp;
private JScrollPane sp;
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
public DraftGUI() throws MalformedURLException {
final JFrame frame = new JFrame("Draft");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set the content pane, we'll add everything to it and then add it to the frame
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
// creates some panels with some default values for now
JPanel jpCards = new JPanel(new BorderLayout());
jpCards.setBackground(Color.BLUE);
JPanel jpInfo = new JPanel();
jpInfo.setBackground(Color.GREEN);
JPanel jpPack = new JPanel(new GridBagLayout());
jpPack.setBackground(Color.RED);
// grab some info to make the JTextPane and make it scroll
tf = new TextField();
doc = new DefaultStyledDocument();
tp = new JTextPane(doc);
tp.setEditable(false);
sp = new JScrollPane(tp);
// adding the quantities to the chat panel
JPanel jpChat = new JPanel();
jpChat.setLayout(new BorderLayout());
jpChat.add("North", tf);
jpChat.add("Center", sp);
// a new GridBagConstraints used to set the properties/location of the panels
GridBagConstraints c = new GridBagConstraints();
// adding some panels to the content pane
// set it to start from the top left of the quadrant if it's too small
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.BOTH; // set it to fill both vertically and horizontally
c.gridx = 0; // set it to quadrant x=0 and
c.gridy = 0; // set it to quadrant y=0
c.weightx = 0.7;
c.weighty = 0.3;
contentPane.add(jpCards, c);
c.gridx = 1;
c.gridy = 0;
c.weightx = 0.3;
c.weighty = 0.3;
contentPane.add(jpInfo, c);
c.gridx = 0;
c.gridy = 1;
c.weightx = 0.7;
c.weighty = 0.7;
contentPane.add(jpPack, c);
c.gridx = 1;
c.gridy = 1;
c.weightx = 0.3;
c.weighty = 0.7;
contentPane.add(jpChat, c);
// set some necessary values
frame.setContentPane(contentPane);
frame.setLocationByPlatform(true);
// This code works for adding an Image
// need to learn how to specify a path not dependent on the specific users's machine
// this is not a high priority for now though
GridBagConstraints d = new GridBagConstraints();
d.weightx = 1.0;
d.weighty = 1.0;
d.fill = GridBagConstraints.BOTH;
d.gridx = 0;
d.gridy = 0;
ImageLabel imageLabel1 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
jpPack.add(imageLabel1, d);
ImageLabel imageLabel2 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
d.gridx++;
jpPack.add(imageLabel2, d);
ImageLabel imageLabel3 = new ImageLabel(new ImageIcon(new URL(IMAGE_URL)));
d.gridy++;
jpPack.add(imageLabel3, d);
imageLabel1.addMouseListener(this);
imageLabel2.addMouseListener(this);
imageLabel3.addMouseListener(this);
frame.pack();
// 223, 310 are the aspect values for a card image, width, height
// these need to be maintained as the GUI size changes
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new DraftGUI();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
public static class ImageLabel extends JPanel {
private static int counter = 1;
private ImageIcon icon;
private int id = counter++;
public ImageLabel(ImageIcon icon) {
super();
setOpaque(false);
this.icon = icon;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(icon.getIconWidth(), icon.getIconHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
double zoom = Math.min((double) getWidth() / icon.getIconWidth(), (double) getHeight() / icon.getIconHeight());
int width = (int) (zoom * icon.getIconWidth());
int height = (int) (zoom * icon.getIconHeight());
g.drawImage(icon.getImage(), (getWidth() - width) / 2, (getHeight() - height) / 2, width, height, this);
g.setFont(g.getFont().deriveFont(36.0f));
g.drawString(String.valueOf(id), getWidth() / 2, getHeight() / 2);
}
}
}
I suggest this way to resize the contents of a window
JPanel jPanel = new JPanel(new BorderLayout()); // Create a panel that contains the elements you want to resize, in this example I use BorderLayout as the layout manager
jPanel.add(somePanel, BorderLayout.NORTH);
// this will resize the con
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
somePanel.setSize(e.getComponent().getSize());
jPanel.paintComponents(getGraphics());
}
});
I have a form with lots of text fields and some of those text fields may contain very long strings. To make it work I made those text fields scrollable using this code:
JScrollPane scroll = new JScrollPane(textField);
scroll.setPreferredSize(new Dimension((int)textField.getPreferredSize().getWidth(), (int)textField.getPreferredSize().getHeight() * 2));
Then I put scroll into my form using GridBagLayout.
Second line in my example is required for scroller to show up. But it has downside. When I resize window to fit whole text in text field, then scroll disapears leaving me with just two times higher then others text field, which looks ridiculous.
How can I make this all work and show me normal size of text field after scroller is hidden?
EDIT:
You may use following as a demo code to reproduce the issue:
import javax.swing.*;
import java.awt.*;
public class ScrollTextDemo extends JFrame{
public ScrollTextDemo(){
super();
this.setPreferredSize(new Dimension(500, 300));
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
textField.setCursor(new Cursor(0));
textField.setEditable(false);
JScrollPane scroll = new JScrollPane(textField);
scroll.setPreferredSize(new Dimension(70, 40) );
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(scroll,gbc);
//let's add one more text field without scroll bar to compare
JTextField textField2 = new JTextField("abc");
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(textField2,gbc);
this.add(panel);
}
public static void main(String args[]){
ScrollTextDemo demo = new ScrollTextDemo();
demo.pack();
demo.setVisible(true);
}
}
For this , in the absence of a good SSCCE, I think you hadn't provided any constraint that goes for fill, which is used for
Used when the component's display area is larger than the component's requested size to determine whether and how to resize the component. Valid values (defined as GridBagConstraints constants) include NONE (the default), HORIZONTAL (make the component wide enough to fill its display area horizontally, but do not change its height), VERTICAL (make the component tall enough to fill its display area vertically, but do not change its width), and BOTH (make the component fill its display area entirely).
So you must add something like this to your GridBagConstraints
constraintsGridBag.fill = GridBagConstraints.HORIZONTAL;
This will only allow it to expand HORIZONTALLY not both ways.
** EDIT : As for the added code **
Never specify setPreferredSize(...) for any component in Swing. Let the Layout Manager you are using, take care for that. Remove all setPreferredSize(...) thingies, will let it remain in normal size upon resizing.
*EDIT 2 : *
Code to tell you what I am saying :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class GridBagTest extends JFrame
{
private JPanel topPanel;
private JPanel bottomPanel;
public GridBagTest()
{
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
//gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 0.8;
// Setting TOP PANEL.
topPanel = new JPanel();
topPanel.setLayout(new GridBagLayout());
GridBagConstraints constraintsTopPanel = new GridBagConstraints();
constraintsTopPanel.gridwidth = 2; // Specifies that this component will take two columns.
constraintsTopPanel.gridheight = 1; // specifies that the component will take one row.
/*
* fill with HORIZONTAL, means the component upon resize, will
* only expand along the X-Axis.
*/
constraintsTopPanel.fill = GridBagConstraints.NONE;
constraintsTopPanel.insets = new Insets(5, 5, 5, 5);
constraintsTopPanel.ipadx = 2;
constraintsTopPanel.ipady = 2;
constraintsTopPanel.weightx = 0.3;
constraintsTopPanel.weighty = 0.2;
constraintsTopPanel.gridx = 0;
constraintsTopPanel.gridy = 0;
JTextField tfield1 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield1, constraintsTopPanel);
constraintsTopPanel.gridx = 2;
constraintsTopPanel.gridy = 0;
final JTextField tfield2 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield2, constraintsTopPanel);
constraintsTopPanel.gridx = 4;
constraintsTopPanel.gridy = 0;
JTextField tfield3 = new JTextField("kajslkajfkl dsjlafj lksdj akljsd lfkajflkdj lkaj flkdjalk jflkaj lkfdsj salkj flkaj flkja dslkfjal ksjdflka jlfjd aflsdj", 10);
topPanel.add(tfield3, constraintsTopPanel);
topPanel.setBackground(Color.WHITE);
add(topPanel, gbc);
constraintsTopPanel.gridx = 0;
constraintsTopPanel.gridy = 2;
constraintsTopPanel.gridwidth = 6; // Specifies that this component will take two columns.
constraintsTopPanel.gridheight = 1; // specifies that the component will take one row.
JButton button = new JButton("REMOVE");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
topPanel.remove(tfield2);
topPanel.revalidate();
topPanel.repaint();
}
});
topPanel.add(button, constraintsTopPanel);
//Setting BOTTOM PANEL.
bottomPanel = new JPanel();
bottomPanel.setLayout(new BorderLayout());
bottomPanel.setBackground(Color.DARK_GRAY);
JLabel label3 = new JLabel("I am a new JLABEL for the bottom JPanel", JLabel.CENTER);
label3.setForeground(Color.WHITE);
bottomPanel.add(label3, BorderLayout.CENTER);
gbc.weighty = 0.2;
add(bottomPanel, gbc);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
setVisible(true);
}
public static void main(String... args)
{
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridBagTest();
}
});
}
}
Well the best I've got is looking ugly in code, but does exactly what I need to the textField. Below is changed sample code from initial question. I'd be thankfull for any ideas how to make it better:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
public class ScrollTextDemo extends JFrame{
public ScrollTextDemo(){
super();
this.setPreferredSize(new Dimension(500, 300));
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
textField.setCursor(new Cursor(0));
textField.setEditable(false);
JScrollPane scroll = new JScrollPane(textField, JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
//gbc.ipady = 20;//gives some room for scroll to appear and don't hide text area under the scroll.
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(scroll,gbc);
//let's add one more text field without scroll bar to compare
JTextField textField2 = new JTextField("bbbbbbbb");
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 2;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 0.5;
gbc.insets = new Insets(5, 5, 0, 5);
panel.add(textField2,gbc);
scroll.addComponentListener( new ScrollTextComponentListener(scroll, textField2));
this.add(panel);
}
public static void main(String args[]){
ScrollTextDemo demo = new ScrollTextDemo();
demo.pack();
demo.setVisible(true);
}
}
class ScrollTextComponentListener implements ComponentListener {
private boolean scrollVisible;
private JScrollPane scroll;
private JComponent compareComponent;
public ScrollTextComponentListener(JScrollPane scroll, JComponent compareComponent) {
this.scroll = scroll;
this.compareComponent = compareComponent;
}
private boolean isScrollVisible() {
return scroll.getHorizontalScrollBar().getModel().getExtent() != scroll.getHorizontalScrollBar().getModel().getMaximum();
}
private void setScrollSize(){
boolean scrollVisible = isScrollVisible();
if (scrollVisible){
scroll.setPreferredSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
//also had to set both min and max sizes, because only preffered size didn't always work
scroll.setMinimumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
scroll.setMaximumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()*2));
}
else {
scroll.setPreferredSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
scroll.setMinimumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
scroll.setMaximumSize(new Dimension(compareComponent.getWidth(),compareComponent.getHeight()));
}
this.scrollVisible = scrollVisible;
}
#Override
public void componentResized(ComponentEvent e) {
if (isScrollVisible() != scrollVisible) setScrollSize();
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentShown(ComponentEvent e) {
setScrollSize();
}
#Override
public void componentHidden(ComponentEvent e) {
}
}