2015-01-13 82 views
0

我有一個程序,我希望能夠在「日」和「夜」模式之間進行切換,其中「夜」模式具有50%灰色背景。我通過調用UIManager.put(關鍵,新的顏色)爲所有從這個頁面中的「背景」鍵這樣做:無法更新外觀和感覺

http://alvinalexander.com/java/java-uimanager-color-keys-list

然後,我結合使用SwingUtilities.updateComponentTreeUI()與Java。 awt.Window.getWindows()獲取現有的窗口來獲取更改。

當我切換模式時,新創建的窗口將具有適當的背景,所以第一部分工作。但是,現有的窗口表現得很奇怪:它們瞬間閃爍新顏色,然後切換回來。例如,如果我在Day模式下啓動程序,那麼主程序窗口會有效地停留在Day模式,反之亦然。

我試圖做一個示例程序。它的行爲與我現有的程序不完全相同,但它的表現仍然很奇怪:外觀只能修改一次。在此之後,新的變化將被忽略:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.Frame; 
import javax.swing.JLabel; 
import java.awt.GridLayout; 
import java.util.Random; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 


public class Demo { 
    public static void main(String[] args) { 
     new Demo(); 
    } 

    public Demo() { 
     JFrame frame = new JFrame("Look and feel test"); 
     frame.setLayout(new GridLayout(3, 3)); 
     // Fill in non-central locations in the layout. 
     // Hacky way to keep the button from monopolizing the frame 
     for (int i = 0; i < 4; ++i) { 
     frame.add(new JLabel("")); 
     } 
     JButton button = new JButton("Set new LAF"); 
     button.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      setNewLAF(); 
     } 
     }); 
     frame.add(button); 
     // Fill in non-central locations in the layout. 
     for (int i = 0; i < 4; ++i) { 
     frame.add(new JLabel("")); 
     } 
     frame.setMinimumSize(new Dimension(400, 400)); 
     frame.show(); 
     System.out.println("Initial frame background is " + frame.getBackground()); 
    } 

    public void setNewLAF() { 
     Random rng = new Random(); 
     Color newBackground = new Color(rng.nextInt(255), 
      rng.nextInt(255), rng.nextInt(255)); 
     System.out.println("New color is " + newBackground); 
     UIManager.put("Panel.background", newBackground); 
     for (Frame f : Frame.getFrames()) { 
     SwingUtilities.updateComponentTreeUI(f); 
     System.out.println("Frame now has background " + f.getBackground());  
     } 
    } 
} 

這將產生輸出,如:

Initial frame background is com.apple.laf.AquaImageFactory$SystemColorProxy[r=238,g=238,b=238] 
New color is java.awt.Color[r=243,g=209,b=134] 
Frame now has background java.awt.Color[r=243,g=209,b=134] 
New color is java.awt.Color[r=205,g=141,b=58] 
Frame now has background java.awt.Color[r=243,g=209,b=134] 
New color is java.awt.Color[r=141,g=22,b=92] 
Frame now has background java.awt.Color[r=243,g=209,b=134] 

感謝你願意分享的任何建議。

+3

如果不是所有UI元素,您至少需要在頂級/根容器上調用'updateUI'。一般而言,外觀和感覺並非真正爲此設計的 – MadProgrammer

+0

您是否有推薦的方法可以在運行時切換幀中的所有組件的背景顏色?外觀和感覺是我可以看到的最接近的選項,它沒有手動遍歷組件層次結構並在每個元素上調用setBackground()。 – chris

回答

1

它仍然表現得很奇怪:外觀只能修改一次。

Color newBackground = new Color(rng.nextInt(255),rng.nextInt(255), rng.nextInt(255)); 

您需要使用:

Color newBackground = new ColorUIResource(rng.nextInt(255),rng.nextInt(255), rng.nextInt(255)); 

的updateComponentTreeUI()只替換用戶界面的一部分資源。您通過將Color包裝在ColorUIResource中來做到這一點。

+0

啊哈,謝謝!這解決了演示程序,並大大改善了實際使用情況 - 現在除了實際處理日夜轉換邏輯的窗口之外的所有窗口都正確更新。我認爲在這一點上,我的操作順序有誤。謝謝! – chris

0

爲什麼不用你的UIManager基於代碼替換這樣的東西?

public void setNewLAF(JFrame frame) { 
    Random rng = new Random(); 
    Color newBackground = new Color(rng.nextInt(255), rng.nextInt(255), 
      rng.nextInt(255)); 
    System.out.println("New color is " + newBackground); 
    frame.setBackground(newBackground); 
    frame.getContentPane().setBackground(newBackground); 
} 

它可能不是你的情況下很好地工作(例如,如果你有很多的幀),但我認爲你可能只轉儲幀爲ArrayList<JFrame>和遍歷他們。

此外,只是爲了讓您知道:show()已棄用。使用setVisible(true)

+0

對不起,我應該在原始問題中提到過 - 如果只設置了框架背景,那麼其他元素(如按鈕,組合框等)的背景仍然是白色的,並且看起來很糟糕。這就是爲什麼我瀏覽UIManager鍵列表並更新每個鍵的原因。 – chris

+0

哦,還有,我相信在Windows上如果你嘗試以這種方式使用'setBackground',那麼它只是平坦不起作用; PLAF用適當的系統覆蓋你的背景顏色。或者至少這是開發人員在這裏的一部分;我沒有親自測試過它。儘管感謝提示關於show()。 – chris

+0

我正在使用Windows 8,它的工作原理。所以它可能是絕殺,或者它可能只適用於8之前的版本。 –