Thank you for the reply. I managed to figure out a way around the issue (after trying 4 or 5 different ways to get around it that didn't work) that I am seeing but to be honest I really don't like how I had to do it. I ended up having to check which method was actually calling the getPreferredSize() method. This is because the adjustPopupLocationToFitScreen call in JPopupMenu calls getPreferredSize() which is always the maximum size of the popup. These methods or parts of them are not accessible so I couldn't simply override them. When I tried to just change the preferred size to be the scrollable size the menu turned out to have tiny wording in it so that didn't work directly. Code wise what I did is extend JidePopupMenu and override the getPreferredScrollableViewportSize() in JidePopupMenu to add storing the calculated scrollableViewportSize. I also overrode the getPreferredSize() call so that it would return the scrollableViewportSize if the adjustPopupLocationToFitScreen is the calling method (this is the part that is really bad coding).
One thing to note is that the first time I clicked the popup the container was null so it used the preferred size. I had to call menu.show(e.getComponent(), e.getX(), e.getY()) twice to get it to work properly on the first click
I have added the code below in case others find themselves in the same predicament but it is with the caveat that this is a horrible way to get around the problem. It would be great if someone were to come up with a better solution that didn't rely on hacky code.
- Code: Select all
/**
Copyright
********************************************************************************
* PROGRAM: WIN-T
*
* EXPORT CONTROL LABEL: U.S. Export Controlled Information: Information
* included herein is controlled under the
* International Traffic in Arms Regulations (ITAR)
* by the U.S. Department of State. Transfer of this
* information to a foreign person or foreign entity
* requires an export license by the U.S. State
* Department or an ITAR exemption to the license
* requirement prior to the export or transfer.
*
* COPYRIGHT: COPYRIGHT 2001 GENERAL DYNAMICS
* ALL RIGHTS RESERVED
*
* GOVERNMENT PURPOSE RIGHTS: This document contains information exempt from
* mandatory disclosure under FOIA. Exemption 1
* applies. This document contains technical data that
* are provided with restrictions in accordance with
* paragraph (b)(3) of the Rights in Technical Data
* - Noncommercial Items clause of Contract
* DAAB07-02-C-F404. These restrictions apply to
* technical data conspicuously marked with a Limited
* Rights legend consistent with the following:
*
* Limited Rights
* Contract No: DAAB07-02-C-F404
* Contractor Name: General Dynamics C4 Systems
* Contractor Address: 400 John Quincy Adams Road,
* Taunton, MA, 02780-1069
*
* The Government’s rights to use, modify, reproduce,
* release, perform, display, or disclose these
* technical data are restricted by paragraph (b)(3)
* of the Rights in Technical Data – Noncommerical
* Items clause contained in the above identified
* contract. Any reproduction of technical data or
* portions thereof marked with this legend must
* also reproduce the markings. Any person other
* than the Government, who has been provided access
* to such data, must promptly notify the above named
* Contractor.
***************************************************************************
*/
package demo;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import com.jidesoft.swing.JideMenu;
import com.jidesoft.swing.JidePopupMenu;
import com.jidesoft.swing.SimpleScrollPane;
import com.jidesoft.utils.PortingUtils;
/**
* Test class to show issue with Y location for popup getting set to zero.
* For large numbers of menu items, when setting the visible menu item count the menu itself sizes properly
* but the Y coordinate for where it gets shown is pushed to the top of the screen (Y location = 0)
*/
public class JidePopupMenuTestForForum extends JFrame
{
/* create the menu */
private JidePopupMenu menu;
/**
* Constructor
*/
public JidePopupMenuTestForForum()
{
menu = new MyJidePopupMenu();
/* make it so that more than 15 items will add the scroll processing */
menu.setVisibleMenuItemCount(15);
/* create the menus and submenus */
for (int i = 1; i < 100; i++) {
JideMenu menuItem = new JideMenu("Menu " + i);
for (int j = 1; j < 10; j++) {
menuItem.add(new JMenuItem("Submenu " + j));
}
menu.add(menuItem);
}
/* add a panel the frame */
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
/* add a label to the panel */
JLabel label = new JLabel("Right click to get a popup");
panel.add(label);
/* add a mouse listener to handle the right click */
addMouseListener(new MouseAdapter(){
/* (non-Javadoc)
* @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
*/
@Override
public void mouseReleased(MouseEvent e)
{
if (e.isPopupTrigger()) {
menu.show(e.getComponent(), e.getX(), e.getY());
/* need to call show a second time because the first time through the
* getPreferredScrollableViewportSize in JidePopupMenu the container is
* null which means the (container instanceof SimpleScrollPane) call is
* false. This has the effect of just returning the preferredSize the first
* time through. I would prefer to not have to call it twice since this is
* bad practice but the second time through the container is set properly */
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
});
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300, 100);
this.setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args)
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
new JidePopupMenuTestForForum();
}
/**
* Extended version of the JidePopupMenu. This is a REALLY bad way to do this but I didn't have access
* in the base classes (e.g. JPopupMenu had package access and couldn't override) to change some of the
* items that would need to be changed in order to fix it properly
*/
public class MyJidePopupMenu extends JidePopupMenu
{
private Dimension scrollableViewportSize = null;
@Override
public Dimension getPreferredScrollableViewportSize()
{
Dimension size = getPreferredSize();
Dimension screenSize = PortingUtils.getLocalScreenSize(this);
Container container = SwingUtilities.getAncestorOfClass(SimpleScrollPane.class, this);
if (container instanceof SimpleScrollPane) {
SimpleScrollPane scrollPane = (SimpleScrollPane) container;
int height = screenSize.height;
// limit it to the height determined by the visible menu item count
if (getVisibleMenuItemCount() > 0) {
int totalHeight = getVisibleMenuItemCount() * getScrollableUnitIncrement(null, 0, 0);
if (height > totalHeight) {
height = totalHeight;
}
}
size.height = Math.min(size.height, height - scrollPane.getScrollUpButton().getPreferredSize().height
- scrollPane.getScrollDownButton().getPreferredSize().height);
scrollableViewportSize = size;
}
return size;
}
@Override
public Dimension getPreferredSize()
{
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
StackTraceElement element = stackTrace[2];
/* it is a VERY BAD PRACTICE to look at what method is calling this method but
* the adjustPopupLocationToFitScreen in JPopupMenu method uses getPreferredSize and if
* the size is too large then it sets the Y-coordinate to 0. In this example, the menu
* was very large but limited by the number of visible items. The adjustPopupLocationToFitScreen
* only looked at the overall size that came back from getPreferredSize and not the smaller
* size that is returned by getPreferredScrollableViewportSize */
if (scrollableViewportSize != null && element.getMethodName().contains("adjustPopupLocationToFitScreen")) {
return scrollableViewportSize;
}
return super.getPreferredSize();
}
}
}
Thank you again
Mike