2016-07-22 68 views
2

我有一個關於鞦韆中的自定義選項卡組件的問題。JTabbedPane TabComponent默認選項卡突出

下面的代碼將增加3個自定義選項卡組成:

public class TabbedExample extends JPanel { 
    public static void main(String... args) { 
    EventQueue.invokeLater(new Runnable() { 
     @Override public void run() { 
     createUI(); 
     } 
    } 
    } 
    public static void createUI() { 
    try { 
     for(LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { 
     if("Nimbus".equals(info.getName())) { 
      UIManager.setLookAndFeel(info.getClassName()); 
      break; 
     } 
     } 
    } catch(Exception e) {} 
    JFrame frame = new JFrame("Tab Test"); 
    frame.setMinimumSize(new Dimension(256,200)); 
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    frame.getContentPane().add(new TabbedExample()); 
    frame.pack(); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
    } 

    public TabbedExample() { 
    super(new BorderLayout()); 

    JTabbedPane pane = new JTabbedPane(); 
    pane.addTab("tmp", new JTextField()); 
    pane.addTab("tmp", new JTextField()); 
    pane.addTab("tmp", new JTextField()); 
    for(int i = 0; i < 3; i++) { 
     JPanel tabPanel = new JPanel(); 
     tabPanel.setBackground(new Color(0,0,0,0)); 
     tabPanel.setLayout(new BoxLayout(tabPanel, BoxLayout.X_AXIS)); 
     JTextField textField = new JTextField("Tab " + i); 
     textField.setOpaque(false); 
     textField.setBackground(new Color(0,0,0,0)); 
     textField.setBorder(new EmptyBorder(0,0,0,0)); 
     tabPanel.add(label); 
     tabPanel.add(new JButton(Integer.toString(i))); 
     pane.setTabComponentAt(i, tabPanel); 
    } 
    add(pane, BorderLayout.CENTER); 
    } 
} 

現在的問題是,默認的選項卡行爲停止工作。通常,當您將鼠標移動到選項卡上時,它通過更改背景顏色自動獲取高亮顯示。但一旦JTextField被擊中,該選項卡很可能會註冊一個mouseExited Event並停止突出顯示選項卡。所以當您將鼠標移動到選項卡上時,選項卡將閃爍。

我現在的問題是: 有沒有一種方法(沒有實現新的突出顯示機制)突出顯示自定義tabComponent所在的選項卡?

+1

通過突出顯示,你的意思是,讓焦點? –

+0

@TamasRev:不,這可能是Nimbus LAF特有的。我不確定其他LAF如何處理這個問題。標籤可以處於不同的狀態(至少這是它看起來像簡單的用戶那樣)。鼠標在選項卡區域(顏色1)外聚焦鼠標,在選項卡區域(顏色2)內聚焦的鼠標,在選項卡區域(顏色3)外的未聚焦的鼠標,在選項卡區域(顏色4)內未聚焦的鼠標。當用戶將光標移動到改變選項卡顏色的選項卡上時,突出顯示的是什麼。使用自定義tabComponent時,將鼠標移動到組件上會有一些閃爍現象。 –

回答

2
  • 這裏是我的嘗試:
    • 使用JLayer派遣從選項卡中的MouseMotionEventJTabbedPane
import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.plaf.*; 

public class TabbedExample2 extends JPanel { 
    public static void main(String... args) { 
    EventQueue.invokeLater(() -> { 
     createUI(); 
    }); 
    } 
    public static void createUI() { 
    try { 
     for (UIManager.LookAndFeelInfo laf: UIManager.getInstalledLookAndFeels()) { 
     if ("Nimbus".equals(laf.getName())) { 
      UIManager.setLookAndFeel(laf.getClassName()); 
     } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    JFrame frame = new JFrame("Tab Test"); 
    frame.setMinimumSize(new Dimension(256, 200)); 
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    frame.getContentPane().add(new TabbedExample2()); 
    frame.setSize(320, 240); 
    frame.setLocationRelativeTo(null); 
    frame.setVisible(true); 
    } 

    public TabbedExample2() { 
    super(new BorderLayout()); 
    JTabbedPane pane = new JTabbedPane(); 
    pane.addTab("tmp", new JTextField(16)); 
    pane.addTab("tmp", new JTextField(16)); 
    pane.addTab("tmp", new JTextField(16)); 
    for (int i = 0; i < 3; i++) { 
     JPanel tabPanel = new JPanel(); 
     tabPanel.setOpaque(false); 
     //tabPanel.setBackground(new Color(0,0,0,0)); 
     tabPanel.setLayout(new BoxLayout(tabPanel, BoxLayout.X_AXIS)); 
     JTextField textField = new JTextField("Tab " + i); 
     //textField.setBackground(new Color(0,0,0,0)); 
     //textField.setBorder(new EmptyBorder(0,0,0,0)); 
     //tabPanel.add(label); //??? 
     tabPanel.add(textField); 
     tabPanel.add(new JButton(Integer.toString(i))); 
     pane.setTabComponentAt(
      i, new JLayer<JPanel>(tabPanel, new DispatchEventLayerUI())); 
    } 
    add(pane); 
    } 
} 

class DispatchEventLayerUI extends LayerUI<JPanel> { 
    @Override 
    public void installUI(JComponent c) { 
    super.installUI(c); 
    if (c instanceof JLayer) { 
     ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK); 
     //TEST: 
     //((JLayer) c).setLayerEventMask(
     // AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); 
    } 
    } 
    @Override 
    public void uninstallUI(JComponent c) { 
    if (c instanceof JLayer) { 
     ((JLayer) c).setLayerEventMask(0); 
    } 
    super.uninstallUI(c); 
    } 
// //TEST: 
// @Override 
// protected void processMouseEvent(MouseEvent e, JLayer<? extends JPanel> l) { 
//  dispatchEvent(e); 
// } 
    @Override 
    protected void processMouseMotionEvent(MouseEvent e, JLayer<? extends JPanel> l) { 
    dispatchEvent(e); 
    } 
    private void dispatchEvent(MouseEvent e) { 
    Component src = e.getComponent(); 
    Container tgt = SwingUtilities.getAncestorOfClass(JTabbedPane.class, src); 
    tgt.dispatchEvent(SwingUtilities.convertMouseEvent(src, e, tgt)); 
    } 
} 
+0

感謝您的sultion。它在這個例子中工作。不幸的是,我正在使用一種更復雜的應用程序,並且它不能輕鬆地集成。無論如何,執行魔術的部分是在你的方法'dispatchEvent(MouseEvent e)'中。如果我忽略整個JLayer部分,並簡單地使用'dispatchEvent'方法,我很容易使用JTextField。不幸的是,我有一個自定義組件(而不是JButton),它在將自定義組件MouseEvent傳遞給'dispatchEvent?'方法 –

+0

Part#2時不起作用:我可以看到的唯一區別是(當使用' system.out.println'用'tgt','src'和'event'表示tgt包含一個稍微不同的值:'javax.swing.JTabbedPane [,0,0,1024x800,invalid,layout = ...'。不同的是關鍵字'無效',但我必須承認,我完全不知道什麼是錯的,爲什麼它不工作。 –