I seem to have the opposite problem of everyone else.
My JDialog has both minimize and maximize buttons by default.
When the maximize button is pressed, the dialog maximizes - but the content doesn't. It just stays the same size, centered in a huge dialog.
Same happens when you just grab the edge and re-size the dialog.
I've tried adding a WindowStateListener - but it never gets invoked.
I added a WindowListener - and it's only invoked on Open/Close/Activate/Deactivate.
So, I either need to be able to get the dialog content to re-size with the dialog, OR remove the maximize button.
(and I'd like to get rid of the minimize button.)
I do do a pack() after creating the dialog, as the controls in the dialog are dynamically created from a block of data, so I don't have an initial size to work with.
Okay, so here's the code. All the generated UI panels are in GridBagLayouts as well.
public class FastAccessDialog extends JDialog implements BeanActionListener {
private static final long serialVersionUID = 1L;
private static final Cursor waitCursor = new Cursor(Cursor.WAIT_CURSOR);
private Cursor oldCursor;
private JPanel cmdOutput;
private JScrollPane cmdOutputScroll;
public FastAccessDialog(Frame owner, ObjectName bean, String methodName) throws InstanceNotFoundException, IntrospectionException,
ReflectionException, IOException {
super(owner);
setResizable(true);
setModal(false);
setTitle(BeanUtil.cleanUpCamelCase(methodName));
boolean enabled = (UIHintUtil.isEnabled(bean) == EnableState.ENABLED);
// Find the BeanOperationInfo for that method.
MBeanInfo info = JMXConnectionSingleton.getInstance().getMBeanInfo(bean);
MBeanOperationInfo[] operations = info.getOperations();
JComponent comp = null;
for (MBeanOperationInfo opInfo : operations) {
if (opInfo.getName().equals(methodName)) {
comp = OperationsManager.getInstance().createControls(bean, opInfo, this, true, enabled);
break;
}
}
if (comp == null) {
throw new IllegalArgumentException("Unknown method name: " + methodName);
}
Container cont = getContentPane();
cont.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(4, 4, 4, 4);
cont.add(comp, gbc);
cont.validate();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
pack();
}
});
return;
}
... other methods invoked when an operation is performed ...
... none of which are invoked before having the re-size problem ...
}
JPanel.(re)validate();
JPanel.repaint();
JDialog.pack();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JDialog.setVisible(true);
}
});
don't extends Top-Level Containers
don't use ContentPane, there no reason ... from Java5
nothing else in the case that JDialog.pack(); and JDialog.setVisible(true); are last code lines in void, method or constructor that returns JDialog instance
Related
I have a JPanel holding a JButton and JScrollPane (in turn holding a JTable) and am currently running into two issues which I believe are related:
The JButton listener's actionPerformed() method is not invoked upon click. The only way in which I can get it to be invoked is by calling doClick() on the JButton. The JButton color changes upon hover but no click animation is shown when the mouse is pressed.
Secondly, if a cell is clicked within the JTable, the cell located 2 rows down in the same column registers the click instead. This offset does not occur when clicking in the column headers (i.e. to adjust cell widths), only when within the cell area.
Left-hand panel. Click position circled
public class InventoryPanel extends JPanel {
// Parent Business object reference for communication and JFrame
private Business parent;
private AddItemPanel addItemPanel;
// Inventory table items
private DefaultTableModel inventoryModel;
private JTable inventoryTable;
private JScrollPane inventoryScrollPane;
private JLabel updateLbl;
private JButton addItemBtn;
// Columns for inventory table
private static final String[] INVENTORY_COLUMNS = {"Item","Stock","Restocking Level","Edit"};
public InventoryPanel(Business parent) {
this.parent = parent;
initGUI();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
//doStuff
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(new PrintStream(System.out));
}
}
}
}).start();
}
// INITIALISES GUI
public void initGUI() {
this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
JLabel titleLabel = new JLabel("<html><B>Inventory</B></html>");
this.add(titleLabel);
// Create empty inventory table
inventoryModel = new DefaultTableModel(new Object[3][4],INVENTORY_COLUMNS);
inventoryTable = new JTable(inventoryModel);
inventoryScrollPane = new JScrollPane(inventoryTable);
// Create button to allow items to be added
addItemBtn = new JButton("Add item");
addItemBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("ADD ITEM PRESSED");
}
});
updateLbl = new JLabel("Loading inventory...");
this.add(addItemBtn);
this.add(inventoryScrollPane);
this.add(updateLbl);
}
I've tried removing the table from the panel to see if that solves the JButton issue and visa-versa, but no luck. I've also tried changing the project JDK but no luck there either.
There are other JPanels adjacent to the troublesome one in a JFrame which work perfectly fine. Any ideas?
Edit: I can create a working instance of the InventoryPanel alone in a frame in another project, as mentioned in the comments. However the exact same code (no calls being made to other objects/methods) in the current project now produces ClassCastExceptions. After some googling this seems to be due to non-EDT threads updating the GUI.
However there is no use of the Business class, and all GUI operations are performed using the SwingUtilities.invokeLater() method like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("test");
frame.add(new InventoryPanel());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
Note: the no-argument constructor InventoryPanel() just calls initGUI().
Thanks for the help so far...still very confused by this.
Ok so In my code I'm asking the user for their name and asking them to click one of 3 buttons which gives a variable a corresponding value. Now in another program I want to call upon this program and then pretty much display the string and use the int value for a certain purpose.
public class MainMenuofgame extends JFrame implements ActionListener{
JButton slow, medium, fast;
JLabel pic1, pic2, pic3, pic4;
JTextField username;
Container frame;
static String name;
static int xspeed = 0;
public MainMenuofgame() {
super ("Main Menu of Rocket Launch");
frame = getContentPane ();
frame.setLayout (null);
pic1 = new JLabel (new ImageIcon ("welcome.png"));
pic2 = new JLabel (new ImageIcon ("name.png"));
pic3 = new JLabel (new ImageIcon ("speed.png"));
pic4 = new JLabel (new ImageIcon ("backgnd.jpg"));
username = new JTextField ();
slow = new JButton("Slow");
// slow.setActionCommand("slowspeed");
slow.addActionListener (this);
medium = new JButton("Medium");
// medium.setActionCommand("mediumspeed");
medium.addActionListener (this);
fast = new JButton("Fast");
// fast.setActionCommand("fastspeed");
fast.addActionListener (this);
pic1.setBounds (30,50, 525, 173);//welcome
pic2.setBounds (100,230,212,73);//name
pic3.setBounds (80,350,428,84);//speed
username.setBounds(310,255,150,30);
slow.setBounds (100,450,100,100);
medium.setBounds (250,450,100,100);
fast.setBounds (400,450,100,100);
//background bound goes in the end
pic4.setBounds (0,0, 600,900);
frame.add (pic1);
frame.add (pic2);
frame.add (pic3);
frame.add (username);
frame.add (slow);
frame.add (medium);
frame.add (fast);
frame.add (pic4);
setSize(600, 900);
setVisible (true);
setDefaultCloseOperation (EXIT_ON_CLOSE);
}
public void actionPerformed (ActionEvent evt){
String name = username.getText();
if (evt.getSource () == slow)
{
xspeed = 1;
}
else if(evt.getSource () == medium)
{
xspeed = 5;
}
else
{
xspeed = 10;
}
}
public static void main(String[] args) {
new MainMenuofgame ();
}
}
The behavior that you describe is not in fact the "transfer values of an int and string from one program to another in Java", but rather much more simply the transfer of data from one object to another, here the objects are represented by GUI components. Don't create two separate programs, but rather create separate objects that interact in a meaningful way. That is the essence of OOPs with Java. The simplest solution is to have the main application display the sub-application's GUI within a modal dialog such as a modal JDialog, and then once the dialog has been dealt with (i.e., is no longer visible) then the main program/object queries the dialog for the state of its components -- the data that was entered.
Also you are painting yourself in a corner by having your class extend JFrame, forcing you to create and display JFrames, when often more flexibility is called for. In fact, I would venture that most of the Swing GUI code that I've created and that I've seen does not extend JFrame, and in fact it is rare that you'll ever want to do this. More commonly your GUI classes will be geared towards creating JPanels, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. This will greatly increase the flexibility of your GUI coding.
For example:
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class MenuDemoMainPanel extends JPanel {
private MenuPanel menuPanel = new MenuPanel();
private JDialog menuDialog = null;
private String name;
private Speed speed;
private JTextField nameField = new JTextField(10);
private JTextField speedField = new JTextField(10);
public MenuDemoMainPanel() {
// these fields are for display only and should not allow user
// interaction
nameField.setFocusable(false);
speedField.setFocusable(false);
// not kosher to set this directly, per kleopatra, but oh well
setPreferredSize(new Dimension(600, 400));
// simple demo GUI -- add components
add(new JLabel("Name:"));
add(nameField);
add(new JLabel("Speed:"));
add(speedField);
add(new JButton(new GetNameAndSpeedAction("Get Name And Speed")));
}
// action for JButton that displays the menuDialog JDialog
private class GetNameAndSpeedAction extends AbstractAction {
public GetNameAndSpeedAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
if (menuDialog == null) {
// if the menu dialog has not been created yet -- create it
Window win = SwingUtilities.getWindowAncestor(MenuDemoMainPanel.this);
menuDialog = new JDialog(win, "Menu", ModalityType.APPLICATION_MODAL);
menuDialog.add(menuPanel);
menuDialog.pack();
menuDialog.setLocationRelativeTo(win);
}
// display the menu JDialog
menuDialog.setVisible(true);
// this code is called only when the dialog is no longer visible
// query the dialog for the state it holds
name = menuPanel.getNameText();
speed = menuPanel.getSpeed();
// and display the state in the main GUI
if (name != null && speed != null) {
nameField.setText(name);
speedField.setText(speed.getText());
}
}
}
private static void createAndShowGui() {
// create the main GUI JPanel
MenuDemoMainPanel mainPanel = new MenuDemoMainPanel();
// then create an application GUI
JFrame frame = new JFrame("Menu Demo -- Main GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel); // place the main panel into the GUI
// and pack and display it:
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
// JPanel to hold menu dialog components
#SuppressWarnings("serial")
class MenuPanel extends JPanel {
private JComboBox<Speed> speedCombo = new JComboBox<>(Speed.values());
private JTextField nameField = new JTextField(10);
public MenuPanel() {
speedCombo.setSelectedIndex(-1);
add(new JLabel("Name:"));
add(nameField);
add(new JLabel("Speed:"));
add(speedCombo);
add(new JButton(new SubmitAction("Submit")));
}
// allow outside classes to query the nameField JTextField's state
public String getNameText() {
return nameField.getText();
}
// allow outside classes to query the speedCombo JComboBox's state
public Speed getSpeed() {
return (Speed) speedCombo.getSelectedItem();
}
// Action for JButton that submits the dialog to the main GUI
private class SubmitAction extends AbstractAction {
public SubmitAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// if the data is not all entered or selected
if (nameField.getText().trim().isEmpty() || speedCombo.getSelectedIndex() == -1) {
Component comp = MenuPanel.this;
String msg = "You must enter your name and select a speed";
String title = "Invalid Data";
int msgType = JOptionPane.ERROR_MESSAGE;
// warn the user and leave this dialog still visible
JOptionPane.showMessageDialog(comp, msg, title, msgType);
} else {
// otherwise dispose of this dialog and thereby pass control
// back to the main application / GUI
Window win = SwingUtilities.getWindowAncestor(MenuPanel.this);
win.dispose();
}
}
}
}
// an enum to encapsulate possible game speeds
enum Speed {
SLOW("Slow"), MEDIUM("Medium"), FAST("Fast");
private String text;
private Speed(String text) {
this.text = text;
}
public String getText() {
return text;
}
#Override
public String toString() {
return getText();
}
}
There are one of two ways that come to mind on how to transfer information from one program to another...
Client-Server applications
This requires you to have a third application running accepting information from each of the other two application (clients) through a socket. For further information Google "Client-Server applications in Java"
Have a text file passing information
To do this you should have a text file that one application stores information in and the other application just simply reads it... This is an easier solution but is less of a learning experience. Here is example code.
Application 1:
private void storeMessage(String msg){
File centralFile = new File("path to your file");
BufferedWriter writer = new BufferedWriter(new FileWriter(centralFile));
writer.write(msg);
writer.close();
}
Application 2:
private String getMessage(){
File centralFile = new File("path to your file");
String msg = "";
BufferedReader reader = new BufferedReader(new FileReader(centralFile));
while (reader.hasNextLine()){
msg += reader.nextLine();
}
reader.close();
return msg;
}
Hope this helps
Um... really all I needed to do was call upon my variable that I wanted to store my data in and then well... store it. This is done in the If statement at the bottom. Thanks everyone for helping but honestly most of your answers rised more questions than answered mine and just confused me but I figured it out so thanks anyways :)
public class MainMenuofgame extends JFrame implements ActionListener{
JButton slow, medium, fast;
JLabel pic1, pic2, pic3, pic4;
JTextField username;
Container frame;
static String name;
static int xspeed = 0;
public MainMenuofgame() {
super ("Main Menu of Rocket Launch");
frame = getContentPane ();
frame.setLayout (null);
pic1 = new JLabel (new ImageIcon ("welcome.png"));
pic2 = new JLabel (new ImageIcon ("name.png"));
pic3 = new JLabel (new ImageIcon ("speed.png"));
pic4 = new JLabel (new ImageIcon ("backgnd.jpg"));
username = new JTextField ();
slow = new JButton("Slow");
// slow.setActionCommand("slowspeed");
slow.addActionListener (this);
medium = new JButton("Medium");
// medium.setActionCommand("mediumspeed");
medium.addActionListener (this);
fast = new JButton("Fast");
// fast.setActionCommand("fastspeed");
fast.addActionListener (this);
pic1.setBounds (30,50, 525, 173);//welcome
pic2.setBounds (100,230,212,73);//name
pic3.setBounds (80,350,428,84);//speed
username.setBounds(310,255,150,30);
slow.setBounds (100,450,100,100);
medium.setBounds (250,450,100,100);
fast.setBounds (400,450,100,100);
//background bound goes in the end
pic4.setBounds (0,0, 600,900);
frame.add (pic1);
frame.add (pic2);
frame.add (pic3);
frame.add (username);
frame.add (slow);
frame.add (medium);
frame.add (fast);
frame.add (pic4);
setSize(600, 900);
setVisible (true);
setDefaultCloseOperation (EXIT_ON_CLOSE);
}
public void actionPerformed (ActionEvent evt){
String name = username.getText();
Rocketlaunch.name = name;
if (evt.getSource () == slow)
{
Rocketlaunch.moveSpeed = 1;
Rocketlaunch.speed = "Slow";
setVisible (false);
}
else if(evt.getSource () == medium)
{
Rocketlaunch.moveSpeed = 5;
Rocketlaunch.speed = "Medium";
setVisible (false);
}
else
{
Rocketlaunch.moveSpeed = 10;
Rocketlaunch.speed = "Fast";
setVisible (false);
}
new Rocketlaunch();
}
public static void main(String[] args) {
new MainMenuofgame ();
}
}
I copied all of the relevant code below, and my problem is that after running the action performed (which is connected to a button) the values I tried to change in the action performed didn't actually change.
I put a sout(ques) at the end of the action performed and I can see the change in value but when I move outside of it, it reverts back to the 0;
public class GameRunner extends JPanel implements ActionListener{
private int x=50,y=600;
private Ball b = new Ball(x,y);
private Timer timer;
private boolean correct , incorrect;
private JButton button;
private JTextField f;
private int ques = 0;
private String[][] math = {{"2X^2","4x"},{"q2","a2"},{"q3","a3"},{"q4","a4"},{"q5","a5"},
{"q6","a6"},{"q7","a7"},{"q8","a8"}};
public void actionPerformed(ActionEvent actionEvent) {
if (f.getText().equals(math[ques][1])) {
correct = true;
} else {
incorrect = true;
}
f.setText("");
if(ques<7)
ques++;
else
ques = 0;
System.out.println(ques);
//I can see the change here
}
public void paint(Graphics g){//called whenever refreshed...
System.out.println(ques);
// But now outside of the action performed the ques and the correct incorrect do not change
if(correct)
b.move();
if(incorrect)
b.move2();
}
public static void main(String[] args) {
GameRunner gui = new GameRunner ();
gui.go();
}
public void go(){
button = new JButton("Guess");
f = new JTextField(15);
button.addActionListener(this);
JFrame frame = new JFrame("Derivative Game");
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(700, 700));
JPanel pan = new JPanel(new BorderLayout());
JPanel pan2 = new GameRunner();
JPanel pan3 = new JPanel();
pan3.add( f);
pan3.add(button);
pan3.setBackground(new Color(80, 218, 213));
pan.add( pan3,BorderLayout.CENTER);
pan.setBackground(new Color(80, 218, 213));
frame.add(pan2);
frame.getContentPane().add(BorderLayout.SOUTH, pan);
frame.setSize(700, 760);
frame.setVisible(true);
frame.setResizable(false);
}
}
The basic problem is that you've actually got two instances of GameRunner here: the one you create in main(), and another one that you add to the JFrame. Since you only call go() on the one not in the JFrame, that instance's paint() method will never be called.
You need to refactor your code to eliminate that second stray GameRunner instance. While you're at it, you should also use paintComponent() instead of paint(), and you should take any "business logic" (like those calls to move()) out of your painting code.
In other words, get rid of this line:
JPanel pan2 = new GameRunner();
Since you're already "in" an instance of GameRunner, you shouldn't be creating another one. Then to use the "current" instance of GameRunner, you can use the this keyword:
frame.add(this);
Edit- You also aren't telling your GameRunner JPanel to repaint itself after the button is clicked. You might want to add a call to repaint() in your actionPerformed() method.
I am writing a wizard of sorts and would like to switch what is displayed using methods. Every time I run this code I get a null pointer exception.
public class EventDispatch {
public static void main(String [] args){
WizardScreen wiz = new WizardScreen();
new Thread(wiz).start();
wiz.welcomeScreen();
}
}
public class WizardScreen implements Runnable{
protected JFrame wizardFrame;
protected JPanel contentPane;
protected JButton newQuote;
protected JButton openQuote;
protected JLabel title;
GridBagConstraints c;
public WizardScreen(){
wizardFrame = new JFrame();
contentPane = new JPanel(new GridBagLayout());
wizardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wizardFrame.setSize(550, 450);
wizardFrame.setResizable(false);
wizardFrame.setLocationRelativeTo(null);
wizardFrame.setTitle("Welcome!");
wizardFrame.setContentPane(contentPane);
wizardFrame.setVisible(true);
}
#Override
public void run() {
System.out.println("Running wizardScreen");
}
public void welcomeScreen(){
title = new JLabel("Welcome to ExSoft Quote Calculator Alpha 1.0");
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = .5;
contentPane.add(title, c);
wizardFrame.validate();
contentPane.repaint();
}
}
What am I doing wrong?
Take a walk through your code...
First, you create an instance of WizardScreen this initialises
wizardFrame
contentPane
Second, you start a Thread...
Third, you call welcomeScreen on the instance of WizardScreen, this initialises...
title
It then tries to access the gridx property of c...which hasn't yet been initialised...
You should have checked the information that the NullPointerException was giving you...
Exception in thread "main" java.lang.NullPointerException
at eventdispatch.EventDispatch$WizardScreen.welcomeScreen(EventDispatch.java:52)
at eventdispatch.EventDispatch.main(EventDispatch.java:20)
It clear states where the exception occurred, this is invaluable information both to you and us.
Beware, Swing is not thread safe, all interactions and modifications to the UI are expected to occur from within the context of the Event Dispatching Thread. See Concurrency in Swing
FYI:
It's generally advisable to use pack of setSize, which should be done last, right before you call setVisible. Also beware, that using setResizable(false) changes the size of the window...
wizardFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//wizardFrame.setSize(550, 450);
//wizardFrame.setResizable(false);
//wizardFrame.setLocationRelativeTo(null);
wizardFrame.setTitle("Welcome!");
wizardFrame.setContentPane(contentPane);
wizardFrame.setResizable(false);
wizardFrame.pack();
wizardFrame.setLocationRelativeTo(null);
wizardFrame.setVisible(true);
Not sure if this has been discussed before. But I am having a odd issue with transparent JTextFields added on a transparent JPanel. For some reason (I could not dig enough to find why) there are additional paintings that get carried out. Perhaps there are dirty regions that needs to be dealt with? not sure.
Let me present this simple example:
public class TextFieldGame extends JPanel {
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame someFrame = new JFrame("Is this odd?");
someFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
someFrame.setSize(200,600);
someFrame.add(new TextFieldGame());
someFrame.setVisible(true);
}
});
}
public TextFieldGame() {
setupContentPane();
}
private void setupContentPane() {
setLayout(new BorderLayout());
final CanvasPanel canvasPanel = new CanvasPanel();
add(canvasPanel, BorderLayout.CENTER);
add(new ControlPanel(canvasPanel), BorderLayout.SOUTH);
}
public static class ControlPanel extends JPanel {
private final CanvasPanel canvasPanel;
ControlPanel(CanvasPanel canvasPanel) {
this.canvasPanel = canvasPanel;
setupContentPane();
}
private void setupContentPane() {
setLayout(new FlowLayout(FlowLayout.RIGHT));
final JButton load = new JButton("load");
add(load);
load.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
canvasPanel.addChildComponent(getComponent());
canvasPanel.revalidate();
canvasPanel.repaint();
}
});
}
private JComponent getComponent() {
final JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
container.setOpaque(false);
for (int i = 0; i < 10; i++) {
final JTextField textField = new JTextField("why you no work?") {
#Override
public Dimension getMaximumSize() {
return new Dimension(Short.MAX_VALUE, getPreferredSize().height);
}
};
textField.setOpaque(false);
container.add(textField);
}
return container;
}
}
public static class CanvasPanel extends JPanel {
private int paintCount = 0;
CanvasPanel() {
setupContentPane();
}
public void setupContentPane() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
setBackground(Color.white);
}
public void addChildComponent(JComponent component) {
component.setAlignmentY(TOP_ALIGNMENT);
add(component);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paint count: " + ++paintCount);
}
}
}
I have added the System out statement to show the count of paint task.
When first loaded, there will be 2/3 paints - fair enough. Then if you are to press the "Load" button, 10 transparent JTextFields will be added to a transparent JPanel, and this transparent JPanel will be added to the CanvasPanel. (Canvas panel is in turn a subchild of the JFrame). You will notice upon doing this, 11 additional paint jobs will be done.
But in theory (well in my understanding) after "Load" is pressed, only one paint job should be carried out. That is because, I have added only one child to CanvasPanel (the child itself might have 10 textfields, but they should all be painted in one shot).
Just to test my understanding, if you are to use 10 JLabels instead of the 10 JTextFields, only one paint job is carried out after "Load" is pressed. Which is what it should be.
Also, if you are to keep JTextField opaque, only one paint job is carried out. (Just tested that if instead of JTextField, a JTextArea is used, one paint is done)
What is going on? Note that JLabel is transparent by default, so I am not sure why transparency of JTextField component causing these additional paints.
Please help/