Примечание: Возможно, вам придется скомпилировать и запустить мой пример, чтобы полностью понять мой вопрос. Если это не кошерно, заранее прошу прощения.
Я пытаюсь создать элемент управления Swing на основе JToggleButton
и JPopupMenu
.
Кнопка переключения выбирается тогда, когда всплывающее меню видно, а кнопка переключения отменяется, если всплывающее меню не отображается. Таким образом, поведение аналогично JComboBox
, за исключением того, что всплывающее окно может содержать произвольные компоненты.
Следующий код является примером того, как я мог бы создать элемент управления (за исключением того, что он был бы в своем собственном классе ... что-то вроде JPopupToggleButton
). К сожалению, он демонстрирует различное поведение при различном внешнем виде и ощущениях (я проверил это с Metal и Nimbus).
Код, размещенный здесь, ведет себя как положено в Metal, но не в Nimbus. При использовании Nimbus просто показывайте и скрывайте всплывающее окно, несколько раз нажимая кнопку переключения, и вы поймете, что я имею в виду.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
public class PopupButtonExample extends JFrame
{
public static void main( String[] args )
{
java.awt.EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
PopupButtonExample example = new PopupButtonExample();
example.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
example.setVisible( true );
}
});
}
public PopupButtonExample()
{
super( "Components in Popup" );
JPanel popupPanel = new JPanel();
popupPanel.setLayout( new BorderLayout() );
popupPanel.add( new JLabel( "This popup has components" ),
BorderLayout.NORTH );
popupPanel.add( new JTextArea( "Some text", 15, 20 ),
BorderLayout.CENTER );
popupPanel.add( new JSlider(), BorderLayout.SOUTH );
final JPopupMenu popupMenu = new JPopupMenu();
popupMenu.add( popupPanel );
final JToggleButton popupButton = new JToggleButton( "Show Popup" );
popupButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
if( popupButton.isSelected() )
popupMenu.show( popupButton, 0, popupButton.getHeight() );
}
});
popupMenu.addPopupMenuListener( new PopupMenuListener()
{
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {}
@Override
public void popupMenuCanceled(PopupMenuEvent pme) {}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
Point componentLoc = popupButton.getLocationOnScreen();
mouseLoc.x -= componentLoc.x;
mouseLoc.y -= componentLoc.y;
if( !popupButton.contains( mouseLoc ) )
popupButton.setSelected( false );
}
});
JPanel toolBarPanel = new JPanel();
toolBarPanel.add( popupButton );
JToolBar toolBar = new JToolBar();
toolBar.add( toolBarPanel );
setLayout( new BorderLayout() );
add( toolBar, BorderLayout.PAGE_START );
setPreferredSize( new Dimension( 640, 480 ) );
pack();
}
}
Комментирование следующих строк заставляет код вести себя, как и ожидалось, в Nimbus, но не в Metal. Опять же, просто продолжайте нажимать кнопку переключения, чтобы понять, что я имею в виду.
// Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
// Point componentLoc = popupButton.getLocationOnScreen();
// mouseLoc.x -= componentLoc.x;
// mouseLoc.y -= componentLoc.y;
// if( !popupButton.contains( mouseLoc ) )
Итак, вот мои два вопроса:
(1) Почему в Nimbus щелчок, скрывающий всплывающую панель, не передается кнопке переключения, как в случае с металлом?
(2) Как я могу решить эту проблему, чтобы она работала со всем внешним видом и ощущениями?