Как получить доступ ко всем компонентам под верхним JFrame

Частично в учебных целях я сделал JFrame с 4 JPanel, 2 JLabel и JMenuBar. Я поместил различные компоненты (кнопки, текстовые поля, текстовое поле) в 4 панели JPanel. Я отключил каждый из компонентов повсюду.

Затем я написал два метода, чтобы попытаться включить все. Работал частично. Вот код:

  public void enableEverything(){
    Component [] p = this.getContentPane().getComponents();
    for(Component pp : p)
      if(pp instanceof JPanel)
        enableAll((JPanel) pp);
  }

  public void enableAll(JPanel p){
    Component [] c = p.getComponents();
    for(Component cc: c)
      cc.setEnabled(true);
    jTextArea1.setEnabled(true);
    jScrollPane1.setEnabled(true);
  }

JTextArea (внутри JScrollPane) не активировался даже с двумя последними строками выше. Почему?

Я также пробовал:

Component [] s = jScrollPane1.getComponents();
for(Component ss: s)
  ss.enableInputMethods(true);

Как включить текстовое поле?

И JMenuBar тоже не включился. Но я действительно не знаю, где его найти. Я читал, что это в JLayeredPane, но... то, что я пробовал, не сработало:

for(int i = 0; i < 2; i++){
  System.out.println(i);
  this.getLayeredPane().getComponent(i).setEnabled(true);
}

На какой панели мне найти JMenuBar и как включить JMenus? (и даже JMenuItems.)

Конечно, это сработало:

menFileAndEdit.setEnabled(true);
mnuFile.setEnabled(true);
mnuEdit.setEnabled(true);
mniFileSave.setEnabled(true);
mniEditUndo.setEnabled(true);
mniEditRedo.setEnabled(true);

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

1-е редактирование

Вот как попасть в строку меню!

Component[] m = this.getJMenuBar().getComponents();
    for(Component mm: m)
      mm.setEnabled(true);

2-е редактирование

См. Ниже рекурсивное частичное решение.

Это "рекурсивный ответ" @maaartinus (хотя я только в эту секунду прочитал его заметку о стеке). Это не ответ на мою проблему, но прогресс.

  public void enableEverything(Container c){
    Component [] p = c.getComponents();
    System.out.println("Component count " + c.getComponentCount() + " for " +   
                                            c.toString().substring(0,40)  );
    for(Component pp : p){
        pp.setEnabled(true);
        if(pp instanceof Container){
          System.out.println("Recursive call for " + pp.toString().substring(0,40));
          enableEverything((Container) pp);
        }
        else System.out.println("No recursive call");
    }

Мне пришлось вызвать его дважды, чтобы включить почти все:

  gameBoard.enableEverything(gameBoard.getContentPane());
  gameBoard.enableEverything(gameBoard.getJMenuBar());

Он отказался от одного метода, поскольку он рекурсивный, и дал те же результаты, поскольку он также НЕ активировал JMenuItems или JTextArea.

Поэтому я все еще ищу, как это сделать.

Это дало интересный результат, поскольку каждый компонент кажется экземпляром Container, что кажется неправильным:

 gameBoard.enableEverything(gameBoard.getContentPane())
Component count 6 for javax.swing.JPanel[null.contentPane,0,23
Recursive call for    javax.swing.JPanel[pnlGameGrid,12,139,59
Component count 1 for javax.swing.JPanel[pnlGameGrid,12,139,59
Recursive call for    javax.swing.JTextField[jTextField1,233,1
Component count 0 for javax.swing.JTextField[jTextField1,233,1
Recursive call for    javax.swing.JPanel[pnlAvailableLetters,1
Component count 1 for javax.swing.JPanel[pnlAvailableLetters,1
Recursive call for    javax.swing.JToggleButton[jToggleButton1
Component count 0 for javax.swing.JToggleButton[jToggleButton1
Recursive call for    javax.swing.JLabel[lblAvailableLetters,1
Component count 0 for javax.swing.JLabel[lblAvailableLetters,1
Recursive call for    javax.swing.JPanel[pnlScore,476,25,107x9
Component count 2 for javax.swing.JPanel[pnlScore,476,25,107x9
Recursive call for    javax.swing.JTextField[txtScore,21,14,66
Component count 0 for javax.swing.JTextField[txtScore,21,14,66
Recursive call for    javax.swing.JButton[btnScore,21,61,66x24
Component count 0 for javax.swing.JButton[btnScore,21,61,66x24
Recursive call for    javax.swing.JPanel[pnlPlays,624,51,271x5
Component count 3 for javax.swing.JPanel[pnlPlays,624,51,271x5
Recursive call for    javax.swing.JScrollPane[jScrollPane1,13,
Component count 3 for javax.swing.JScrollPane[jScrollPane1,13,
Recursive call for    javax.swing.JViewport[,1,1,220x80,layout
Component count 1 for javax.swing.JViewport[,1,1,220x80,layout
Recursive call for    javax.swing.JTextArea[jTextArea1,0,0,220
Component count 0 for javax.swing.JTextArea[jTextArea1,0,0,220
Recursive call for    javax.swing.JScrollPane$ScrollBar[,0,0,0
Component count 2 for javax.swing.JScrollPane$ScrollBar[,0,0,0
Recursive call for    javax.swing.plaf.metal.MetalScrollButton
Component count 0 for javax.swing.plaf.metal.MetalScrollButton
Recursive call for    javax.swing.plaf.metal.MetalScrollButton
Component count 0 for javax.swing.plaf.metal.MetalScrollButton
Recursive call for    javax.swing.JScrollPane$ScrollBar[,0,0,0
Component count 2 for javax.swing.JScrollPane$ScrollBar[,0,0,0
Recursive call for    javax.swing.plaf.metal.MetalScrollButton
Component count 0 for javax.swing.plaf.metal.MetalScrollButton
Recursive call for    javax.swing.plaf.metal.MetalScrollButton
Component count 0 for javax.swing.plaf.metal.MetalScrollButton
Recursive call for    javax.swing.JButton[jButton1,61,262,81x2
Component count 0 for javax.swing.JButton[jButton1,61,262,81x2
Recursive call for    javax.swing.JCheckBox[jCheckBox1,49,207,
Component count 0 for javax.swing.JCheckBox[jCheckBox1,49,207,
Recursive call for    javax.swing.JLabel[lblPlays,624,29,100x1
Component count 0 for javax.swing.JLabel[lblPlays,624,29,100x1


gameBoard.enableEverything(gameBoard.getJMenuBar())
Component count 2 for javax.swing.JMenuBar[menFileAndEdit,0,0,
Recursive call for    javax.swing.JMenu[mnuFile,0,0,31x21,alig
Component count 0 for javax.swing.JMenu[mnuFile,0,0,31x21,alig
Recursive call for    javax.swing.JMenu[mnuEdit,31,0,33x21,ali
Component count 0 for javax.swing.JMenu[mnuEdit,31,0,33x21,ali

Я надеялся, что рекурсия доберется до JMenuItems, но не тут-то было. Есть мысли о том, как это сделать?


person DSlomer64    schedule 20.04.2014    source источник
comment
Чтобы быстрее получить помощь, опубликуйте MCVE (минимальный полный и проверяемый пример). См. также эту MCVE.   -  person Andrew Thompson    schedule 20.04.2014
comment
Я знаю, @AndrewThompson, я надеялся быть кратким, так как вопрос казался шаблонным. И если бы я только что не понял, как добраться до JMenuBar, я бы опубликовал MCVE. Я могу просто выяснить все это, что было бы лучше для меня. (Кстати, я нашел ваш ответ ранее, и это побудило меня с большим интересом прочитать ваше «Почему учителя CS должны прекратить преподавать Java-апплеты».)   -  person DSlomer64    schedule 20.04.2014
comment
О, @AndrewThompson, я НЕ видел ссылку. СПАСИБО! Я изучу это.   -  person DSlomer64    schedule 20.04.2014
comment
@AndrewThompson - ссылка привела меня в другое место, о котором я недавно думал, поэтому, я думаю, вы спасли меня от этого вопроса, хотя я думаю, что этот вопрос очень похож на него. Еще раз спасибо.   -  person DSlomer64    schedule 20.04.2014
comment
Относительно вашего удаленного ответа: опубликуйте новый вопрос Как перечислить элементы JMenuBar. У меня нет с собой моего кода, где я это делал. Помнится, были и более частные случаи. Возможно, getSubElements сделал бы? Я бы также начал с gameBoard.enableEverything(gameBoard) вместо двух вызовов (для простоты).   -  person maaartinus    schedule 20.04.2014
comment
@maaatrinus - Спасибо, я нащупываю свой путь сюда, действительно не уверен как в кодировании, так и в этикете - теперь, когда вы это сказали, просто передать gameBoard в enableEverything для ОДНОГО звонка довольно очевидно! Он сделал то же, что и оба других подхода, но, хотя он по-прежнему не включает текстовую область или пункты меню, это более аккуратное и гораздо лучшее решение. В соответствии с просьбой, я опубликую новый вопрос. Я никогда не знаю, когда это уместно, так как это как бы оставляет нить в подвешенном состоянии, лишь частично решая исходную проблему и не имея связи с остальными. Тем не менее, эта ветка кажется мертвой, так что сойдет.   -  person DSlomer64    schedule 21.04.2014
comment
-1 за то, что не отображается SSCCE (предлагал старую аббревиатуру зверя @AndrewThompson ;-) - что-то не так в коде, который вы не показываете   -  person kleopatra    schedule 21.04.2014


Ответы (4)


Я думаю, вам нужно рекурсировать все дерево, что-то вроде

  • начни с корня
  • повторить все компоненты
  • включить каждый из них
  • проверить, является ли это экземпляром Container
  • если да, сделайте рекурсивный вызов

Для ScrollPane вам, вероятно, понадобится дополнительный тест instanceof, а затем getViewPort или что-то в этом роде.

person maaartinus    schedule 20.04.2014
comment
Рекурсивный вызов... Мне нравится! - person DSlomer64; 20.04.2014
comment
Просто проверяю, что вы видели редактирование моего комментария. Там была ссылка на пример. - person Andrew Thompson; 20.04.2014
comment
@ DSlomer64: А если вам не нравится рекурсия, вы можете использовать стек (List) или Queue для ее имитации. Это даст вам контроль над порядком обработки. - person maaartinus; 20.04.2014
comment
@AndrewThompson: Нет, я раньше не видел твоего комментария. Но я понимаю, что ты был быстрее меня. - person maaartinus; 20.04.2014
comment
Извините, я должен был дать понять, что разговаривал с ОП. Я полагаю, вам не нужен пример того, что вы сказали. ;) О, и спасибо за напоминание, я забыл проголосовать. :) - person Andrew Thompson; 20.04.2014
comment
@AndrewThompson: я не был уверен, что вы имели в виду. Спасибо. - person maaartinus; 20.04.2014
comment
@Эндрю Томпсон: Спасибо, что указали на мои ошибки в суждениях и этикете и правильно отредактировали мой исходный пост. Я бы с радостью удалил, как просили, но он заблокирован и предлагает пометить для внимания модератора, что я и сделал, хотя не был уверен, что должен, так как он уже привлек большое внимание модератора. - person DSlomer64; 21.04.2014

«На какой панели я могу найти JMenuBar и как включить JMenus? (И даже JMenuItems».

Корневая панель JFrame содержит JMenuBar.

JFrame.getRootPane().getJMenuBar();

Конечно, вы всегда можете просто вызвать JFrame.getJMenuBar() без доступа к корневой панели.

Чтобы получить меню строки меню, вы можете JMenuBar.getSubElements вернуть MenuElement[]. JMenu Также есть getSubElements. Имейте в виду, однако, что MenuELement может быть JMenu или JMenuItem, а JMenu может иметь больше слоев JMenus., поэтому вам придется выполнить некоторые рекурсивные вызовы, если вы хотите попытаться получить к ним доступ таким образом.

Что касается попытки получить доступ к определенным типам компонентов, проверка if (obj instanceof SomeComponentType) поможет вам в том, чего вы пытаетесь достичь.

person Paul Samsotha    schedule 20.04.2014
comment
Я уже понял одну часть того, на что вы ответили, но не другие, так что большое спасибо. Или стек. Какой бы ни. - person DSlomer64; 20.04.2014
comment
@peeskillet - я пытался и пытался использовать getJMenuBar() для включения, но я даже не смог получить компиляцию, не говоря уже о том, чтобы понять, как применить рекурсию. Если вы найдете время, я бы хотел посмотреть, что вы предложили. Между тем, я нашел способ включить элементы меню, хотя это не то, что я бы назвал гладким кодом. - person DSlomer64; 21.04.2014
comment
Опубликуйте пример со всеми вашими меню и пунктами меню и укажите, чего именно вы пытаетесь достичь. - person Paul Samsotha; 21.04.2014
comment
@peeskillet--@kleopatra представил это в перспективе - это не то, как управлять железной дорогой, [отключая] таким образом пункты меню. Код в «Ответе». Вот то, что сработало ниже, помогло мне пройти через пункты меню; все включено; учебное занятие завершено; ничего практического не сделано. Я больше не буду беспокоить вас всех этим. Я подожду, пока какая-нибудь реальная проблема с кодированием не поднимет голову и не поставит меня в тупик в контексте разработки основ этой программы, а затем опубликую MCVE. - person DSlomer64; 21.04.2014
comment
@peeskillet--P.S. Я просто искал способ получить доступ к КАЖДОМУ компоненту от JFrame до JMenuItem с помощью одной рекурсивной процедуры. Не мог; но нашел второй кусок кода для этого. И Клеопатра предполагает, что это возможно, и предлагает найти ошибку в моем коде, которую я, возможно, скоро устраню. - person DSlomer64; 21.04.2014

Вот что сработало.

  for(int i = 0; i < menFileAndEdit.getMenuCount(); i++){

      menFileAndEdit.getMenu(i).setEnabled(true);

      Component [] cc = menFileAndEdit.getMenu(i).getMenuComponents();

      for(Component c : cc)

          c.setEnabled(true);
  }

Это включает каждый JMenuItem в JMenu menFileAndEdit в JMenuBar для формы.

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

Мне также интересно, есть ли способ использовать цикл for на основе коллекции. Я пробовал пару вещей, но они не компилировались.

person DSlomer64    schedule 21.04.2014
comment
в элементах меню нет ничего особенного - технически вы проходите по иерархии контейнеров рекурсивно точно так же, как и по любой другой иерархии контейнеров. Если по какой-то причине это не работает, значит, где-то в вашем коде есть ошибка. С другой стороны, неправильно включать/отключать элемент меню - вместо этого используйте действия и включайте/отключайте эти действия. - person kleopatra; 21.04.2014

Шесть месяцев спустя у меня есть приличный, не совсем неэлегантный способ получить доступ ко всему, что мне нужно, ниже основного JFrame, в контексте действия пункта меню, которое устанавливает все подсказки на "":

private void tipsOff(Container container)
{
  Component [] c = container.getComponents();
  Component s;
  for (Component cc : c) {
    ((JComponent)cc).setToolTipText("");
    if(cc instanceof JPanel)      tipsOff((Container) cc);
    if(cc instanceof JScrollPane) tipsOff(((JScrollPane)cc).getViewport());
  }
}  

private void mniPrefTooltipsActionPerformed(java.awt.event.ActionEvent evt)
{                                                
  tipsOff(gui.getContentPane());
  tipsOff(gui.mbrMenuBar);
}     

Обратите внимание на рекурсивный вызов tipsOff.

Также обратите внимание на комментарии и ответ об использовании ToolTipManagerэтой темы, который работает в контексте моего первоначального вопроса, чтобы сократить весь код до одной строки. Дело в том, что можно применить любую другую операцию вместо ""-подсказок инструментов - например, установка невидимости или отключение. .. так далее.

Спасибо maaartinus за строку JScrollPane в tipsOff.

person DSlomer64    schedule 17.10.2014
comment
((JScrollPane) c).getViewport()).getView() выполняет свою работу. - person maaartinus; 19.10.2014
comment
@maaartinus--getView Возвращает один дочерний объект JViewport или null. У меня Component s; s = (((JScrollPane)cc).getViewport()).getView();, но как отключить всплывающие подсказки? Я попробовал s.setTooltips..., но получил ошибку - setTooltips недействителен в контексте. - person DSlomer64; 21.10.2014
comment
Возвращенный Component может быть чем угодно. Если это Container, вы просто передаете его tipsOff. Если это JComponent, то звоните setToolTipText. Очевидно, что это может быть как JComponent extends Container. Если ни то, ни другое, то, вероятно, ничего не нужно делать, но напечатайте s.getClass(), чтобы узнать больше. - person maaartinus; 21.10.2014
comment
Или гораздо проще: (JScrollPane)cc).getViewport() — это JComponent, следовательно, также Container, так что передайте его tipsOff, и все готово. - person maaartinus; 21.10.2014
comment
Связано: Сохранение значений по умолчанию Атрибуты JComponent Для функций уровня компонента, таких как isVisible или isEnabled, вы можете сохранить и повторно преобразовать состояния атрибутов в инициализированное состояние (т. е. текстовое поле отключено, пока не установлен флажок). - person Compass; 22.10.2014
comment
@Компас - спасибо за ссылку! Я собираюсь изучить его. Я новичок в хеш-картах - это главная проблема. Но ваш пост читается достаточно хорошо, чтобы я был на нем. - person DSlomer64; 23.10.2014