JScrollBar não sendo adicionado ao JPanel

Um rapaz aqui no trabalho falou sobre um trabalho de escola que ele estava fazendo e disse que não conseguia colocar um scrollbar na sua aplicação. Como eu não mexo muito com a parte “visual” do Java, dei uma googlada e mandei o básico pra ele, mas parece que não rolou. Vocês saberiam dizer o por quê da scrollbar não aparecer? O código compila normalmente.

[parte do código relacionada]

JScrollPane scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        JF.setExtendedState(JFrame.MAXIMIZED_BOTH);
        JF.setLayout(new BorderLayout());
        JF.setVisible(true);
        JF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JF.add(scroll);

        Canvas[] videoCanvas = new Canvas[Num_Video];
        JPanel mainPanel = new JPanel(new FlowLayout());
        JPanel[] vidPanel = new JPanel[Num_Video];

        for (int i = 0; i < Num_Video; i++) {
            vidPanel[i] = new JPanel();
            videoCanvas[i] = new Canvas();
            vidPanel[i].setPreferredSize(new Dimension(Video_Width, Video_Height));
            vidPanel[i].setBackground(Color.black);
            vidPanel[i].setLayout(new BorderLayout());
            videoCanvas[i].setBackground(Color.black);
            vidPanel[i].add(videoCanvas[i], BorderLayout.CENTER);
            mainPanel.add(vidPanel[i]);

        }

        for (int i = 0; i < Num_Video; i++) {
            factory[i] = new MediaPlayerFactory();
            mediaPlayer[i] = factory[i].newEmbeddedMediaPlayer();
            mediaPlayer[i].setVideoSurface(factory[i].newVideoSurface(videoCanvas[i]));
            mediaPlayer[i].setPlaySubItems(true);
            mediaPlayer[i].addMediaPlayerEventListener(new MediaPlayerEventAdapter() {

                @Override
                public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) {
                    List<String> items = mediaPlayer.subItems();
                    System.out.println(items);
                }
            });
        }
        JF.add(mainPanel, BorderLayout.CENTER);
        JF.add(statusPanel, BorderLayout.SOUTH);
    }

EDIT: Eu disse para ele criar o JFrame e tentar alterar ali, ele refez e disse que ainda nd.

É que na verdade o JPanel precisa ser adicionado ao JScrollBar. No JFrame, insere o JScroll e Depois o JPanel, se tentar mudar a cor do painel, verá que foi alterado

@rodriguesabner comecei a brincar um pouco pra ver se ajudava o meninão e achei o JScrollBar. Adicionei ele e apareceu suave, mas sem funcionalidade. Dá pra fazer da sua forma usando o JScrollBar?

this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.setLayout(new BorderLayout());
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Canvas[] videoCanvas = new Canvas[Num_Video];
        JPanel mainPanel = new JPanel(new FlowLayout());
        JPanel[] vidPanel = new JPanel[Num_Video];
        JScrollBar scroll = new JScrollBar();

        for (int i = 0; i < Num_Video; i++) {
            vidPanel[i] = new JPanel();
            videoCanvas[i] = new Canvas();
            vidPanel[i].setPreferredSize(new Dimension(Video_Width, Video_Height));
            vidPanel[i].setBackground(Color.black);
            vidPanel[i].setLayout(new BorderLayout());
            videoCanvas[i].setBackground(Color.black);
            vidPanel[i].add(videoCanvas[i], BorderLayout.CENTER);
            mainPanel.add(vidPanel[i]);

        }

        for (int i = 0; i < Num_Video; i++) {
            factory[i] = new MediaPlayerFactory();
            mediaPlayer[i] = factory[i].newEmbeddedMediaPlayer();
            mediaPlayer[i].setVideoSurface(factory[i].newVideoSurface(videoCanvas[i]));
            mediaPlayer[i].setPlaySubItems(true);
            mediaPlayer[i].addMediaPlayerEventListener(new MediaPlayerEventAdapter() {

                @Override
                public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) {
                    List<String> items = mediaPlayer.subItems();
                    System.out.println(items);
                }
            });
        }
        this.add(mainPanel, BorderLayout.CENTER);
        this.add(statusPanel, BorderLayout.SOUTH);
        this.add(scroll, BorderLayout.EAST);

Fiz isso que tu falou da seguinte forma:

 Canvas[] videoCanvas = new Canvas[Num_Video];
        JPanel mainPanel = new JPanel(new FlowLayout());
        JPanel[] vidPanel = new JPanel[Num_Video];
        JScrollPane scroll = new JScrollPane(mainPanel);
[...]
   this.add(scroll, BorderLayout.EAST);
        this.add(mainPanel, BorderLayout.CENTER);
        this.add(statusPanel, BorderLayout.SOUTH);

Mas sumiu a barra e tudo mais.

Aí é só ir adicionando os itens, se você tentar colocar qualquer coisa no limite do JPanel, você vai ver que a barra é adicionada sozinha

Você pode instanciar normalmente o JScrollPane adicioná-lo no Frame e colocar na visão dele o JPanel que deseja mostrar no método setViewportView(JPanel), como é feito com JTable.
Você está instanciando o JScrollPane sem argumentos no construtor? Se sim, ele só vai mostrar a barra se o JPanel for maior que ele.
E se ele mudar em tempo de execução o tamanho do JPanel deixando ele maior, precisa chamar o revalidate().

Ele não desce não shusuhsuhsuhhu nesse exemplo tá usando o JScrollBar, com o JScrollPane nem aparece o lance. Código dessa tela:

this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLayout(new BorderLayout());
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Canvas[] videoCanvas = new Canvas[Num_Video];
JPanel mainPanel = new JPanel(new FlowLayout());
JPanel[] vidPanel = new JPanel[Num_Video];
JScrollBar scroll = new JScrollBar();

for (int i = 0; i < Num_Video; i++) {
    vidPanel[i] = new JPanel();
    videoCanvas[i] = new Canvas();
    vidPanel[i].setPreferredSize(new Dimension(Video_Width, Video_Height));
    vidPanel[i].setBackground(Color.black);
    vidPanel[i].setLayout(new BorderLayout());
    videoCanvas[i].setBackground(Color.black);
    vidPanel[i].add(videoCanvas[i], BorderLayout.CENTER);
    mainPanel.add(vidPanel[i]);

}

for (int i = 0; i < Num_Video; i++) {
    factory[i] = new MediaPlayerFactory();
    mediaPlayer[i] = factory[i].newEmbeddedMediaPlayer();
    mediaPlayer[i].setVideoSurface(factory[i].newVideoSurface(videoCanvas[i]));
    mediaPlayer[i].setPlaySubItems(true);
    mediaPlayer[i].addMediaPlayerEventListener(new MediaPlayerEventAdapter() {

        @Override
        public void mediaSubItemAdded(MediaPlayer mediaPlayer, libvlc_media_t subItem) {
            List<String> items = mediaPlayer.subItems();
            System.out.println(items);
        }
    });
}
mainPanel.add(scroll);
this.add(scroll, BorderLayout.EAST); // sem isso ele aparece por ultimo, minusculo, e sem funcionalidade aparente
this.add(mainPanel, BorderLayout.CENTER);
this.add(statusPanel, BorderLayout.SOUTH);
}

Ahhhhhhh, puts, ignora. Você precisa adicionar o seu JPanel em um JScrollPane, vacilei cara

E depois usar o Jscrollbar, é isso? asuhhusa

No final, envés de colocar isso:
mainPanel.add(scroll);
this.add(scroll, BorderLayout.EAST);
this.add(mainPanel, BorderLayout.CENTER);
this.add(statusPanel, BorderLayout.SOUTH);

Colocar isso:
this.add(scroll, BorderLayout.CENTER)
Não funciona??

Então Daniel95, eu percebi que o mainPanel.add(scroll); tava meio que boiando ali, retirei e talz. O lance é que só conseguimos fazer a barra aparecer com o JScrollBar, mas sem funcionalidade. Comecei a pensar no que o Abner disse, talvez precisamos colocar o mainPanel dentro de um “lugar scrollável”, ou seja, o JScrollPane, e depois associar o JScrollBar a esse Pane. Mas como fazer isso? Talvez eu esteja até pensando errado, mas creio ser isso msm.

O JPanel que precisa ser “scrollavel” deve ser colocado no JScrollPane utilizando o método setViewportView(Component) que eu coloquei acima, se no caso for o mainPanel é só colocar:
scroll.setViewportView(mainPanel);
Depois é só adicionar o JScrollPane no frame:
this.add(scroll, BorderLayout.CENTER);

Com esse código, a barra deveria aparecer automaticamente? Ou eu preciso cria-lá com JScrollBar?

No caso, usando o que você passou para nós, a barra não aparece e talz.

Se o JPanel que ta sendo exibido for maior que o JScrollPane ele deve aparecer automaticamente sim, até se o Frame for resizable e você alterar a dimensão dele pro JScrollPane ficar maior comportando tudo, o LayoutManager já vai tomar conta disso e as barras vão sumir.
Se elas não tão aparecendo ou ta sendo passado algo no construtor do JScrollPane (Você pode passar ao construtor politicas pra sempre aparecer as barras, quando precisar, ou nunca aparecer). Ou a ordem de exibição ou algo do tipo pode não estar validando ele. Esperimenta dar um revalidate no mainPanel no final.

Então, com esse código:

Canvas[] videoCanvas = new Canvas[Num_Video];
        JPanel mainPanel = new JPanel(new FlowLayout());
        JPanel[] vidPanel = new JPanel[Num_Video];
        JScrollPane scroll = new JScrollPane(mainPanel);
[...]
     scroll.setViewportView(mainPanel);
scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        this.add(mainPanel, BorderLayout.CENTER);
        this.add(statusPanel, BorderLayout.SOUTH);
        mainPanel.revalidate();

Temos esse resultado:

Sem barra e sem scroll, apesar de que na teoria tá tudo setado. As políticas e tal

Então mas, no código que eu postei ali encima não é o mainPanel que é adicionado ao frame, mas sim o JScrollPane.
Esta linha:
this.add(mainPanel, BorderLayout.CENTER);
troque por esta:
this.add(scroll, BorderLayout.CENTER);

1 curtida

Interessante! Realmente eu esqueci esse detalhe e, de fato, ele funcionou.
Porém ele apresenta o seguinte comportamento: jogou tudo na vertical, uhsuhsuhs
Como posso arrumar isso? (De antemão: muito obrigado pela ajuda! Tava complicado de entender.)

Se ele ta tudo ok então pode remover estas linhas:
scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
mainPanel.revalidate();

Então cara, eu acho que é isso mesmo que deveria acontecer, porque ele está usando um flowLayout no mainPanel e adicionando os vidPanel um a um, eles deveriam ficar um do lado do outro mesmo.
Se ele quiser que fique de três em três e centralizado ou algo do tipo, aí já é papel do LayoutManager mesmo, ele precisa especificar isso.

Será? Afinal ele usa o flow pra deixar na forma de 3 centralizado, conforme postei em cima… o LayoutManager é complexo de configurar?

Nessa parte do código aí ele coloca nada no layout pra ficar de 3 em 3 não, só se ele colocar em outra. Alí no print ele deve ter ficado de 3 em 3 provavelmente porque você tava adicionando o Panel direto no frame então como não tinha mais espaço pro lado ele ia pra baixo, mas com o scroll ele abre quanto espaço for necessário pra ele fluir.

Cara não é não, eu gosto de utilizar o MigLayout é uma api externa que da pra fazer uns layouts bem fáceis nela, só precisa passar umas strings na hora de adicionar os componentes pra ele saber o que fazer.

1 curtida

Bacana cara, obrigadão pela ajuda. Vou deixar o meninão pesquisar sobre o MigLayout.