Java Swing尝试在JScrollPane上添加固定JButton

cpjpxq1n  于 2023-02-11  发布在  Java
关注(0)|答案(2)|浏览(158)

我试图使一个文本编辑器的按钮,出现在右下角的编辑器,无论你向上或向下滚动,并出现在文本区

import javax.swing.*;
import java.awt.*;

public class Problem{

    public static void main(String[] args){
        //Setting up the frame
        JFrame window = new JFrame();
        window.setSize(600, 400);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Making the LayeredPane
        JLayeredPane LP = new JLayeredPane();
        LP.setLayout(new BorderLayout());

        //Making the ScrollPane and JTextArea
        JTextArea textArea = new JTextArea(100,50);
        textArea.setText("Test Text");
        JScrollPane back = new JScrollPane();
        back.setViewportView(textArea);

        //Making the panel that appears in the front of the text
        JPanel front = new JPanel();
        front.setLayout(null);
        front.setBackground(new Color(0,0,0,0));
        front.setOpaque(false);
        JButton button = new JButton("test");
        button.setBounds(200,200,50,20);
        front.add(button);

        LP.add(back,BorderLayout.CENTER);
        LP.setLayer(back,0,0);

        LP.add(front,BorderLayout.CENTER);
        LP.setLayer(front,1,0);

        window.add(LP);
        window.setVisible(true);
    }
}

我看到的只是白色背景的JButton,如果不添加第二层“front”,则会看到背面的JScrollPane和JTextArea

gjmwrych

gjmwrych1#

警告

我不是这个想法的粉丝。这不是一个"常见"的用户体验概念,许多桌面用户会看到,有很多,可以说,更好的解决方案,利用现有的用户体验。
这需要一些"黑客"来工作,所以,不能保证它会在所有平台上工作或继续工作到未来。
∮ ∮为什么不管用?∮
这是一个相当技术性的问题,它深入探究了Swing的核心,特别是JScrollPane的工作原理。这么说吧,我没有时间也不想深入探究,但我知道JScrollPane经过了大量优化,这可能会影响到覆盖它的任何内容的更新方式--或者这可能只是绘画系统的工作方式。

可运行示例...

这是camickr的想法(这都归功于他),但不是用OverlayLayout,而是用GridBagLayout来定位按钮,为什么呢?因为GridBagLayout让我对按钮的位置有更多的控制权--这是个人的事情。

import java.awt.*;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.swing.*;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());

            JTextArea textArea = new JTextArea(40, 40);
            try (Reader reader = new InputStreamReader(getClass().getResourceAsStream("/resources/StarWarsNewHope.txt"))) {
                textArea.read(reader, "A long list");
            } catch (IOException exp) {
                exp.printStackTrace();
            }
            JButton button = new JButton("Am I in your way yet");

            JPanel contentPane = new JPanel() {
                @Override
                public boolean isOptimizedDrawingEnabled() {
                    return false;
                }
            };
            contentPane.setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1.0;
            gbc.weighty = 1.0;
            // Change this to reposition the button some where else
            gbc.anchor = GridBagConstraints.FIRST_LINE_END;
            gbc.insets = new Insets(32, 32, 32, 32);
            gbc.ipadx = 16;
            gbc.ipady = 16;
            contentPane.add(button, gbc);

            gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1.0;
            gbc.weighty = 1.0;
            gbc.fill = GridBagConstraints.BOTH;

            JScrollPane scrollPane = new JScrollPane(textArea);
            contentPane.add(scrollPane, gbc);

            add(contentPane);
        }

    }
}

您可能还应该查看How to Use Scroll Panes和有关提供自定义装饰的部分,了解一些替代方法

pwuypxnk

pwuypxnk2#

Swing被设计/优化为二维显示/绘制组件。绝大多数布局管理器会确保组件不重叠。
这意味着您不能在分层窗格上使用布局管理器(如果您希望组件重叠),而是必须手动设置组件在每一层上的大小/位置。
当您使用JLayeredPane时,每一层上组件的绘制都是经过管理的,因此最后绘制较高的层。
因此,您的代码可能会更改为如下形式:

import java.awt.*;
import javax.swing.*;

public class Main
{
    public static void main(String[] args)
    {
        JFrame window = new JFrame();
        window.setSize(600, 400);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Making the LayeredPane
        JLayeredPane LP = new JLayeredPane();

        //Making the ScrollPane and JTextArea
        JTextArea textArea = new JTextArea(20,40);
        textArea.setText("Test Text");
        textArea.setSize( textArea.getPreferredSize() );
        JScrollPane back = new JScrollPane( textArea);
        back.setSize( textArea.getSize() );

        JButton button = new JButton("test");
        button.setBounds(200,200,50,20);

        LP.add(back, new Integer(0));
        LP.add(button, new Integer(1));

        window.add(LP);
        window.setVisible(true);
    }
}

JDK中有一个布局管理器OverlayLayout,它被设计成将组件堆叠在另一个组件的顶部。然而,当组件重叠时,即使是这个布局管理器也不能正确地绘制组件。使用这个布局管理器的技巧是使用布局管理器覆盖面板的isOptimizedDrawing()方法,以确保所有组件始终被重绘。在这种情况下,确保底板总是在顶板之前涂漆。

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class Main2
{
    public static void main(String[] args)
    {
        JFrame window = new JFrame();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel contentPane = new JPanel()
        {
            @Override
            public boolean isOptimizedDrawingEnabled()
            {
                return false;
            }
        };
        contentPane.setLayout( new OverlayLayout(contentPane) );

        JPanel top = new JPanel( new GridBagLayout() );
        top.setBorder( new EmptyBorder(0, 0, 16, 16) );
        top.setOpaque(false);
        top.setAlignmentX(1.0f);
        top.setAlignmentY(1.0f);

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        gbc.anchor = GridBagConstraints.LAST_LINE_END;

        JButton button = new JButton("test");
        top.add(button, gbc);
        contentPane.add(top);

        //Making the ScrollPane and JTextArea
        JTextArea textArea = new JTextArea(10,25);
        textArea.setText("Test Text");
        JScrollPane back = new JScrollPane( textArea);
        back.setAlignmentX(1.0f);
        back.setAlignmentY(1.0f);
        contentPane.add(back);

        window.add(contentPane);
        window.pack();
        window.setVisible(true);
    }
}

这种方法的好处是按钮会随着框架的大小调整而移动。
然而,作为一个用户,我仍然会对文本区域中文本上方出现的按钮感到恼火。
编辑:
如果您确实需要组件重叠,那么我建议您可以:
1.看看MadProgrammers使用GridBagLayout的解决方案,这种方法对组件的对齐提供了更多的控制
1.检查Overlap Layout,它在对齐重叠组件时也提供了更大的灵活性
需要注意的是,上述两种方法都需要覆盖isOptimizedDrawEnabled(...)方法以确保组件被正确绘制,我不知道有哪个布局管理器允许您重叠组件,并且不需要覆盖。

相关问题