I have been studying java for a couple of months and decided to file a sea battle where the playing field is a panel with 10x10 buttons. Tell me how to make such a panel inactive with inactive buttons for the duration of one of the players

    2 answers 2

    I think there are the following ways to solve the problem (in order of complexity):

    1. In the loop, call all the necessary buttons setEnabled . Buttons can be stored in a collection or an array, or placed in a separate container ( JPanel , for example) and use its Component[] Container.getComponents() method.
    2. Decorate the playing field (panel with buttons) using JLayer and intercept mouse and keyboard events in it. This will allow something to draw on top of the blocked playing field. If you want to place other swing components on top, you can use JLayeredPane instead of JLayeredPane ( my example to another question).
    3. Abandon buttons and draw the playing field yourself. You will need to handle mouse events, etc.

    An example of the implementation of the first two methods with comments in the code:

     import java.awt.*; import java.awt.event.*; import java.awt.geom.Rectangle2D; import javax.swing.*; import javax.swing.plaf.LayerUI; public class SwingDisableButtons { // т.к. примера два, общая часть (создание кнопок и установка слушателей) // вынесена в абстрактный класс. static abstract class GamePanel extends JPanel { static final int GRID_SIZE = 20; public GamePanel() { setLayout( new GridLayout( GRID_SIZE, GRID_SIZE ) ); for ( int row = 0; row < GRID_SIZE; row++ ) { for ( int col = 0; col < GRID_SIZE; col++ ) { JButton btn = new JButton( String.format( "%dx%d", col, row ) ); btn.addActionListener( makeListener( row, col ) ); add( btn ); } } } ActionListener makeListener( int row, int col ) { return event -> onButtonClick( event, row, col ); } void onButtonClick( ActionEvent event, int row, int col ) { System.out.printf( "button at r: %d, c: %d click.%n", row, col ); } /** * Устанавливает доступность игрового поля. * * @param enabled */ public abstract void setFieldEnabled( boolean enabled ); /** * Возвращает компонент для установки в интерфейс * * @return */ // это не обязательно, но поскольку я запихал JLayer внутрь следующего класса, // то его надо будет отдавать наружу, для вставки во фрейм public abstract JComponent getUi(); } static class GamePanelWithSetEnabled extends GamePanel { @Override public void setFieldEnabled(boolean enabled) { RepaintManager manager = RepaintManager.currentManager( this ); // getComponents() возвращает все дочерние компоненты этой панели. // поскольку на ней одни кнопки, то можно включать/выключать все подряд for ( Component c : getComponents() ) { c.setEnabled( enabled ); // использование RepaintManager позволяет избежать эффекта // постепенного отключения // вызов сообщает менеджеру, что компонент перерисовывать не надо manager.markCompletelyClean( (JComponent)c ); } // запрашиваем перерисовку для всей панели разом repaint(); } @Override public JComponent getUi() { return this; } } static class GamePanelWithJLayer extends GamePanel { // класс оверлея, который будет рисоваться поверх нашей кнопочной панели // и заодно перехватывать события мыши и клавиатуры, когда активен. static class OverlayUi<V extends Component> extends LayerUI<V> { // признак видимости оверлея private boolean visible = false; private JLayer<?> layer; public void setVisible( boolean visible ) { this.visible = visible; if (layer != null) layer.repaint(); } // перехватчик событий @Override public void eventDispatched(AWTEvent e, JLayer<? extends V> l) { if ( visible ) { // если оверлей виден, не пропускаем пришедшее событие к панели if (e instanceof InputEvent) { ((InputEvent) e).consume(); } } else { super.eventDispatched(e, l); } } @Override public void installUI( JComponent c ) { super.installUI(c); layer = (JLayer<?>) c; // задаем маску событий, которые оверлей должен перехватывать layer.setLayerEventMask( AWTEvent.MOUSE_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK ); } // отрисовка оверлея. Заливает все полупрозрачным серым // и выводит поверх надпись "Ждите..." // В официальной обучалке показаны более интересные вещи, например // размытие: http://docs.oracle.com/javase/tutorial/uiswing/misc/jlayer.html#drawing // (см. BlurLayerUI) @Override public void paint( Graphics g, JComponent c ) { super.paint( g, c ); if ( !visible ) return; Graphics2D g2d = (Graphics2D)g.create(); g2d.setColor( new Color( 0.5f, 0.5f, 0.5f, 0.5f ) ); g2d.fillRect( 0, 0, c.getWidth(), c.getHeight() ); g2d.setFont( c.getFont().deriveFont( 20f ) ); g2d.setColor( Color.ORANGE ); String text = "Ждите..."; Rectangle2D stringBounds = g2d.getFontMetrics().getStringBounds( text, g2d ); double x = (c.getWidth() - stringBounds.getWidth())/2; double y = (c.getHeight() - stringBounds.getHeight())/2; g2d.drawString( text, (float)x, (float)y ); g2d.dispose(); } } @Override public void setFieldEnabled(boolean enabled) { if ( myJLayer != null ) { myOverlayUi.setVisible( !enabled ); } } JLayer<GamePanelWithJLayer> myJLayer; OverlayUi<GamePanelWithJLayer> myOverlayUi; // нужно вернуть JLayer для вставки во фрейм @Override public JLayer<GamePanelWithJLayer> getUi() { if ( myJLayer == null ) { myOverlayUi = new OverlayUi<>(); myJLayer = new JLayer<>( this, myOverlayUi ); } return myJLayer; } } static void initUi() { JFrame frame = new JFrame( "test" ); frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE ); // на выбор: GamePanel gamePanel = new GamePanelWithSetEnabled(); //GamePanel gamePanel = new GamePanelWithJLayer(); JPanel content = new JPanel( new BorderLayout() ); content.add( gamePanel.getUi(), BorderLayout.CENTER ); JButton button = new JButton( "click me!" ); button.addActionListener( new ActionListener() { boolean enabled = true; @Override public void actionPerformed(ActionEvent e) { enabled = !enabled; gamePanel.setFieldEnabled( enabled ); } }); content.add( button, BorderLayout.SOUTH ); frame.setContentPane( content ); frame.pack(); frame.setVisible( true ); } public static void main(String[] args) { SwingUtilities.invokeLater( SwingDisableButtons::initUi ); } } 
    • wow, this is the answer =) thank you very much! Thank you all - Void

    https://stackoverflow.com/a/1625878

     JButton startButton = new JButton("Start"); startButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { startButton.setEnabled(false); stopButton.setEnabled(true); } } ); 
    • Thanks for the answer. As I understand it, you will have to specify the setEnabled () = method for each of the hundred buttons. I wanted something more elegant - Emptiness
    • @ Void if the buttons do not change the appearance, then you can make somewhere available a variable that determines whose course, and when you click on the button, check the validity of the action. - AivanF.
    • one
      Please try to write more detailed answers. I am sure the author of the question was grateful for your comment. - Nicolas Chabanovsky