ListSelectionListener и CardLayout

Я создаю программу, которая считывает данные из файла, отображает их в графическом интерфейсе с JList и JButtons. Я пытаюсь написать его с помощью CardLayout, чтобы соответствующая JPanel могла отображаться при выборе элемента из JList или нажатии JButton (т.е. следующего, предыдущего, первого и последнего). Я могу успешно читать из файла и отображать данные в графическом интерфейсе. Я столкнулся с двумя проблемами, и я пытался найти ответы в Интернете, но, похоже, не могу понять это: 1) Как мне заставить JPanels переключаться с помощью CardLayout? 2) Как мне получить данные, которые будут отображаться в графическом интерфейсе в текстовых полях, когда пользователь щелкает элемент из JList? JList действительно появляется, и мой ListSelectionListener работает, потому что, когда я нажимаю на определенный элемент, он печатается на консоли (в качестве теста).

Если я закомментирую все JPanels, кроме 1, то он отображается правильно, но когда я помещаю их все, то он не переключается.

Пока у меня есть это для моего ListSelectionListener (как внутренний класс):

public class CancerSelectionListener implements ListSelectionListener {

    @Override
    public void valueChanged(ListSelectionEvent e) {
       Integer selection = (Integer)(((JList) e.getSource()).getSelectedIndex());
       if(selection == 0) {
           System.out.println("blah"); // works
           // switch to the corresponding JPanel in CardLayout 
       }

    }   
}

String[] tester;
    String teste;

    listModel = new DefaultListModel();

    for(int i = 0; i < 36; i++) {

        tester = _controller.readCancer(i); // reads from the file, this part works!
        teste = tester[0];

        listModel.addElement(teste);

    }

    cancerList = new JList(listModel);
    cancerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    cancerList.setSelectedIndex(-1);
    cancerList.setVisibleRowCount(5);

    cancerListScroller = new JScrollPane(cancerList);

    CardLayout myCardLayout;
    myCardLayout = new CardLayout();
    mainPanel2.setLayout(myCardLayout);

    myCardLayout.show(mainPanel2, "test");

    CancerPanels.aplPanel apl = new CancerPanels.aplPanel();
    CancerPanels.fcPanels fc = new CancerPanels.fcPanels();
    CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
    CancerPanels.pdgPanels pdg = new CancerPanels.pdgPanels();
    CancerPanels.cebpaPanels cebpa = new CancerPanels.cebpaPanels();


    mainPanel2.add(apl.aplReturn(), "test");
    mainPanel2.add(fc.fcReturn());
    mainPanel2.add(vhls.vhlsReturn());
    mainPanel2.add(pdg.pdgReturn());
    mainPanel2.add(cebpa.cebpaReturn()); 
    // I have 37 JPanels that are placed in the JPanel that uses CardLayout but I didn't post all    of them as it would take up lots of space

Данные для каждой панели JPanel заполняются из статических внутренних классов в классе CancerPanels (отображается только 1, так как каждый из них очень длинный!)

public class CancerPanels extends CancerGUI {

static JPanel cards;
static CancerController _cons = new CancerController();
static String[] cancerData;
static JScrollPane treatmentsScroller = new JScrollPane(txtTreatments,   JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

static JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

public static class aplPanel extends JPanel {

    public JPanel aplReturn() {
        treatmentsScroller.setViewportView(txtTreatments);
        txtTreatments.setEditable(false);
        causesScroller.setViewportView(txtCauses);
        txtCauses.setEditable(false);
        symptomsScroller.setViewportView(txtSymptoms);
        txtSymptoms.setEditable(false);
        cards = new JPanel(new GridLayout(6,1));
        cancerData = _cons.readCancer(0);
        resultName.setText(cancerData[0]);
        txtSymptoms.setText(cancerData[1]);
        txtCauses.setText(cancerData[2]);
        txtTreatments.setText(cancerData[3]);
        resultRate.setText(cancerData[4]);
        resultPrognosis.setText(cancerData[5]);
        cards.add(resultName);
        cards.add(symptomsScroller);
        cards.add(causesScroller);
        cards.add(treatmentsScroller);
        cards.add(resultRate);
        cards.add(resultPrognosis); 
        return cards;
    }
}

Редактировать:

Вот моя последняя попытка. Я могу прокручивать JList, но он не отображает правильно соответствующую JPanel (на самом деле он ничего не отображает, за исключением случаев, когда я нажимаю последнюю кнопку, я не знаю, почему эта кнопка работает). Мне удалось разместить ItemListener в JComboBox, но в конечном итоге я хочу, чтобы CardLayout работал. Наш инструктор предоставил нам пример кода для использования, но когда я пытаюсь его использовать, панели JPanel не переключаются (а если и переключаются, то скрыты, не знаю почему).

Каждый из моих слушателей является общедоступными внутренними классами в общем классе CancerGUI.

public CancerGUI() {
    CancerPanels.aplPanel apl = new CancerPanels.aplPanel();
    CancerPanels.fcPanels fc = new CancerPanels.fcPanels();
    CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
    // more than 30 JPanels that I add to the JPanel that uses CardLayout, so I only posted 3
    // each of them uses the GridLayout

mainPanel2 = new JPanel(new CardLayout());

    mainPanel2.add(apl.aplReturn(), "1");
    mainPanel2.add(fc.fcReturn(), "2");
    mainPanel2.add(vhls.vhlsReturn(), "3");

CancerActionButtons _cab = new CancerActionButtons();

   btnNext = new JButton("Next");
    btnPrevious = new JButton("Previous");
    btnFirst = new JButton("First");
    btnLast = new JButton("Last");
    btnClear = new JButton("Clear");

   btnNext.addActionListener(_cab);
   btnPrevious.addActionListener(_cab);

    btnFirst.addActionListener(_cab);
    btnLast.addActionListener(_cab);

CancerItemListener _item = new CancerItemListener(); // this listener works!
    renalC.addItemListener(_item);
    skinC.addItemListener(_item);
    brainC.addItemListener(_item);
    bladderC.addItemListener(_item);
    ovarianC.addItemListener(_item);
    pancC.addItemListener(_item);
    breastC.addItemListener(_item);

String[] tester;
    String teste;

    listModel = new DefaultListModel();

    for(int i = 0; i < 36; i++) {

        tester = _controller.readCancer(i);
        teste = tester[0];

        listModel.addElement(teste);

    }

    cancerList = new JList(listModel);
    cancerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    cancerList.setSelectedIndex(-1);
    cancerList.setVisibleRowCount(5);
    cancerListScroller = new JScrollPane(cancerList);
    ListSelection _list = new ListSelection();
    cancerList.addListSelectionListener(_list);

    JScrollPane treatmentsScroller = new JScrollPane(txtTreatments, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    treatmentsScroller.setViewportView(txtTreatments);
    JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    causesScroller.setViewportView(txtCauses);
    JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    symptomsScroller.setViewportView(txtSymptoms);

public class ListSelection implements ListSelectionListener {

    @Override
    public void valueChanged(ListSelectionEvent e) {
        String selection = (String)(((JList)e.getSource()).getSelectedValue());
        ((CardLayout) mainPanel2.getLayout()).show(mainPanel2, selection);
        ((CardLayout) mainPanel2.getLayout()).show(mainPanel2, selection);
    }

}

public class CancerActionButtons implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        switch(e.getActionCommand()) {
            case "First":
                ((CardLayout) mainPanel2.getLayout()).first(mainPanel2);    
            cancerCount = 1;                                            
                break;
            case "Last":
                ((CardLayout) mainPanel2.getLayout()).last(mainPanel2);
            cancerCount = 11;
                break;
            case "Previous":
                ((CardLayout) mainPanel2.getLayout()).previous(mainPanel2);
            cancerCount--;
            cancerCount = cancerCount < 1 ? 11 : cancerCount;
                break;
            case "Next":
                ((CardLayout) mainPanel2.getLayout()).next(mainPanel2);
            cancerCount++;
            cancerCount = cancerCount > 11 ? 1 : cancerCount;      //
                break;
        }
        cancerList.setSelectedIndex(cancerCount-1);
    }

}

/**
 * Inner class that responds to any user interaction with a JComboBox for 
 * general types of cancers. 
 */

public class CancerItemListener implements ItemListener {

    @Override
    public void itemStateChanged(ItemEvent e) {
        JPanel showPanel = new JPanel();
        if(e.getStateChange() == ItemEvent.SELECTED) {
            String selection = (String) e.getItem();
            if(selection.equalsIgnoreCase("skin cancer")) {
                CancerPanels.skin skin = new CancerPanels.skin();
                showPanel = skin.skinReturn(); 
            } else if (selection.equalsIgnoreCase("bladder cancer")) {
                CancerPanels.bladder bladder = new CancerPanels.bladder();
                showPanel = bladder.bladderReturn();
            } else if (selection.equalsIgnoreCase("pancreatic cancer")) {
                CancerPanels.pancreatic pancreatic = new CancerPanels.pancreatic();
                showPanel = pancreatic.returnPancreatic();
            } else if (selection.equalsIgnoreCase("renal cancer")) {
                CancerPanels.renal renal = new CancerPanels.renal();
                showPanel = renal.returnRenal();
            } else if (selection.equalsIgnoreCase("ovarian cancer")) {
                CancerPanels.ovarian ovarian = new CancerPanels.ovarian();
                showPanel = ovarian.ovarianReturn();
            } else if (selection.equalsIgnoreCase("breast cancer")) {
                CancerPanels.breast breast = new CancerPanels.breast();
                showPanel = breast.returnBreast();
            } else if (selection.equalsIgnoreCase("brain cancer")) {
                CancerPanels.brain brain = new CancerPanels.brain();
                showPanel = brain.returnBrain();  
            } else if (selection.equalsIgnoreCase("von hippel-lindau syndrome")) {
                CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
                showPanel = vhls.vhlsReturn();
            }
            JOptionPane.showMessageDialog(null, showPanel);
        }
    }
}        

Отдельный класс, в котором создаются панели JPanel перед добавлением в CardLayout:

public class CancerPanels extends CancerGUI {

static String name;
static JPanel cards;
static CancerController _cons = new CancerController();
static String[] cancerData;
static JScrollPane treatmentsScroller = new JScrollPane(txtTreatments, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

static JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

public static class aplPanel extends JPanel {

    public JPanel aplReturn() {
        treatmentsScroller.setViewportView(txtTreatments);
        txtTreatments.setEditable(false);
        causesScroller.setViewportView(txtCauses);
        txtCauses.setEditable(false);
        symptomsScroller.setViewportView(txtSymptoms);
        txtSymptoms.setEditable(false);
        cards = new JPanel(new GridLayout(6,1));
        cancerData = _cons.readCancer(0);
        resultName.setText(cancerData[0]);
        txtSymptoms.setText(cancerData[1]);
        txtCauses.setText(cancerData[2]);
        txtTreatments.setText(cancerData[3]);
        resultRate.setText(cancerData[4]);
        resultPrognosis.setText(cancerData[5]);
        cards.add(resultName);
        cards.add(symptomsScroller);
        cards.add(causesScroller);
        cards.add(treatmentsScroller);
        cards.add(resultRate);
        cards.add(resultPrognosis); 
        return cards;
    }

person Cucko Oooo    schedule 19.04.2013    source источник
comment
Чтобы быстрее получить помощь, опубликуйте SSCCE. У меня есть 37 панелей JPanel, которые размещены в панели JPanel, использующей CardLayout. Проблему можно продемонстрировать, используя всего две панели в SSCCE.   -  person Andrew Thompson    schedule 19.04.2013
comment
Почему CancerPanels расширяет возможности CancerGUI? Это выглядит как плохое использование наследования, и если что-то только испортит ситуацию, я боюсь. Кроме того, поскольку вы не опубликовали код, который упрощает вашу проблему и который компилируется для нас, ваш опубликованный код бесполезен для нас, поскольку он не может дать нам понимание вашей проблемы. Я решительно поддерживаю приведенную выше рекомендацию @AndrewThompson о создании и публикации sscce.   -  person Hovercraft Full Of Eels    schedule 20.04.2013
comment
Привет? Ты здесь?   -  person Hovercraft Full Of Eels    schedule 20.04.2013


Ответы (1)


  • По сути, вы пытаетесь изменить состояние одного класса от другого.
  • То, как это делается с графическим интерфейсом пользователя Swing, ничем не отличается от того, как это делается для программ без графического интерфейса: один класс вызывает общедоступные методы другого класса.
  • Одним из ключевых моментов является наличие проводки, позволяющей этому произойти, что означает, что ссылки для одного класса должны быть доступны для другого класса, чтобы соответствующие методы могли вызываться для соответствующих ссылок. Дьявол, как говорится, кроется в деталях.
  • "1) How do I get the JPanels to switch using CardLayout?" -- Таким образом, класс, содержащий CardLayout, может, например, иметь общедоступные методы, next(), previous() и, возможно, show(SOME_STRING_CONSTANT) или какой-либо другой метод swapView(...).
  • "2) How do I get the data to be displayed in the GUI in text fields when a user clicks an item from the JList?" -- Это будет связано с использованием слушателей -- класс, содержащий JTextFields, будет прослушивать уведомления от класса, содержащего JList, и, получив уведомление, получит необходимую информацию от класса, отображающего список. Здесь может хорошо работать PropertyChangeListener.

e.g.,

public class CancerSelectionListener implements ListSelectionListener {
    private CardDisplayingView cardDisplayingView = null;

    public CancerSelectionListener(CardDisplayingView cardDisplayingView) {
       this.cardDisplayingView = cardDisplayingView;
    }

    @Override
    public void valueChanged(ListSelectionEvent e) {
       int selection = ((JList) e.getSource()).getSelectedIndex();
       if(selection == 0) {
           if (cardDisplayingView != null) {
             cardDisplayingView.swapView(...);
           }
       }

    }   
}
person Hovercraft Full Of Eels    schedule 19.04.2013
comment
Я искал свойстваchangelistener, но не совсем понял, как их можно использовать для моих целей. Кроме того, будут ли они более подходящими по сравнению с ActionListeners и ListSelectionListeners, или как их использовать? Я сделал еще один проход в своем коде и заставил его работать, но он по-прежнему ведет себя странно, не выдавая никаких сообщений об ошибках. Я опубликовал свою последнюю попытку в качестве ответа. - person Cucko Oooo; 19.04.2013