Java Swing - как показать панель поверх другой панели?

Я хочу иметь внутренний (не оконный) диалог для запроса ввода участника. Я хотел бы, чтобы диалог был размещен централизованно на существующей панели JPanel.

Я просмотрел многослойные панели, и они кажутся непригодными для использования из-за наличие только одного менеджера компоновки (или без менеджера компоновки) на всех панелях. Я думаю, я мог бы попытаться переопределить JLayeredPane и предоставить собственный макет, но это кажется экстремальным.

стеклянные панели также не подходят.

Как это может быть сделано? Нет ли полезной концепции z-индексов в Swing?

ИЗМЕНИТЬ

Причина, по которой многослойные панели не подходили, заключалась в отсутствии менеджера компоновки для каждого слоя. Размер панели можно изменить, панель A должна оставаться на 100% площади, а панель B должна оставаться централизованной.


person Pool    schedule 12.05.2009    source источник
comment
Посмотрите, как вариант, как (очень просто) расширить JLayeredPane, чтобы он принимал LayouManager любого типа. stackoverflow.com/questions/42413590/   -  person Mischa    schedule 23.02.2017


Ответы (6)


Я думаю, что LayeredPane — ваш лучший выбор. Однако вам понадобится третья панель, содержащая A и B. Эта третья панель будет многоуровневой панелью, а затем панели A и B все еще могут иметь хорошие LayoutManagers. Все, что вам нужно сделать, это центрировать B над A, и в Swing trail есть довольно много примеров того, как это сделать. Учебник по позиционированию без LayoutManager.

public class Main {
    private JFrame frame = new JFrame();
    private JLayeredPane lpane = new JLayeredPane();
    private JPanel panelBlue = new JPanel();
    private JPanel panelGreen = new JPanel();
    public Main()
    {
        frame.setPreferredSize(new Dimension(600, 400));
        frame.setLayout(new BorderLayout());
        frame.add(lpane, BorderLayout.CENTER);
        lpane.setBounds(0, 0, 600, 400);
        panelBlue.setBackground(Color.BLUE);
        panelBlue.setBounds(0, 0, 600, 400);
        panelBlue.setOpaque(true);
        panelGreen.setBackground(Color.GREEN);
        panelGreen.setBounds(200, 100, 100, 100);
        panelGreen.setOpaque(true);
        lpane.add(panelBlue, new Integer(0), 0);
        lpane.add(panelGreen, new Integer(1), 0);
        frame.pack();
        frame.setVisible(true);
    }


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Main();
    }

}

Вы используете setBounds для размещения панелей внутри многослойной панели, а также для установки их размеров.

Редактировать, чтобы отразить изменения в исходном сообщении. Вам потребуется добавить прослушиватели компонентов, которые обнаруживают изменение размера родительского контейнера, а затем динамически изменяют границы панелей A и B.

person willcodejavaforfood    schedule 12.05.2009
comment
Привет, это путь, который я изначально преследовал, но я не могу понять, как заставить A и B вести себя без использования setBounds. В документах для JLayeredPane упоминается, что все менеджеры компоновки, предоставляемые платформой Java, располагают компоненты так, как если бы все они находились на одном уровне. - person Pool; 12.05.2009
comment
Да это верно. Чтобы расположить A и B, вам нужно использовать setBounds. Панели A и B могут по-прежнему иметь любой LayoutManager, который вы хотите разместить внутри них. Это отвечает на ваш вопрос? - person willcodejavaforfood; 12.05.2009
comment
Причина, по которой я пытался использовать менеджер компоновки вместо setBounds, заключается в том, что размер панели можно изменить. Возможно, расширение JLayeredPane, прослушивание изменений компонентов и вызов setBounds для его дочерних элементов - правильный способ решить эту проблему. (Я также отредактирую исходный вопрос, чтобы уточнить это.) - person Pool; 12.05.2009

Вы можете добавить недекорированный JDialog следующим образом:

import java.awt.event.*;

import javax.swing.*;

public class TestSwing {
  public static void main(String[] args) throws Exception {
    JFrame frame = new JFrame("Parent");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(800, 600);
    frame.setVisible(true);

    final JDialog dialog = new JDialog(frame, "Child", true);    
    dialog.setSize(300, 200);
    dialog.setLocationRelativeTo(frame);
    JButton button = new JButton("Button");
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        dialog.dispose();
      }
    });
    dialog.add(button);
    dialog.setUndecorated(true);
    dialog.setVisible(true);
  }
}
person mavroprovato    schedule 12.05.2009
comment
Спасибо, к сожалению, это создает новое окно, +1 за неукрашенное, очень хороший эффект. - person Pool; 12.05.2009
comment
И почему это проблема? Теперь, когда я смотрю на ваш вопрос во второй раз, вы можете сделать диалоговое окно немодальным и изменить его положение при изменении размера родительского фрейма. - person mavroprovato; 12.05.2009
comment
Это требование. Диалог/окно не имеет смысла для этой панели. - person Pool; 12.05.2009

Я просто решил добавить, что существует понятие Z-порядка в Swing, см. [java.awt.Component#setComponentZOrder][1]

который влияет на позиции компонента в его родительском массиве компонентов, который определяет порядок рисования.

Обратите внимание, что вы должны переопределить javax. swing.JComponent#isOptimizedDrawingEnabled для возврата false в родительском контейнере, чтобы ваши перекрывающиеся компоненты правильно перерисовывались, иначе их перерисовки будут сбивать друг друга. (JComponents предполагает отсутствие перекрывающихся дочерних элементов, если isOptimizedDrawingEnabled не возвращает false)

[1]: http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Container.html#setComponentZOrder(java.awt.Component, int)

person CarlG    schedule 13.05.2009

Используйте GridLayout 1 на 1 в существующей JPanel, затем добавьте свою панель в эту JPanel. Единственная проблема с GridLayout 1 на 1 заключается в том, что вы не сможете разместить другие элементы на JPanel. В этом случае вам придется придумать подходящий макет. Каждая панель, которую вы используете, может использовать свой собственный макет, так что это не будет проблемой.

Я правильно понимаю этот вопрос?

person AlbertoPL    schedule 12.05.2009
comment
Спасибо, я добавил диаграмму выше, чтобы пояснить. По сути, это наложение компонентов друг на друга (индекс z), в чем я не уверен. - person Pool; 12.05.2009
comment
О, хорошо, я вижу, моя ошибка. Спасибо за дополнительное разъяснение. - person AlbertoPL; 12.05.2009

JOptionPane.showInternalInputDialog, вероятно, делает то, что вы хотите. Если нет, было бы полезно понять, чего ему не хватает.

person Yishai    schedule 12.05.2009
comment
Спасибо, насколько я понимаю, это покажет внутреннюю рамку, которая будет выглядеть и чувствовать себя как окно. Мне действительно нужна полная настройка, которую предлагает панель. - person Pool; 12.05.2009

Здесь может быть интересен еще один менеджер компоновки: Макет наложения Вот простой учебник: OverlayLayout: для управления компоновкой компонентов, лежащих на друг над другом. Макет наложения позволяет размещать панели друг над другом и устанавливать макет внутри каждой панели. Вы также можете установить размер и положение каждой панели отдельно.

(Причина, по которой я отвечаю на этот вопрос много лет назад, заключается в том, что я наткнулся на ту же проблему, и я видел очень мало упоминаний о макете наложения в StackOverflow, хотя он, кажется, довольно хорошо задокументирован. Надеюсь, это может кому-то помочь. другой, кто продолжает искать его.)

person AgataB    schedule 21.07.2016