Preventing Menu from exceeding screen size [duplicate] - java

I would like to add a way to scroll through menu items in a JPopupMenu, much like scrolling through a list of items in a JComboBox.
Let's say I have 10 menu items. I would like to display only 5 menu items at a time, and I would use a vertical scroll button at the bottom or top of the JPopupMenu to show the menu items that are not listed and hide the ones that I just saw.
Is it possible? I am using JIDE Software's JideSplitButton, which displays a JPopupMenu when clicked. I am trying to keep the look and feel of the command bar on which I placed the JideSplitButton, so I don't want to replace it with a JComboBox unless I really have to.

Here is a version I created using a scrollbar. It is just a simple example, so adapt as you see fit:
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
public class JScrollPopupMenu extends JPopupMenu {
protected int maximumVisibleRows = 10;
public JScrollPopupMenu() {
this(null);
}
public JScrollPopupMenu(String label) {
super(label);
setLayout(new ScrollPopupMenuLayout());
super.add(getScrollBar());
addMouseWheelListener(new MouseWheelListener() {
#Override public void mouseWheelMoved(MouseWheelEvent event) {
JScrollBar scrollBar = getScrollBar();
int amount = (event.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
? event.getUnitsToScroll() * scrollBar.getUnitIncrement()
: (event.getWheelRotation() < 0 ? -1 : 1) * scrollBar.getBlockIncrement();
scrollBar.setValue(scrollBar.getValue() + amount);
event.consume();
}
});
}
private JScrollBar popupScrollBar;
protected JScrollBar getScrollBar() {
if(popupScrollBar == null) {
popupScrollBar = new JScrollBar(JScrollBar.VERTICAL);
popupScrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override public void adjustmentValueChanged(AdjustmentEvent e) {
doLayout();
repaint();
}
});
popupScrollBar.setVisible(false);
}
return popupScrollBar;
}
public int getMaximumVisibleRows() {
return maximumVisibleRows;
}
public void setMaximumVisibleRows(int maximumVisibleRows) {
this.maximumVisibleRows = maximumVisibleRows;
}
public void paintChildren(Graphics g){
Insets insets = getInsets();
g.clipRect(insets.left, insets.top, getWidth(), getHeight() - insets.top - insets.bottom);
super.paintChildren(g);
}
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if(maximumVisibleRows < getComponentCount()-1) {
getScrollBar().setVisible(true);
}
}
public void remove(int index) {
// can't remove the scrollbar
++index;
super.remove(index);
if(maximumVisibleRows >= getComponentCount()-1) {
getScrollBar().setVisible(false);
}
}
public void show(Component invoker, int x, int y){
JScrollBar scrollBar = getScrollBar();
if(scrollBar.isVisible()){
int extent = 0;
int max = 0;
int i = 0;
int unit = -1;
int width = 0;
for(Component comp : getComponents()) {
if(!(comp instanceof JScrollBar)) {
Dimension preferredSize = comp.getPreferredSize();
width = Math.max(width, preferredSize.width);
if(unit < 0){
unit = preferredSize.height;
}
if(i++ < maximumVisibleRows) {
extent += preferredSize.height;
}
max += preferredSize.height;
}
}
Insets insets = getInsets();
int widthMargin = insets.left + insets.right;
int heightMargin = insets.top + insets.bottom;
scrollBar.setUnitIncrement(unit);
scrollBar.setBlockIncrement(extent);
scrollBar.setValues(0, heightMargin + extent, 0, heightMargin + max);
width += scrollBar.getPreferredSize().width + widthMargin;
int height = heightMargin + extent;
setPopupSize(new Dimension(width, height));
}
super.show(invoker, x, y);
}
protected static class ScrollPopupMenuLayout implements LayoutManager{
#Override public void addLayoutComponent(String name, Component comp) {}
#Override public void removeLayoutComponent(Component comp) {}
#Override public Dimension preferredLayoutSize(Container parent) {
int visibleAmount = Integer.MAX_VALUE;
Dimension dim = new Dimension();
for(Component comp :parent.getComponents()){
if(comp.isVisible()) {
if(comp instanceof JScrollBar){
JScrollBar scrollBar = (JScrollBar) comp;
visibleAmount = scrollBar.getVisibleAmount();
}
else {
Dimension pref = comp.getPreferredSize();
dim.width = Math.max(dim.width, pref.width);
dim.height += pref.height;
}
}
}
Insets insets = parent.getInsets();
dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
return dim;
}
#Override public Dimension minimumLayoutSize(Container parent) {
int visibleAmount = Integer.MAX_VALUE;
Dimension dim = new Dimension();
for(Component comp : parent.getComponents()) {
if(comp.isVisible()){
if(comp instanceof JScrollBar) {
JScrollBar scrollBar = (JScrollBar) comp;
visibleAmount = scrollBar.getVisibleAmount();
}
else {
Dimension min = comp.getMinimumSize();
dim.width = Math.max(dim.width, min.width);
dim.height += min.height;
}
}
}
Insets insets = parent.getInsets();
dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
return dim;
}
#Override public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int width = parent.getWidth() - insets.left - insets.right;
int height = parent.getHeight() - insets.top - insets.bottom;
int x = insets.left;
int y = insets.top;
int position = 0;
for(Component comp : parent.getComponents()) {
if((comp instanceof JScrollBar) && comp.isVisible()) {
JScrollBar scrollBar = (JScrollBar) comp;
Dimension dim = scrollBar.getPreferredSize();
scrollBar.setBounds(x + width-dim.width, y, dim.width, height);
width -= dim.width;
position = scrollBar.getValue();
}
}
y -= position;
for(Component comp : parent.getComponents()) {
if(!(comp instanceof JScrollBar) && comp.isVisible()) {
Dimension pref = comp.getPreferredSize();
comp.setBounds(x, y, width, pref.height);
y += pref.height;
}
}
}
}
}

In addition to the JScrollPopupMenu above, I also needed a a scroll bar in a sub menu (aka a "Pull Right Menu.") This seems to be a more common case. So I adapted a JMenu to use the JScrollPopupMenu called JScrollMenu:
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.UIManager;
import javax.swing.plaf.MenuItemUI;
import javax.swing.plaf.PopupMenuUI;
import java.awt.Component;
import java.awt.ComponentOrientation;
public class JScrollMenu extends JMenu {
// Covers the one in the JMenu because the method that creates it in JMenu is private
/** The popup menu portion of the menu.*/
private JPopupMenu popupMenu;
/**
* Constructs a new <code>JMenu</code> with no text.
*/
public JScrollMenu() {
this("");
}
/**
* Constructs a new <code>JMenu</code> with the supplied string as its text.
*
* #param s the text for the menu label
*/
public JScrollMenu(String s) {
super(s);
}
/**
* Constructs a menu whose properties are taken from the <code>Action</code> supplied.
*
* #param a an <code>Action</code>
*/
public JScrollMenu(Action a) {
this();
setAction(a);
}
/**
* Lazily creates the popup menu. This method will create the popup using the <code>JScrollPopupMenu</code> class.
*/
protected void ensurePopupMenuCreated() {
if(popupMenu == null) {
this.popupMenu = new JScrollPopupMenu();
popupMenu.setInvoker(this);
popupListener = createWinListener(popupMenu);
}
}
//////////////////////////////
//// All of these methods are necessary because ensurePopupMenuCreated() is private in JMenu
//////////////////////////////
#Override
public void updateUI() {
setUI((MenuItemUI) UIManager.getUI(this));
if(popupMenu != null) {
popupMenu.setUI((PopupMenuUI) UIManager.getUI(popupMenu));
}
}
#Override
public boolean isPopupMenuVisible() {
ensurePopupMenuCreated();
return popupMenu.isVisible();
}
#Override
public void setMenuLocation(int x, int y) {
super.setMenuLocation(x, y);
if(popupMenu != null) {
popupMenu.setLocation(x, y);
}
}
#Override
public JMenuItem add(JMenuItem menuItem) {
ensurePopupMenuCreated();
return popupMenu.add(menuItem);
}
#Override
public Component add(Component c) {
ensurePopupMenuCreated();
popupMenu.add(c);
return c;
}
#Override
public Component add(Component c, int index) {
ensurePopupMenuCreated();
popupMenu.add(c, index);
return c;
}
#Override
public void addSeparator() {
ensurePopupMenuCreated();
popupMenu.addSeparator();
}
#Override
public void insert(String s, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(new JMenuItem(s), pos);
}
#Override
public JMenuItem insert(JMenuItem mi, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(mi, pos);
return mi;
}
#Override
public JMenuItem insert(Action a, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
JMenuItem mi = new JMenuItem(a);
mi.setHorizontalTextPosition(JButton.TRAILING);
mi.setVerticalTextPosition(JButton.CENTER);
popupMenu.insert(mi, pos);
return mi;
}
#Override
public void insertSeparator(int index) {
if(index < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(new JPopupMenu.Separator(), index);
}
#Override
public void remove(JMenuItem item) {
if(popupMenu != null){
popupMenu.remove(item);
}
}
#Override
public void remove(int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
if(pos > getItemCount()) {
throw new IllegalArgumentException("index greater than the number of items.");
}
if(popupMenu != null){
popupMenu.remove(pos);
}
}
#Override
public void remove(Component c) {
if(popupMenu != null){
popupMenu.remove(c);
}
}
#Override
public void removeAll() {
if(popupMenu != null){
popupMenu.removeAll();
}
}
#Override
public int getMenuComponentCount() {
return (popupMenu == null) ? 0 : popupMenu.getComponentCount();
}
#Override
public Component getMenuComponent(int n) {
return (popupMenu == null) ? null : popupMenu.getComponent(n);
}
#Override
public Component[] getMenuComponents() {
return (popupMenu == null) ? new Component[0] : popupMenu.getComponents();
}
#Override
public JPopupMenu getPopupMenu() {
ensurePopupMenuCreated();
return popupMenu;
}
#Override
public MenuElement[] getSubElements() {
return popupMenu == null ? new MenuElement[0] : new MenuElement[]{popupMenu};
}
#Override
public void applyComponentOrientation(ComponentOrientation o) {
super.applyComponentOrientation(o);
if(popupMenu != null) {
int ncomponents = getMenuComponentCount();
for(int i = 0; i < ncomponents; ++i) {
getMenuComponent(i).applyComponentOrientation(o);
}
popupMenu.setComponentOrientation(o);
}
}
#Override
public void setComponentOrientation(ComponentOrientation o) {
super.setComponentOrientation(o);
if(popupMenu != null) {
popupMenu.setComponentOrientation(o);
}
}
}

Here's another one I found very useful: https://tips4java.wordpress.com/2009/02/01/menu-scroller/
It can be called on JMenu or JPopupMenu like this:
MenuScroller.setScrollerFor(menuInstance, 8, 125, 3, 1);

May be this
http://www.javabeginner.com/java-swing/java-scrollable-popup-menu

Basically you can add any JComponents to the JPopupMenu, you can add JScrollpane to the JPopup by nesting JPanel / JList with another JComponents,
Notice but there is rule that swing GUI doesn't allowing two lightweight popup window in same time, best example is common Bug in Swing about JComboBox in the JPopup
you have look at JWindow, create once time and re_use that for another Action, nothing best around as to check how popup JWindow really works for JCalendar by Kai Toedter

Alternately you may want to consider JidePopupMenu: Scrollable JPopupMenu

As I needed popup menu with Scrollbar, I just reused popup menu from JComboBox.
The trick was to put JComboBox in a JViewport, so that only arrow button was visible. You may make it just one pixel small or even lesser and use event from JideSplitButton to open popup.
You may find code on github.

Adding to the JScrollPopupMenu answer above (I can't edit it).
In order to have it scroll on arrow navigation etc., I added this:
#Override public void scrollRectToVisible(Rectangle aRect) {
final Insets insets = getInsets();
final int scrollY = popupScrollBar.getValue();
int y = aRect.y;
if (y - insets.top < 0)
popupScrollBar.setValue(scrollY + y - insets.top);
else {
y += aRect.height;
final int bottom = getHeight() - insets.bottom;
if (y > bottom)
popupScrollBar.setValue(scrollY + y - bottom);
}
}
Which then be called like so:
popupMenu.scrollRectToVisible(menuItem.getBounds());

Related

JTable AutoScrolling like IntelliJ Console

I want to add a Scroll To End (Autoscroll) function to a jtable with maximum up to 50 rows.
AutoScroll function should work as IntelliJ Scroll To End.
Initially there are 0 rows. In several milliseconds (say 100 ms.) a few item (1-5 items) is added to the end of the table. If the table row count reaches to the max (50), the first row will be deleted before the next insertion.
When user scrolls to the end with mouse dragging or scroll wheel, scroll to end checkbox selected and function will be enabled. From that moment, the scrollpane should be scrolled to the bottom of the table like:
scrollRectToVisible(getCellRect(getRowCount() - 1, 0, true));
When user changes scrollbar position other than the bottom of viewport by dragging or mouse scroll wheel, scroll to end checkbox will deselected and function will be disabled.
While scroll to end checkbox is not selected, the table will react to scroll bar movements which are sourced by dragging or mouse wheel. But the viewport should show same data.
If it is impossible to show same data in the viewport because of deletions of the consequent first rows, the visible first data in the viewport will go to the up.
This is the exact behavior of the IntelliJ console log screen.
I wrote Scroll To End enable functionality (90% percent working).
I could not write Scroll To End disable functionality, I don't know to preserve current viewport as stated above.
Thanks for your help.
package org.example.table;
import com.bsbls.home.gui.test.GuiTester;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class MyTable extends JTable {
JScrollPane scrollPane;
boolean autoScroll;
private Consumer<Boolean> scrollToEndListener;
private Object lastValue;
private ScheduledFuture<?> future;
public MyTable(int max) {
this.setFillsViewportHeight(true);
this.setRowHeight(24);
this.setModel(new MyTableModel(max));
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
if (autoScroll) {
scrollToEnd();
}
}
});
}
public MyTableModel getTableModel() {
return (MyTableModel) getModel();
}
private void scrollToEnd() {
scrollRectToVisible(getCellRect(getRowCount() - 1, 0, true));
}
public void setScrollToEnd(boolean autoScroll) {
this.autoScroll = autoScroll;
if (autoScroll) {
scrollToEnd();
}
if (scrollToEndListener != null) {
scrollToEndListener.accept(autoScroll);
}
}
public void setScrollToEndListener(Consumer<Boolean> scrollToEndListener) {
this.scrollToEndListener = scrollToEndListener;
}
public JScrollPane wrap() {
if (scrollPane == null) {
scrollPane = new JScrollPane(this);
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.addAdjustmentListener(e -> {
if (e.getValue() + scrollBar.getVisibleAmount() == scrollBar.getMaximum()) {
setScrollToEnd(true);
} else {
setScrollToEnd(false);
}
});
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scrollPane.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (future != null) {
future.cancel(false);
}
future = scheduler.schedule(() -> {
EventQueue.invokeLater(() -> {
System.out.println("Yes");
JViewport viewport = scrollPane.getViewport();
Point p = viewport.getViewPosition();
Dimension extentSize = viewport.getExtentSize();
//p.translate(extentSize.width, extentSize.height);
int rowIndex = rowAtPoint(p);
if (rowIndex >= 0) {
lastValue = getValueAt(rowIndex, 0);
}
});
}, 500, TimeUnit.MILLISECONDS);
}
});
scrollBar.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
//System.out.println(e);
}
#Override
public void mousePressed(MouseEvent e) {
//System.out.println(e);
lastValue = null;
}
#Override
public void mouseReleased(MouseEvent e) {
//System.out.println(e);
JViewport viewport = scrollPane.getViewport();
Point p = viewport.getViewPosition();
Dimension extentSize = viewport.getExtentSize();
//p.translate(extentSize.width, extentSize.height);
int rowIndex = rowAtPoint(p);
if (rowIndex >= 0) {
lastValue = getValueAt(rowIndex, 0);
}
}
#Override
public void mouseEntered(MouseEvent e) {
//System.out.println(e);
}
#Override
public void mouseExited(MouseEvent e) {
//System.out.println(e);
}
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
//System.out.println(e);
}
#Override
public void mouseDragged(MouseEvent e) {
// System.out.println(e);
}
#Override
public void mouseMoved(MouseEvent e) {
//System.out.println(e);
}
});
getTableModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
if (lastValue != null && !autoScroll) {
int rowCount = getRowCount();
int newIndex = -1;
for (int i = 0; i < rowCount; i++) {
Object indexValue = getValueAt(i, 0);
if (indexValue == lastValue) {
newIndex = i;
break;
}
}
System.out.println(lastValue + " " + newIndex);
if (newIndex > 1) {
scrollRectToVisible(getCellRect(newIndex - 1, 0, true));
} else {
lastValue = null;
}
}
}
});
}
return scrollPane;
}
static int counter;
public static void main(String[] args) {
GuiTester.test(f -> {
JPanel panel = new JPanel(new BorderLayout());
MyTable table = new MyTable(50);
MyTableModel model = table.getTableModel();
Random random = new Random();
Timer timer = new Timer(100, e -> {
Data data = new Data();
data.setName(++counter + "");
data.setX(random.nextInt());
data.setY(random.nextInt());
data.setZ(random.nextInt());
data.setFlag(random.nextBoolean());
model.addRow(data.toObjectArray());
});
timer.start();
DataPanel dataPanel = new DataPanel();
table.getSelectionModel().addListSelectionListener(e -> {
int index = e.getFirstIndex();
if (index >= 0) {
Data data = (Data) table.getValueAt(index, 5);
dataPanel.setData(data);
}
});
JCheckBox checkBox = new JCheckBox("Scroll To End");
table.setScrollToEndListener(flag -> {
checkBox.setSelected(flag);
});
checkBox.addItemListener(e -> {
table.setScrollToEnd(checkBox.isSelected());
});
panel.add(checkBox, BorderLayout.NORTH);
panel.add(table.wrap(), BorderLayout.CENTER);
panel.add(dataPanel.getPanel(), BorderLayout.EAST);
return panel;
});
}
}
Table Model
package org.example.table;
import javax.swing.table.DefaultTableModel;
public class MyTableModel extends DefaultTableModel {
private int max = -1;
public MyTableModel() {
this(-1);
}
public MyTableModel(int max) {
super(new Object[]{
"Name", "Flag", "X", "Y", "Z", "Data"
}, 0);
this.max = max;
}
#Override
public void addRow(Object[] rowData) {
if (getRowCount() == max) {
super.removeRow(0);
}
super.addRow(rowData);
}
}
Dummy data
package org.example.table;
public class Data {
private String name;
private boolean flag;
private int x;
private int y;
private int z;
public Object[] toObjectArray() {
Object[] array = new Object[6];
array[0] = name;
array[1] = flag;
array[2] = x;
array[3] = y;
array[4] = z;
array[5] = this;
return array;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
}
DatPanel which is a dummy IntelliJ form:
package org.example.table;
import javax.swing.*;
public class DataPanel {
private JTextField fieldName;
private JCheckBox flagCheckBox;
private JTextField fieldX;
private JTextField fieldY;
private JTextField fieldZ;
private JPanel panel;
public JPanel getPanel() {
return panel;
}
public void setData(Data data) {
fieldName.setText(data.getName());
fieldX.setText(data.getX() + "");
fieldY.setText(data.getY() + "");
fieldZ.setText(data.getZ() + " ");
flagCheckBox.setSelected(data.isFlag());
}
}
EDIT:
I have added to mouse and mouse wheel listeners, and find the first visible row.
And changed scroll mode to simple or backingstore.
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
In that case I have got a better function.
I am still open for better approaches.

Why while changing the content in the text box is not changing the size of the scroll bars?

English is not my native language excuse me if there is grammar mistakes.
This is a program for a text editor.
The Rule class is used as row header for ScrollableTextArea The ScrollableTextArea extends JTextArea and implements Scrollable it also implementsMouseMotionListener so user can scroll(move the knob) by clicking on the track.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
/**
*Classes required
*Rule.java
*ScrollableTextArea
* #author Dev Parzival
*/
public class Note extends JPanel{
static int NUMBER_PANEL_WIDTH=50;
private ScrollableTextArea scrollableTextArea;
private Rule rowView;
private JScrollPane scroll;
public Note(Dimension size,File file) {
rowView=new Rule(SwingConstants.VERTICAL,getIncrement());
scrollableTextArea=new ScrollableTextArea(rowView.getIncrement());
boolean flag=fetchData(scrollableTextArea, file);
rowView.setPreferredHeight(scrollableTextArea.getHeight());
if(!flag)
return;
scroll=new JScrollPane(scrollableTextArea);
scroll.setPreferredSize(size);
scroll.setRowHeaderView(rowView);
scroll.setViewportBorder(BorderFactory.createLineBorder(Color.black));
add(scroll);
setSize(size);
setVisible(true);
}
private boolean fetchData(JTextArea text,File file){
FileReader scan;
BufferedReader br;
try{
scan=new FileReader(file);
String msg="";
br=new BufferedReader(scan);
try{
while(true){
String data=br.readLine();
if(data==null)
break;
msg+=data+"\n";
}
text.setText(msg);
}
catch(IOException ex){
JOptionPane.showMessageDialog(this,"Error Occured while reading "+file.getAbsolutePath()+".","Error",JOptionPane.INFORMATION_MESSAGE);
}
}
catch(FileNotFoundException ex){
JOptionPane.showMessageDialog(this,"Cannot found this path : "+file.getAbsoluteFile(),"Error",JOptionPane.INFORMATION_MESSAGE);
return false;
}
return true;
}
/*Here the unit is the height of the text inside the textArea*/
public int getIncrement(){
JTextArea ta=new JTextArea();
return ta.getFontMetrics(ta.getFont()).getHeight();
}
public static void createAndShowGUI(){
JFrame frame = new JFrame("ScrollDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
//Create and set up the content pane.
JComponent newContentPane = new Note(frame.getSize(),new File("C:\\Users\\DevParzival\\Documents\\pro.txt"));
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
//frame.pack();
frame.setVisible(true);
}
public static void main(String $[]){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
class Rule extends JComponent {
public static int INCH;
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int SIZE = 35;
public int orientation;
private int increment;
private int units;
public Rule(int o,int height) {
orientation = o;
INCH=height;
setIncrementAndUnits();
}
private void setIncrementAndUnits() {
increment = units=INCH;
}
public int getIncrement() {
return increment;
}
public void setPreferredHeight(int ph) {
setPreferredSize(new Dimension(SIZE, ph));
}
public void setPreferredWidth(int pw) {
setPreferredSize(new Dimension(pw, SIZE));
}
protected void paintComponent(Graphics g) {
Rectangle drawHere = g.getClipBounds();
System.out.println(drawHere);
// Fill clipping area with dirty brown/orange.
g.setColor(new Color(230, 163, 4));
g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height);
// Do the ruler labels in a small font that's black.
g.setFont(new Font("SansSerif", Font.PLAIN, 10));
g.setColor(Color.black);
// Some vars we need.
int end = 0;
int start = 0;
int tickLength = 0;
String text = null;
// Use clipping bounds to calculate first and last tick locations.
if (orientation == HORIZONTAL) {
start = (drawHere.x / increment) * increment;
end = (((drawHere.x + drawHere.width) / increment) + 1)
* increment;
} else {
start = (drawHere.y / increment) * increment;
end = (((drawHere.y + drawHere.height) / increment) + 1)
* increment;
}
// Make a special case of 0 to display the number
// within the rule and draw a units label.
// if (start == 0) {
// text = Integer.toString(0);
// tickLength = 10;
// if (orientation == HORIZONTAL) {
// g.drawLine(0, SIZE-1, 0, SIZE-tickLength-1);
// g.drawString(text, 2, 21);
// } else {
// g.drawLine(SIZE-1, 0, SIZE-tickLength-1, 0);
// g.drawString(text, 9, 10);
// }
// text = null;
// start = increment;
// }
// ticks and labels
for (int i = start; i < end; i += increment) {
if (i % units == 0) {
tickLength = 10;
text = Integer.toString(i/units);
} else {
tickLength = 7;
text = null;
}
if (tickLength != 0) {
if (orientation == HORIZONTAL) {
g.drawLine(i, SIZE-1, i, SIZE-tickLength-1);
if (text != null)
g.drawString(text, i-3, 21);
} else {
g.drawLine(SIZE-1, i, SIZE-tickLength-1, i);
if (text != null)
g.drawString(text, 9, i+3+increment/2);
}
}
}
}
}
class ScrollableTextArea extends JTextArea implements Scrollable,MouseMotionListener {
private int maxUnitIncrement = 1;
public ScrollableTextArea(int m) {
maxUnitIncrement = m;
//Let the user scroll by dragging to outside the window.
setAutoscrolls(true); //enable synthetic drag events
addMouseMotionListener(this); //handle mouse drags
}
//Methods required by the MouseMotionListener interface:
public void mouseMoved(MouseEvent e) { }
public void mouseDragged(MouseEvent e) {
//The user is dragging us, so scroll!
Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
scrollRectToVisible(r);
}
public Dimension getPreferredSize() {
return new Dimension(500,500);
}
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation,
int direction) {
//Get the current position.
int currentPosition = 0;
if (orientation == SwingConstants.HORIZONTAL) {
currentPosition = visibleRect.x;
} else {
currentPosition = visibleRect.y;
}
//Return the number of pixels between currentPosition
//and the nearest tick mark in the indicated direction.
if (direction < 0) {
int newPosition = currentPosition -
(currentPosition / maxUnitIncrement)
* maxUnitIncrement;
return (newPosition == 0) ? maxUnitIncrement : newPosition;
} else {
return ((currentPosition / maxUnitIncrement) + 1)
* maxUnitIncrement
- currentPosition;
}
}
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation,
int direction) {
if (orientation == SwingConstants.HORIZONTAL) {
return visibleRect.width - maxUnitIncrement;
} else {
return visibleRect.height - maxUnitIncrement;
}
}
public boolean getScrollableTracksViewportWidth() {
return false;
}
public boolean getScrollableTracksViewportHeight() {
return false;
}
public void setMaxUnitIncrement(int pixels) {
maxUnitIncrement = pixels;
}
}
From the above pic it is visible that changing the content of the
textArea is not changing the size of the scroll bars.
How could we make the scroll bar to adjust as the content inside the scrollableTextArea changes?
How to fix the bug?
Thanks in advance.

Choosing a Layout Manager - Java

I'm having trouble to find the right Layout Manager. I have some images inside a JPanel, they are all different size so I wanted to use a Flow Layout to let the manager handle them. The manager fills all the first row as possible and then warps to another line. This is all ok, but what I want is to stop at second "warp". I just want to show 2 rows of images and if then you want to see more you must click a JButton to load the others. Actually the FlowLayout keeps inserting in a third line and the images are cutted by half because the panel is not "tall" enough. Any tips?
I've already tried with Flow Layout and Mig Layout without success.
Combine a FlowLayout(outerPanel) with a GridBagLayout(innerPannel)
u can define the rows by yourself, and then u put a JScrollPane over it so it wont cut your pictures and u will still be able to see them in full size(my suggestion)
I couldn't resist trying to solve this. I had hoped to make use of FlowLayouts, but in the end, I ended up using only GridBagLayouts: One for each row of images, plus one for the entire container. I may have over-engineered in terms of flexibility, but I imagine something like this may be useful to myself or others in the future.
In essence, every time the container changes size, or images are added/removed, or any of its visual properties change, updateLayout() is called, which rebuilds all of the GridBagLayout panels from scratch. I'm sure there are ways to make this more efficient, and I'm sure it's possible to write a LayoutManager2 implementation from scatch that does the job, but this performed reasonably well for me.
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ImagePanel
extends JPanel {
private static final long serialVersionUID = 1;
/** #serial */
private final List<Icon> images = new ArrayList<>();
/** #serial */
private final List<Icon> scaledImages = new ArrayList<>();
/** #serial */
private int maxRowCount = 2;
/** #serial */
private int hgap = 6;
/** #serial */
private int vgap = 6;
/** #serial */
private int maxImageWidth = 200;
/** #serial */
private int maxImageHeight = 200;
public ImagePanel() {
setLayout(new GridBagLayout());
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent event) {
updateLayout();
}
});
}
#Override
public void addNotify() {
super.addNotify();
updateLayout();
}
#Override
public Dimension getPreferredSize() {
Rectangle screen = findGraphicsConfiguration().getBounds();
Dimension size = new Dimension();
Dimension row = new Dimension();
int rowsComputed = 0;
int gap = 0;
for (Icon image : scaledImages) {
if (row.width > 0 &&
row.width + gap + image.getIconWidth() > screen.width) {
if (++rowsComputed >= maxRowCount) {
break;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
row.setSize(0, 0);
gap = 0;
}
row.width += gap + image.getIconWidth();
row.height = Math.max(row.height, image.getIconHeight());
gap = hgap;
}
size.width = Math.max(size.width, row.width);
size.height += (size.height > 0 ? vgap : 0) + row.height;
return size;
}
private void updateLayout() {
int width = getWidth();
if (width == 0) {
return;
}
for (Component rowContainer : getComponents()) {
((JComponent) rowContainer).removeAll();
}
GridBagConstraints rowConstraints = new GridBagConstraints();
rowConstraints.gridwidth = GridBagConstraints.REMAINDER;
rowConstraints.weightx = 1;
rowConstraints.anchor = GridBagConstraints.FIRST_LINE_START;
int row = -1;
int rowWidth = 0;
GridBagConstraints gbc = new GridBagConstraints();
for (Icon image : scaledImages) {
JComponent rowContainer = (row >= 0 && row < getComponentCount() ?
(JComponent) getComponent(row) : null);
int gap = (rowWidth > 0 ? hgap : 0);
if (rowContainer == null ||
rowWidth + gap + image.getIconWidth() > width) {
if (++row >= maxRowCount) {
break;
}
gap = 0;
rowWidth = 0;
if (row < getComponentCount()) {
rowContainer = (JComponent) getComponent(row);
} else {
rowContainer = new JPanel(new GridBagLayout());
add(rowContainer, rowConstraints);
}
rowConstraints.insets.top = vgap;
}
gbc.insets.left = gap;
JComponent imageContainer = new JLabel(image);
rowContainer.add(imageContainer, gbc);
rowWidth += gap + image.getIconWidth();
}
for (int i = getComponentCount() - 1; i >= maxRowCount; i--) {
remove(i);
}
}
private GraphicsConfiguration findGraphicsConfiguration() {
GraphicsConfiguration config = getGraphicsConfiguration();
if (config == null) {
GraphicsEnvironment env =
GraphicsEnvironment.getLocalGraphicsEnvironment();
config = env.getDefaultScreenDevice().getDefaultConfiguration();
}
return config;
}
private Icon scale(Icon image) {
int imageWidth = image.getIconWidth();
int imageHeight = image.getIconHeight();
if (imageWidth > maxImageWidth || imageHeight > maxImageHeight) {
float scale = Math.min((float) maxImageWidth / imageWidth,
(float) maxImageHeight / imageHeight);
if (scale < 1) {
GraphicsConfiguration config = findGraphicsConfiguration();
BufferedImage scaledImage = config.createCompatibleImage(
(int) (imageWidth * scale),
(int) (imageHeight * scale));
Graphics2D g = scaledImage.createGraphics();
g.scale(scale, scale);
image.paintIcon(this, g, 0, 0);
g.dispose();
image = new ImageIcon(scaledImage);
}
}
return image;
}
public List<Icon> getImages() {
return new ArrayList<>(images);
}
public void clearImages() {
images.clear();
updateLayout();
revalidate();
}
public void addImage(Icon image) {
Objects.requireNonNull(image, "Image cannot be null");
images.add(image);
scaledImages.add(scale(image));
updateLayout();
revalidate();
}
public void removeImage(Icon image) {
int index = images.indexOf(image);
if (index >= 0) {
removeImage(index);
}
}
public void removeImage(int index) {
images.remove(index);
scaledImages.remove(index);
updateLayout();
revalidate();
}
public int getHgap() {
return hgap;
}
public void setHgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.hgap;
this.hgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("hgap", old, gap);
}
public int getVgap() {
return vgap;
}
public void setVgap(int gap) {
if (gap < 0) {
throw new IllegalArgumentException("Gap must be at least zero");
}
int old = this.vgap;
this.vgap = gap;
if (old != gap) {
updateLayout();
revalidate();
}
firePropertyChange("vgap", old, gap);
}
public int getMaxRowCount() {
return maxRowCount;
}
public void setMaxRowCount(int count) {
if (count < 0) {
throw new IllegalArgumentException("Count must be at least zero");
}
int old = this.maxRowCount;
this.maxRowCount = count;
if (old != count) {
updateLayout();
revalidate();
}
firePropertyChange("maxRowCount", old, count);
}
public int getMaxImageWidth() {
return maxImageWidth;
}
private void recomputeScaledImages() {
scaledImages.clear();
for (Icon image : images) {
scaledImages.add(scale(image));
}
}
public void setMaxImageWidth(int width) {
if (width <= 0) {
throw new IllegalArgumentException("Width must be positive");
}
int old = this.maxImageWidth;
this.maxImageWidth = width;
if (old != width) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageWidth", old, width);
}
public int getMaxImageHeight() {
return maxImageHeight;
}
public void setMaxImageHeight(int height) {
if (height <= 0) {
throw new IllegalArgumentException("Height must be positive");
}
int old = this.maxImageHeight;
this.maxImageHeight = height;
if (old != height) {
recomputeScaledImages();
updateLayout();
revalidate();
}
firePropertyChange("maxImageHeight", old, height);
}
public static void main(final String[] args)
throws java.io.IOException {
if (args.length == 0) {
System.err.println("Usage: java " + ImagePanel.class.getName()
+ " <directory> | <url1> <url2> ...");
System.exit(2);
}
final List<java.net.URL> urls;
if (args.length == 1 && !args[0].contains(":")) {
urls = new ArrayList<>();
try (java.nio.file.DirectoryStream<java.nio.file.Path> dir =
java.nio.file.Files.newDirectoryStream(
java.nio.file.Paths.get(args[0]))) {
for (java.nio.file.Path file : dir) {
urls.add(file.toUri().toURL());
}
}
} else {
urls = new ArrayList<>(args.length);
for (String url : args) {
urls.add(new java.net.URL(url));
}
}
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ImagePanel imagePanel = new ImagePanel();
for (java.net.URL url : urls) {
imagePanel.addImage(new ImageIcon(url));
}
javax.swing.JFrame frame =
new javax.swing.JFrame("ImagePanel");
frame.setDefaultCloseOperation(
javax.swing.JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(imagePanel, gbc);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}

How can I add to or change a label on a JMenuItem?

I need to add a label on the right hand side of a JMenuItem, like the labels shown below:
I have an application that uses Ctrl++ and Ctrl+- to zoom into an image. However, the + key by default (without Shift) is the = key. When I try adding accelerators for these menu items, the Ctrl+- shortcut label displays as "Ctrl+Minus" (I would prefer "Ctrl -") and the Ctrl++ shortcut label displays as "Ctrl+Equals" (even worse - in the interest of user experience, I would prefer "Ctrl +"):
menuBar_view_zoomIn.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, ActionEvent.CTRL_MASK));
I want Ctrl++ to display as "Ctrl +" and Ctrl+- to display as "Ctrl -". How can this be done?
not an answer, you need to search for
paint() to heavy, paintComponent() for lightweight JPopup, JMenu (for custom painting can be switch to isHeavyWeight...)
overlay JLabel into container (few question about JTable by #Guillaume Polet and #Robin)
create own JMenu/JPopup (see my comment to your question)
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.plaf.basic.BasicArrowButton;
public class ComboBoxMenuExample extends JFrame {
public ComboBoxMenuExample() {
super("ComboBoxMenu Example");
String[] itemStr = {"name", "Red", "Blue", "number", "255,0,0", "0,0,255",
/*separator*/ "system", "control", "controlHighlight", "controlShadow", "text"};
JMenuItem[] menuItems = new JMenuItem[7];
menuItems[0] = new JMenuItem(itemStr[1]);
menuItems[1] = new JMenuItem(itemStr[2]);
menuItems[2] = new JMenuItem(itemStr[4]);
menuItems[3] = new JMenuItem(itemStr[5]);
menuItems[4] = new JMenuItem(itemStr[8]);
menuItems[5] = new JMenuItem(itemStr[9]);
menuItems[6] = new JMenuItem(itemStr[10]);
JMenu[] menus = new JMenu[4];
menus[0] = new JMenu(itemStr[0]);
menus[1] = new JMenu(itemStr[3]);
menus[2] = new JMenu(itemStr[6]);
menus[3] = new JMenu(itemStr[7]);
menus[0].add(menuItems[0]);
menus[0].add(menuItems[1]);
menus[1].add(menuItems[2]);
menus[1].add(menuItems[3]);
menus[3].add(menuItems[4]);
menus[3].add(menuItems[5]);
menus[2].add(menus[3]);
menus[2].add(menuItems[6]);
JMenu menu = ComboMenuBar.createMenu(menuItems[0].getText());
menu.add(menus[0]);
menu.add(menus[1]);
menu.addSeparator();
menu.add(menus[2]);
ComboMenuBar comboMenu = new ComboMenuBar(menu);
JComboBox combo = new JComboBox();
combo.addItem(itemStr[1]);
combo.addItem(itemStr[2]);
combo.addItem(itemStr[4]);
combo.addItem(itemStr[5]);
combo.addItem(itemStr[8]);
combo.addItem(itemStr[9]);
combo.addItem(itemStr[10]);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new ComboPanel("Fake ComboBox", comboMenu));
getContentPane().add(new ComboPanel("ComboBox", combo));
}
class ComboPanel extends JPanel {
ComboPanel(String title, JComponent c) {
setLayout(new FlowLayout());
setBorder(new TitledBorder(title));
add(c);
}
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {
}
ComboBoxMenuExample frame = new ComboBoxMenuExample();
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.setSize(370, 100);
frame.setVisible(true);
}
}
class ComboMenuBar extends JMenuBar {
JMenu menu;
Dimension preferredSize;
public ComboMenuBar(JMenu menu) {
this.menu = menu;
Color color = UIManager.getColor("Menu.selectionBackground");
UIManager.put("Menu.selectionBackground", UIManager.getColor("Menu.background"));
UIManager.put("Menu.selectionBackground", color);
menu.updateUI();
MenuItemListener listener = new MenuItemListener();
setListener(menu, listener);
add(menu);
}
class MenuItemListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
JMenuItem item = (JMenuItem) e.getSource();
menu.setText(item.getText());
menu.requestFocus();
}
}
private void setListener(JMenuItem item, ActionListener listener) {
if (item instanceof JMenu) {
JMenu menu1 = (JMenu) item;
int n = menu1.getItemCount();
for (int i = 0; i < n; i++) {
setListener(menu1.getItem(i), listener);
}
} else if (item != null) { // null means separator
item.addActionListener(listener);
}
}
public String getSelectedItem() {
return menu.getText();
}
#Override
public void setPreferredSize(Dimension size) {
preferredSize = size;
}
#Override
public Dimension getPreferredSize() {
if (preferredSize == null) {
Dimension sd = super.getPreferredSize();
Dimension menuD = getItemSize(menu);
Insets margin = menu.getMargin();
Dimension retD = new Dimension(menuD.width, margin.top
+ margin.bottom + menuD.height);
menu.setPreferredSize(retD);
preferredSize = retD;
}
return preferredSize;
}
private Dimension getItemSize(JMenu menu) {
Dimension d = new Dimension(0, 0);
int n = menu.getItemCount();
for (int i = 0; i < n; i++) {
Dimension itemD;
JMenuItem item = menu.getItem(i);
if (item instanceof JMenu) {
itemD = getItemSize((JMenu) item);
} else if (item != null) {
itemD = item.getPreferredSize();
} else {
itemD = new Dimension(0, 0); // separator
}
d.width = Math.max(d.width, itemD.width);
d.height = Math.max(d.height, itemD.height);
}
return d;
}
public static class ComboMenu extends JMenu {
ArrowIcon iconRenderer;
public ComboMenu(String label) {
super(label);
iconRenderer = new ArrowIcon(SwingConstants.SOUTH, true);
setBorder(new EtchedBorder());
setIcon(new BlankIcon(null, 11));
setHorizontalTextPosition(JButton.LEFT);
setFocusPainted(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = this.getPreferredSize();
int x = Math.max(0, d.width - iconRenderer.getIconWidth() - 3);
int y = Math.max(0,
(d.height - iconRenderer.getIconHeight()) / 2 - 2);
iconRenderer.paintIcon(this, g, x, y);
}
}
public static JMenu createMenu(String label) {
return new ComboMenu(label);
}
}
class ArrowIcon implements Icon, SwingConstants {
private static final int DEFAULT_SIZE = 11;
//private static final int DEFAULT_SIZE = 5;
private int size;
private int iconSize;
private int direction;
private boolean isEnabled;
private BasicArrowButton iconRenderer;
public ArrowIcon(int direction, boolean isPressedView) {
this(DEFAULT_SIZE, direction, isPressedView);
}
public ArrowIcon(int iconSize, int direction, boolean isEnabled) {
this.size = iconSize / 2;
this.iconSize = iconSize;
this.direction = direction;
this.isEnabled = isEnabled;
iconRenderer = new BasicArrowButton(direction);
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
iconRenderer.paintTriangle(g, x, y, size, direction, isEnabled);
}
#Override
public int getIconWidth() {
//int retCode;
switch (direction) {
case NORTH:
case SOUTH:
return iconSize;
case EAST:
case WEST:
return size;
}
return iconSize;
}
#Override
public int getIconHeight() {
switch (direction) {
case NORTH:
case SOUTH:
return size;
case EAST:
case WEST:
return iconSize;
}
return size;
}
}
class BlankIcon implements Icon {
private Color fillColor;
private int size;
public BlankIcon() {
this(null, 11);
}
public BlankIcon(Color color, int size) {
//UIManager.getColor("control")
//UIManager.getColor("controlShadow")
fillColor = color;
this.size = size;
}
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (fillColor != null) {
g.setColor(fillColor);
g.drawRect(x, y, size - 1, size - 1);
}
}
#Override
public int getIconWidth() {
return size;
}
#Override
public int getIconHeight() {
return size;
}
}

Java snail line layout manager

i am looking for a java custom layout manager that arranges a couple of data (e.g. jlabels) in a way similar to the snail's back line.
So far, i have tried to work on the circle layout that i found on the internet to customize it but with no luck.. Any ideas???
You can write your own layouts. Spiral formula i got from Spirals. It Archimedean while a snail is more like Fermat's spiral, you could change the calculatePoint() method to return a different spiral.
Note: this layout is a bit inefficient since it recalculates all components positions every times instead of caching it.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
public class SpiralLayout implements LayoutManager2 {
private enum Size { MIN, MAX, PREF }
private double radiusStep;
private double angleStep;
public SpiralLayout() {
this(10, Math.toRadians(15.0));
}
public SpiralLayout(double radius, double stepSize) {
this.radiusStep = radius;
this.angleStep = stepSize;
}
public void setRadiusStep(double radiusStep) {
this.radiusStep = radiusStep;
}
public void setAngleStep(double angleStep) {
this.angleStep = angleStep;
}
#Override
public void addLayoutComponent(String name, Component comp) {
// calculated on the fly
}
#Override
public void removeLayoutComponent(Component comp) {
// calculated on the fly
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return getSize(parent, Size.PREF);
}
private Dimension getSize(Container parent, Size size) {
doLayoutContainer(parent, Short.MAX_VALUE, Short.MAX_VALUE, size);
Point min = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
Point max = new Point(0, 0);
for(Component component : parent.getComponents()) {
Dimension preferredSize = getSize(component, size);
min.x = Math.min(min.x, component.getX());
min.y = Math.min(min.y, component.getY());
max.x = Math.max(max.x, component.getX() + preferredSize.width);
max.y = Math.max(max.y, component.getY() + preferredSize.height);
}
int center = Short.MAX_VALUE / 2;
return new Dimension(
Math.max(Math.abs(center - min.x), Math.abs(center - max.x) * 2),
Math.max(Math.abs(center - min.y), Math.abs(center - max.y) * 2));
}
private Dimension getSize(Component component, Size size) {
switch(size) {
case MAX:
return component.getMaximumSize();
case MIN:
return component.getMinimumSize();
case PREF:
return component.getPreferredSize();
default:
assert false : "Unknown size: " + size;
return new Dimension();
}
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return getSize(parent, Size.MIN);
}
#Override
public void layoutContainer(Container parent) {
doLayoutContainer(parent,
parent.getWidth(), parent.getHeight(), Size.PREF);
}
private List<Rectangle> doLayoutContainer(Container parent,
int width, int height, Size size) {
Point offset = new Point(width / 2, height / 2);
List<Rectangle> componentBounds = new ArrayList<Rectangle>();
double angle = 0;
double radius = 1;
for(Component component : parent.getComponents()) {
Dimension preferredSize = getSize(component, size);
Rectangle bounds;
do {
bounds = new Rectangle(
add(calculatePoint(angle, radius), offset),
preferredSize);
angle += angleStep;
radius += radiusStep;
}
while(overlaps(bounds, componentBounds));
component.setBounds(bounds);
componentBounds.add(bounds);
}
return componentBounds;
}
private Point calculatePoint(double angle, double radius) {
double x = radius * Math.cos(angle);
double y = radius * Math.sin(angle);
return new Point((int) x, (int) y);
}
private boolean overlaps(Rectangle bounds, List<Rectangle> componentBounds) {
for(Rectangle other : componentBounds) {
if(other.intersects(bounds)) {
return true;
}
}
return false;
}
private Point add(Point a, Point b) {
return new Point(a.x + b.x, a.y + b.y);
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
// calculated on the fly
}
#Override
public Dimension maximumLayoutSize(Container parent) {
return getSize(parent, Size.MAX);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void invalidateLayout(Container target) {
// calculated on the fly
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final SpiralLayout layout = new SpiralLayout();
final JPanel panel = new JPanel(layout);
final JSpinner angleSpinner = new JSpinner(new SpinnerNumberModel(Math.toDegrees(layout.angleStep), 1.0, 360.0, 5.0));
angleSpinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
double angle = (Double) angleSpinner.getValue();
layout.setAngleStep(Math.toRadians(angle));
panel.revalidate();
}
});
final JSpinner radiusSpinner = new JSpinner(new SpinnerNumberModel((int) layout.radiusStep, 1, 1000, 1));
radiusSpinner.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int radius = (Integer) radiusSpinner.getValue();
layout.setRadiusStep(radius);
panel.revalidate();
}
});
JPanel buttons = new JPanel();
buttons.add(new JLabel("Radius step:"));
buttons.add(radiusSpinner);
buttons.add(new JLabel("Angle step"));
buttons.add(angleSpinner);
for(int i = 1; i <= 25; i++) {
panel.add(new JLabel("Label " + i));
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(buttons, BorderLayout.PAGE_START);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}

Categories

Resources