swing:JSlider 但具有粗/细控制?

发布于 2024-08-16 04:28:32 字数 135 浏览 5 评论 0原文

我有一个 JSlider,有 65536 个不同的值。它非常适合粗调和非常精细的调整(使用向上/向下箭头+/-1),但在中间效果很差。

还有什么更好的吗?我可以模糊地想象使用两个滑块,一个用于粗调+微调,但无法真正弄清楚如何让它们一起工作。

I have a JSlider with 65536 different values. It works great for coarse adjustments and for very fine adjustments (+/-1 using up/down arrow) but is very poor in the middle.

Is there anything out there that would be better? I can vaguely imagine taking 2 sliders one for coarse + fine adjustments, but can't really figure out how to get them to work together.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

叹梦 2024-08-23 04:28:32

使用 JSpinner 而不是 JSlider 怎么样?使用 SpinnerNumberModel,您可以设置步长,甚至可以动态更改步长。

如果您同意拥有多个控件,您甚至可以拥有两个微调器,一个用于设置值,另一个用于设置第一个微调器使用的步长。

作为一个例子,我采用了 SliderDemo Swing 滑块教程 中的代码并将其修改为使用两个 JSpinners 而不是单个 JSlider。这是我更改的代码中最有趣的部分:

//Create the slider^H^H^H^H^H^H spinners.
// JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
//                                       FPS_MIN, FPS_MAX, FPS_INIT);
final int initStep = 1;
final SpinnerNumberModel animationModel = new SpinnerNumberModel(FPS_INIT,
                                                                 FPS_MIN,
                                                                 FPS_MAX,
                                                                 initStep);
final SpinnerNumberModel stepSizeModel = new SpinnerNumberModel(initStep,
                                                                1,
                                                                10,
                                                                1);
final JSpinner framesSpinner = new JSpinner(animationModel);
framesSpinner.addChangeListener(this);

final JSpinner stepSpinner = new JSpinner(stepSizeModel);
stepSpinner.addChangeListener(new ChangeListener() 
{
    public void stateChanged(ChangeEvent arg0)
    {
        animationModel.setStepSize(stepSizeModel.getNumber());
    } 
});

我还必须进行一些不太有趣的更改,例如为步长微调器创建标签,将新标签和新微调器添加到容器,以及更改 < this 上的 code>stateChanged() 方法将事件源强制转换为 JSpinner,而不是强制转换为 JSlider

当然,您可以进一步详细说明,例如增加步长微调器的步长(例如,只需单击一次即可将步长从 1 更改为 101)。您还可以使用不同的控件而不是 JSpinner 来设置步长,例如组合框。

最后,为了使这一切真正易于使用,您可能需要连接一些按键加速器(可能通过菜单?),以便您可以更改步长,而无需实际将鼠标或键盘焦点从一个微调器移动到另一个微调器。

编辑:考虑到无论如何你都必须使用 JSlider,你是否知道你可以使用 PgUp/PgDn 上下移动 1/10总范围的第 th

如果您想更改 1/10th 数量(例如使其动态),则需要重写方法 BasicSliderUI.scrollByBlock()

在下面的示例中,我刚刚覆盖了 JSlider 的 UI 类,以按范围的 1/4 步进,而不是 1/10th >:

//Create the slider.
JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
                                      FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.setUI(new javax.swing.plaf.metal.MetalSliderUI() {

    private static final int SLIDER_FRACTION = 4;

    /**
     * This code is cut, paste, and modified from
     * {@link javax.swing.plaf.basic.BasicSliderUI#scrollByBlock(int).
     * I should be ashamed of cutting and pasting, but whoever hardcoded the magic
     * number "10" in the original code should be more ashamed than me. ;-) 
     *
     * @param direction
     *          either +1 or -1
     */   
    @Override
    public void scrollByBlock(final int direction) {
        synchronized(slider)    {
            int oldValue = slider.getValue();
            int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / SLIDER_FRACTION;
            if (blockIncrement <= 0 && slider.getMaximum() > slider.getMinimum()) {
                blockIncrement = 1;
            }
            int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
            slider.setValue(oldValue + delta);          
        }
    }
});

从这里开始,用另一个滑块或微调器设置的变量替换该常量 SLIDER_FRACTION 不会太难,不是吗?

What about using a JSpinner instead of a JSlider? With a SpinnerNumberModel, you can set the step size and even change the step size dynamically.

If you're OK with having multiple controls, you could even have two spinners, one for setting your values and another for setting the step size that is used by the first spinner.

For an example of this, I took the SliderDemo code from the Swing slider tutorial and modified it instead to use two JSpinners instead of a single JSlider. Here's the most interesting part of the code that I changed:

//Create the slider^H^H^H^H^H^H spinners.
// JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
//                                       FPS_MIN, FPS_MAX, FPS_INIT);
final int initStep = 1;
final SpinnerNumberModel animationModel = new SpinnerNumberModel(FPS_INIT,
                                                                 FPS_MIN,
                                                                 FPS_MAX,
                                                                 initStep);
final SpinnerNumberModel stepSizeModel = new SpinnerNumberModel(initStep,
                                                                1,
                                                                10,
                                                                1);
final JSpinner framesSpinner = new JSpinner(animationModel);
framesSpinner.addChangeListener(this);

final JSpinner stepSpinner = new JSpinner(stepSizeModel);
stepSpinner.addChangeListener(new ChangeListener() 
{
    public void stateChanged(ChangeEvent arg0)
    {
        animationModel.setStepSize(stepSizeModel.getNumber());
    } 
});

I also had to make a bunch of less interesting changes, such as creating a label for the step size spinner, adding the new label and new spinner to the container, and changing the stateChanged() method on this to cast the source of the event to a JSpinner instead of casting it to a JSlider.

You could, of course, elaborate on this further, such as increasing the step size for the step size spinner (for example, so that you can change the step size from 1 to 101 in a single click). You could also use a different control instead of a JSpinner to set the step size, such as a combo box.

Finally, to make this all really easy to use, you would likely want to hook up some keystroke accelerators (possibly through a menu?) so that you could change the step size without actually moving the mouse or the keyboard focus from one spinner to another.

Edit: Given that you have to use a JSlider no matter what, are you aware that you can use PgUp/PgDn to move up and down by 1/10th of the total range?

If you want to change that 1/10th amount (such as making it dynamic), then you'll need to override the the method BasicSliderUI.scrollByBlock().

Here's an example where I just overrode the UI class of a JSlider to step by 1/4th of the range, instead of 1/10th:

//Create the slider.
JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
                                      FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.setUI(new javax.swing.plaf.metal.MetalSliderUI() {

    private static final int SLIDER_FRACTION = 4;

    /**
     * This code is cut, paste, and modified from
     * {@link javax.swing.plaf.basic.BasicSliderUI#scrollByBlock(int).
     * I should be ashamed of cutting and pasting, but whoever hardcoded the magic
     * number "10" in the original code should be more ashamed than me. ;-) 
     *
     * @param direction
     *          either +1 or -1
     */   
    @Override
    public void scrollByBlock(final int direction) {
        synchronized(slider)    {
            int oldValue = slider.getValue();
            int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / SLIDER_FRACTION;
            if (blockIncrement <= 0 && slider.getMaximum() > slider.getMinimum()) {
                blockIncrement = 1;
            }
            int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
            slider.setValue(oldValue + delta);          
        }
    }
});

From here, it wouldn't be too hard to replace that constant SLIDER_FRACTION with a variable that was set by another slider or by a spinner, would it?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文