I'm trying to create a program that lists movies in a Netflix style to learn Front-End coding.
How I want it to look in the end:
My guess is that every movie is a button component with an image a name label and a release year label.
I'm struggling to recreate this look. This is how it looks when I try it:
The navigationbar in my image is at the page start of a border layout. Below the navigationbar the movie container is in the center of the border layout.
My idea was creating a GridLayout and then create a button for each movie and adding it to the GridLayout.
You can recreate this with this code:
public class Main {
private static JFrame frame;
public static void main(String[] args) throws HeadlessException {
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setBackground(new Color(32, 32, 32));
JPanel navigationPanel = createNavigationBar();
frame.add(navigationPanel, BorderLayout.PAGE_START);
JPanel moviePanel = createMoviePanel();
frame.add(moviePanel, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(1920, 1080));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Example App");
frame.pack();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
}
public static JPanel createMoviePanel() {
JPanel moviePanel = new JPanel();
GridLayout layout = new GridLayout(0, 10);
layout.setHgap(3);
layout.setVgap(3);
moviePanel.setLayout(layout);
moviePanel.setBackground(new Color(32, 32, 32));
ArrayList<String> exampleList = new ArrayList<>();
// Add stuff to the example list
for(int i = 0; i < 120; i++) {
exampleList.add(Integer.toString(i));
}
final File root = new File("");
for(final String movie : exampleList) {
JLabel picLabel = new JLabel();
try {
File imageFile = new File(root.getAbsolutePath() + "\\src\\images\\" + "imageName.jpg"); // Try to find the cover image
if(imageFile.exists()) {
BufferedImage movieCover = ImageIO.read(imageFile);
picLabel = new JLabel(new ImageIcon(movieCover));
} else {
BufferedImage movieCover = ImageIO.read(new File(root.getAbsolutePath() + "\\src\\images\\temp.jpg")); // Get a temp image
picLabel = new JLabel(new ImageIcon(movieCover));
}
} catch (IOException e) {
e.printStackTrace();
}
JLabel movieName = new JLabel("New Movie");
movieName.setForeground(Color.WHITE);;
JButton movieButton = new JButton();
movieButton.setLayout(new GridLayout(0, 1));
//movieButton.setContentAreaFilled(false);
//movieButton.setBorderPainted(false);
//movieButton.setFocusPainted(false);
movieButton.add(picLabel);
movieButton.add(movieName);
moviePanel.add(movieButton);
}
return moviePanel;
}
public static JPanel createNavigationBar() {
JPanel navBar = new JPanel();
navBar.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 20));
navBar.setBackground(new Color(25, 25, 25));
JButton homeButton = new JButton("Home");
homeButton.setContentAreaFilled(false);
homeButton.setBorderPainted(false);
homeButton.setFocusPainted(false);
JButton movieButton = new JButton("Movies");
movieButton.setContentAreaFilled(false);
movieButton.setBorderPainted(false);
movieButton.setFocusPainted(false);
// Add all the buttons to the navbar
navBar.add(homeButton);
navBar.add(movieButton);
return navBar;
}
}
I noticed that the GridLayout always tries to fit everything onto the window.
All that's needed is a properly configured JButton in a GridLayout.
E.G.
public static JPanel createMoviePanel() {
JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
movieLibraryPanel.setBackground(new Color(132, 132, 132));
int m = 5;
BufferedImage image = new BufferedImage(9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
for (int ii = 1; ii < 21; ii++) {
JButton picButton = new JButton("Mov " + ii, new ImageIcon(image));
picButton.setMargin(new Insets(0,0,0,0));
picButton.setForeground(Color.WHITE);
picButton.setContentAreaFilled(false);
picButton.setHorizontalTextPosition(JButton.CENTER);
picButton.setVerticalTextPosition(JButton.BOTTOM);
movieLibraryPanel.add(picButton);
}
return movieLibraryPanel;
}
Here is a complete source for the above with a tweak to put the year on a new line. It uses HTML in the JButton to break the button text into two lines.
The input focus is on the first button, whereas the mouse hovers over the '2009' movie:
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
class MovieGrid {
MovieGrid() {
JFrame f = new JFrame("Movie Grid");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.add(createMoviePanel());
f.pack();
f.setVisible(true);
}
public static JPanel createMoviePanel() {
JPanel movieLibraryPanel = new JPanel(new GridLayout(0, 10, 3, 3));
movieLibraryPanel.setBackground(new Color(132, 132, 132));
int m = 5;
BufferedImage image = new BufferedImage(
9 * m, 16 * m, BufferedImage.TYPE_INT_RGB);
for (int ii = 2001; ii < 2021; ii++) {
JButton picButton = new JButton(
"<html>Movie<br>" + ii, new ImageIcon(image));
picButton.setMargin(new Insets(0,0,0,0));
picButton.setForeground(Color.WHITE);
picButton.setContentAreaFilled(false);
picButton.setHorizontalTextPosition(JButton.CENTER);
picButton.setVerticalTextPosition(JButton.BOTTOM);
movieLibraryPanel.add(picButton);
}
return movieLibraryPanel;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new MovieGrid();
}
};
SwingUtilities.invokeLater(r);
}
}
Same idea's from Andrew Thompson answer but with some minor text alignment changes and hover effect
final class Testing
{
public static void main(String[] args)
{
JFrame frame=new JFrame("NEFLIX");
frame.setContentPane(new GridDisplay());
frame.pack();
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static final class GridDisplay extends JPanel implements ActionListener
{
private GridDisplay()
{
super(new GridLayout(0,5,20,20));
setBackground(new Color(0,0,0,255));
BufferedImage image=new BufferedImage(150,200,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d=(Graphics2D)image.getGraphics();
g2d.setColor(Color.BLUE);
g2d.fillRect(0,0,image.getWidth(),image.getHeight());
HoverPainter painter=new HoverPainter();
for(int i=0;i<10;i++)
{
TVShowCard card=new TVShowCard(image,"Show "+i,"199"+i);
card.addMouseListener(painter);
add(card);
}
}
//highlight only on hover
private final class HoverPainter extends MouseAdapter
{
#Override
public void mouseExited(MouseEvent e) {
((TVShowCard)e.getSource()).setBorderPainted(false);
}
#Override
public void mouseEntered(MouseEvent e) {
((TVShowCard)e.getSource()).setBorderPainted(true);
}
}
private final class TVShowCard extends JButton
{
private TVShowCard(BufferedImage preview,String name,String year)
{
super();
setContentAreaFilled(false);
setBackground(new Color(0,0,0,0));
setFocusPainted(false);
setBorderPainted(false);
//I didn't use image icon & text horizontal alignment because the text always horizontally centered aligned but from the expected output it was left so created 2 labels for the job
setLayout(new GridBagLayout());
addIcon(preview);
addLabel(name,year);
addActionListener(GridDisplay.this);
}
private void addIcon(BufferedImage preview)
{
JLabel icon=new JLabel();
icon.setIcon(new ImageIcon(preview));
add(icon,new GridBagConstraints(0,0,1,1,1.0f,0.0f,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
}
private void addLabel(String name,String year)
{
JLabel label=new JLabel("<html><body>"+name+"<br>"+year+"</body></html>");
label.setForeground(Color.white);
label.setBackground(new Color(0,0,0,0));
add(label,new GridBagConstraints(0,1,1,1,1.0f,1.0f,GridBagConstraints.SOUTHWEST,GridBagConstraints.NONE,new Insets(5,0,0,0),0,0));
}
}
#Override
public void actionPerformed(ActionEvent e)
{
TVShowCard card=(TVShowCard)e.getSource();
//do stuff with it
}
}
}
I got a project where I always want to center the focused JPanel. So I thought I can just change the Viewport position. But I can't use the viewport. I created an example project to show how I use the viewport. I just want that the user only see one of the orange boxes. But it should be also possible to view all boxes at once. So the view has to zoom in or something like this. How can I fix this problem?
My example:
import javax.swing.*;
import java.awt.*;
public class main {
public static void main(String [] args){
//create JFrame
JFrame _frame = new JFrame();
//create Viewport
JViewport _view = new JViewport();
//create Mainpanel
JPanel _mainPanel = new JPanel();
//tell the view to handle mainpanel
_view.setView(_mainPanel);
//create Layout
GridLayout _layout = new GridLayout(3,3,3,3);
//set gridlayout to mainpanel
_mainPanel.setLayout(_layout);
for(int i = 0;i<12;i++){
JPanel _tempPanel = new JPanel();
_tempPanel.setBackground(Color.ORANGE);
_tempPanel.setBorder(BorderFactory.createLineBorder(Color.black));
_mainPanel.add(_tempPanel);
}
_view.setExtentSize(new Dimension(300,300));
//add mainpanel to frame
_frame.add(_mainPanel);
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.pack();
//set size of Jframe
_frame.setSize(1000,1000);
_frame.setVisible(true);
}
}
JViewPort can not help you with your requirement.
Here is an ugly but running code. You can improve it yourself.
public static void main(String[] args) {
// create JFrame
JFrame _frame = new JFrame();
JPanel conPanel = new JPanel(new BorderLayout());
// create Mainpanel
JPanel _mainPanel = new JPanel() {
#Override
public String toString() {
return "All";
}
};
// create Layout
GridLayout _layout = new GridLayout(3, 3, 3, 3);
// set gridlayout to mainpanel
_mainPanel.setLayout(_layout);
JComboBox<JPanel> combo = new JComboBox<>();
combo.addItem(_mainPanel);
for (int i = 0; i < 12; i++) {
final int fi = i;
JPanel _tempPanel = new JPanel() {
#Override
public String toString() {
return "Panel" + fi;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(toString(), 5, 15);
}
};
_tempPanel.setBackground(Color.ORANGE);
_tempPanel.setBorder(BorderFactory.createLineBorder(Color.black));
_mainPanel.add(_tempPanel);
combo.addItem(_tempPanel);
}
combo.addActionListener( e -> {
JPanel panel = (JPanel)combo.getSelectedItem();
conPanel.remove(_mainPanel);
_mainPanel.removeAll();
for(int i = 1; i < combo.getItemCount(); i++)
_mainPanel.add(combo.getItemAt(i));
conPanel.add(panel, BorderLayout.CENTER);
conPanel.revalidate();
conPanel.repaint();
} );
conPanel.add(_mainPanel, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
buttonsPanel.add(combo);
conPanel.add(buttonsPanel, BorderLayout.SOUTH);
// add mainpanel to frame
_frame.setContentPane(conPanel);
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set size of Jframe
_frame.setSize(1000, 1000);
_frame.setVisible(true);
}
I have a list and I want each time when I select a value from the list, its index to be displayed into a JPanel. I must mention that when I print the index in the console it gets printed the right way, but in the JPanel I don't get anything. An very intresting that I noticed is that in first instance if I select a value nothing is displayed in the JPanel, but if I minimize the frame and then maximize it back the index is displayed in the panel.
Any explanations for this strange behaviour?
public class Start extends JFrame {
private static JPanel leftPanel = new JPanel();
private static JPanel rightPanel = new JPanel();
private JList leftList = new JList();
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private static JScrollPane listScrollPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
new Start();
JFrame frame = new JFrame();
frame.add(leftPanel,BorderLayout.EAST);
frame.add(listScrollPane,BorderLayout.WEST);
frame.add(rightPanel);
frame.setTitle("Example");
frame.setSize(600,400);
frame.setLocation(200,100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Start() {
leftPanel.setLayout(new BoxLayout(leftPanel,BoxLayout.PAGE_AXIS));
leftList = new JList(listModel);
leftList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listScrollPane = new JScrollPane(leftList);
listScrollPane.setBorder(BorderFactory.createTitledBorder("Proteins"));
rightPanel.setBackground(Color.cyan);
rightPanel.setLayout(new FlowLayout());
for (String name : allNames) {
listModel.addElement(name);
}
leftList.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent event) {
if(!event.getValueIsAdjusting()) {
int indexndex = leftList.getSelectedIndex();
JLabel lbl = new JLabel();
lbl.setText("index = " + index);
rightPanel.add(lbl);
System.out.println(index);
}
}
});
}
}
Please look into the small code below. The scroll pane appears, but the sliders do not.
Even if I resize the frame the sliders do not. Please help.
import javax.swing.*;
public class sample {
static JFrame frame;
public static void main(String[] args) {
String Msg = "Sample Message To Test Scrolling";
frame = new JFrame("Sample Program");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
JPanel panel = new JPanel();
panel.setLayout(null);
for (int ypos = 0, i = 0; i < 40; i++) {
JLabel label = new JLabel("" + i + " " + Msg);
label.setFont(new Font("Courier", Font.BOLD, 12));
panel.add(label);
label.setBounds(10, ypos + 5,
label.getPreferredSize().width,
label.getPreferredSize().height);
ypos += label.getPreferredSize().height;
}
JScrollPane scroll = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
frame.setLayout(new BorderLayput());
frame.add(scroll);
frame.setVisible(true);
}
}
The sliders will only appear if and when the component contained by the JScrollPane's viewport is larger than the viewport. Based on your posted code, I don't see why your component would be larger than the viewport as the panel's size will be based on its preferredSize, something that will never change since for one, you're adding components to it with it using a null layout.
As an aside you should almost never use null layout.
For example:
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class Sample2 {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int MAX_ROWS = 400;
private static final String TEXT_BODY = "Sample Message To Test Scrolling";;
private static void createAndShowGui() {
JPanel panel = new JPanel(new GridLayout(0, 1));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
for (int i = 0; i < MAX_ROWS; i++) {
String text = String.format("%03d %s", i, TEXT_BODY);
JLabel label = new JLabel(text);
panel.add(label);
}
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setPreferredSize(new Dimension(PREF_W, PREF_H));
JFrame frame = new JFrame("Sample2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I'm building a JFrame that will eventually display the output of a program that has a variable number of sections in it. I have parsed the output but displaying it in the frame is a problem.
When the frame appears, it is completely empty with the exception of the scroll pane. How do I get these labels to show up?
public class OutputPanel extends JFrame {
public OutputPanel(Vector parsedOutput) {
this.setTitle("Output");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
Iterator<Vector> outputIter = parsedOutput.iterator();
while(outputIter.hasNext()) {
Vector section = outputIter.next();
JLabel sectionLabel = new JLabel((String)section.get(0));
System.out.println((String)section.get(0));
scrollPane.add(sectionLabel);
}
this.add(scrollPane);
this.pack();
this.setVisible(true);
}
}
You shouldn't add components to the scrollPane
scrollPane.add(sectionLabel);
but rather add them to a separate panel, and either use
scrollPane = new JScrollPane(thePanel);
or
scrollPane.setViewportView(thePanel);
Example:
import java.awt.GridLayout;
import java.util.Vector;
import javax.swing.*;
class Test {
public static void main(String[] args) {
new OutputPanel(null);
}
}
class OutputPanel extends JFrame {
public OutputPanel(Vector parsedOutput) {
this.setTitle("Output");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel content = new JPanel(new GridLayout(0, 1));
for (int i = 0; i < 100; i++) {
JLabel sectionLabel = new JLabel("hello " + i);
content.add(sectionLabel);
}
JScrollPane scrollPane = new JScrollPane(content);
this.add(scrollPane);
this.pack();
this.setVisible(true);
}
}
Produces:
You should use setViewPortView() with a container instead of add() for JScrollPane.
Try this.
public class OutputPanel extends JFrame {
public OutputPanel(Vector parsedOutput) {
this.setTitle("Output");
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
Iterator<Vector> outputIter = parsedOutput.iterator();
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
scrollPane.setViewportView(panel);
while(outputIter.hasNext()) {
Vector section = outputIter.next();
JLabel sectionLabel = new JLabel((String)section.get(0));
System.out.println((String)section.get(0));
panel.add(sectionLabel);
}
this.add(scrollPane);
this.pack();
this.setVisible(true);
}
}