2009-11-25 19 views
1

我試圖模仿(或找到一個已經存在的組件),模仿從Word 2007中的縮放滑塊:型仿變焦條(修改JSlider的)

Two state zoom bar http://i49.tinypic.com/iyk65l.png

主要有兩種這個組件和一個標準的Java JSlider的差異:

  1. 不捕捉到蜱除了在100%以上,按扣,當你滑動杆,而當您鬆開鼠標比
  2. 滑塊不可線性貫穿整個過程:滑塊的左半部分從10%變爲100%;右側從100%到500%。

這是我到目前爲止有: Java clone http://i45.tinypic.com/2i8dms9.png

來源:

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JSlider; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 

/** 
* 
* @author NDUNN 
* @date Nov 25, 2009 
*/ 
public class ZoomBar extends JPanel implements ActionListener, ChangeListener { 

    private JLabel zoomAmount; 
    private JButton minus; 
    private JButton plus; 
    private JSlider slider; 

    private static final int MIN_ZOOM = 10; 
    private static final int MAX_ZOOM = 200; 
    private static final int DEFAULT_ZOOM = 100; 

    private static final int MAJOR_ZOOM_SPACING = 50; 
    private static final int MINOR_ZOOM_SPACING = 10; 

    public ZoomBar() { 
     super(); 

     minus = new JButton("-"); 
     plus = new JButton("+"); 
     slider = new JSlider(MIN_ZOOM, MAX_ZOOM, DEFAULT_ZOOM); 

     slider.setMinorTickSpacing(MINOR_ZOOM_SPACING); 
     slider.setMajorTickSpacing(MAJOR_ZOOM_SPACING); 
     slider.setPaintTicks(true); 
     slider.setSnapToTicks(true); 

     zoomAmount = new JLabel(slider.getValue() + "%"); 

     add(zoomAmount); 
     add(minus); 
     add(slider); 
     add(plus); 

     plus.addActionListener(this); 
     minus.addActionListener(this); 

     slider.addChangeListener(this); 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame("Zoom bar clone"); 
     frame.setContentPane(new ZoomBar()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public void actionPerformed(ActionEvent e) { 
     if (e.getSource() == plus) { 
      slider.setValue(slider.getValue() + MINOR_ZOOM_SPACING); 
     } 
     else if (e.getSource() == minus) { 
      slider.setValue(slider.getValue() - MINOR_ZOOM_SPACING); 
     } 
    } 

    public void stateChanged(ChangeEvent e) { 
     if (slider.getValueIsAdjusting()) { 
      return; 
     } 
     zoomAmount.setText(slider.getValue() + "%"); 
    } 

} 

基本上只是模仿外觀,但不具備上述兩個特徵。我沒有看到JSlider API中的任何內容讓我得到這種行爲。我是否必須從頭開始才能獲得這種行爲?如果是這樣,這不值得花時間,但是如果有人知道獲得這種行爲的好方法,我認爲在我正在進行的項目中有很好的參與。

感謝,

尼克


編輯:

感謝PSpeed大約只是映射0..50和50..100爲不同值的想法。代碼如下所示。

不幸的是,有關將setValue更改爲快照的想法並不奏效。

public void stateChanged(ChangeEvent e) { 
    // While slider is moving, snap it to midpoint 
    int value = slider.getValue(); 
    if (slider.getValueIsAdjusting()) { 
     return; 
    } 

    zoomValue = fromSlider(value); 
    zoomLabel.setText(zoomValue + "%"); 
} 

public int fromSlider(int sliderValue) { 
    int mappedValue = 0; 
    if (sliderValue <= 50) { 
     // Map from [0, 50] to [MIN ... DEFAULT] 
     mappedValue = (int) map(sliderValue, 0, 50, MIN_ZOOM, DEFAULT_ZOOM); 
    } 
    else { 
     // Convert from (50, 100] to (DEFAULT ... MAX] 
     mappedValue = (int) map(sliderValue, 50, 100, DEFAULT_ZOOM, MAX_ZOOM); 
    } 
    return mappedValue; 
} 

public int toSlider(int modelValue) { 
    int mappedValue = 0; 
    if (modelValue <= DEFAULT_ZOOM) { 
     // Map from [MIN_ZOOM, DEFAULT_ZOOM] to [0 ... 50] 
     mappedValue = (int) map(modelValue, MIN_ZOOM, DEFAULT_ZOOM, 0, 50); 
    } 
    else { 
     // Convert from (DEFAULT ... MAX] to (50, 100] 
     mappedValue = (int) map(modelValue, DEFAULT_ZOOM, MAX_ZOOM, 50, 100); 
    } 
    return mappedValue; 
} 


/** 
* @param value The incoming value to be converted 
* @param low1 Lower bound of the value's current range 
* @param high1 Upper bound of the value's current range 
* @param low2 Lower bound of the value's target range 
* @param high2 Upper bound of the value's target range 
* @return 
*/ 
public static final double map(double value, double low1, double high1, double low2, double high2) { 

    double diff = value - low1; 
    double proportion = diff/(high1 - low1); 

    return lerp(low2, high2, proportion); 
} 

public static final double lerp(double value1, double value2, double amt) { 
    return ((value2 - value1) * amt) + value1; 
} 

編輯2: 另外一個區別,我注意到的是,一個JButton不會讓你抱下來到消防按鈕多次,而在辦公室+/-按鈕做。任何想法如何模仿這個?

+0

你在哪裏做對齊?這個想法是在自定義有限範圍模型內部完成的。理論上,JSlider會試圖告訴你47,但是模型不會聽,只是將它自己的值設置爲50 ...但它仍然需要發起更改事件。這樣JSlider就會知道拇指的正確位置。由於用戶仍在拖動,鼠標仍應處於'47'位置,並且如果它們向左移動多一點,則應該抓拍。如果你描述實際發生的事情,那麼也許我可以想到其他的東西。 – PSpeed 2009-11-26 02:56:53

+0

回覆:您的編輯2,自定義的ButtonModel應該能夠處理... Swing可能已經有一個他們在他們的旋轉器中使用,但沒有暴露。其實,看起來他們在動作監聽器中做了一些複雜的技巧。我仍然認爲乍一看自定義按鈕模型會是最簡單的。 setPressed(true)啓動一個觸發執行動作的定時器,setPressed(false)停止定時器。添加一個初始延遲,讓它感覺更好。 – PSpeed 2009-11-26 03:12:52

+0

我嘗試了BoundedRangeModel和JSlider本身。 http://pastebin.com/f10ddb17f 值肯定是包裝(我注意到它在我還更新的標籤中),但問題是拇指的位置與鼠標光標的位置牢固相關。 – I82Much 2009-11-26 03:19:11

回答

2

我相信你可以用一個自定義的BoundedRangeModel獲得所有這些行爲。關鍵是讓模型報告一個正常類型的值範圍,但是當你想要縮放因子時對它進行不同的處理。例如,如果你讓你的範圍從0到100的範圍內運行,你會以單向50-50的方式(分別爲10-100%和100-500%)處理0-50。

爲了獲得捕捉行爲,我敢肯定你可以重寫setValue()來捕捉你想要的範圍。因此,使用0-100作爲數值範圍,如果使用47-53調用setValue(),那麼只需將該值捕捉到50.