I'm writing a GUI in Swing where I want to do a file chooser that is in the main window, looking something like the image below:
while there seem to be quite a few tutorials on how to write a popup file chooser, i don't see much information on how this type of chooser might be accomplished in swing.
also sorry if this has been asked before, i did a good bit of searching around and wan't able to find anything else..
PanelBrowser, shown below, is a basic prototype that functions similarly to the Mac OS X Finder column view illustrated in your question.
Update: Added horizontal scrolling and more file information.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileSystemView;
/**
* #see http://stackoverflow.com/a/15104660/230513
*/
public class PanelBrowser extends Box {
private static final Dimension SIZE = new Dimension(200, 300);
private List<FilePanel> list = new ArrayList<FilePanel>();
public PanelBrowser(File root) {
super(BoxLayout.LINE_AXIS);
setBackground(Color.red);
FilePanel panel = new FilePanel(this, root);
list.add(panel);
this.add(panel);
}
private void update(FilePanel fp, File file) {
int index = list.indexOf(fp);
int i = list.size() - 1;
while (i > index) {
list.remove(i);
this.remove(i);
i--;
}
final FilePanel panel = new FilePanel(this, file);
list.add(panel);
this.add(panel);
revalidate();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
scrollRectToVisible(panel.getBounds());
}
});
}
private static class FilePanel extends Box {
private static FileSystemView fsv = FileSystemView.getFileSystemView();
private static DateFormat df = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.DEFAULT);
private PanelBrowser parent;
private JList list;
public FilePanel(PanelBrowser parent, File file) {
super(BoxLayout.PAGE_AXIS);
this.parent = parent;
DefaultListModel model = new DefaultListModel();
if (file.isFile()) {
JLabel name = new JLabel(file.getName());
name.setIcon(fsv.getSystemIcon(file));
this.add(name);
Date d = new Date(file.lastModified());
JLabel mod = new JLabel("Date: " + df.format(d));
this.add(mod);
final String v = String.valueOf(file.length());
JLabel length = new JLabel("Size: " + v);
this.add(length);
}
if (file.isDirectory()) {
for (File f : file.listFiles()) {
model.addElement(f);
}
list = new JList(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new FileRenderer());
list.addListSelectionListener(new SelectionHandler());
this.add(new JScrollPane(list) {
#Override
public int getVerticalScrollBarPolicy() {
return JScrollPane.VERTICAL_SCROLLBAR_ALWAYS;
}
});
}
}
private static class FileRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
File f = (File) value;
setText(f.getName());
setIcon(fsv.getSystemIcon(f));
return label;
}
}
private class SelectionHandler implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
File f = (File) list.getSelectedValue();
parent.update(FilePanel.this, f);
}
}
}
#Override
public Dimension getMinimumSize() {
return new Dimension(SIZE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SIZE);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(SIZE.width, Short.MAX_VALUE);
}
}
private static void display() {
String path = System.getProperty("user.dir");
PanelBrowser browser = new PanelBrowser(new File(path));
JFrame f = new JFrame(path);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(browser) {
#Override
public int getVerticalScrollBarPolicy() {
return JScrollPane.VERTICAL_SCROLLBAR_NEVER;
}
});
f.pack();
f.setSize(4 * SIZE.width, SIZE.height);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}
JFileChooser actually extends JComponent, so you can use like any other component. Here is an example with two in-pane file choosers:
public class TestInPaneChoosers {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
buildFrame();
}
});
}
private static void buildFrame() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
f.add(new JFileChooser());
f.add(new JFileChooser());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Related
I have a code in which I must drag two images from my desktop and drop it on a frame in two draggable buttons. The buttons have already been made on the frame. But while dragging the images, they can only be dragged to one button. The images don't get dragged to the other one. I have made a DragListener class where the dragging methods prevail and the main class DragInitialListener where I have passed objects of class DragButton so that two draggable buttons are created. I have tried everything I could think of, made two DragListener classes, passed the methods differently but the image could only be dragged in one button. I want both the buttons to be able to hold images. Please help me with it. Here's the code that I have made so far:
//This is the main class
public class DragInitialListener extends javax.swing.JFrame {
private volatile int draggedAtX, draggedAtY;
public DragInitialListener() {
initComponents();
Droptargets();
Droptarget();
}
public void Droptarget()
{
DragListener d;
DragButton db = new DragButton();
db.setSize(170,140);
d= new DragListener(db);
DropTarget drop = new DropTarget(this,d);
this.getContentPane().add(db);
}
public void Droptargets()
{
DragListener dd;
DragButton db1 = new DragButton();
db1.setSize(170,140);
dd= new DragListener(db1);
DropTarget drop1 = new DropTarget(this,dd);
this.getContentPane().add(db1);
}
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DragInitialListener().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
//This is the DragListener class
public class DragListener extends JButton implements DropTargetListener
{
JButton imagebutton = new JButton();
// JButton imagebutton1 = new JButton();
private volatile int draggedAtX, draggedAtY;
DragListener(JButton image) {
imagebutton=image;
}
#Override
public void dragEnter(DropTargetDragEvent dtde) {
}
#Override
public void dragOver(DropTargetDragEvent dtde) {
}
#Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
#Override
public void dragExit(DropTargetEvent dte) {
}
#Override
public void drop(DropTargetDropEvent ev) {
ev.acceptDrop(DnDConstants.ACTION_COPY);
Transferable t = ev.getTransferable();
//DropTarget test = (DropTarget) ev.getSource();
DataFlavor[] df= t.getTransferDataFlavors();
for(DataFlavor f:df)
{
try
{
if(f.isFlavorJavaFileListType())
{
List<File> files =(List<File>) t.getTransferData(f);
for(File file : files)
{
displayImage(file.getPath());
}
}
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, ex);
}
}
}
private void displayImage(String path)
{
BufferedImage img = null;
try
{
img =ImageIO.read(new File(path));
}
catch(Exception e)
{
}
ImageIcon icon = new ImageIcon(img);
imagebutton.setIcon(icon);
}
}
Start simple, get one button to work, if you can get one to work, you can get 100 to work
This is a very simple example, which makes use of the transfer API, because you really only care about dropping and not dragging
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
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);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Drop here");
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
btn.setTransferHandler(new ImageTransferHandler());
add(btn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static class ImageTransferHandler extends TransferHandler {
public static final DataFlavor[] SUPPORTED_DATA_FLAVORS = new DataFlavor[]{
DataFlavor.javaFileListFlavor,
DataFlavor.imageFlavor
};
#Override
public boolean canImport(TransferHandler.TransferSupport support) {
boolean canImport = false;
for (DataFlavor flavor : SUPPORTED_DATA_FLAVORS) {
if (support.isDataFlavorSupported(flavor)) {
canImport = true;
break;
}
}
return canImport;
}
#Override
public boolean importData(TransferHandler.TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Component component = support.getComponent();
if (component instanceof JButton) {
Image image = null;
if (support.isDataFlavorSupported(DataFlavor.imageFlavor)) {
image = (Image) t.getTransferData(DataFlavor.imageFlavor);
} else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
if (files.size() > 0) {
image = ImageIO.read((File) files.get(0));
}
}
ImageIcon icon = null;
if (image != null) {
icon = new ImageIcon(image);
}
((JButton) component).setIcon(icon);
accept = true;
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
return accept;
}
}
}
So, by doing nothing more then changing the layout and replicating the button using
public TestPane() {
setLayout(new GridLayout(5, 5));
for (int index = 0; index < 5 * 5; index++) {
JButton btn = new JButton("Drop here");
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
btn.setTransferHandler(new ImageTransferHandler());
add(btn);
}
}
I was able to achieve...
Updated...
So apparently I might have misunderstood the question, not the first time. From what's been explained to me, you might want to drag multiple images and have them applied to the buttons. Surprising, the process doesn't change that much.
In this example, I've applied the TransferHandler to the JPanel instead of the button and supplied it the buttons I want updated. You could easily update this to have a variable number of buttons, but I've started with two.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
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);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton left = makeButton("Left");
JButton right = makeButton("Right");
add(left);
add(right);
setTransferHandler(new ImageTransferHandler(left, right));
}
protected JButton makeButton(String text) {
JButton btn = new JButton(text);
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
return btn;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static class ImageTransferHandler extends TransferHandler {
public static final DataFlavor[] SUPPORTED_DATA_FLAVORS = new DataFlavor[]{
DataFlavor.javaFileListFlavor,};
private JButton left, right;
public ImageTransferHandler(JButton left, JButton right) {
this.left = left;
this.right = right;
}
#Override
public boolean canImport(TransferHandler.TransferSupport support) {
boolean canImport = false;
for (DataFlavor flavor : SUPPORTED_DATA_FLAVORS) {
if (support.isDataFlavorSupported(flavor)) {
canImport = true;
break;
}
}
return canImport;
}
#Override
public boolean importData(TransferHandler.TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Image image = null;
if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
JButton buttons[] = new JButton[]{left, right};
for (int index = 0; index < Math.min(files.size(), 2); index++) {
if (files.size() > 0) {
image = ImageIO.read((File) files.get(index));
ImageIcon icon = null;
if (image != null) {
icon = new ImageIcon(image);
}
buttons[index].setIcon(icon);
}
}
accept = true;
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
return accept;
}
}
}
Now, there are rules you will need to define yourself, for example, what happens when the user only drags a single image? Do you apply it to the first button (as I have) every time, or do you try and find the button without an image and update it? What happens if all the buttons have images? Where does it go then?
Do you reject drags with more than 2 images?
A Stepped ComboBox is very useful to make the drop-down pop-up wider than the text field. However when new content is added to the list, the pop-up gets its initial width back.
By default
After refresh (new element)
SSCCE
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
public class SteppedComboBoxRefresh extends JFrame {
private List<String> list;
private final SteppedComboBox combo;
public SteppedComboBoxRefresh() {
super("SteppedComboBox Refresh");
this.list = new ArrayList<String>(Arrays.asList(new String[]{
"AAA", "AAAAAA"
}));
this.combo = new SteppedComboBox(this.list.toArray());
this.combo.setDimensions(50);
JButton addButton = new JButton("Add longer string");
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
list.add(list.get(list.size()-1) + "AAA");
combo.setModel(new DefaultComboBoxModel(list.toArray()));
combo.setDimensions(50);
}
});
getContentPane().setLayout(new FlowLayout());
getContentPane().add(this.combo);
getContentPane().add(addButton);
}
public static void main (String args[]) {
SteppedComboBoxRefresh f = new SteppedComboBoxRefresh();
f.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize (300, 100);
f.setVisible(true);
}
}
class SteppedComboBoxUI extends MetalComboBoxUI {
#Override
protected ComboPopup createPopup() {
BasicComboPopup popup = new BasicComboPopup( this.comboBox ) {
#Override
public void show() {
Dimension popupSize = ((SteppedComboBox)this.comboBox).getPopupSize();
popupSize.setSize( popupSize.width,
getPopupHeightForRowCount( this.comboBox.getMaximumRowCount() ) );
Rectangle popupBounds = computePopupBounds( 0,
this.comboBox.getBounds().height, popupSize.width, popupSize.height);
this.scroller.setMaximumSize( popupBounds.getSize() );
this.scroller.setPreferredSize( popupBounds.getSize() );
this.scroller.setMinimumSize( popupBounds.getSize() );
this.list.invalidate();
int selectedIndex = this.comboBox.getSelectedIndex();
if ( selectedIndex == -1 ) {
this.list.clearSelection();
} else {
this.list.setSelectedIndex( selectedIndex );
}
this.list.ensureIndexIsVisible( this.list.getSelectedIndex() );
setLightWeightPopupEnabled( this.comboBox.isLightWeightPopupEnabled() );
show( this.comboBox, popupBounds.x, popupBounds.y );
}
};
popup.getAccessibleContext().setAccessibleParent(this.comboBox);
return popup;
}
}
class SteppedComboBox extends JComboBox {
protected int popupWidth;
public SteppedComboBox(ComboBoxModel aModel) {
super(aModel);
setUI(new SteppedComboBoxUI());
this.popupWidth = 0;
}
public SteppedComboBox(final Object[] items) {
super(items);
setUI(new SteppedComboBoxUI());
this.popupWidth = 0;
}
public SteppedComboBox(Vector items) {
super(items);
setUI(new SteppedComboBoxUI());
this.popupWidth = 0;
}
public void setPopupWidth(int width) {
this.popupWidth = width;
}
public Dimension getPopupSize() {
Dimension size = getSize();
if (this.popupWidth < 1) {
this.popupWidth = size.width;
}
return new Dimension(this.popupWidth, size.height);
}
public void setDimensions(int width) {
Dimension d = getPreferredSize();
setPreferredSize(new Dimension(width, d.height));
setPopupWidth(d.width);
}
}
The ComboBox still uses its previous PreferredSize. It's needed to set the preferred size back to null, so that we get the size which is preferred by the new content in the list.
void javax.swing.JComponent.setPreferredSize(Dimension preferredSize)
Sets the preferred size of this component. If preferredSize is null, the UI will be asked for the preferred size.
public void setDimensions(int width) {
setPreferredSize(null);
Dimension d = getPreferredSize();
setPreferredSize(new Dimension(width, d.height));
setPopupWidth(d.width);
}
Result
You could use the Combo Box Popup.
It is a more flexible version of the Stepped Combo Box. Best of all it can be used on any combo box since the logic is implemented in a `PopupMenuListener'.
You can control the maximum width of the popup. You can even have the popup display above the combo box instead of below.
Okay so I am working on a file management GUI and want all the listed files in directory X to be listed in a JTable cell. I have this part working. The JTable is nested in a JTabbedPane which is nested in the main JPane. My question is how can I add an ActionListener so that when I click on the file name in the JTable cell it will open a new tab. I will then display the text in the new tab.
public class FileManager extends JFrame implements Runnable
{
JPanel mainPanel;
JTabbedPane viewerPane;
DefaultTableModel model;
JTable table;
String col[] = {"File Name", "Date Added"};
ArrayList<String> uploadedFiles = new ArrayList<>();
File currentFile;
File savedFile;
public FileManager()
{
super("File Managment System");
currentFile = null;
savedFile = null;
mainPanel = new JPanel();
viewerPane = new JTabbedPane();
}
public void run()
{
setSize(1200,700);
getContentPane().add(mainPanel);
model = new DefaultTableModel(col,uploadedFiles.size())
{
#Override
public boolean isCellEditable(int arg0, int arg1)
{
return false;
}
};
table = new JTable(model);
table.getTableHeader().setReorderingAllowed(false);
mainPanel.setLayout(new GridLayout(1,2));
mainPanel.add(contentPanel);
mainPanel.add(viewerPane);
viewerPane.add(table);
makeTable();
setVisible(true);
}
public void makeTable()
{
int k = 0;
for(String s:uploadedFiles)
{
table.setValueAt(s,k,0);
table.setValueAt(LocalDate.now(),k,1);
k++;
}
}
public static void main(String[] args)
{
FileManager fm = new FileManager();
javax.swing.SwingUtilities.invokeLater(dcms);
}
}
Try this:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
public class FileManager extends JFrame implements Runnable {
JPanel mainPanel;
JTabbedPane viewerPane;
DefaultTableModel model;
JTable table;
String col[] = {"File Name", "Date Added"};
ArrayList<String> uploadedFiles = new ArrayList<>();
File currentFile;
File savedFile;
public FileManager() {
super("File Managment System");
currentFile = null;
savedFile = null;
mainPanel = new JPanel();
viewerPane = new JTabbedPane();
}
#Override
public void run() {
uploadedFiles.add("C:\\");
model = new DefaultTableModel(col, uploadedFiles.size()) {
#Override
public boolean isCellEditable(int arg0, int arg1) {
return false;
}
};
table = new JTable(model);
table.getTableHeader().setReorderingAllowed(false);
makeTable();
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
int row = table.getSelectedRow();
viewerPane.add((String) table.getValueAt(row, 0), new JPanel());
viewerPane.setSelectedIndex(viewerPane.getComponentCount()-1);
}
}
});
mainPanel.setLayout(new GridLayout(1, 2));
viewerPane.add("Files", table);
mainPanel.add(viewerPane);
getContentPane().add(mainPanel);
setSize(1200, 700);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void makeTable() {
int k = 0;
for (String s : uploadedFiles) {
table.setValueAt(s, k, 0);
table.setValueAt(LocalDate.now(), k, 1);
k++;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new FileManager());
}
}
Probably a noob question, but im new to java. I have a need for a checkbox list which I found is not supported in swing, but I found this custom control here
http://www.devx.com/tips/Tip/5342
So I created a class file named CheckBoxList, and copied the code from the link into it:
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class CheckBoxList extends JList
{
protected static Border noFocusBorder =
new EmptyBorder(1, 1, 1, 1);
public CheckBoxList()
{
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(
!checkbox.isSelected());
repaint();
}
}
}
);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ?
getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ?
getSelectionForeground() : getForeground());
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ?
UIManager.getBorder(
"List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}
The problem is I don't know how to implement it in my GUI file. I tried a lot of code, but they never showed an example. Just
To use the class, simply instantiate it, then pass it an array of
JCheckBox objects (or subclasses of JCheckBox objects) by calling
setListData
So does that mean that I will not see the control in the Graphical Design view? My client wants to be able to edit it himself and add stuff so I want it to be easy and graphical if possible. If someone could show an example of instantiating it or give a good hint I would appreciate it. Thanks!
Can you just tell me how?
Use a one column JTable and an appropriate renderer and editor. Based on this example, the code below relies on the default renderer for a data value of type Boolean.Class. A more general example is cited here.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
/** #see https://stackoverflow.com/a/13919878/230513 */
public class CheckTable {
private static final CheckModel model = new CheckModel(5000);
private static final JTable table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(150, 300);
}
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
JCheckBox jcb = (JCheckBox) super.prepareRenderer(renderer, row, column);
jcb.setHorizontalTextPosition(JCheckBox.LEADING);
jcb.setText(String.valueOf(row));
return jcb;
}
};
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("CheckTable");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0));
f.add(new JScrollPane(table));
f.add(new DisplayPanel(model));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class DisplayPanel extends JPanel {
private DefaultListModel dlm = new DefaultListModel();
private JList list = new JList(dlm);
public DisplayPanel(final CheckModel model) {
super(new GridLayout());
this.setBorder(BorderFactory.createTitledBorder("Checked"));
this.add(new JScrollPane(list));
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
dlm.removeAllElements();
for (Integer integer : model.checked) {
dlm.addElement(integer);
}
}
});
}
}
private static class CheckModel extends AbstractTableModel {
private final int rows;
private List<Boolean> rowList;
private Set<Integer> checked = new TreeSet<Integer>();
public CheckModel(int rows) {
this.rows = rows;
rowList = new ArrayList<Boolean>(rows);
for (int i = 0; i < rows; i++) {
rowList.add(Boolean.FALSE);
}
}
#Override
public int getRowCount() {
return rows;
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public String getColumnName(int col) {
return "Column " + col;
}
#Override
public Object getValueAt(int row, int col) {
return rowList.get(row);
}
#Override
public void setValueAt(Object aValue, int row, int col) {
boolean b = (Boolean) aValue;
rowList.set(row, b);
if (b) {
checked.add(row);
} else {
checked.remove(row);
}
fireTableRowsUpdated(row, row);
}
#Override
public Class<?> getColumnClass(int col) {
return getValueAt(0, col).getClass();
}
#Override
public boolean isCellEditable(int row, int col) {
return true;
}
}
}
The code is expecting a list of JCheckBox objects - so this works
CheckBoxList cbList = new CheckBoxList(); // the class you have
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2}; list of checkbox object
cbList.setListData(myList); // set the list data for the object
Small Swing program using your class below
util;
import javax.swing.*;
public class HelloWorldSwing {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckBoxList cbList = new CheckBoxList();
JCheckBox check1 = new JCheckBox("One");
JCheckBox check2 = new JCheckBox("two");
JCheckBox[] myList = { check1, check2};
cbList.setListData(myList);
frame.getContentPane().add(cbList);
//Display the window.
frame.pack();
frame.setVisible(true);
}
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();
}
});
}
}
I've got an application that uses custom buttons all over the place for text and icons. Works great for windows and linux, but now OSX users are complaining. Text doesn't display on the mac, just '...'. The code seems simple enough, but I'm clueless when it comes to macs. How can I fix this?
Test case:
package example.swingx;
import example.utils.ResourceLoader;
import com.xduke.xlayouts.XTableLayout;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import java.awt.*;
import java.awt.event.ActionEvent;
public class SmallButton extends JButton {
private static ComponentUI ui = new SmallButtonUI();
public SmallButton() {
super();
/* final RepaintManager repaintManager = RepaintManager.currentManager(this);
repaintManager.setDoubleBufferingEnabled(false);
setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);*/
}
public SmallButton(AbstractAction action) {
super(action);
}
public SmallButton(String text) {
super(text);
}
public SmallButton(Icon icon) {
super(icon);
}
public void updateUI() {
setUI(ui);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel buttonPanel = new JPanel(new XTableLayout());
SmallButton firstSmallButton = new SmallButton("One");
SmallButton secondSmallButton = new SmallButton("Two");
SmallButton thirdSmallButton = new SmallButton();
ImageIcon cameraIcon = (ImageIcon) ResourceLoader.getIcon("camera");
SmallButton fourth = new SmallButton();
fourth.setAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
System.out.println("Fourth button pressed!");
}
});
fourth.setIcon(cameraIcon);
buttonPanel.add(firstSmallButton, "+");
buttonPanel.add(secondSmallButton, "+");
buttonPanel.add(thirdSmallButton, "+");
buttonPanel.add(fourth, "+");
final Container container = frame.getContentPane();
container.add(buttonPanel);
frame.pack();
frame.setVisible(true);
}
}
UI:
package example.swingx;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
public class SmallButtonUI extends BasicButtonUI {
private static final Color FOCUS_COLOR = new Color(0, 0, 0);
private static final Color BACKGROUND_COLOR = new Color(173, 193, 226);
private static final Color SELECT_COLOR = new Color(102, 132, 186);
private static final Color DISABLE_TEXT_COLOR = new Color(44, 44, 61);
private static final Insets DEFAULT_SMALLBUTTON_MARGIN = new Insets(2, 4, 2, 4);
private final static SmallButtonUI smallButtonUI = new SmallButtonUI();
public static ComponentUI createUI(JComponent component) {
return smallButtonUI;
}
protected Color getSelectColor() {
return SELECT_COLOR;
}
protected Color getDisabledTextColor() {
return DISABLE_TEXT_COLOR;
}
protected Color getFocusColor() {
return FOCUS_COLOR;
}
public void paint(Graphics g, JComponent c) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
protected void paintButtonPressed(Graphics graphics, AbstractButton button) {
if (button.isContentAreaFilled()) {
Dimension size = button.getSize();
graphics.setColor(getSelectColor());
graphics.fillRect(0, 0, size.width, size.height);
}
}
public Dimension getMinimumSize(JComponent component) {
final AbstractButton button = ((AbstractButton) component);
// Handle icon buttons:
Icon buttonIcon = button.getIcon();
if (buttonIcon != null) {
return new Dimension(
buttonIcon.getIconWidth(),
buttonIcon.getIconHeight()
);
}
// Handle text buttons:
final Font fontButton = button.getFont();
final FontMetrics fontMetrics = button.getFontMetrics(fontButton);
final String buttonText = button.getText();
if (buttonText != null) {
final int buttonTextWidth = fontMetrics.stringWidth(buttonText);
return new Dimension(buttonTextWidth + 15,
fontMetrics.getHeight() + 5);
}
return null;
}
protected void installDefaults(AbstractButton button) {
super.installDefaults(button);
button.setMargin(DEFAULT_SMALLBUTTON_MARGIN);
button.setBackground(getBackgroundColor());
}
private Color getBackgroundColor() {
return BACKGROUND_COLOR;
}
public Dimension getPreferredSize(JComponent component) {
return getMinimumSize(component);
}
public Dimension getMaximumSize(JComponent component) {
return super.getMinimumSize(component);
}
public SmallButtonUI() {
super();
}
}
EDIT: After debugging, it seems getMinimumSize() is the same on both platforms. Also, when I stop on anywhere Graphics is used, it seems that the mac has a transY value of 47, while linux has 0. This 47 seems to feed into the clipping regions as well. Where could that be getting set?\
Your calculation of preferred size is incorrect.
BasicButtonUI uses SwingUtilities.layoutCompoundLabel, examined here. In a label, the ellipsis is added if the string is too long, but a button is typically sized to fit its entire text.
Absent a better understanding of your context, I would use a sizeVariant, shown below. I've also shown a simple BasicButtonUI example using a smaller, derived Font. The UI menu can be used in conjunction with Quaqua for testing.
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicButtonUI;
/**
* #see https://stackoverflow.com/a/14599176/230513
* #see https://stackoverflow.com/a/11949899/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setBackground(new Color(0xfff0f0f0));
f.setLayout(new GridLayout(0, 1));
f.add(createToolBar(f));
f.add(variantPanel("mini"));
f.add(variantPanel("small"));
f.add(variantPanel("regular"));
f.add(variantPanel("large"));
JPanel customPanel = new JPanel();
customPanel.add(createCustom("One"));
customPanel.add(createCustom("Two"));
customPanel.add(createCustom("Three"));
f.add(customPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static JPanel variantPanel(String size) {
JPanel variantPanel = new JPanel();
variantPanel.add(createVariant("One", size));
variantPanel.add(createVariant("Two", size));
variantPanel.add(createVariant("Three", size));
return variantPanel;
}
private static JButton createVariant(String name, String size) {
JButton b = new JButton(name);
b.putClientProperty("JComponent.sizeVariant", size);
return b;
}
private static JButton createCustom(String name) {
JButton b = new JButton(name) {
#Override
public void updateUI() {
super.updateUI();
setUI(new CustomButtonUI());
}
};
return b;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
private static class CustomButtonUI extends BasicButtonUI {
private static final Color BACKGROUND_COLOR = new Color(173, 193, 226);
private static final Color SELECT_COLOR = new Color(102, 132, 186);
#Override
protected void paintText(Graphics g, AbstractButton b, Rectangle r, String t) {
super.paintText(g, b, r, t);
g.setColor(SELECT_COLOR);
g.drawRect(r.x, r.y, r.width, r.height);
}
#Override
protected void paintFocus(Graphics g, AbstractButton b,
Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
super.paintFocus(g, b, viewRect, textRect, iconRect);
g.setColor(Color.blue.darker());
g.drawRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
}
#Override
protected void paintButtonPressed(Graphics g, AbstractButton b) {
if (b.isContentAreaFilled()) {
g.setColor(SELECT_COLOR);
g.fillRect(0, 0, b.getWidth(), b.getHeight());
}
}
#Override
protected void installDefaults(AbstractButton b) {
super.installDefaults(b);
b.setFont(b.getFont().deriveFont(11f));
b.setBackground(BACKGROUND_COLOR);
}
public CustomButtonUI() {
super();
}
}
private static JToolBar createToolBar(final Component parent) {
final UIManager.LookAndFeelInfo[] available =
UIManager.getInstalledLookAndFeels();
List<String> names = new ArrayList<String>();
for (UIManager.LookAndFeelInfo info : available) {
names.add(info.getName());
}
final JComboBox combo = new JComboBox(names.toArray());
String current = UIManager.getLookAndFeel().getName();
combo.setSelectedItem(current);
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
int index = combo.getSelectedIndex();
try {
UIManager.setLookAndFeel(
available[index].getClassName());
SwingUtilities.updateComponentTreeUI(parent);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
});
JToolBar bar = new JToolBar("L&F");
bar.setLayout(new FlowLayout(FlowLayout.LEFT));
bar.add(combo);
return bar;
}
}