Как переключать вкладки с кнопки, размещенной в другом классе / пакете?

#java #swing #oop

#java #swing #ооп

Вопрос:

Я хочу спросить, есть ли возможный способ переключения панелей вкладок одним нажатием кнопки в другом классе. У меня есть 2 класса, и classA он находится в пакете по умолчанию, а другой — в другом пакете. Моя кнопка помещена, classB а мои панели с вкладками находятся внутри classA .

Как я могу изменить вкладки, нажав кнопку в моем classB ?

Если передача переменных не будет работать между пакетом по умолчанию и другим пакетом, все в порядке, я просто добавлю classB тот же пакет, чтобы было легче получить доступ к переменным classA .

** РЕДАКТИРОВАТЬ **

Хорошо, я сделал короткую версию своего кода, и это результат:

Test.java

   package test;

  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import javax.swing.*;
  import btn.button;

public class Test {

JFrame frame = new JFrame();
JTabbedPane tabpane = new JTabbedPane();
JPanel panel1 = new JPanel();
GridBagConstraints c = new GridBagConstraints();
final static boolean shouldFill = true;
GridBagLayout grid = new GridBagLayout();

public Test() {
    // TODO code application logic here

   // public button switch;

    frame.setVisible(true);
    frame.setSize(821,421);


    final Toolkit toolkit = Toolkit.getDefaultToolkit();
    Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();      
int x=(int)((dimension.getWidth() - frame.getWidth())/2);
int y=(int)((dimension.getHeight() - frame.getHeight())/2);

    frame.setLocation(x, y);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

     JPanel container = new JPanel();
     container.setLayout(new BorderLayout());
     container.setBackground(new Color(0,128,0));

tabpane = new JTabbedPane(); //Tab Pane
tabpane.setBackground(new Color(0,128,0));
tabpane.setSize(801,351);       


JPanel jp1 = new JPanel(); // First Tab Panel
jp1.setBackground(new Color(0,128,0));
jp1.setLayout(grid);

    JButton popout = new JButton("MORE");
    popout.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        button button = new button();     
        }
    });
    jp1.add(popout);

JPanel jp2 = new JPanel(); // Second Tab Panel
jp2.setBackground(new Color(0,128,0));
jp2.setLayout(grid);

    JPanel jp3 = new JPanel(); // Third Tab Panel
jp3.setBackground(new Color(0,128,0));
jp3.setLayout(grid);

    tabpane.addTab("Tab 1", jp1);
    //add selectedIndex here (1);
    tabpane.addTab("Tab 2", jp2);
    //add selectedIndex here (2);
    tabpane.addTab("Tab 3", jp3);
    //add selectedIndex here (3);

    frame.add(container);
    container.add(tabpane, BorderLayout.NORTH);

}

 public static void main(String[] args){
     //Use the event dispatch thread for Swing components
 EventQueue.invokeLater(new Runnable()
 {
    @Override
     public void run()
     {
         new Test();         
     }
 });

 }
}
  

button.java

  package btn;

import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class button {
 JFrame frame2 = new JFrame();
 GridBagLayout grid = new GridBagLayout();      

 public button(){

         frame2.setVisible(true);
         frame2.setSize(200,200);

         JPanel jp = new JPanel(); // First Tab Panel
         jp.setBackground(new Color(0,128,0));
         jp.setLayout(grid);

         JButton btn = new JButton("SWITCH TO PANEL 2");
         btn.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
        //what should i put here???
        }
    });

         jp.add(btn);

         frame2.add(jp);
 }
}
  

Я знаю, что мне не хватает заданного выбранного индекса для каждой вкладки, но я не знаю, как это повторить, потому что в моем проекте эти вкладки находятся в отдельном файле Java. Поэтому, чтобы сократить его, я сделал это в одном файле Java. Так что да. Как вы можете видеть, у меня есть кнопка «Еще», а затем кнопка переключения для вкладки 2. Мой вопрос в том, как я могу переключиться на панель 2, нажав кнопку во всплывающем окне?

Комментарии:

1. да, это возможно в текущей JVM, с помощью CardLayout или программно

2. «.. все в порядке, я просто помещу ClassB в тот же пакет» Класс A не должен быть в пакете по умолчанию, поэтому вместо этого переместите его в пакет of ClassB (или другой пакет). Могут ли они обращаться друг к другу, тогда зависит от а) содержат ли они ссылку на другой класс б) модификаторов доступа к любым методам или атрибутам, объявленным другим классом.

3. "i dont think cardlayout will work on panels on different classes." — Извините, но это просто безумный разговор. Если вы делаете подобные заявления, это означает, что вы пытаетесь создать Swing GUI до изучения основ Java, поскольку любой, кто хорошо разбирается в основах, знает, что это просто неправда. Пожалуйста, сделайте себе одолжение и прочитайте хорошую книгу по Java и ООП, поскольку это очень поможет вам во всех аспектах вашего кодирования, так же, как это помогло мне.

4. Тогда вы понимаете, что CardLayout является подходящим и, вероятно, лучшим решением. Лучше всего попытаться использовать его, и если это не сработает, попробуйте отладить свою попытку.

5. @AndrewThompson «Совет: сделайте 2 отдельных комментария. 😉 » да, я это сделал. Спасибо! Я прочитаю предоставленную вами ссылку.

Ответ №1:

Что вам нужно сделать, это передать ссылку на объект из исходного класса (здесь Test ) в класс, который должен изменить состояние тестируемого объекта, и под состоянием я подразумеваю, которое показывает JTabbedPane, но конкретное состояние не имеет значения. Опять же, важна передача ссылок и предоставление тестовых общедоступных методов, которые второй класс может вызывать для изменения состояния. Например:

 import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

//!! import btn.button;

public class Test {

   private JFrame frame = new JFrame();
   private JTabbedPane tabpane = new JTabbedPane();
   private JPanel panel1 = new JPanel();
   private GridBagConstraints c = new GridBagConstraints();
   private final static boolean SHOULD_FILL = true;
   private GridBagLayout grid = new GridBagLayout();

   public Test() {

      frame.setVisible(true);
      frame.setSize(821, 421);

      final Toolkit toolkit = Toolkit.getDefaultToolkit();
      Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
      int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
      int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);

      frame.setLocation(x, y);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      JPanel container = new JPanel();
      container.setLayout(new BorderLayout());
      container.setBackground(new Color(0, 128, 0));

      tabpane = new JTabbedPane(); // Tab Pane
      tabpane.setBackground(new Color(0, 128, 0));
      tabpane.setSize(801, 351);

      JPanel jp1 = new JPanel(); // First Tab Panel
      jp1.setBackground(new Color(0, 128, 0));
      jp1.setLayout(grid);

      JButton popout = new JButton("MORE");
      popout.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            //!! HisTestButton button = new HisTestButton();

            new HisTestButton(Test.this); //!! passing in this
         }
      });
      jp1.add(popout);

      JPanel jp2 = new JPanel(); // Second Tab Panel
      jp2.setBackground(new Color(0, 128, 0));
      jp2.setLayout(grid);

      JPanel jp3 = new JPanel(); // Third Tab Panel
      jp3.setBackground(new Color(0, 128, 0));
      jp3.setLayout(grid);

      tabpane.addTab("Tab 1", jp1);
      // add selectedIndex here (1);
      tabpane.addTab("Tab 2", jp2);
      // add selectedIndex here (2);
      tabpane.addTab("Tab 3", jp3);
      // add selectedIndex here (3);

      frame.add(container);
      container.add(tabpane, BorderLayout.NORTH);

   }

   // !! public method that other classes can call to change tab
   public void openNextTab() {
      int selectedIndex = tabpane.getSelectedIndex();
      selectedIndex  ;
      selectedIndex %= tabpane.getTabCount();
      tabpane.setSelectedIndex(selectedIndex);
   }

   //!! needed by JDialog
   public JFrame getFrame() {
      return frame;
   }

   public static void main(String[] args) {
      // Use the event dispatch thread for Swing components
      EventQueue.invokeLater(new Runnable() {
         @Override
         public void run() {
            new Test();
         }
      });

   }
}

class HisTestButton {
   protected static final int PREF_W = 200;
   protected static final int PREF_H = 200;
   JDialog dialog; // !! make this a JDialog
   GridBagLayout grid = new GridBagLayout();
   private Test test;  //!! add field

   //!! changed constructor parameter
   public HisTestButton(final Test test) {
      this.test = test; // !! set field

      // !! create our JDialog. Going to make it non-modal 
      dialog = new JDialog(test.getFrame(), "MyDialog", ModalityType.MODELESS);

      //!! frame2.setVisible(true);
      // !! frame2.setSize(200, 200); // never set visible til after components added

      JPanel jp = new JPanel() {
         @Override
         public Dimension getPreferredSize() {
            return new Dimension(PREF_W, PREF_H);
         }
      };
      jp.setBackground(new Color(0, 128, 0));
      jp.setLayout(grid);

      JButton btn = new JButton("SWITCH TO PANEL 2");
      btn.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            //!! 
            test.openNextTab();
         }
      });

      jp.add(btn);

      dialog.add(jp);

      // !! added
      dialog.pack();
      dialog.setVisible(true);
   }
}
  

Ключевым моментом здесь является то, что я дал второму классу тестовое поле, а затем изменил конструктор 2-го класса, чтобы разрешить передачу в него объекта тестового класса:

 class HisTestButton {
   protected static final int PREF_W = 200;
   protected static final int PREF_H = 200;
   JDialog dialog; // !! make this a JDialog
   GridBagLayout grid = new GridBagLayout();
   private Test test;  //!! add field   ****************

   //!! changed constructor parameter
   public HisTestButton(final Test test) { // *****
      this.test = test; // !! set field
  

Я дал тестовые общедоступные методы, которые можно вызвать:

 // !! public method that other classes can call to change tab
public void openNextTab() {
  int selectedIndex = tabpane.getSelectedIndex();
  selectedIndex  ;
  selectedIndex %= tabpane.getTabCount();
  tabpane.setSelectedIndex(selectedIndex);
}

//!! needed by JDialog constructor
public JFrame getFrame() {
  return frame;
}
  

И при создании второго класса я передаю текущий экземпляр Test , Test.this потому что он находится во внутреннем классе, в конструктор второго класса:

      public void actionPerformed(ActionEvent e) {
        //!! HisTestButton button = new HisTestButton();

        new HisTestButton(Test.this); //!! passing in this
     }
  

Теперь второй класс может вызывать методы тестовых объектов:

      @Override
     public void actionPerformed(ActionEvent e) {
        //!! 
        test.openNextTab();
     }
  

Обратите внимание, что вы можете использовать CardLayout точно так же, снова вызывая общедоступные методы одного класса другим, если у 2-го класса есть жизнеспособная ссылка на текущий отображаемый экземпляр первого класса. Получение дескриптора правильных ссылок, как всегда, является ключевым.


Также обратите внимание, что все ваши классы в пакете по умолчанию должны быть размещены в пакетах, либо в существующих пакетах, либо в новых пакетах, в зависимости от того, что имеет больше смысла, и в зависимости от того, что объединяет подобное с подобным. Единственными классами, которые входят в пакет по умолчанию, являются классы toy, которые не требуют взаимодействия с другими классами.

Комментарии:

1. Привет @ Судно на воздушной подушке, полное угрей! Я так рад, что вы нашли время, чтобы помочь мне с моей проблемой. Можно ли это также сделать в разных пакетах?