【问题标题】:Align items in a panel to the top swing将面板中的项目与顶部摆动对齐
【发布时间】:2021-03-24 14:27:12
【问题描述】:

我正在尝试将一些项目动态添加到 jpanel。我使用 gridbaglayout 作为这个 jpanel 的经理(下面是红色背景色),我想将面板及其项目垂直对齐到顶部。知道如何让这个面板进入面板顶部吗?

这是我的代码:

public class WebcamFrame extends JFrame implements Runnable {
    private Webcam webcam;
    private WebcamPanel webcamPanel;
    private JLabel labelText;
    private JPanel actionsPanel;
    private boolean running;
    private HashSet<String> cardsPlayed;
    private final JPanel actionsContainer;
    private final JPanel buttonsPanel;
    private final GridBagConstraints constraints;

    public WebcamFrame( Callback killWebcam, Callback handleSubmit ) {
        running = true;
        setLayout( new FlowLayout() );
        setTitle( "Scan a card" );
        setIconImage( new ImageIcon(getClass().getResource("/tslogo.png")).getImage() );
        setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
        addWindowListener( new WindowAdapter() {
            @Override
            public void windowClosing( WindowEvent e ) {
                super.windowClosing( e );
                killWebcam.call();
            }
        } );
        cardsPlayed = new HashSet<>();
        Dimension size = WebcamResolution.QVGA.getSize();
        webcam = Webcam.getDefault();
        webcam.setViewSize( size );
        webcamPanel = new WebcamPanel( webcam );
        webcamPanel.setPreferredSize( size );
        webcamPanel.setLayout( new BorderLayout() );
        labelText = new JLabel( "", SwingConstants.CENTER );
        if( Webcam.getDefault() == null ) labelText.setText( "No Webcam detected" );
        actionsContainer = new JPanel( new BorderLayout() );
        JButton confirmButton = new JButton( "Confirm Selection" );
        confirmButton.addActionListener( e -> {
            List<CardDataModel> cardsToSubmit = new ArrayList<>();
            cardsPlayed.forEach( cardName -> {
                CardDataModel card = new CardDataModel();
                card.cardName = cardName;
                cardsToSubmit.add( card );
            } );
            handleSubmit.call( cardsToSubmit );
        } );
        JButton clearButton = new JButton( "Clear Selection" );
        buttonsPanel = new JPanel();
        buttonsPanel.add( confirmButton );
        buttonsPanel.add( clearButton );
        buttonsPanel.setVisible( false );
        
        constraints = new GridBagConstraints();
        
        clearButton.addActionListener( e -> { 
            cardsPlayed.clear();
            actionsPanel.removeAll();
            constraints.gridy = 0;
            actionsPanel.add( new JLabel( "Played Cards"), constraints );
            actionsContainer.setVisible( false );
            buttonsPanel.setVisible( false );
            labelText.setVisible( false );
            constraints.gridy = 0;
            pack();
        } );
        
        JPanel subPanel = new JPanel();
        subPanel.setLayout( new BorderLayout() );
        subPanel.add( labelText, BorderLayout.NORTH );
        subPanel.add( buttonsPanel, BorderLayout.SOUTH );
        webcamPanel.add( subPanel, BorderLayout.SOUTH );
        
        actionsPanel = new JPanel( new GridBagLayout() ); 
        constraints.gridy = 0;
        constraints.insets = new Insets( 0, 0, 5, 0 );
        actionsPanel.add( new JLabel( "Played Cards"), constraints );
        actionsPanel.setBackground(Color.red);
        JScrollPane scrollPane = new JScrollPane( actionsPanel );
        actionsContainer.add( scrollPane, BorderLayout.NORTH );
        actionsContainer.setVisible( false );
        add( webcamPanel );
        add( actionsContainer );
        
        pack();
        setLocationRelativeTo( null );
        setVisible( false );
        setResizable( false );
    }

    @Override
    public void run() {
        do {
            try {
                Thread.sleep( 100 );
            } catch( InterruptedException e ) {
                e.printStackTrace();
            }
            Result result = null;
            BufferedImage image;
            // Only try to read qr code if webcam is open and frame is webCamFrame is visible
            if( webcam.isOpen() && isVisible() ) {
                if( (image = webcam.getImage()) == null ) {
                    continue;
                }
                LuminanceSource source = new BufferedImageLuminanceSource( image );
                BinaryBitmap bitmap = new BinaryBitmap( new HybridBinarizer(source) );
                try {
                    result = new MultiFormatReader().decode( bitmap );
                } catch( NotFoundException e ) {
                    // fall through if there is no QR code in image
                }
            }
            if( result != null ) {
                String cardName = result.getText();
                if( !cardsPlayed.contains( cardName ) ) {
                    labelText.setText( "Play card" + (cardsPlayed.size() > 0 ? "s" : "") + "?" );
                    cardsPlayed.add( cardName ); 
                    JPanel cardPlayedPanel = new JPanel( new GridLayout( 0, 1, 5, 5) );
                    cardPlayedPanel.setBorder( BorderFactory.createCompoundBorder(new LineBorder(Color.BLACK), new EmptyBorder(2, 2, 2, 2)) );
                    cardPlayedPanel.setOpaque( true );
                    cardPlayedPanel.setBackground( Color.LIGHT_GRAY );
                    cardPlayedPanel.add( new JLabel(cardName) );
                    constraints.gridy++;
                    actionsPanel.add(cardPlayedPanel, constraints );
                    actionsContainer.setVisible( true );
                    buttonsPanel.setVisible( true );
                    pack();
                }
            }
        } while( running );
    }
}

提前感谢您的帮助

【问题讨论】:

  • 1) 为了尽快获得更好的帮助,edit 添加minimal reproducible exampleShort, Self Contained, Correct Example。布局问题不需要网络摄像头之类的东西。只需添加 JLabel 即可。 2) GridLayout 适用于单列组件。要将其置于面板顶部,请将网格布局面板添加到 PAGE_STARTBorderLayout
  • 把GridBagLayout JPanel放到FlowLayout JPanel里面,把FlowLayout JPanel放到JFrame上。
  • @c0der 是的,我只接受能回答我问题的答案。没想到这是犯罪
  • @Tamjid 没有意识到这是犯罪 - 是的,这是犯罪。如果人们花时间提供帮助并提供建议,那么您至少可以“接受”答案,或者回复 cmets 说明这些建议是否有帮助。你在这里得到帮助:stackoverflow.com/questions/65929527/… 和这里:stackoverflow.com/questions/66309992/…。我不知道你是否愿意阅读这些建议。如果您不感谢所提供的帮助,我们为什么要继续提供帮助?
  • 我没有说你可以“接受”评论。我建议您可以添加自己的评论以表明该建议是否有帮助。这样我们至少知道您花时间阅读评论并尝试建议。

标签: java swing layout-manager gridbaglayout


【解决方案1】:

我想将面板及其项目垂直对齐到顶部。

阅读 How to Use GridBagLayout 上的 Swing 教程。

您可以使用GridBagConstraints 对象的anchor 约束来控制组件在可用空间中的位置。

编辑:

如果有人知道解决此问题的更好方法,请发布答案!

我们不能给出“准确”的答案,因为布局管理总是处理框架调整大小。我们不知道哪些组件会随着帧大小的变化而增大或缩小。

在任何情况下,解决方案总是相同的。使用不同的布局管理器嵌套面板以实现所需的布局。

我意识到这个问题的发生是因为我的框架使用了 flowlayout 并且 flowlayout 中的 2 个组件的高度不同

所以我上面的回答仍然有效。您将框架布局更改为也使用GridBagLayout(而不是 FlowLayout)。然后将两个子面板添加到框架中。您使用“anchor”约束将每个面板锚定到单元格的垂直顶部。

或者,如果您真的想使用 BoxLayout 而不是 FlowLayout,那么当您将面板添加到 BoxLayout 时,您需要使用:

panel.setAlignmentY(0.0f);

在每个面板上。这应该告诉每个面板与顶部对齐。不需要重写 getBaseLine() 方法。

【讨论】:

  • 我想你误解了发生了什么,gridbaglayout中的项目在面板的顶部,但是带有gridbaglayout本身的面板不在其父组件的顶部(请看我的附件截图)
  • 你用GridBagLayout 标记了这个问题,所以我假设你对整个框架使用了 GridBagLayout,在这种情况下我的建议会起作用。
  • 感谢您抽出宝贵时间 :)
【解决方案2】:

通过我自己的实验,我意识到会出现这个问题,因为我的框架使用了 flowlayout,并且 flowlayout 中的 2 个组件的高度不同。然后因为流程布局总是垂直居中我的问题正在发生。我从这里用一些 hacky 代码解决了这个问题: https://stackoverflow.com/a/28878404/6716062 但是,如果有人知道解决此问题的更好方法,请发布答案! :)

【讨论】:

  • 解决方案的一部分是停止思考“单一布局”。大多数 GUI 将使用多个布局,每个布局都被选为整个 GUI 一部分的正确布局。我在my comment 的第 (2) 部分中提到了这一点
  • 虽然我有嵌套布局,但我没有这样做吗
  • 好吧,如果使用复合布局效果很好,你就不需要“hacks”了。
猜你喜欢
  • 2014-09-25
  • 2021-03-29
  • 2012-05-03
  • 2016-04-26
  • 2016-03-01
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多