3

a JTabbedPane is just what I need for my purpose. I have very limited horizontal space, so my Tabs get stacked, which is perfectly ok.

But the default behaviour is that if user clicks on a Tab, the *Tabs get re-sorted so that the active Tab becomes the lower-mos*t. What looks very intuitive and logical in theory, is a nightmare in practical use, because the users loose track of "which was which". Its just simply plain confusing, I am told again and again.

I guess it should be possible to override some method of the UI to avoid this behaviour (and I dont care whether this would be physically possible with paper cards :-) .

Has anyone any idea where I need to do that? I am using Nimbus LAF, which does not seem to make it easier.

(I thought about using radiobuttons/cardLayout, but I need to put a custom panel in the tab title, and radiobuttons can only have a string or icon. Same for JToggleButton...)

Any hints are greatly welcome!

Thanks & Kind regards, Philipp

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Philippp
  • 847
  • 1
  • 8
  • 17
  • When you say they get re-sorted, do you mean that the result of `JTabbedPane.indexOfComponent(Component c)` changes? –  Sep 20 '11 at 08:43
  • I would try to use a debugger to follow the code when you click on a tab. – Angel O'Sphere Sep 20 '11 at 08:56
  • Hmmm, just found that I could override setSelectedIndex() in a custom JTabbedPane, so that it essentially does nothing but switching the card of a cardlayout of a panel that I place below. I would always have super.setSelectedTabindex(-1) to avoid confusion. The downside is that besides the missing highlighting of the active tab, also the focus does not get painted. So I would have to fake these two... – Philippp Sep 20 '11 at 09:21
  • trashgod, thanks - scrolling is not convenient in this case. The tabs need to be instantly accessible, also because of the buttons I have in the tab labels. Each tab label horizontally is about as wide as the screen space I totally have for the TabbedPane. – Philippp Sep 20 '11 at 09:23
  • Bringer128, no, I mean just visually. The selected Tab get the bottom-most place on screen. Perhaps "re-arranged" would be the better word for that? – Philippp Sep 20 '11 at 09:24
  • Possible duplicate of [Tabs at fixed positions in JTabbedPane or in one row](https://stackoverflow.com/questions/9636601/tabs-at-fixed-positions-in-jtabbedpane-or-in-one-row) – Zezombye Apr 30 '18 at 23:05

3 Answers3

3

sscce for potential answerer(s) for Nimbus L&f (by using another L&f isn't possible to reproduce this funny issue), in case that Containers#Size packed Tabs to the two or more Lines, enter image description hereenter image description here

as I know there is only one possible solutions (without override NimbusTabbedPaneUI) by aephyr

from 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();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • mKorbel, thanks for the sample code (now I know what an sccee is :-) – Philippp Sep 21 '11 at 04:30
  • mKorbel, thanks very much for the sample code - probably this would have been my duty, sorry (now I know what an sscce is :-) I just played araound with the aephyr TabFolder, but I do not manage to add any tabs to the TabFolder (I could not find any documentation). I created some DefaultTabs, but there is nothing like TabFolder.addTab() ...?? (Is there any sscce for that? ;-) – Philippp Sep 21 '11 at 04:38
  • this code is about one Java/Swing guru who's played with Nimbus, JTreeTable and another, no there isn't doc, just his knowledge in code form – mKorbel Sep 21 '11 at 06:14
  • hmmmm aephyr.swing.tabfolder and aephyr.swing.ui, really there is more knowledges about Swing as lots of people around knows together (including me), maybe better would be check this thread http://stackoverflow.com/questions/3954616/look-and-feel-in-java/3954646#3954646 – mKorbel Sep 21 '11 at 06:19
  • ok, thanks. (JTreeTable really looks fascinating, and I got the example running - I will keep that in case we need it later.) – Philippp Sep 23 '11 at 16:26
2

Okay, I found the Problem. In

package javax.swing.plaf.basic.BasicTabbedPaneUI;

it says something like this

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

Its a pity that there seems to be no easy set-a-flag-and-there-you-go-way is for changing that.

Although you should be fine if you omitted the call to rotateTabRuns(tabPlacement, selectedRun); or change shouldRotateTabRuns(tabPlacement) for that matter... however, to do so you would have to override a whole bunch of classes... depending on which plaf you use.

It inherits like this

Basic > Synth > Nimbus

And on each L&F-level there are several classes to customize... I didn't count.

Hope it helps! :D

Edit Oh yeah... @mkorbel already provided sort of the solution with this aephyr why not use that?

Omphaloskopie
  • 1,952
  • 1
  • 14
  • 24
  • not sure but I still think that aephyr was involved to the Nimbus, thanks for notice +1 – mKorbel Nov 21 '11 at 17:30
  • mKorbel, wow, great - thanks!

    \n Still, this seems to require a lot of work, I will look at it later.

    In the meantime I have implemented a lousy hack (ugly, but it works).

    I played around with aephyr, but there seems to be zero documentation in the code, and I could not get the tabbed--pane part working.
    (sorry for editing twice, I still keep hitting the return key for a line break but this submits the form)

    – Philippp Dec 03 '11 at 06:52
1

It's a bit of a hack but you can override the Nimbus defaults to have the plain old Java look-and-feel for the tabbed pane, whilst keeping everything else the same. The plain Java look-and-feel for a tabbed pane doesn't do the annoying reordering. Just store the defaults before you set the look-and-feel and then set them back.

// 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);
  • Thanks for the inspiration! (However, in the meantime we have abandoned the tabbedpane in that particular application, so I cannot try it out any more. But good to know for the next time!) – Philippp Jun 04 '18 at 19:56