JTabbedPane: избегайте автоматического переупорядочения вкладок, если они расположены друг над другом / Nimbus

JTabbedPane — это то, что мне нужно для моей цели. У меня очень ограниченное горизонтальное пространство, поэтому мои вкладки складываются, что совершенно нормально.

Но поведение по умолчанию заключается в том, что если пользователь нажимает на вкладку, *вкладки пересортируются так, что активная вкладка становится более низкой*t. То, что в теории выглядит очень интуитивно понятным и логичным, на практике оказывается кошмаром, потому что пользователи не понимают, «что было чем». Это просто сбивает с толку, говорят мне снова и снова.

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

Кто-нибудь знает, где мне нужно это сделать? Я использую Nimbus LAF, что не делает его проще.

(Я думал об использовании radiobuttons/cardLayout, но мне нужно поместить пользовательскую панель в заголовок вкладки, а radiobuttons может иметь только строку или значок. То же самое для JToggleButton...)

Любые подсказки очень приветствуются!

Спасибо и с уважением, Филипп


person Philippp    schedule 20.09.2011    source источник
comment
Когда вы говорите, что они пересортируются, вы имеете в виду, что результат JTabbedPane.indexOfComponent(Component c) изменяется?   -  person Bringer128    schedule 20.09.2011
comment
Я бы попытался использовать отладчик, чтобы следовать коду, когда вы нажимаете на вкладку.   -  person Angel O'Sphere    schedule 20.09.2011
comment
Хммм, только что обнаружил, что я могу переопределить setSelectedIndex() в пользовательской JTabbedPane, так что он по сути ничего не делает, кроме переключения карты макета карты панели, которую я размещаю ниже. Я бы всегда использовал super.setSelectedTabindex(-1), чтобы избежать путаницы. Минус в том, что кроме пропавшей подсветки активной вкладки, еще и фокус не прокрашивается. Так что мне придется подделать этих двоих...   -  person Philippp    schedule 20.09.2011
comment
trashgod, спасибо - листать не удобно в данном случае. Вкладки должны быть мгновенно доступны, в том числе из-за кнопок, которые у меня есть в ярлыках вкладок. Каждая метка вкладки по горизонтали примерно равна ширине экрана, которая у меня есть для TabbedPane.   -  person Philippp    schedule 20.09.2011
comment
Bringer128, нет, я имею в виду только визуально. Выбранная вкладка занимает самое нижнее место на экране. Возможно, лучше всего для этого подойдет слово «перестроенный»?   -  person Philippp    schedule 20.09.2011
comment
Возможный дубликат вкладок в фиксированных позициях в JTabbedPane или в одном строка   -  person Zezombye    schedule 01.05.2018


Ответы (3)


Хорошо, я нашел проблему. В

package javax.swing.plaf.basic.BasicTabbedPaneUI;

это говорит что-то вроде этого

// Rotate run array so that selected run is first
            if (shouldRotateTabRuns(tabPlacement)) {
                rotateTabRuns(tabPlacement, selectedRun);
            }

Жаль, что, кажется, нет простого способа изменить это.

Хотя вы должны быть в порядке, если вы пропустили вызов rotateTabRuns(tabPlacement, selectedRun); или изменили shouldRotateTabRuns(tabPlacement) в этом отношении... однако для этого вам пришлось бы переопределить целую кучу классов... в зависимости от того, какой плаф вы используете.

Он наследует так

Basic > Synth > Nimbus

И на каждом L&F-уровне есть несколько классов для настройки... Я не считал.

Надеюсь, поможет! :D

Редактировать О, да... @mkorbel уже предложил решение с этим aephyr, почему бы не использовать его?

person Omphaloskopie    schedule 21.11.2011
comment
не уверен, но я все еще думаю, что эфир был связан с Нимбусом, спасибо за уведомление +1 - person mKorbel; 21.11.2011
comment
mKorbel, вау, здорово - спасибо!‹p›\n Тем не менее, кажется, что это требует большой работы, я посмотрю на это позже.‹p› Тем временем я реализовал паршивый хак (некрасиво, но работает) .‹p›Я поигрался с aephyr, но, похоже, в коде отсутствует документация, и я не смог заставить работать панель с вкладками.‹br›(извините за редактирование дважды, я все еще продолжаю нажимать клавишу возврата для разрыва строки, но это отправляет форму) - person Philippp; 03.12.2011

sscce для потенциальных ответчиков для Nimbus L&f (с помощью другого L&f невозможно воспроизвести эту забавную проблему) , если Containers#Size упаковывает вкладки в два или более Lines, введите здесь описание изображениявведите здесь описание изображения

насколько я знаю, есть только одна возможные решения (без переопределения NimbusTabbedPaneUI) от aephyr

из sscce

import java.awt.BorderLayout;
import javax.swing.*;

public class TabbedPane {

    private static final long serialVersionUID = 1L;

    public TabbedPane() {
        JPanel jp = new JPanel();
        jp.setLayout(new BorderLayout());
        JTabbedPane tb = new JTabbedPane();
        //tb.setUI(new CustomTabbedPaneUI());
        tb.add("Tab1", new JTextArea(10, 20));
        tb.add("Tab2", new JTextArea(10, 20));
        tb.add("Tab3", new JTextArea(10, 20));
        tb.add("Tab4", new JTextArea(10, 20));
        tb.add("Tab5", new JTextArea(10, 20));
        jp.add(tb, BorderLayout.CENTER);
        //add(jp, BorderLayout.CENTER);
        //tb.setEnabledAt(1, false);
        //tb.setEnabledAt(3, false);
        JFrame frame = new JFrame();
        frame.setLayout(new BorderLayout());
        frame.add(jp, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception system) {
            system.printStackTrace();
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                TabbedPane tP = new TabbedPane();
            }
        });
    }
}
person mKorbel    schedule 20.09.2011
comment
mKorbel, спасибо за пример кода (теперь я знаю, что такое sccee :-) - person Philippp; 21.09.2011
comment
mKorbel, большое спасибо за пример кода - возможно, это было бы моей обязанностью, извините (теперь я знаю, что такое sscce :-) Я только что поигрался с aephyr TabFolder, но мне не удается добавить ни одной вкладки в папку. TabFolder (документации не нашел). Я создал несколько вкладок по умолчанию, но нет ничего похожего на TabFolder.addTab() ...?? (Есть ли для этого sscce? ;-) - person Philippp; 21.09.2011
comment
этот код посвящен одному гуру Java/Swing, который играл с Nimbus, JTreeTable и другими, нет, это не документ, а только его знания в виде кода. - person mKorbel; 21.09.2011
comment
хмммм aephyr.swing.tabfolder и aephyr.swing.ui, действительно есть больше знаний о Swing, так как многие люди знают вместе (включая меня), может быть, лучше было бы проверить эту тему stackoverflow.com/questions/3954616/look-and-feel-in-java/ - person mKorbel; 21.09.2011
comment
хорошо спасибо. (JTreeTable действительно выглядит увлекательно, и я запустил пример — я сохраню его на случай, если он нам понадобится позже.) - person Philippp; 23.09.2011

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

// get the defaults to keep
HashMap<Object, Object> defaultsToKeep = new HashMap<>();
for (Map.Entry<Object, Object> entry : UIManager.getDefaults().entrySet()) {
    boolean isStringKey = entry.getKey().getClass() == String.class ;
    String key = isStringKey ? ((String) entry.getKey()):"";    
    if (key.startsWith("TabbedPane")) {
        defaultsToKeep.put(entry.getKey(), entry.getValue());
    }
}

// set nimbus look and feel
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
    if ("Nimbus".equals(info.getName())) {
        UIManager.setLookAndFeel(info.getClassName());
        break;
    }
}

// set back your originals
for (Map.Entry<Object, Object> entry : defaultsToKeep.entrySet()) {
    UIManager.getDefaults().put(entry.getKey(), entry.getValue());
}

JFrame.setDefaultLookAndFeelDecorated(true);
person Open Door Logistics    schedule 18.09.2015
comment
Спасибо за вдохновение! (Однако тем временем мы отказались от панели вкладок в этом конкретном приложении, поэтому я больше не могу его пробовать. Но полезно знать в следующий раз!) - person Philippp; 04.06.2018