JPanel comonents not updating without mouse click - java

I was just having a problem with this:
public class Sales extends JPanel{
ArrayList<JPanel> panes;
ArrayList<String> tabs;
JTabbedPane tp;
public Sales(Dimension d){
setSize(d);
setLayout(null);
tp = new JTabbedPane();
Font f = new Font("Arial",Font.PLAIN,32);
tp.setFont(f);
for(Menu menu : FileManager.menus){
JPanel tmp = new JPanel();
/*int s = (int) Math.ceil(Math.sqrt(menu.products.size()));
tmp.setLayout(new GridLayout(s,s));
System.out.println("size" + s);
for(Product p : menu.products){
p.setFont(f);
tmp.add(p);
}*/
tp.addTab(menu.name,null,tmp,"What is this?");
}
tp.setBounds(0,0,getWidth(),getHeight());
add(tp);
}
}
Where Sales is just added to a simple JFrame:
public Main(){
super("HoboGames Pos System");
setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
sale = new Sales(getSize());
add(sale);
}
Everything works, except the components don't paint until the window is updated because of a click or something. So it's a blank screen until you click stuff.(Sorry, I cut some corners on things like making it full screen...)

They don't update because you've made the window visible before you've finished adding components to it.
Try something like...
GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
sale = new Sales(getSize());
add(sale);
setVisible(true);
Alternatively, you could call revalidate and repaint on the frame after you've finished adding your components, but to be honest, it's simpler the first way.
Side Note
Using setSize on a component is strongly discouraged, you should be relying an appropriate layout managed, like BorderLayout to make the decision about the size of the component.

Related

JPanel won't display components when layout is null

I'm trying to create a GUI, and I want to place elements in certain places. I made the layout of my panel null, so I could do this. However, Nothing will appear when the panel is null. Here's the code:
public class OverView extends JFrame {
//height and width of screen
Toolkit tk = Toolkit.getDefaultToolkit();
int x = ((int) tk.getScreenSize().getWidth());//length of screen
int y = ((int) tk.getScreenSize().getHeight());//height
//components
private JLabel title;
private JLabel description;
private JPanel panel;
private ArrayList<JButton> farms;
//farm variables
public ArrayList<Farm> owned;
public OverView(ArrayList<Farm> owned) {
super("The Lolipop Farm - Overview");
setSize(700, 700);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
//initialize variables
this.owned = owned;
panel = new JPanel();
panel.setLayout(null);
title = new JLabel("<html>Your Farms - The Lolipop Farm"
+ "<br> <font size=1000> <i> An Eph Production </i> </font></html>");
//set background color, color, and font of JComponents
title.setFont(new Font("serif", Font.BOLD, 25));
title.setBackground(Color.GRAY);
title.setOpaque(true);
//set size and location of the components
title.setSize(350, 120);
title.setLocation(x / 2, 600);
//add to panel
panel.add(title);
//add panel to the screen
add(panel);
}
}
Why isn't the panel showing anything when the layout's null?
As Overview is a Frame, I think you must call the method
setVisible(true);
according to https://docs.oracle.com/javase/tutorial/uiswing/layout/using.html in order to make it visible .
Now, if that doesn't work, I wonder if you have created an instance of the Overview class somewhere else in your code, or in the Main method. If you haven't, then there is no object that can show the panel inside of your class so your program won't show anything.
Your problem is with the code
setLayout(null);
This will set the layout of the JFrame to null since you are extending (inheriting it). You must have a layout for a JFrame although you can do without layout for JPanel. Just remove that line and it will be fine.
EDIT:
And of course you need to call setVisible(true) like the other guy said.

Java: Removing a JLayeredPane and adding a ContentPane

I have set a game menu screen on my JFrame using a layered panel. I want to remove all the components from the JFrame and add a new content panel. I've spent a few hours trying to work through this issue but I am unable to come up with a good solution.
public myJFrame ()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize (1030, 727);
setVisible(true);
newGame = new JButton();
loadGame = new JButton();
quitGame = new JButton();
newGame.setBounds(new Rectangle(10,600,200,110));
newGame.setIcon(pic1);
newGame.setOpaque(false);
newGame.setContentAreaFilled(false);
newGame.setBorderPainted(false);
loadGame.setBounds(new Rectangle(210,600,200,110));
loadGame.setIcon(pic2);
loadGame.setOpaque(false);
loadGame.setContentAreaFilled(false);
loadGame.setBorderPainted(false);
quitGame.setBounds(new Rectangle(410,600,200,110));
quitGame.setIcon(pic3);
quitGame.setOpaque(false);
quitGame.setContentAreaFilled(false);
quitGame.setBorderPainted(false);
background.setBounds(0,0,1030,727);
titletext.setBounds(0,0,726,170);
lp = getLayeredPane();
lp.add(titletext, new Integer (4)); //* I messed around with these integers quite a bit. *//
lp.add(newGame, new Integer (20)); //* They don't seem to be logically adding to the panel. *//
lp.add(loadGame, new Integer(20)); //* I want the background and titletext to appear behind *//
lp.add(quitGame, new Integer (20)); //* the JButtons. *//
lp.add(background, new Integer (1));
newGame.addActionListener(this);
loadGame.addActionListener(this);
quitGame.addActionListener(this);
}
public void actionPerformed(ActionEvent event)
{
Object obj = event.getSource();
if (obj == newGame)
{
System.out.println("New Game");
lp.remove(4);
getContentPane().add(mop, "Center"); //* Removes myWelcomePanel mwp and adds myOptionsPanel mop *//
repaint();
mop.startgame.addActionListener(this);
}
I have tried repainting, revalidating and removing only certain components but nothing seems to work. I would expect the code posted above to remove the titletext image, but it removes the background image instead.
I would prefer not to mess with the second content pane because it contains a number of objects which I have configured previously.
JLayeredPane.remove(int) refers to the child's absolute index, not its layer position. Why don't you either remove by reference, or simply set the child component's visibility to hidden?
I found a way to make it work. It seems that I must remove each component individually instead of using removeAll(). I identified a new GridLayout sp and set that as the layout. Finally, I had to use revalidate instead of repaint. Repaint left me with a blank screen. If anyone could comment on what is happening here, I would appreciate it!
public void actionPerformed(ActionEvent event)
{
Object obj = event.getSource();
if (obj == newGame)
{
System.out.println("New Game");
lp.remove(background);
lp.remove(titletext);
lp.remove(newGame);
lp.remove(loadGame);
lp.remove(quitGame);
getContentPane().setLayout(sp);
getContentPane().add(mop, "Center");
revalidate();
mop.startgame.addActionListener(this);
}

Changing layout of a JPanel sent to JOptionPane with the pane still running

Trying to change the look of a JOptionPane while its open, depending on which radiobutton the user clicks. What am I doing wrong? It works perfect if I for example add a button and move a JLabel from side to side of the window.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import static javax.swing.JOptionPane.*;
public class ChangePanel extends JFrame{
private JButton click = new JButton("CLICK ME!");
ChangePanel(){
add(click, BorderLayout.SOUTH);
click.addActionListener(new ButtonListen());
setVisible(true);
setSize(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public class ButtonListen implements ActionListener{
public void actionPerformed(ActionEvent e){
PopUpPanel pop = new PopUpPanel();
showConfirmDialog(ChangePanel.this, pop, "Changeable", OK_CANCEL_OPTION);
}
}
//Send this as Parameter to the ConfirmDialog
public class PopUpPanel extends JPanel implements ActionListener{
JRadioButton jewelry = new JRadioButton("Jewelry");
JRadioButton shares = new JRadioButton("Shares");
JRadioButton machine = new JRadioButton("Machine");
PopUpPanel(){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
ButtonGroup bg = new ButtonGroup();
JPanel north = new JPanel();
bg.add(jewelry);
jewelry.addActionListener(this);
bg.add(shares);
shares.addActionListener(this);
bg.add(machine);
machine.addActionListener(this);
north.add(jewelry);
north.add(shares);
north.add(machine);
add(north);
}
//Listener for RadioButtons
public void actionPerformed(ActionEvent e){
JTextField info1Txt = new JTextField(12);
JTextField info2Txt = new JTextField(12);
JTextField info3Txt = new JTextField(3);;
JRadioButton b = (JRadioButton)e.getSource();
if(b.getText().equals("Jewelry")){
//Dummy test text
System.out.println("Jewelry");
JPanel info1 = new JPanel();
info1.add(new JLabel("info1:"));
info1.add(info1Txt);
add(info1);
JPanel info2 = new JPanel();
info2.add(new JLabel("info2:"));
info2.add(info2Txt);
add(info2);
JPanel info3 = new JPanel();
info3.add(new JLabel("info3:"));
info3.add(info3Txt);
add(info3);
validate();
repaint();
}else if(b.getText().equals("Shares")){
//Dummy test text
System.out.println("Shares");
}else
//Dummy test text
System.out.println("Machine");
}
}
public static void main(String[] args){
new ChangePanel();
}
}
As you are working with BoxLayout, you should provide size hints to the PopUpPanel panel, which you haven't given.
When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components.
check out the official tutorial page discussion: BoxLayout Feature
Call revalidate() and repaint() on the container after removing or adding components to it. So if you change the following lines:
validate();
repaint();
to:
revalidate();
repaint();
The content should appear. Though, it will not fit the original size of the JOptionPane. You can override PopUpPanel.getPreferredSize() to return desired size so that JOptionPane is packed properly, ie:
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
You can also use JDialog instead of JOptionPane.
Also, consider using CardLayout instead of swapping components manually. Check How to Use CardLayout for examples.
Why not just use setPreferredSize(new Dimension(300, 300)) in PopUpPanel constructor? Works fine for me. Good eye on revalidate and repaint.

Java Swing - JTable not showing

I'm having some troubles with Java Swing.
I'm trying to make a frame with a control panel at the top with some buttons in it.
and below that i want a JTable to show
I've been trying but the table is not showing.
If I remove the controlPanel at the top, it sometimes shows and sometimes not.
The code that I use inside my constructor of my JTable is provided in the same application,
so it's no network error
public ServerMainFrame(GuiController gc){
this.gc = gc;
initGUI();
}
private void initGUI() {
System.out.println("initiating GUI");
createFrame();
addContentPanel();
addControls();
//openPopUpServerSettings();
addSongTable();
}
private void createFrame()
{
this.setTitle("AudioBuddy 0.1");
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(800, 600);
this.setResizable(false);
this.setLocationRelativeTo(null);
}
private void addContentPanel()
{
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
p.setSize(new Dimension(800, 600));
this.setContentPane(p);
}
private void addControls()
{
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
controlPanel.setBorder(BorderFactory.createLineBorder(Color.black));
controlPanel.setSize(700,100);
// Buttons
JButton play = new JButton("Play");
JButton pause = new JButton("Pause");
JButton stop = new JButton ("Stop");
JButton next = new JButton("Next");
JButton prev = new JButton("Previous");
controlPanel.add(play);
controlPanel.add(pause);
controlPanel.add(stop);
controlPanel.add(next);
controlPanel.add(prev);
// Currently playing
JLabel playing = new JLabel("Currently playing:");
controlPanel.add(playing);
JLabel current = new JLabel("Johnny Cash - Mean as Hell");
controlPanel.add(current);
this.getContentPane().add(controlPanel);
}
private void addSongTable()
{
JTable songTable = new JTable(Server.getSongTableModel());
songTable.setVisible(true);
JPanel tablePanel = new JPanel();
tablePanel.setVisible(true);
tablePanel.add(songTable);
songTable.repaint();
this.getContentPane().add(tablePanel);
JButton btnMulticastList = new JButton("send list to clients");
btnMulticastList.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Server.MulticastPlaylist();
}
});
getContentPane().add(btnMulticastList);
}
if I remove the controlPanel at the top, it sometimes shows and
sometimes not.
everything is hidden in Server.getSongTableModel(), nobody knows without posting an SSCCE with hardcoded value returns from
GUI has issue with Concurency in Swing
XxxModel loading data continiously with building GUi, then exception caused described problems
The code that I use inside my constructor of my JTable is provided in
the same application, so it's no network error
no idea what you talking about
have to create an empty GUI, see InitialTread
showing GUI, then to start loading data to JTable
then starting Workers Thread (Backgroung Task) from SwingWorker or (descr. Network issue) better Runnable#Thread (confortable for catching an exceptions and processing separate threads)
output from Runnable to the Swing GUI must be wrapped into invokeLater()
If you want controls at the top of your window, and the table filling the majority of the window, then I'd suggest you try using BorderLayout instead of FlowLayout. Create it like this...
private void addContentPanel()
{
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.setSize(new Dimension(800, 600));
this.setContentPane(p);
}
And add the components by specifying the location in the BorderLayout. In this case, the controls should be added to the top in their minimal size...
this.getContentPane().add(controlPanel,BorderLayout.NORTH);
And the table should be in the center, filling the remaining window space...
this.getContentPane().add(tablePanel,BorderLayout.CENTER);
In your case, you also have a button at the bottom...
getContentPane().add(btnMulticastList,BorderLayout.SOUTH);
For the layout you're after, BorderLayout is much more appropriate. The benefit of using BorderLayout here is that the components should be automatically resized to the size of the window, and you're explicitly stating where each component resides, so panels shouldn't not appear.
It would also be my recommendation that you find an alternative to calling getContentPane() in all your methods. Maybe consider keeping a global variable for the main panel, like this...
private mainPanel;
private void addContentPanel()
{
mainPanel = new JPanel(new BorderLayout());
mainPanel.setSize(new Dimension(800, 600));
this.setContentPane(mainPanel);
}
Then you can reference the panel directly when you want to add() components to it.
Finally, I'd also suggest using GridLayout for your controls, as it will allow you to place all your buttons in it, and they'll be the same size for consistency. Define it like this to allow 5 buttons in a horizontal alignment...
JPanel controlPanel = new JPanel(new GridLayout(5,1));
then you just add the buttons normally using controlPanel.add(button) and they'll be added to the next slot in the grid.
For more information, read about GridLayout or BorderLayout, or just see the Java Tutorial for a Visual Guide to Layout Managers to see what alternatives you have and the best one for your situation. In general, I try to avoid FlowLayout, as I find that there are other LayoutManagers that are more suitable in the majority of instances.

Overlay panel (above another)

I am learning how to use Swing and found myself quite difficult task.
What I am trying to accomplish: I want to have panel (call it menu panel) on the left side (let's say 100px width) and the second panel (call it content panel), which takes the rest of available place.
In menu panel there are 3 buttons. When I press on of them, to the right side of menu panel (over content panel) second menu panel (submenu) should appear (and it should start in the middle of button which was pressed).
It may be hard to understand, so I've created simple draft:
I tried JLayeredPane but there were problems with resizing window (elements in Layered Pane didn't resize).
JLayeredPane miss implementations for LayoutManager, you have to setPreferredSize or setBounds manually for sizing/place JComponents,
there is one possible workaround you can add ComponentListener to the JFrame, then on componentResized(ComponentEvent e) you can resize/replace JComponent(s) to the desired Bounds
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class LayeredPaneWithOverlap {
private JTextArea textArea = new JTextArea(2, 10);
private JPanel textPanel = new JPanel(new BorderLayout());
private JTable table = new JTable(30, 5);
private JScrollPane scroll = new JScrollPane(table);
private JLayeredPane layer = new JLayeredPane();
private JFrame frame = new JFrame("Frame with resiziable JLayeredPane");
public void makeUI() {
textArea.setBorder(new LineBorder(Color.DARK_GRAY));
textArea.setText("Frame with resiziable JLayeredPane");
textPanel.setOpaque(false);
textPanel.add(textArea, BorderLayout.NORTH);
Font font = textArea.getFont();
FontMetrics fontMetrics = textArea.getFontMetrics(font);
int h = fontMetrics.getHeight() + frame.getInsets().top +
textPanel.getInsets().top + textArea.getInsets().top
+ textArea.getInsets().bottom;
scroll.setBounds(0, h, 400, 300);
layer.add(textPanel, new Integer(2));
layer.add(scroll, new Integer(1));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
resizeAll();
}
});
}
});
frame.setLocationRelativeTo(null);
frame.add(layer);
resizeAll();
frame.setVisible(true);
}
void resizeAll() {
Insets insets = frame.getInsets();
int w = frame.getWidth() - insets.left - insets.right;
int h = frame.getHeight() - insets.top - insets.bottom;
textPanel.setSize(w, h);
scroll.setSize(w, h - scroll.getY());
layer.revalidate();
layer.repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LayeredPaneWithOverlap().makeUI();
}
});
}
}
You can set a layoutmanager for the layered pane, javax.swing.OverlayLayout uses the full available space and allows resizing.
JLayeredPane layer = new JLayeredPane();
layer.setLayout(new OverlayLayout(layer));
You probably don't want the submenu to occupy the fullspace. To avoid it you can override its get…size-methods. Or you can add a second LayeredPane (for it's transperancy and it's layoutmanager), set a normal BoxLayout and use a spacer.
JPanel normalContents = new JPanel();
layer.add(normalContents, JLayeredPane.DEFAULT_LAYER);
JLayeredPane subMenuAuxiliaryLayer = new JLayeredPane()
subMenuAuxiliaryLayer.setLayout(new BoxLayout(subMenuAuxiliaryLayer, BoxLayout.LINE_AXIS));
layer.add(subMenuAuxiliaryLayer, JLayeredPane.PALETTE_LAYER);
JPanel submenuContents = new JPanel();
subMenuAuliliaryLayer.add(submenuContents);
subMenuAuxiliaryLayer.add(Box.createHorizontalGlue());
contentPanel.setLayout(null); // Absolute positioning of children.
#Override
public void actionPerformed(ActionEvent evt) {
final JButton btn = (JButton) evt.getSource();
final int buttonY = btn.getY(); // Must be final for usage in new Runnable object.
SwingUtilities.invokeLater(new Runnable() { // Return fast from event handling.
#Override
public void run() {
JPanel child = new JPanel();
child.setBackground(Color.RED); // So we'll see it.
child.setBounds(0, buttonY, 100, 300);
contentPanel.removeAll(); // Clear content panel of prior additions.
contentPanel.add(child); // Add a new panel.
contentPanel.repaint(10L);
}
});
}
The JLayeredPane works by defualt with no Layout manager, which means that you are using absolute positioning and no resizing. You could add a resize listener and adjust positions and size of inner components from code, as you see fit.
If you don't want to do this from code, you will need a layout manager, nothing fancy, just something to fill the container as it resizes. But here's the thing... if you add a layout manager, it will layout the components as if they are all in one layer, but most layout managers don't overlap their children so they are useless. The only one you could use is the OverlayLayout - it can also resize children. But using an OverlayLayout with JLayeredPane is overkill. You can just use OverlayLayout with a JPanel. So, yes, JLayeredPane is kind of useless. I recommend using a JPanel with an OverlayLayout instead.
Here is how to set things up so that you can have great control over almost any overlapping UI scenario out there: Using a JPanel with an OverlayLayout, have a separate transparent JPanel for each layer. In this way you can combine various LayoutManagers on different layers, by setting a diferent layout manager for each pane, including absolute positioning if necessary. Then add your visible components inside the panels representing the layers. Don't add them directly to the OverlayLayout panel. Just make sure that all of the JPanels you are using as layers have setAlignmentX and Y to center (0.5f) so that they fill the entire OverlayLayout panel as it resizes.

Categories

Resources