سؤال

أحاول تقليد (أو أجد مكونًا موجودًا مسبقًا) يحاكي شريط تشغيل التكبير من Word 2007:

Two state zoom bar

هناك نوعان من الاختلافات الرئيسية بين هذا المكون و Java JSlider قياسي:

  1. لا يتم التخلص من القراد إلا عند 100 ٪ ، وتستقر أثناء انزلاق الشريط بدلاً من أن تصدر الماوس
  2. شريط التمرير ليس خطيًا طوال الطريق: النصف الأيسر من التمرير ينتقل من 10 ٪ إلى 100 ٪ ؛ الجانب الأيمن يذهب من 100 ٪ إلى 500 ٪.

هذا ما لدي حتى الآن:Java clone

مصدر:

    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 إلى Snap.

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 إلى 100 ، فستعامل 0-50 بطريقة و 50-100 طريقة أخرى (10-100 ٪ و 100-500 ٪ على التوالي).

للحصول على سلوك SNAP ، أنا متأكد تمامًا من أنه يمكنك فقط تجاوز setValue () لالتقاط النطاق الذي تريده. لذا ، باستخدام 0-100 كمدى قيمة ، إذا تم استدعاء setValue () مع 47-53 ، فحسب في التقاط القيمة إلى 50.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top