您好,登錄后才能下訂單哦!
小編給大家分享一下如何使用Swing動態界面設計技術,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Swing 工具包提供各種用于創建用戶界面的工具和幾乎令人眼花繚亂的選項,這些選項用于在程序生存期間修改界面。小心地使用這些功能可以導致界面能夠適應用戶的需要并簡化交互過程。粗心地使用同樣的功能可以導致非常混亂或徹底不可用的程序。本文介紹Swng動態界面設計的技術和體系,并提供有關構建有效的界面的幫助。您將修改隨 Sun JDK 一起提供的基于 SwingSet2 示例應用程序的源代碼;此應用程序的 UI 使用許多動態的特性并且可以作為理解它們的極好的起點。
禁用小部件
Swing動態界面設計的最簡單形式是使不可用的菜單項或按鈕變灰的 UI。禁用 UI 小部件與禁用所有小部件的方法都是相同的。setEnabled() 函數是 Component 類的一個功能。清單 1 顯示了禁用按鈕的代碼:
清單 1. 禁用按鈕
1 button.setEnabled(false);
正如您看到的,十分簡單。關鍵問題是何時應該 啟用或禁用一個按鈕。通常的設計決策是當按鈕不可用時禁用它。例如,當一個文件從上一次保存以來還沒有被修改時,很多程序禁用 Save 按鈕(以及任何相應的菜單項)。
關于禁用按鈕的重要警告是要記住在適當的時候重新啟用它們。例如,如果在單擊按鈕和按鈕的動作完成之間有一個確認步驟,即使確認失敗也應該重新啟用按鈕。
調整范圍
有時,應用程序需要動態地調整數值小部件的范圍,例如 Spinner 或者 Slider。這可能比它看起來要復雜許多。特別是 Slider 有二級功能 —— 刻度、刻度間隔和標簽 —— 這些可能需要隨著范圍的調整而加以調整以避免災難發生。
SwingSet2 示例沒有進行任何一項調整,所以您需要通過把 ChangeListener 連接到一個可以修改其他滑塊的滑塊來修改它。輸入新的 SliderChangeListener 類, 如清單 2 所示:
清單 2. 更改滑塊的范圍
1 class SliderChangeListener implements ChangeListener { 2 JSlider h; 3 4 SliderChangeListener(JSlider h) { 5 this.h = h; 6 } 7 8 public void stateChanged(ChangeEvent e) { 9 JSlider js = (JSlider) e.getSource(); 10 int i = js.getValue(); 11 h.setMaximum(i); 12 h.repaint(); 13 } 14 }
當創建第三個水平滑塊時(最初示例中的滑塊在每個單位處帶有標記,在 5、10 和 11 等處帶有標簽), 另外還創建了一個新的 SliderChangeListener,它把滑塊作為構造器參數傳遞。當創建第三個垂直的滑塊(范圍從 0 到 100)時,新的 SliderChangeListener 作為變更監聽器添加到它。這大致按預期的那樣工作:調整垂直滑塊改變了水平滑塊的范圍。
不幸的是,刻度和標簽根本不能很好地工作。當范圍變得不是太大時,每五個刻度處的標簽能正確地工作,但是刻度 11 處的額外標簽很快成為一個可用性問題,如圖 1 所示:
圖 1. 一起運行的標簽
更新刻度和標簽
在Swing動態界面設計時,明顯的解決方案是,只要滑塊的***值被更新,就在水平滑塊上簡單地設置刻度間隔,如清單 3 所示:
清單 3. 設置刻度間隔
1 // DOES NOT WORK 2 int tickMajor, tickMinor; 3 tickMajor = (i > 5) ? (i / 5) : 1; 4 tickMinor = (tickMajor > 2) ? (tickMajor / 2) : tickMajor; 5 h.setMajorTickSpacing(tickMajor); 6 h.setMinorTickSpacing(tickMinor); 7 h.repaint();
目前清單 3 是正確的,但是它沒有引起畫在屏幕上的標簽的任何變化。必須使用 setLabelTable() 分別設置標簽。 添加額外一行修復它:
1 h.setLabelTable(h.createStandardLabels(tickMajor));
這仍然出現在刻度 11 處存在最初設置的標簽這樣的錯誤。當然本來的意圖是想在滑塊的最右端始終有一個標簽。可以通過刪除舊的標簽(在設置新的***值之前)然后添加一個新的標簽達到這一目的。此代碼 “幾乎” 可以工作:
清單 4. 替換標簽
1 public void stateChanged(ChangeEvent e) { 2 JSlider js = (JSlider) e.getSource(); 3 int i = js.getValue(); 4 5 // clear old label for top value 6 h.getLabelTable().remove(h.getMaximum()); 7 8 h.setMaximum(i); 9 10 int tickMajor, tickMinor; 11 tickMajor = (i > 5) ? (i / 5) : 1; 12 tickMinor = (tickMajor > 2) ? (tickMajor / 2) : tickMajor; 13 h.setMajorTickSpacing(tickMajor); 14 h.setMinorTickSpacing(tickMinor); 15 h.setLabelTable(h.createStandardLabels(tickMajor)); 16 h.getLabelTable().put(new Integer(i), 17 new JLabel(new Integer(i).toString(), JLabel.CENTER)); 18 h.repaint(); 19 }
如果我已經告訴過您一次,那么我就已經告訴您兩次了。
我使用幾乎 的意思是,雖然清單 4 中的代碼刪除了刻度 11 處的標簽,但是它沒有在刻度 i 處添加新標簽;相反,只能看到間隔為 tickMajor 的標簽。首先此解決方法相當令人討厭:
清單 5. 強迫顯示更新
1 h.setLabelTable(h.getLabelTable());
這個看起來無意義的操作實際上有重大的作用。每當設置標簽表時就生成滑塊的標簽。沒有為了修改對表進行特殊回調,所以添加到表中的新值不必產生效果;很顯然,清單 5 中的空操作具有使 Swing 知道它必須更新顯示的副作用。(以免您認為這是我自己發明的,請注意最初的 SwingSet 代碼包括這樣一個調用。)
這只留下了一個問題。標簽出現在滑塊的末端這個非常合理的期望有時使兩個標簽互相直接相鄰,乃至重疊,如圖 2 所示:
圖 2. 滑塊末端的重疊標簽
很多解決此問題的方法都是可行的。編寫自己的代碼以使用值來填充標簽表并停止以前的序列以便序列中的***標簽與滑塊的末端有一些隔離。我將把這個作為作業留給您。
在許多情況下,為了啟用和禁用菜單項而限制菜單修改是很實際的。此方法容易受到用于禁用項的常規警告的影響:避免由于偶然地禁用重要項而使程序處于不可用狀態。
添加或刪除菜單項或子菜單也是可能的。修改 JMenuBar 沒有這么容易;沒有從工具欄上刪除和替換單個菜單的接口。如果您想修改工具欄(而不是向最右端添加菜單),需要制作一個新的工具欄并用它替換舊的工具欄。
修改單個菜單會立即生效;您不必在將菜單連接到工具欄或另一個菜單之前構建一個菜單。當需要修改菜單選項的選擇時,最容易的方法是修改選定的菜單。您可能仍然想添加或刪除完整的菜單,并且這么做并不是特別難。清單 6 顯示一個將菜單插入到菜單條中給定索引前的方法的簡單示例。此示例假定要替換的 JMenuBar 連接到 JFrame 對象,但是任何能使您獲得和設置菜單條的東西的工作方式都是一樣的:
清單 6. 把一個菜單插入到菜單條中
1 public void insertMenu(JFrame frame, JMenu menu, int index) { 2 JMenuBar newBar = new JMenuBar(); 3 JMenuBar oldBar = frame.getJMenuBar(); 4 MenuElement[] oldMenus = oldBar.getSubElements(); 5 int count = oldBar.getMenuCount(); 6 int i; 7 8 for (i = 0; i < count; ++i) { 9 if (i == index) 10 newBar.add(menu); 11 newBar.add((JMenu) oldMenus[i]); 12 } 13 frame.setJMenuBar(newBar); 14 }
上面的代碼我不是開始時就試圖編成這樣;這是最終的版本,已經很好地修復過了所以它能夠運行并反映一些有趣的怪事。初看起來,實現此功能的明顯方法似乎應該是使用 getComponentAtIndex(),但是這種方法已經受到了反對。幸運的是,getSubElements() 已經足夠好。為 newBar.add() 而進行到 JMenu 的強制類型轉換可能是安全的,但是我不喜歡這樣。getSubElements() 接口不僅對菜單條而且對菜單進行操作,菜單可能具有幾種類型的子元素,JMenu 是可以添加到 JMenuBar 的惟一元素。所以必須把元素強制轉換為 JMenu 以把它傳遞到 JMenuBar.add() 方法。不幸的是,如果將來的 API 修訂版允許將除 JMenu 類型之外的元素添加到 JMenuBar,就不再需要把返回的元素強制轉換 JMenu了。
清單 6 中的代碼反映了另外一個相當微妙的界面怪事;菜單數必須提前緩存起來。當把菜單添加到新的菜單條時,它們從舊的菜單條中被刪除。雖然看起來相似,但是清單 7 中的代碼不能工作,因為循環提前結束了:
清單 7. 循環結束太早
1 // DOES NOT WORK 2 for (i = 0; i < oldBar.getMenuCount(); ++i) { 3 if (i == index) 4 newBar.add(menu); 5 newBar.add((JMenu) oldMenus[i]); 6 }
清單 7 中的循環只復制一半數量的菜單。例如,如果開始菜單條上有 4 個 菜單,它復制前面的兩個菜單。復制完***個菜單以后, i 的值為 1 并且 getMenuCount() 返回 3;在復制完第二個菜單以后,i 的值為 2 并且 getMenuCount() 返回 2,因此循環結束。我沒有找到任何介紹通過向菜單條添加菜單從而從另一個菜單條刪除菜單這樣的特性的文檔,因此可能不是有意這樣。但是,它很容易達到這個目的。
從菜單條刪除菜單稍微容易一些;只是把所有其他的菜單從舊的菜單條復制到新的菜單條,就完成了刪除菜單。很容易!
如果界面使用了很多動態菜單更新,創建一組菜單條并在它們之間切換而不是一直動態地更新它們也許會更好一些。但是,如果如此快地改變菜單,可能會使用戶完全發瘋。
勘誤:在本文的草稿階段,我忽略了 JMenuBar 類的繼承方法的列表。其實,它有 remove 和 add 方法可以用來在指定的索引處進行刪除和插入。另外一個教訓是:查看繼承的方法而不僅僅是特定于類的方法。
調整窗口大小
所幸的是對于大多數情況,窗口大小調整是自動進行的。但是需要考慮調整大小產生的一些影響。在非常小的窗口中,按鈕條、菜單條和類似功能可能變成有問題的。管理程序自身的圖形面板需要響應調整大小事件。讓 Swing 處理對 UI 元素的包裝,但是要密切注視組件的大小;不要獲取一次組件的尺寸然后就一直使用這些值。
更微妙的地方是,一些設計決策(例如滑塊上刻度的密度)可能被適度地更新以響應窗口大小調整事件。100 像素寬度的滑塊不能具有像 400 像素寬度的滑塊那樣多的可讀標簽。您可能想通過添加全新的有用功能來讓 UI 更進一步用在大型顯示器上。
但是,在多數情況下,可以忽略窗口大小調整。您不應該做的是不必要地阻止或重寫它。布局代碼中的窗口一側的便捷工具不是必需的。最小的窗口大小可能是無可厚非的,但是要讓人們能把窗口調整到他們所需要的大小。
一般原則
Swing 工具包在Swing動態界面設計方面提供了很大的靈活性。如果小心地使用,動態更新界面的選項能夠極大地簡化該界面;例如,只有應用菜單的選項時,用戶才能容易地顯示菜單。不幸的是,一些 API 的特性可能使此方法產生一些離奇的行為,并且副作用和相互影響并不總是像您期望的那樣記錄下來。如果您有使用動態界面的想法,就要準備在調試上花費一些額外的時間。您可能從 Swing 庫的困境中走出來并發現自己需要處理出人意料的行為和/或 bug。
不要讓缺乏明顯的實現讓您氣餒。像本文的 JMenuBar 示例所顯示的,即使當 API 不支持某個任務時,您也能自己實現它,雖然有一點間接。盡量不要走極端。當動態 UI 讓用戶清楚它們的固有限制時,它們才能***地發揮作用。理想的情況是,用戶甚至可能不會注意到界面變化。如果他們能夠使用程序的 Object 菜單的惟一時刻是當他們使某個對象被選擇時,那么其余的時間他們將不會介意不存在該菜單。
另一方面,如果存在這種可能性:用戶不能猜測出一個選項不可用的原因,這時讓用戶嘗試操作并獲得包含信息的消息也許會更好。這對于一些操作尤其重要。如果保存選項被禁用,而我想保存數據,那么這不會發生作用。程序可能認為已經保存了數據,但是為什么不讓我無論如何都保存它呢?如果存在不能保存文件的特殊原因,我可能想知道是什么原因。
盡管研究了很多年,界面設計在很多方面仍舊是一個較新的領域,只進行了很少的試驗。Swing動態界面設計是一個很好的特性,能夠使 UI 更清晰、更簡單和反應更迅速。添加動態特性需要從幾分鐘的工作到大量時間的花費不等。
以上是“如何使用Swing動態界面設計技術”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。