2015-04-21 5 views
1

Я пытаюсь разработать форму гармонического меню. Есть небольшое количество (2-12) опций, которые можно переключать вкл/выкл. При включении появится JPanel с дополнительными настройками, которые станут видимыми. При переключении дополнительные настройки не будут видны.Как решить эти проблемы с размерами с помощью JToggleButtons, JPanels и JScrollPanes?

Я создал SelectableExpandablePanel класс, который расширяет JPanel и реализует ActionListener и ComponentListener. Панель содержит две вещи: JToggleButton и ребенок Component (обычно это JPanel, но я не хочу ограничивать себя для повторного использования этой концепции) в BoxLayout для обеспечения соблюдения одного столбца. Когда выбрана кнопка переключения, ребенок становится видимым. Когда переключатель не выбран, ребенок скрыт.

Когда я использую этот компонент, я намерен разместить его на JPanel внутри JScrollPane, как показано в основном методе образца.

Там, кажется, две проблемы, которые у меня возникают проблемы с преодолением:

  1. Если я не указать JFrame размер, достаточно только большой по ширине каждого ребенка и достаточно высокий для трех кнопок. Когда я нажимаю на кнопку, я ожидаю, что JScrollPane выполнит свою задачу и создаст вертикальную полосу прокрутки. Этого не происходит.

  2. Я бы хотел, чтобы кнопки переключения были полной шириной JPanel, которая их содержит. Я думал, что то, что я сделал в конструкторе плюс Component Listener, обработало бы это, но это не так.

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

import javax.swing.BoxLayout; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JToggleButton; 

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 

public class SelectableExpandablePanel extends JPanel implements 
     ActionListener, ComponentListener { 
    private JToggleButton titleButton; 
    private JComponent childComponent; 

    public SelectableExpandablePanel(JComponent child) { 
     this(child, null, null); 
    } 

    public SelectableExpandablePanel(JComponent child, String title) { 
     this(child, title, null); 
    } 

    public SelectableExpandablePanel(JComponent child, String title, 
      String tooltip) { 
     super(); 

     if (child == null) { 
      throw new IllegalArgumentException("Child component cannot be null"); 
     } 

     childComponent = child; 

     titleButton = new JToggleButton(); 
     titleButton.setText(title); 
     titleButton.addActionListener(this); 
     titleButton.setPreferredSize(new Dimension(getSize().width, titleButton 
       .getPreferredSize().height)); 
     titleButton.setToolTipText(tooltip); 

     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 
     setPreferredSize(new Dimension(childComponent.getPreferredSize().width, 
       titleButton.getPreferredSize().height)); 
     setSize(new Dimension(childComponent.getPreferredSize().width, 
       titleButton.getPreferredSize().height)); 

     add(titleButton); 

     this.addComponentListener(this); 
    } 

    public void actionPerformed(ActionEvent e) { 
     if (titleButton.isSelected()) { 
      add(childComponent); 
      setSize(new Dimension(childComponent.getPreferredSize().width, 
        titleButton.getPreferredSize().height 
          + childComponent.getPreferredSize().height)); 

     } else { 
      remove(childComponent); 
      setSize(new Dimension(childComponent.getPreferredSize().width, 
        titleButton.getPreferredSize().height)); 
     } 

     invalidate(); 
     revalidate(); 
    } 

    public void componentHidden(ComponentEvent arg0) { 
     // Do nothing 
    } 

    public void componentMoved(ComponentEvent arg0) { 
     // Do nothing 
    } 

    public void componentResized(ComponentEvent arg0) { 
     titleButton.setSize(this.getWidth(), 
       titleButton.getPreferredSize().height); 
    } 

    public void componentShown(ComponentEvent arg0) { 
     // Do nothing 
    } 

    public static void main(String[] args) { 
     JScrollPane scrollPane = new JScrollPane(); 

     // These panels simulates a complex, multi-line configuration panel. 
     JPanel testPanel = new JPanel(); 
     testPanel.setLayout(new BoxLayout(testPanel, BoxLayout.Y_AXIS)); 
     testPanel.add(new JLabel("Test JLabel")); 
     testPanel.add(new JLabel("Test JLabel 2")); 
     testPanel.add(new JLabel("Test JLabel 3")); 

     JPanel testPanel2 = new JPanel(); 
     testPanel2.setLayout(new BoxLayout(testPanel2, BoxLayout.Y_AXIS)); 
     testPanel2.add(new JLabel("Test JLabel")); 
     testPanel2.add(new JLabel("Test JLabel 2")); 
     testPanel2.add(new JLabel("Test JLabel 3")); 

     JPanel testPanel3 = new JPanel(); 
     testPanel3.setLayout(new BoxLayout(testPanel3, BoxLayout.Y_AXIS)); 
     testPanel3.add(new JLabel("Test JLabel")); 
     testPanel3.add(new JLabel("Test JLabel 2")); 
     testPanel3.add(new JLabel("Test JLabel 3")); 

     // This panel simulates the panel that will contain each of the 
     // SelectableExpandablePanels. 
     JPanel testHolder = new JPanel(); 
     testHolder.setLayout(new BoxLayout(testHolder, BoxLayout.Y_AXIS)); 
     testHolder.add(new SelectableExpandablePanel(testPanel, "Test")); 
     testHolder.add(new SelectableExpandablePanel(testPanel2, "Test 2")); 
     testHolder.add(new SelectableExpandablePanel(testPanel3, "Test 3")); 

     // We add the test holder to the scroll pane. The intention is that if 
     // the expansion is too big to fit, the holding JFrame won't expand, but 
     // the scroll pane will get scroll bars to let the user scroll up and 
     // down through the toggle buttons and any enabled items. 
     scrollPane.setViewportView(testHolder); 

     JFrame testFrame = new JFrame("Expandable Panel Test"); 
     testFrame.getContentPane().add(scrollPane); 
     testFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     testFrame.pack(); 
     testFrame.setVisible(true); 
    } 
} 
+0

[DYM] (http://stackoverflow.com/a/8166223/714968) или [DYM] (http: // stackoverflow.com/a/11261110/714968), все зависит от того, что, как, когда дети JFrames (если да или нет) изменяются по размеру – mKorbel

+0

@mKorbel Позвольте мне взглянуть на них. Глядя быстро, похоже, что использование setVisible вместо добавления или удаления скорее всего будет лучшей ставкой. Мне нужно глубже разбираться в проблемах с полосой прокрутки и проблемах с шириной. –

+0

using setVisible вместо добавления или удаления, вероятно, будет лучше ---> не имеет значения внутри JScrollPane, это мой вопрос к вам – mKorbel

ответ

2

Не пытайтесь управлять размерами от себя:

//titleButton.setPreferredSize(new Dimension(getSize().width, titleButton.getPreferredSize().height)); 
titleButton.setToolTipText(tooltip); 

setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 
//setPreferredSize(new Dimension(childComponent.getPreferredSize().width, titleButton.getPreferredSize().height)); 
//setSize(new Dimension(childComponent.getPreferredSize().width, titleButton.getPreferredSize().height)); 

Кроме того, избавиться от setSize() кода в ActionListener. Это будет проигнорировано, так как менеджер макета определит размер.

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

Примечание: Для этого я обычно использую BorderLayout. Поместите кнопку на PAGE_START и другую панель в CENTER. Компоненты будут автоматически заполнять доступное пространство.

+0

Не могли бы вы рассмотреть предпочтительный метод размер области прокрутки? На данный момент это в моем основном методе. Я думаю, что я буду сталкиваться с этой проблемой, когда я использую этот компонент. Если я брошу его в панель прокрутки, как в основном примере, панель прокрутки будет шириной кнопок, которые в некоторых случаях намного более узкие, чем дочерние компоненты. Мне нужно заставить панель прокрутки быть шириной самого широкого дочернего компонента. Какой был бы лучший подход к этому? –

+1

@ThomasOwens. Если вам нужно управлять предпочтительным размером панели, переопределите метод getPreferredSize() вашего класса. Таким образом, предпочтительный размер будет рассчитываться динамически каждый раз, когда вызывается менеджер компоновки. – camickr

2
  1. Удалить все вызовы setSize/setPreferredSize и позволить LayoutManager выполнять свою работу.
  2. Чтобы позволить JButtons заполнить ширину панели, вы можете использовать BorderLayout (например, добавить кнопку в CENTER и дочерний контейнер в SOUTH и удалить все эти значения setSize, чтобы обработать LayoutManager).
+0

Это прекрасно. Я думаю. Мне нужно проверить больше, но это похоже на функциональность, в которой я нуждаюсь. –

+1

Не используйте setPreferredSize(), то есть задание менеджера компоновки. – camickr

+0

Единственная проблема заключается в том, что если я удалю setSize/setPreferredSize, размер SelectableExpandablePanel будет только шириной кнопок. Ширина должна быть шириной самого широкого дочернего компонента, так как я бы хотел предотвратить горизонтальную прокрутку. Кроме того, все работает хорошо. –

 Смежные вопросы

  • Нет связанных вопросов^_^