how to repaint a jpanel with button click and also switch between 2 panels
I am trying to repaint a panel with a button click, but its not happening. i tried using many methods like setEnabled(true), setVisible(true), repaint(), but none of these are working. And also i want to switch between two panels, like, if i click the «Total Vote» button, one panel should display, when i click on «Departmentwise Vote», another panel should display in the same place. please help. Thanks in advance. here i m providing the code :
public class RSummary extends JFrame implements ActionListener < JFrame rframe = new JFrame(); JPanel panel1, panel2, panel3, panel4, panel5; JTable table; JScrollPane scroll; JSplitPane splitPane; JButton butx; public RSummary() < rframe.setSize(550,300); rframe.setLocationRelativeTo(null); setSize(550,300); rframe.setTitle("Summary Report"); /* Total Vote & Department wise vote buttons */ panel1= new JPanel(); JButton but1 = new JButton("TOTAL VOTE"); JButton but2 = new JButton("DEPTARTMENT WISE VOTE"); but1.addActionListener(this); panel1.add(but1); panel1.add(but2); /* Report contents according to button */ panel2 = new JPanel(); String[] columnNames = ; DefaultTableModel model1 = new DefaultTableModel(); model1.setColumnIdentifiers(columnNames); table = new JTable(); table.setModel(model1); table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); table.setFillsViewportHeight(true); scroll = new JScrollPane(table); panel2.add(scroll); panel2.setVisible(false); /* close button */ panel3 = new JPanel(); JButton but4= new JButton("CLOSE"); but4.addActionListener(this); panel3.add(but4); /* Page heading */ panel4 = new JPanel(); JLabel lab =new JLabel("VOTE SUMMARY REPORT"); panel4.add(lab); /* dummy panel */ panel5 = new JPanel(); JButton butx = new JButton("Hello butx"); panel5.add(butx); splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel1, panel2); rframe.add(splitPane); rframe.add(panel3,BorderLayout.SOUTH); rframe.add(panel4,BorderLayout.NORTH); rframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); rframe.setVisible(true); > public void actionPerformed(ActionEvent ae) < String action=ae.getActionCommand(); if(action == "CLOSE") < rframe.setVisible(false); >if(action == "TOTAL VOTE") < panel2.setVisible(true); //this code is not working, i want the solution here. >> public static void main(String args[]) throws ClassNotFoundException, SQLException < new RSummary(); >>
«how to repaint a jpanel with button click and also switch between 2 panels» Which is the one matter of the two you want answered here, now? They are candidates for 2 questions with 2 SSCCEs.
2 Answers 2
The first problem is you’re comparing the object references of your String values and not there contents.
Because of the way String s are managed by Java, it is very unlikely that these will ever be equal.
String comparison in Java is done using String#equals
if ("TOTAL VOTE".equals(action))
Your second problem may be related to the fact the setVisible may not be invalidating the container hierarchy, which would tell the layout framework that the containers need to be updated.
You have two solutions, the first would be to call revalidate on the parent container, the second, and better, would be to use a CardLayout , which is designed to just what you are trying to do.
Take a look at How to use Card Layout for more details
Update after running the Code
You have a series of compounding issues.
- You never set the action command of any of the buttons, so when the actionPerformed event is raised, the action is actually null
- RSummary extends from JFrame , yet you create a second JFrame called rframe . This is very confusing and could potentially lead to more problems if you’re not dealing with the correct frame.
Start by setting the actionCommand property of your buttons.
JButton but1 = new JButton("TOTAL VOTE"); but1.setActionCommand("TOTAL VOTE");
Then remove extends JFrame from RSummary , as it is doing nothing but adding to the confusion and adds no benefit
Setting a frame invisible will not «close» it. Instead use JFrame#dispose
Finally, making a component visible while it’s part of split pane won’t resize the split divider. Once you’ve made the corrections, you will need to manually move the divider.
You may consider placing a empty panel into the split pane and using a CardLayout , add the other components to it, switching them in and out using the CardLayout
Updated with modified code
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.SQLException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.table.DefaultTableModel; public class RSummary extends JFrame implements ActionListener < JFrame rframe = new JFrame(); JPanel panel1, panel2, panel3, panel4, panel5; JTable table; JScrollPane scroll; JSplitPane splitPane; JButton butx; public RSummary() < rframe.setSize(550, 300); rframe.setLocationRelativeTo(null); setSize(550, 300); rframe.setTitle("Summary Report"); /* Total Vote & Department wise vote buttons */ panel1 = new JPanel(); JButton but1 = new JButton("TOTAL VOTE"); but1.setActionCommand("TOTAL VOTE"); JButton but2 = new JButton("DEPTARTMENT WISE VOTE"); but1.addActionListener(this); panel1.add(but1); panel1.add(but2); /* Report contents according to button */ panel2 = new JPanel(); String[] columnNames = ; DefaultTableModel model1 = new DefaultTableModel(); model1.setColumnIdentifiers(columnNames); table = new JTable(); table.setModel(model1); table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); table.setFillsViewportHeight(true); scroll = new JScrollPane(table); panel2.add(scroll); panel2.setVisible(false); /* close button */ panel3 = new JPanel(); JButton but4 = new JButton("CLOSE"); but4.addActionListener(this); panel3.add(but4); /* Page heading */ panel4 = new JPanel(); JLabel lab = new JLabel("VOTE SUMMARY REPORT"); panel4.add(lab); /* dummy panel */ panel5 = new JPanel(); JButton butx = new JButton("Hello butx"); panel5.add(butx); splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, panel1, panel2); rframe.add(splitPane); rframe.add(panel3, BorderLayout.SOUTH); rframe.add(panel4, BorderLayout.NORTH); rframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); rframe.setVisible(true); > public void actionPerformed(ActionEvent ae) < String action = ae.getActionCommand(); if ("CLOSE".equals(action)) < rframe.dispose(); >if ("TOTAL VOTE".equals(action)) < panel2.setVisible(true); //this code is not working, i want the solution here. panel2.getParent().revalidate(); >> public static void main(String args[]) throws ClassNotFoundException, SQLException < new RSummary(); >>
How to add JPanel by clicking JButton?
I’m trying to create a small GUI, it has 2 JButtons, and 2 JPanels with some drawing animation on each of them. By default it must show first JPanel, and by clicking on second JButton I want to see my second JPanel. So : I create JFrame, Panel1 and Panel2, where I have drawn my animations, create Button1 and Button2 and adding to them ActionListeners. I have also MainPanel which has in a fields variable i. By changing this «i» my constructor adds to MainPanel either Panel1 (default) or Panel2 (by clicking on JButton2 I change i). Than I add this MainPanel to my frame. So my question : in the class MainPanel I have refreshMe method, what should I write there to make my GUI working properly? Thanks. Here is my code:
import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class GuiTest < public static void main(String[] args) < JFrame f = new JFrame(); MainPanel myPanel = new MainPanel(); f.add(myPanel); Button1 button1 = new Button1(); Button2 button2 = new Button2(); myPanel.add(button1); myPanel.add(button2); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); >> class MainPanel extends JPanel < Panel1 p1 = new Panel1(); Panel2 p2 = new Panel2(); public int i = 1; //this is being changed later by clicking JButton // I use this setter later in actionPerformed in order to change i public void setI(int i) < this.i = i; >MainPanel() < if (i == 1) < this.add(p1); >if (i == 2) < this.add(p2); >> public void refreshMe() < // Need some help here: // I don't know what should I write, how to make a repaint of myPanel? System.out.println("just test, if the method refreshMe working by clicking some button"); >> class Panel1 extends JPanel < public Panel1() < this.setBackground(Color.BLUE); // a lot of drawing stuff going on here >@Override public Dimension getPreferredSize() < return new Dimension(200, 200); >> class Panel2 extends JPanel < public Panel2() < this.setBackground(Color.GREEN); // a lot of drawing stuff going on here >@Override public Dimension getPreferredSize() < return new Dimension(200, 200); >> class Button1 extends JButton < MainPanel someObj1 = new MainPanel(); Button1() < setText("Show Annimation A"); addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < someObj1.setI(1); System.out.println("The variable i is now: " + someObj1.i); someObj1.refreshMe(); >>); > > class Button2 extends JButton < MainPanel someObj2 = new MainPanel(); Button2() < setText("Show Annimation B"); addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < someObj2.setI(2); System.out.println("The variable i is now: " + someObj2.i); someObj2.refreshMe(); >>); > >
2 Answers 2
In order to reflect changes after adding/removing or resizing a component that is on a visible container call revalidate() and repaint() on the containers instance after adding/removing or resizing the component.
Though this will not work in your code the main reason being inside JButton classes you recreate a new instance of MainPanel when in fact the 2 JButtons should share the single instance which is being used (you could pass MainPanel instance to the JButton s constructors, but you shouldn’t really be extending a JButton unless adding custom functionality):
class Button2 extends JButton < MainPanel someObj2 = new MainPanel();//you create an instance of MainPanel which isnt even showing and than do changes on that, this way you will never see any of the changes Button2() < >>
A few other suggestions on your code:
- Dont extend JButton class unnecessarily, simply create an instance of JButton like you did with JFrame and call methods on JButton instance.
- Dont forget to create/manipulate Swing components on Event Dispatch Thread , via SwingUtilities.invokeLater(..) block, read here for more.
Here is your code fixed (above suggestions ect implemented):
import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class Test < public static void main(String[] args) < SwingUtilities.invokeLater(new Runnable() < @Override public void run() < JFrame f = new JFrame(); final MainPanel myPanel = new MainPanel(); f.add(myPanel); JButton button1 = new JButton("Show Animation A"); JButton button2 = new JButton("Show Animation B"); button1.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < myPanel.setI(1); System.out.println("The variable i is now: " + myPanel.i); myPanel.refreshMe(); >>); button2.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < myPanel.setI(2); System.out.println("The variable i is now: " + myPanel.i); myPanel.refreshMe(); >>); myPanel.add(button1); myPanel.add(button2); myPanel.checkPanel(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); > >); > > class MainPanel extends JPanel < Panel1 p1 = new Panel1(); Panel2 p2 = new Panel2(); public int i = 1; //this is being changed later by clicking JButton // I use this setter later in actionPerformed in order to change i public void setI(int i) < this.i = i; >public void refreshMe() < checkPanel(); revalidate(); repaint(); // Need some help here: // I don't know what should I write, how to make a repaint of myPanel? System.out.println("just test, if the method refreshMe working by clicking some button"); >public void checkPanel() < if (i == 1) < this.add(p1); this.remove(p2);//or it will remain there as this is default flowlayout >else if (i == 2) < this.add(p2); this.remove(p1); >> > class Panel1 extends JPanel < public Panel1() < this.setBackground(Color.BLUE); // a lot of drawing stuff going on here >@Override public Dimension getPreferredSize() < return new Dimension(200, 200); >> class Panel2 extends JPanel < public Panel2() < this.setBackground(Color.GREEN); // a lot of drawing stuff going on here >@Override public Dimension getPreferredSize() < return new Dimension(200, 200); >>
However Id suggest something simpler, fortunately you have 2 choices:
1) Use CardLayout which will allow you to flip between multiple components on a single JFrame /container.
Here is an example I made:
import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class Test < private final static String PANEL1 = "panel 1"; private final static String PANEL2 = "panel 2"; public Test() < initComponents(); >public static void main(String[] args) < SwingUtilities.invokeLater(new Runnable() < @Override public void run() < new Test(); >>); > private void initComponents() < JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel1 = new JPanel(); panel1.add(new JLabel("Panel 1")); JPanel panel2 = new JPanel(); panel2.add(new JLabel("Panel 2")); //Create the panel that contains the "cards". final JPanel cards = new JPanel(new CardLayout()); cards.add(panel1, PANEL1); cards.add(panel2, PANEL2); //create button to allow chnage to next card JButton buttonNext = new JButton(">"); buttonNext.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent ae) < CardLayout cl = (CardLayout) (cards.getLayout());//get cards cl.next(cards); >>); //create button to allow chnage to previous card JButton buttonPrev = new JButton(" <"); buttonPrev.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent ae) < CardLayout cl = (CardLayout) (cards.getLayout());//get cards cl.previous(cards); >>); //create panel to hold buttons which will allow switching between cards JPanel buttonPanel = new JPanel(); buttonPanel.add(buttonPrev); buttonPanel.add(buttonNext); frame.add(cards); frame.add(buttonPanel, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); > >
2) Use removeAll() technique i.e call frame.getContentPane().removeAll() which will remove all components currently on JFrame and than add the new content and call revalidate() and repaint() (also might want to add pack() in there) on JFrame instance to reflect changes. Though Id recommend CardLayout .
Simulate a mouse click within Board (JPanel)
I am writing a simple TicTacToe game in java. The basic implementation is done. Player vs Player is working flawlessly. But now, when I am implementing the AI, I’ve a problem. I have calculated the move for the computer, but I cannot make the computer click that location [with (x, y) coordinates] on the JPanel. I’ve seen the Robot class, but it doesn’t click on the required place, and seems to click outside the window. Here is the code, which draws the board on a JPanel :
private class Board extends JPanel < /** * */ private static final long serialVersionUID = 1L; public Board()< this.setSize(new Dimension(board_width, board_height)); this.setPreferredSize(new Dimension(board_width, board_height)); this.setBackground(new Color(0x84ACFF)); this.setOpaque(true); >@Override public void paintComponent(Graphics g) < super.paintComponent(g); //g.setColor(new Color(0xf9d1af)); g.setColor(Color.white); g.drawLine((board_width/3), 0, (board_width/3), board_height); g.drawLine((board_width/3)*2, 0, (board_width/3)*2, board_height); g.drawLine(0, (board_height/3), (board_width), (board_height/3)); g.drawLine(0, (board_height/3)*2, (board_width), (board_height/3)*2); g.finalize(); >>
@Override public void mousePressed(MouseEvent e) < Graphics g = this.getGraphics(); int X = e.getX(); int Y = e.getY(); //JOptionPane.showMessageDialog(null, e.getXOnScreen()+":"+e.getYOnScreen()); int block_x = board_width/3; int block_y = board_height/3; X = X/block_x; Y = Y/block_y; //For array Assignment Click_X = Y; Click_Y = X; //Keep copy of the originals Orig_X = X; Orig_Y = Y; //------------------------------------------ // Assign to array & Draw //------------------------------------------ if (computer)< if (start.equals("Computer"))< if (game_board[Click_X][Click_Y] != ' ') return; moves++; game_board[Click_X][Click_Y] = Cross; drawCross(((X+1)*block_x)+25, ((Y+1)*block_y)+25, 50, 50, g); dcsn = new Decision(game_board, moves); >else < if (game_board[Click_X][Click_Y] != ' ') return; moves++; game_board[Click_X][Click_Y] = Nought; drawNought(((X+1)*block_x), ((Y+1)*block_y), 50, 50, g); dcsn = new Decision(game_board, moves); >> else < if (start.equals("Human"))< if (game_board[Click_X][Click_Y] != ' ') return; moves++; game_board[Click_X][Click_Y] = Cross; drawCross(((X+1)*block_x)+25, ((Y+1)*block_y)+25, 50, 50, g); dcsn = new Decision(game_board, moves); >else < if (game_board[Click_X][Click_Y] != ' ') return; moves++; game_board[Click_X][Click_Y] = Nought; drawNought(((X+1)*block_x), ((Y+1)*block_y), 50, 50, g); dcsn = new Decision(game_board, moves); >> switch (dcsn.gameOver()) < case "X": JOptionPane.showMessageDialog(null,"X has won!"); break; case "O": JOptionPane.showMessageDialog(null,"O has won!"); break; case "draw": JOptionPane.showMessageDialog(null,"Draw!"); break; case " ": break; >switchTurn(); >
Now how do I make the computer click at the calculated location ? Any ideas ? Here is the link to full source code : Download Source It is otherwise difficult to reproduce the situation.
1) Why don’t you just add a MouseListener for every cell? Would make things much easier and clearer (You don’t need a robot class). 2) Please consider posting a MCVE (or SSCCE), I can’t reproduce your problem. 3) Shouldn’t Click_X = Y; Click_Y = X; be Click_X = X; Click_Y = Y; ?
You could create a method assignToArrayAndDraw() that you could call either from the mousePressed() method, or from your AI.
@LuxxMiner : No, the Click_X = Y is okay, as I need the thing in , [(00),(01),(02)] format, for storing the cross/nought in array.
The point is that you don’t need a robot to click on the board. Your AI should directly call the code inside mousePressed() (except you should package this code inside another method, that would be independent from the mouse coordinates — it would only use the grid coordinates)
1 Answer 1
I’d like to give you an example on how to do it like I suggested in the comments. («Why don’t you just add a MouseListener for every cell«, «You don’t need a robot class«) Of course you don’t have to do it this way, but I think it is just easier to code & to understand. Right now the computer just picks random cells and there’s no restart/win/lose, I just wanted to show you the concept. I wouldn’t use the robot class in this case, the program shouldn’t be able to take control over the cursor 😉
import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.border.LineBorder; public class TicTacToe < Cell[][] cells = new Cell[3][3]; boolean humanTurn = true; public TicTacToe() < JFrame frame = new JFrame("T I C - T A C - T O E"); JPanel panel = new JPanel(new GridLayout(3, 3)); addCells(panel); frame.add(panel); frame.setSize(600, 600); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setVisible(true); ActionListener actionListener = new ActionListener() < Random r = new Random(); @Override public void actionPerformed(ActionEvent e) < if (!humanTurn) < // Random cell int x = r.nextInt(3); int y = r.nextInt(3); Cell cell = cells[x][y]; if (!cell.clicked) < // Only the computer runs the gameloop, so false cell.human = false; cell.cross = false; cell.repaint(); // Make sure the panel repaints before setting next // booleans EventQueue.invokeLater(new Runnable() < public void run() < humanTurn = true; cell.clicked = true; >>); > > > >; Timer gameloop = new Timer(10, actionListener); gameloop.start(); > private void addCells(JPanel panel) < for (int y = 0; y < 3; y++) < for (int x = 0; x < 3; x++) < Cell cell = new Cell(); cell.setBorder(new LineBorder(Color.BLACK)); cells[x][y] = cell; panel.add(cell); >> > public static void main(String[] args) < EventQueue.invokeLater(new Runnable() < public void run() < new TicTacToe(); >>); > class Cell extends JPanel implements MouseListener < boolean clicked = false; boolean human = true; boolean cross = false; public Cell() < addMouseListener(this); >@Override public void paintComponent(Graphics g) < super.paintComponent(g); Graphics2D gg = (Graphics2D) g; // Makes drawing smooth gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Drawing blue cross (player) if (human && cross) < gg.setColor(Color.BLUE); gg.drawLine(20, 20, getWidth() - 20, getHeight() - 20); gg.drawLine(getWidth() - 20, 20, 20, getHeight() - 20); >// Drawing red circle (computer) else if (!human && !cross) < gg.setColor(Color.RED); gg.drawOval(10, 10, getWidth() - 20, getHeight() - 20); >> @Override public void mouseClicked(MouseEvent arg0) < if (humanTurn && !clicked) < // Only human can click on the panel, so true human = true; cross = true; repaint(); // Make sure the panel repaints before setting next booleans EventQueue.invokeLater(new Runnable() < public void run() < humanTurn = false; clicked = true; >>); > > @Override public void mouseEntered(MouseEvent arg0) < >@Override public void mouseExited(MouseEvent arg0) < >@Override public void mousePressed(MouseEvent arg0) < >@Override public void mouseReleased(MouseEvent arg0) < >> >
How to call a panel from a button with ActionListener
So I’m making a simple program that jumps from panel to panel and am using an actionlistener Button to make the jump. What kind of method or operation do I use to jump from panel to panel? I tried to use setVisible(true); under the action listener, but I get just a blanks screen. Tried using setContentPane(differentPanel); but that doesn’t work.
ackage Com.conebind.Characters; import Com.conebind.Tech.TechA16; import Com.conebind.Overviews.OverviewA16; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JLabel; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Char_A16 extends JFrame < private JButton combosButton16; private JButton techButton16; private JButton overviewButton16; private JLabel Image16; private JPanel panel16; private JPanel panelOverviewA16; public Char_A16() < overviewButton16.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < OverviewA16 overview16 = new OverviewA16(); overview16.setVisible(true); overview16.pack(); overview16.setContentPane(new Char_A16().panelOverviewA16); >>); techButton16.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < //Todo >>); > private void createUIComponents() < Image16 = new JLabel(new ImageIcon("Android 16.png")); >public static void main (String[] args) < JFrame frame = new JFrame("Android 16"); frame.setContentPane(new Char_A16().panel16); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true);>>
1 Answer 1
Please check this demo project showing how to use CardLayout with IntelliJ IDEA GUI Designer.
The main form has a method that switches between 2 forms displayed inside it:
public void showPanel(String id)
Both forms are added to the card layout during the main form initialization:
FormOne one = new FormOne(); one.setParentForm(this); cardPanel.add(one.getPanel(), FORM_ONE); FormTwo two = new FormTwo(); two.setParentForm(this); cardPanel.add(two.getPanel(), FORM_TWO); final CardLayout cl = (CardLayout) cardPanel.getLayout(); cl.show(cardPanel, FORM_ONE);
A reference to the main parent form is passed to these 2 forms using setParentForm() method so that FormOne and FormTwo classes can access the showPanel() method of the MainForm .
In a more basic case you may have a button or some other control that switches the forms located directly on the MainForm , then you may not need passing the main form reference to the subforms, but it can be still useful depending on your app logic.