1 回答

TA貢獻1898條經驗 獲得超8個贊
在 99% 的案例中,您在示例應用程序中看到的任何問題都是由于不透明和/或非不透明組件的不正確混合而發生的。
正如我從代碼中看到的那樣 - 您正在使用setOpaque(...)來更改各種組件的不透明度,但它非?;靵y。很快,opaque屬性的作用 - 它會影響 Swing 在需要對特定 UI 元素(面板/標簽/按鈕/等)進行視覺更新時重新繪制該元素的方式。
例如,當您用鼠標懸停按鈕時 - 如果它具有不同的懸停狀態,則可能需要重新繪制它,無論它只是一個圖標還是稍微/完全不同的樣式。這就是不透明度發揮作用的地方——opaque=true組件永遠不會在它們自己的“下方”傳遞重繪調用(用其他/適當的術語來說——傳遞給它們的父組件)。這意味著如果您在面板上有一個不透明的按鈕,并且當它變為“懸?!睜顟B時必須重新繪制它 - 該按鈕將是唯一要重新繪制的組件,因為沒有理由重新繪制它下面的任何東西,因為它是不透明,你實際上不應該能夠看透它,所以圖形應該用不透明的顏色填充該按鈕邊界內的所有像素。
理論上。在實踐中,如果您將按鈕設置為不透明狀態,但保持其圖形內容透明或半透明(這顯然是一個錯誤,但 Swing 永遠不會告訴您)——您最終會看到各種視覺偽像,例如你在你的應用程序中看到。發生這種情況是因為Graphics2D實現經常在 (0,0) 坐標執行不同的繪制操作以優化它們的速度——知道這一點并不重要,但這部分是為什么你可能會看到其他組件“部分”混合在你的組件邊界時是透明的。它比那更復雜一點,但它不應該真正重要,因為它只是一個內部 Swing 優化。
類似的視覺問題也可能是由同一布局上的混合opaque=true和組件引起的。opaque=false您的問題很可能也是如此。我確實很快嘗試將您的演示中的所有內容都設置為opaque=false并且它確實解決了問題,但這并不是解決問題的正確方法,特別是如果您想讓某些組件不透明。這只是意味著問題在于在單個容器中將具有不同不透明度類型的組件相互混合的方式。
我的個人建議 - 永遠不要在一個布局中混合不透明和非不透明組件,即使它們有可能重疊(意味著它們的邊界將在布局內相交)。甚至更好——永遠不要在單個容器中將組件重疊在一起。使用具有適當非空布局的多個嵌套容器,這也將在以后幫助您輕松修改 UI。
我可以給你一個簡單的例子來說明為什么它不好:
/**
* @author Mikle Garin
*/
public class OpacityGlitch
{
public static void main ( String[] args )
{
SwingUtilities.invokeLater ( () -> {
final JFrame frame = new JFrame ( "Opacity glitch sample" );
// Opaque by default
final JPanel panel = new JPanel ( null );
// Opaque by default, but might vary with L&F
final JButton button1 = new JButton ( "1111111" );
panel.add ( button1 );
// Non-opaque to demonstrate the problem
final JButton button2 = new JButton ( "2222222" );
panel.add ( button2 );
// Intersecting buttons
button1.setBounds ( 100, 100, 150, 30 );
button2.setBounds ( 130, 115, 150, 30 );
frame.getContentPane ().add ( panel );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setSize ( 500, 500 );
frame.setLocationRelativeTo ( null );
frame.setVisible ( true );
} );
}
}
理論上你應該得到的button1總是在最上面(因為它被更早地添加并且最后被涂在容器上),但在實踐中 - 如果你嘗試懸停其中一個按鈕,那么哪個按鈕是完全可見的并且在另一個按鈕之上將會改變按鈕。發生這種情況是因為兩個按鈕都是不透明的,并且重繪調用不會通過按鈕組件到達它們的容器以及與它們進一步相交的任何內容。button2要解決這種特殊情況,使其成為非不透明就足夠了,因為它應該始終保持在 下方button1,并且如果它是非不透明的,它將安全地將重繪調用至少傳遞給它的容器:
button2.setOpaque ( false );
盡管我個人建議在這種情況下使所有涉及的組件不透明,以避免在將來可能更改組件順序或由于任何用戶交互而發生其他可能的問題——例如,應用程序中的滾動條就是最好的例子。容器不必是非不透明的,因為它會正確地在放置在其中的組件之間傳遞重繪調用,并且也會正確地重繪自身。
一旦將我上面示例中的按鈕更改為非不透明,由于為它們正確處理了重繪,問題就會消失。
對于 Swing 的初學者來說,這可能是一個復雜的話題,但我強烈建議您充分理解為什么會發生這種情況以及如何發生這種情況,否則一旦您的應用程序變大,它將成為您未來的一個大問題。
添加回答
舉報