I am kinda new to java. I was reading java codes to learn more about it, and this had me confused. A method would only be performed if only it is called, right? But how about those methods of built-in classes like paint(), paintComponent(), run() in Runnable class, etc. Are these methods performed without explicitly calling them, once a class that implements these methods is used to instantiate an object? Is that really how it works?
Like for example in this code, method paint() was not really called.
import javax.swing.*;
import java.awt.*;
public class FrameExampleTest{
public static void main(String args[]){
FrameExample frame = new FrameExample();
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class FrameExample extends JFrame{
PanelExample panel;
public FrameExample(){
Container c = getContentPane();
panel = new PanelExample();
c.add(panel,BorderLayout.CENTER);
}
}
class PanelExample extends JPanel{
public PanelExample(){
setSize(300,200);
}
public void paint(Graphics g){
g.fillArc(20,20,30,30,0,360);
}
}
You don't call paint or run yourself, but other code in the JVM does call it for you. For instance code inside the Thread class will call your run method. Code inside the event loop will call paint or paintComponent. Over time, you will see that there's nothing magical. Whenever a method is called, some other code calls it.
Yes. The window framework calls paint and paintComponent methods for you. It figures out when the paint/repaint is required (e.g. when window is moved, opened, re-opened, resized, etc). Javadoc to these methods sometimes mentions it isn't advised/not required to call them directly, but is required to implement them to do such and such things.
Related
I was looking at an applet code and it struck me.
My Questions:
why is setForeground() used without an object here despite it being defined as a non-static method in the API
the code is as follows:
import java.applet.Applet;
import java.awt.*;
/*<applet code = "swings.class" height = "500" width = "500"></applet>*/
public class Swings extends Applet{
public void init(){
setBackground(Color.yellow);
setForeground(Color.red);
Font f = new Font("Comic Sans MS",Font.BOLD,25);
setFont(f);
}
public void paint(Graphics g){
g.drawString("Welcome to Applets",100,100);
}
}
setForeground is declared as public in Component, Swings is a subclass of Component,
which means setForeground will be inherited by Swings as its own class member, so you can call setForeground in Swings directly.
You can check jls for more details.
update
In java, if both non-static methods are in the same class, they can call each other directly, without creating a new instance.
Since setForeground is inherited by Swings, setForeground and init are both members of class Swings. So you can call setForeground in init directly.
I want to have a JPanel respond to a MouseEvent, such as, mousePressed(), but not others.
I can do it via the following code added to the JPanel object:
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
//Some action here
}
});
However, the anonymous function requires that I use final variables inside there. And my program specifications do not allow me to that.
I can also define the MouseEvents not as an inner class, but outside, but then I have to provide implementations for all the functions in the MouseListener interface, such as mouseClicked(), mouseEntered(), mouseExited(), etc.
Is there any other way of achieving what I'm trying to do, i.e. define the mousePressed() function without having to use final variables inside it, and also without having to define the other functions in the interface ?
Thanks a lot !
EDIT: I realize that the code I have provided runs without error because the inner class is creating an object of MouseAdapter which is an abstract class.
However, my question still remains : if I dont want to define all methods of the abstract class, and also not have to use inner classes, is there any way of doing so ?
One of the examples:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainClass extends JPanel {
public MainClass() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new MainClass());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
Also, you can use official tutorial here.
OK, I am going to try to explain this as best as I can. I am fairly proficient at Java but am unable to find a logical solution to this after extensive searching. Lets say that I have a JPanel class inside package A that will contain a graph that will be drawn.
package A
public class DrawGraph extends JPanel
{
public DrawGraph()
{
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// other stuff
}
public void updateGraph()
{
repaint();
}
}
In a different class inside package B I have a JCheckBox that when selected should trigger a repaint of the graph in package A. This class does not initialize the DrawGraph class. That class is initialized elsewhere.
package B
public class CheckBoxClass extends JPanel
public CheckBoxClass
{
graphicsCheckBox.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent cb)
{
GUI_Data.graphics = true;
DrawGraph.updateGraph(); // Calls Update Graph function
}
});
}
Now how do I call the updateGraph function in my DrawGraph class without having to create a new instance of the DrawGraph class? I know that I cannot make the updateGraph method static since repaint() is not static. I feel like there has to be a way to do this without repainting via a timer or some other convoluted and inefficient method. Am I looking at this problem in the wrong way? Basically I need a way to trigger a repaint of the DrawGraph class from the JCheckBox class actionlistener. If this question isn't clear, please let me know so I can revise it. Thank you guys in advance, this is my first question but I have been using you guys for several years.
There seem to be a bit of confusion of concepts here, let me try to explain.
static vs. instance methods:
A class can have static and non static methods. non-static methods can be called only on an instance of the class. static can be called only on the class (although you can call them through a variable containing an instnace of the class).
method visibility: a method can be private, protected, package-protected or public. private methods can be called only from within the same class). protected can be called only from within the class or subclasses. package-protected (without any qualifier) can be called from classes within the same package. public can be called from anywhere.
In your case, the fact that the CheckBoxClass is not in the same package has nothing to do with the fact that you can't call DrawGraph.updateGraph(). updateGraph() is an instance method (non-static), hence you have to have an instance to call it. Now, if you know that there is going to be only one instance of DrawGraph in your program, then you can use the singleton pattern:
1) in the DrawGraph class have a static variable initialized to an instance of the class itself. Also have a static method that returns such instance:
public class DrawGraph {
private static DrawGraph singleton = new DrawGraph();
public static getInstance() {
return singleton;
}
}
Now you can do the following from CheckBoxClass:
#Override
public void actionPerformed(ActionEvent cb)
{
GUI_Data.graphics = true;
DrawGraph.getInstance().updateGraph(); // Calls Update Graph function
}
I've got two classes. My QuizatMainClass class and a class called window. I'm trying to create a window from the Quizat class with a set size but it won't compile. I've set the parameter to (x and y) e.g (1080 and 720). But it does'nt like that. I'm new to Java and don't really understand why I can't do this. The way the IDE fixes it is with something about superclass stuff. If someone could explain what this means to me or a more simple way to do what I'm trying to run I'd appreciate it. Layman's terms please.
QuizatMainClass:
package Quizat;
public class QuizatMainClass extends Window{
public static void main(String[] args) {
Window QuizatHomeScreen = new Window(1080, 20);
}
}
Window Class:
package Quizat;
import javax.swing.JFrame;
public class Window{
public Window(int x, int y){
JFrame window = new JFrame();
window.setSize(x,y);
window.setLocationRelativeTo(null);
window.setResizable(false);
window.setVisible(true);
}
}
The explanation for your problem is that since QuizatMainClass extends the Window class, and Window has a specific parameter-using constructor, the QuizatMainClass will either need to create a constructor that specifically calls Window's super constructor with parameters, or else give Window a default no-arg constructor.
Having said that your real problem is that you're misusing inheritance. QuizatMainClass shouldn't extend the Window class, that's it.
This is how my code looked in the beginning: https://gist.github.com/anonymous/8270001
Now I removed the ActionListener to a separate class: https://gist.github.com/anonymous/8257038
The program should give me a little UI, but it just keeps running without any UI popup or errors.
Someone told me this:
In your GUI class constructor, you are creating a new nupuVajutus object, but since nupuVajutus extends the GUI class, when you create a nupuVajutus, you are also inherently calling the GUI class constructor by default, thus creating an infinite loop
If this is really the problem, then I have to say I am not that good and could use some help getting this program working with the classes separated.
You have indeed already been given the answer, although what you have is not an infinite loop, but infinite recursion, which will eventually cause a StackOverflowError.
Here's what happens:
new GUI() calls new nupuVajutus(). This creates a new nupuVajutus object by calling its constructor. Because nupuVajutus extends GUI, this means a nupuVajutus object is a GUI object with additional functionality. Therefore, because it is a GUI object, a GUI constructor needs to be called. The nupuVajutus constructor does not explicitly call a super constructor, so it implicitly calls the GUI() (no argument) constructor before executing. In this new call to the GUI() constructor, another new nupuVajutus() call is encountered, and so on, ad infinitum...
It seems to me you need to do some more research around Object Oriented Programming, in particular the topics of sub-classing, inheritance, object instances, and encapsulation. There are plenty of resources available to help you.
After you extracted your ActionListener into a separate file, you should not have changed it to extend GUI. That extends the class (which is like a blueprint) not an instance (which is like a something built using that blueprint) - remember: you can create multiple instances of a class.
Previously, the "nupuVajutus" ActionListener was an inner class, so it had access to all of the enclosing class' fields and methods. Now that it is no longer an inner class, it needs to be passed a reference to the GUI instance so that it can access its methods. Something like this:
public class NupuVajutus implements ActionListener {
private final GUI gui;
public NupuVajutus(GUI gui) {
this.gui = gui;
}
public void actionPerformed(ActionEvent e) {
// The GUI instance can now be accessed through the gui field, for example:
gui.something();
// ...
}
}
And in the GUI() constructor:
NupuVajutus nV = new NupuVajutus(this);
To be honest, though, there is nothing wrong with keeping your ActionListener as an inner class. If you're never going to use that class outside of the GUI class, then it is probably preferable for it to remain as an inner class.
What you are doing it extending the GUI class. This Does Not make then share the Same Fields Say you have a field field in your GUI class
public class GUI {
String field = "Hello";
}
Just because your Listener class extends GUI doesn't mean they will share the exact same field object. I think that's what you think is supposed to occur
public class Listener extends GUI implements ActionListener {
public void actionPerformed(ActionEvent e) {
field = "World";
}
}
The above does nothing the field in GUI. If you were to do this, you would need to access in a static way like line GUI.field = "World";. The above is also what causes in an infinite loop, as you need to instantiate the Listener in the GUI class. This is not really good practice or design.
One option would to use some sort of MVC pattern.
Another option would be to pass the values you need, to a constructor in your Listener class, and instantiate it in your GUI class with those values.
Run this example to see what I'm talking about. I have a MyListener class that I pass a Jlabel to, the same JLabel in the GUI class
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FieldTest {
private JLabel label = new JLabel(" ");
private JButton button = new JButton("Set Text");
public FieldTest() {
MyListener listener = new MyListener(label);
button.addActionListener(listener);
JFrame frame = new JFrame();
frame.add(label, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FieldTest();
}
});
}
}
class MyListener implements ActionListener {
JLabel label;
public MyListener(JLabel label) {
this.label = label;
}
#Override
public void actionPerformed(ActionEvent arg0) {
label.setText("Hello, FieldTest!");
}
}