【问题标题】:Custom Swing Component and updating JScrollPane scrollbars自定义 Swing 组件和更新 JScrollPane 滚动条
【发布时间】:2012-09-02 21:23:23
【问题描述】:

我创建了一个在paintComponent 中绘制文本的自定义JComponent。将其放入 ScrollPane 我想在附加文本超出视口时自动显示 scollbars。当我调整整个框架的大小时,滚动条会正确更新。但我想以编程方式进行。我尝试了几次#validate() 和#invalidate() 调用,但都无济于事。

如何使用自定义组件作为客户端更新滚动窗格的滚动条?

我创建了一个简化的可运行示例来说明我的意思:

package swingscroll;

import java.awt.Color;
import java.awt.Dimension;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class SwingScroll {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI() {
        final JFrame frame = new JFrame(SwingScroll.class.getSimpleName());
        final JComponent myComponent = new JComponent() {
            private Dimension preferredSize;

            @Override
            public void setPreferredSize(Dimension preferredSize) {
                super.setPreferredSize(preferredSize);
                this.preferredSize = preferredSize;
            }


            @Override
            public Dimension getPreferredSize() {
                return this.preferredSize;
            }

        };
        myComponent.setPreferredSize(new Dimension(380, 50));

        final JScrollPane scrollPane = new JScrollPane(myComponent);
        frame.getContentPane().add(scrollPane);

        frame.setSize(400, 100);
        frame.setVisible(true);

        // simulate the internal change of preferredSize in myComponent
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(SwingScroll.class.getName()).log(Level.SEVERE, null, ex);
                }
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        // this should trigger the scrollbar right?
                        myComponent.setPreferredSize(new Dimension(380, 1000));
                        // TODO insert code to update scrollbars
                    }
                });
            }
        }).start();
    }
}

【问题讨论】:

  • “我已经创建了一个自定义 JComponent 来绘制文本..” 自定义代码做了什么(除了失败),而不能在JLabelJTextFieldJTextAreaJEditorPane 等等?
  • 它允许可拖动的垂直标尺(带有右对齐的文本)和或多或少的智能文本选择。我不确定它不能使用 JTextComponent 或类似的东西来完成。用 jlabel 替换自定义组件并调用 #setText 行为正确。但我在#setText 中看到的只是重新验证和重新绘制。当我在我的简单示例中添加重新验证和重新绘制时,滚动条仍然没有更新。我无法遵循代码还有什么必要的。 JLabel 如何更新滚动条?

标签: java swing custom-controls


【解决方案1】:
// TODO insert code to update scrollbars
myComponent.revalidate();

刚刚看到你的评论:

当我在我的简单示例中添加重新验证和重新绘制时,滚动条仍然没有更新。

Worksforme - 虽然您的示例的问题是滚动条总是显示,所以看起来什么都没有发生。调整大小以使最初没有垂直滚动条,然后更新到必须显示条的高度就可以了。

顺便说一句:我假设示例中的 setPref 仅用于演示,不是在生产代码中。

【讨论】:

  • 谢谢,它有效。是的,setPref 的东西只是演示。我现在在我的自定义组件的 paintComponent() 方法的末尾添加了 revalidate(),这解决了我的问题。不知何故,我觉得我做错了。 paintComponent 渲染文本并缓存每个文本的矩形,以便 getPreferredSize 可以使用这些缓存的矩形来计算整个组件所需的高度。是否应该以其他方式完成?
  • 您的感觉是正确的 - 永远不会在绘画时改变组件的状态。相反,更改状态,然后根据需要调用 repaint/revalidate
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-30
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多