Java inheritance or GUI gone wrong - java

despite some tips, I'm still getting this one wrong. I end up with one basic window and another one with extra features, but without the basic ones from the previous window. Instead, I would like one new window combining the basic and new features. Here is the code I've got: (also which approach would you advise?)
package windows;
import java.awt.*;
import javax.swing.*;
public abstract class WindowTemplate extends JFrame {
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
public WindowTemplate () {
JFrame myFrame = new JFrame("My first window");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
myFrame.setSize(550, 450);
myFrame.setLocationRelativeTo(null);
// JLabel emptyLabel = new JLabel("");
// emptyLabel.setPreferredSize(new Dimension(550, 450));
// myFrame.getContentPane().setLayout(new CardLayout());
// myFrame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
// myFrame.pack();
}
}
now the one that is meant to be "extended":
package windows;
import java.awt.*;
import javax.swing.*;
public class a_Welcome extends WindowTemplate {
public a_Welcome() {
JPanel area = new JPanel();
JLabel text = new JLabel("One line another line and another line"); // , JLabel.CENTER);
// text.setBounds(80, 400, 400, 50);
add(area);
// area.setLayout(null);
area.add(text, new CardLayout());
// area.add(text); // , BorderLayout.CENTER);
Font font = new Font("SansSerif", Font.BOLD, 30);
text.setFont(font);
text.setForeground(Color.green);
area.setBackground(Color.darkGray);
area.setSize(550, 450);
}
}
// timer-after 5 seconds-go to the next window (countdown in the bottom right corner)
and the main:
package windows;
public class Launcher {
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// WindowTemplate.createWindow();
// a_Welcome.createWindow();
a_Welcome window = new a_Welcome();
window.setVisible(true);
}
});
}
}
-- Alternatively --
public class WindowTemplate extends JFrame {
// Constructor
public WindowTemplate() {
init();
}
public void init() {
// add basic components
JFrame myFrame = new JFrame("My first window");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
myFrame.setSize(550, 450);
myFrame.setLocationRelativeTo(null);
}
}
and
public class a_Welcome extends WindowTemplate {
public a_Welcome() {
super();
}
#Override
public void init() {
super.init(); // important so you get the base stuff
// add other components
JPanel area = new JPanel();
JLabel text = new JLabel("One line another line and another line");
add(area);
area.add(text, new CardLayout());
Font font = new Font("SansSerif", Font.BOLD, 30);
text.setFont(font);
text.setForeground(Color.green);
area.setBackground(Color.darkGray);
area.setSize(550, 450);
}
}
Sorry for lots of code and thanks for your help!

I'm not quite sure what your problem is, but your WindowTemplate basically is a JFrame, so you don't want to create a new JFrame in your constructor but rather "apply" those method to this instead of myFrame.
Try something like this:
public WindowTemplate()
{
super("My first window");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // "this" is optional
setVisible(true);
setSize(550, 450);
setLocationRelativeTo(null);
}
and
public a_Welcome()
{
super(); // this is implicit, because a_Welcome extends WindowTemplate, which has got a constructor without parameters
//[add more stuff here]
}
When you're creating a new a_Welcome, its constructor will call the super constructor, which is WindowTemplate which will in turn call the JFrame constructor

First, although you extend JFrame, you create a new JFrame and use it in each constructor. It should be looking like that:
public WindowTemplate () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setPreferredSize(new Dimension(550, 450));
this.pack();
this.setVisible(true);
Now, if you do it like that, you can add JComponents in each constructor / init method. Instead, you create two separate JFrames, one in each constructor.
I would recommend to avoid too deep hierarchy in case of swing components, since you will face many unexpected layout issues, what works for one, doesn't work for the other, when more components are added.

I think in your second example, in WindowTemplate, you're creating another JFrame when you think you're initializing the this JFrame.
Instead of
JFrame myFrame = new JFrame("My first window");
you probably want
super("My first window");
and then replace any myFrame references thereafter with this

If I read your code correctly, WindowTemplate is a JFrame. And within WindowTemplate's constructor you instantiate another JFrame? This does not make much sense. Instead of creating and configuring myFrame, you should configure this
public WindowTemplate () {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
...
}
as you are doing it in the subclass, where you are calling this.add(area)

Related

Adding JPanel to another JPanel in a different class

I'm trying to add a JPanel to another JPanel from another class. The program does not longer throw an error and all methods have been run, but the new panel just has a black screen. A basic version of the program looks as follows:
package ninjadragon;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class NinjaDragon extends JFrame implements ActionListener{
public JPanel panelMain;
public JPanel panelTurnBase;
public static void main(String[] args) {
NinjaDragon();
}
public static void NinjaDragon() {
NinjaDragon frame;
frame = new NinjaDragon();
frame.CreateMenuScreen();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.setSize(750, 750);
frame.show();
frame.setResizable(false);
frame.pack();
}
private void CreateMenuScreen() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container window = getContentPane();
panelMain =new JPanel();
panelMain.setPreferredSize(new Dimension(750,750));
panelMain.setBackground(Color.BLACK);
panelMain.setLayout (new FlowLayout());
window.add(panelMain);
PanelTop();
PanelButtons();
PanelIcon();
}
#Override
public void actionPerformed(ActionEvent event) {
Object eventSource = event.getSource();
if (eventSource == buttonStart) {
panelMain.removeAll();
TurnBase TB = new TurnBase();
TB.CreateTurnBase();
}
}
The other class looks something like this:
public void CreateTurnBase() {
panelMain=new JPanel();
panelTurnBase =new JPanel();
setLayout(new FlowLayout());
setPreferredSize(new Dimension(750,750));
setBackground(Color.BLUE);
panelTurnBase.setLayout (new FlowLayout());
panelMain.add(panelTurnBase);
System.out.println("1");
PanelTurnBaseTop();
PanelGameScreen();
PanelTurnBaseBottom();
repaint();
revalidate();
buttonAttack = new JButton("Attack");
buttonAttack.addActionListener(this);
panelTurnBase.add(buttonAttack);
System.out.println("2");
}
The reason the panel has "just a black screen" is because you dont add anything to it, and you tell it to have a black screen.
i.e
panel.setBackground(Color.BLACK);
You never actually do anything to that first panel inside of any of those methods, which I can assume based on your representation of your second "class" (it's a method). Hence why it stays black.
You say:
panelMain=new JPanel();
panelTurnBase =new JPanel();
You're creating new JPanels every time and just call them panelMain and they just sit inside of that method, never leaving. You either need to return a JPanel or give it a JPanel as an argument.
The program is doing exactly what you tell it to do.
Also, do not compare Objects like this:
eventSource == buttonStart
You should use:
eventSource.equals(buttonStart);

Using repaint() method properly

I have a button that when pressed calls a changecolor() method in a different class where some drawing is done. The button listener works fine and I see from some logging that the color was in fact changed but my drawing is not updated. This is my current implementation:
(This method is called when a button is clicked)
public void changeWarningLightColor(){
System.out.println("change color method called");
if(warningLights.equals(Color.GREEN)){
warningLights=Color.RED;
System.out.println(warningLights);
repaint();
}
else{
warningLights=Color.GREEN;
repaint();
}
}
and my drawing is created in the same file in the above method as follows:
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawSomething();
//draw a bunch of lines
}
My question is what is the proper way to call repaint() in order to actually update the drawing? Do I need to somehow call g.repaint() or do something different?
Separate class where the frame is created:
public class MainWindow extends JFrame {
public MainWindow(){
JPanel Window = new JPanel();
JPanel LeftSidePanel = new JPanel();
LeftSidePanel.setLayout(new BorderLayout());
LeftSidePanel.add(new DrawStatus(),BorderLayout.CENTER); //where the drawing is added
Window.setLayout(new BoxLayout(Window,0));
Window.add(LeftSidePanel);
add(Window);
}
public static void main(String[] args) {
//main method for showing the frame we created with the panels, and circles inside it
MainWindow frame = new MainWindow();
frame.setSize((int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getWidth()),(int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getHeight()));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setTitle("DVPWS v1.0");
frame.setResizable(false);
MenuBar menu = new MenuBar();
frame.setJMenuBar(menu);
frame.setVisible(true);
}
}
If you are using a Jframe (most likely are) do
yourFrame.repaint();
Optionally
yourPanel.repaint();
In this case you could do
public MainWindow mw = new MainWindow();
mw.repaint();
If that doesnt work(i had a similar problem) than your going to have to make an instance of JFrame instead of extending it.

Why is it not showing my label?

I am new to swing, can anyone help me out with this...
It is not showing my "label" , instead it shows me only components which are in the "panel" class.
One more question, can anyone clarify me about LayoutManagers ?
Can 2 or more LayoutManagers be used in a frame ? like for the frame i will be using FlowLayout and i have a JPanel added to the frame for which i will be using BoxLayout ... is it possible in the first place ??
import javax.swing.*;
import java.awt.event.*;
import java.awt.Graphics;
public class JForm1 extends JFrame
{
public JForm1()
{
init();
}
public static void main(String[] args)
{
JForm1 form = new JForm1();
}
public void init()
{
JFrame frame = new JFrame("My Form 1");
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
JLabel label = new JLabel("Enter your Name : ");
panel MyPanel = new panel();
frame.getContentPane().add(label);
frame.getContentPane().add(MyPanel);
frame.setVisible(true);
}
}
class panel extends JPanel implements ActionListener
{
JButton submitButton;
JTextField text;
panel()
{
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
public void paintComponent(Graphics g)
{
text = new JTextField("Enter Name here");
text.setSize(100,25);
submitButton = new JButton("Submit");
submitButton.setSize(50,90);
submitButton.setBounds(200, 0, 80, 80);
submitButton.addActionListener(this);
this.add(text);
this.add(submitButton);
}
public void actionPerformed(ActionEvent event)
{
if(event.getSource()==submitButton)
{
System.out.println("The Entered Name is : "+text.getText());
}
}
}
What is this ?:
public void paintComponent(Graphics g)
{
text = new JTextField("Enter Name here");
text.setSize(100,25);
submitButton = new JButton("Submit");
submitButton.setSize(50,90);
submitButton.setBounds(200, 0, 80, 80);
submitButton.addActionListener(this);
this.add(text);
this.add(submitButton);
}
This code has nothing to do in paintComponent. paintComponent is about "painting a component", ie, paint a rectangle, draw a line, fill an oval, etc... This is absolutely not the place where to add your components. Instead, call that code in your constructor.
Additionally, if you are using LayoutManager's (which you should), calling setSize/setBounds/setLocation is useless (dimply remove those calls).
A few more things:
If you override paintComponent, make sure to invoke the super-method
Don't extends JFrame if not needed (here it is clearly not needed)
Follow Java naming conventions (class names should start with an UpperCase letter, variables and methods with a lowerCase letter)
All Swing-related code must be called on the EDT. Start your UI within a SwingUtilities.invokeLater() block.
Try by changing layout to FlowLayout for mypanel.
mypanel.setLayout(new FlowLayout());

Unable to set button's location in java swing application

I am new to Java and was trying to develop a basic swing application. I wanted to set the location of the button on the JFrame. I tried to do this but was unable to do this this is my code. I am using eclipse for development
public class MyUI extends JFrame {
JButton button1 = new JButton("Click");
JTextField tb1 = new JTextField(5);
JPanel panel1 = new JPanel();
public MyUI() {
super("Test");
setVisible(true);
this.setLayout(null);
panel1.setLayout(null);
panel1.setVisible(true);
button1.setVisible(true);
panel1.add(button1);
add(panel1);
panel1.setLocation(10, 10);
button1.setLocation(10, 10);
setDefaultCloseOperation(EXIT_ON_CLOSE);
button1.addActionListener(this);
}
public static void main(String[] args) {
MyUI gui = new MyUI();
gui.setSize(400, 300);
}
}
1.why you put two JComponents to the same Bounds
panel1.setLocation(10, 10);
button1.setLocation(10, 10);
2.have look at Initials Thread
3.public class MyUI extends JFrame {
should be
public class MyUI extends JFrame implements ActionListener{
4.don't extend JFrame, create a local variable
5.setVisible(true); should be (in this form) only last code line into MyUI() constructor
6.setVisible(true); is important issue, you visibled JFrame and then to add JComponent(s)
7.don't use NullLayout, use proper LayoutManager, in the case that you remove this.setLayout(null); and panel1.setLayout(null); added JComponents could be visible
8.use pack() before setVisible(true) as last two code lines in constructor
EDIT (by using built_in LayoutManagers, BorderLayout for JFrame and FlowLayout for JPanel)
import java.awt.event.*;
import javax.swing.*;
public class MyUI extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JButton button1 = new JButton("Click");
private JTextField tb1 = new JTextField(5);
private JPanel panel1 = new JPanel();
public MyUI() {
super("Test");
panel1.add(tb1);
panel1.add(button1);
add(panel1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
button1.addActionListener(this);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyUI testing = new MyUI();
}
});
}
}
Your panel and button are not seen because they have zero size. Add something like:
panel1.setSize(100, 100);
button1.setSize(80, 30);
or use the setBounds method which is more convenient to set location and size simultaneously:
panel1.setBounds(10, 10, 100, 100);
button1.setBounds(10, 10, 80, 30);
Would like to suggest something, though its not the direct immediate answer to your question, but still its important from my point of view....
You can use Group Layout which was developed by NetBeans team back in 2005, its awesome to work with.... Try using the Windows Builder Pro which is provided by Google for free now... You can get your application up and running in no time......

JFrame removing JPanels and adding a new JPanel

I currrently have a SwingWorker that sends a HTTP Request and I override the SwingWorker's done() method to change contents in a JFrame. I want to basically remove everything and add a new members panel on the JFrame depending on the values returned from the Server.
Now, the problem I am facing is that when I invoke the following methods below on the JFrame, it doesn't remove anything from the JFrame nor does it change it's contents contained within the Frame.
//TODO: Investigate why JFrame content pane won't repaint.
f.removeAll();
//Pass the frame f reference only into MainDisplay, it doesn't actually do anything apart from allowing a class to add a JMenuBar on the JFrame.
f.add(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
The current fix I have is this below but I would rather change the contents of the JFrame rather then loading a new one up.
f.dispose();
f=new ApplicationFrame();
I've looked through previous answers on here and on Google and some state use validate() or invalidate() whilst calling repaint() to repaint the JFrame.
Any suggestions/help would be much appreciated.
Edit: I think I am going to debug more since there must be something else going wrong.
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame {
private static final long serialVersionUID = 1L;
public MyFrame() {
final JPanel parentPanel = new JPanel();
parentPanel.setLayout(new BorderLayout(10, 10));
final JPanel childPanel1 = new JPanel();
childPanel1.setBackground(Color.red);
childPanel1.setPreferredSize(new Dimension(300, 40));
final JPanel childPanel2 = new JPanel();
childPanel2.setBackground(Color.blue);
childPanel2.setPreferredSize(new Dimension(800, 600));
JButton myButton = new JButton("Add Component ");
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
parentPanel.remove(childPanel1);
parentPanel.add(childPanel2, BorderLayout.CENTER);
parentPanel.revalidate();
parentPanel.repaint();
pack();
}
});
setTitle("My Empty Frame");
setLocation(10, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
parentPanel.add(childPanel1, BorderLayout.CENTER);
parentPanel.add(myButton, BorderLayout.SOUTH);
add(parentPanel);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame myFrame = new MyFrame();
}
});
}
}
You are trying to repaint()/validate() the ContentPane. Did you try doing same on the JFrame?
You can also try JFrame#pack().
modification of your code
f.setContentPane(new MainDisplay(f));
f.getContentPane().invalidate();
f.getContentPane().validate();
f.getContentPane().repaint();
You may try using Frame.pack() again it worked for me. Or try one od those following methods:
Frame.setOpaque(false);
Frame.setEnabled(false);
Frame.setVisible(false);
Frame.removeAll();

Categories