使用Java模拟Office 2007中的缩放栏(修改后的JSlider)
-
05-07-2019 - |
题
我正在尝试模仿(或找到一个预先存在的组件),模仿Word 2007中的缩放滑块:
此组件与标准Java JSlider有两个主要区别:
- 除了100%之外不会对齐刻度线,并且在您滑动条形图时而不是在释放鼠标时快照按钮
- 滑块在整个过程中不是线性的:滑块的左半部分从10%变为100%;右边从100%到500%。 醇>
来源:
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不允许你多次按住它来触发按钮,而办公室中的+/-按钮则可以。知道如何模仿这个吗?
解决方案
我相信你可以通过自定义BoundedRangeModel获得所有这些行为。关键是要使模型报告为正常类型的值范围,但在需要缩放系数时对其进行不同的处理。
因此,例如,如果你让你的范围从0到100,那么你可以单程0-50,另一种方式50-100(分别为10-100%和100-500%)。
为了获得捕捉行为,我很确定你可以覆盖setValue()来捕捉你想要的范围。因此,使用0-100作为值范围,如果使用47-53调用setValue(),则只需将值捕捉到50。
不隶属于 StackOverflow