Cannot apply the customer JPanel - java

I have a class which extends JPanel, but it is not working. Would someone tell me how can I solve the issue. It looks like the error is on "super";
This is my class:
public class DivCommentJPane extends JPanel {
private BeanPanel thisBean;
private CommentItem thisComment;
private String pageErrorPrefix="Error On DivCommentJPane.java : ";
private PDFNotesBean bean;
public DivCommentJPane(CommentItem comment ){
//thisBean=bean;
super();
thisComment=comment;
setting();
}
The code below is to add DivCommentJPane into another JPane:
ArrayList<CommentItem>sortComment= lstComment;
Collections.sort(sortComment,CommentItem.sortPage);
for(CommentItem comm: sortComment){
DivCommentJPane d=new DivCommentJPane(comm);
listCommentPane.add(d, BorderLayout.CENTER);
}

Since you are using a BorderLayout, "[e]ach region may contain no more than one component."
Therefore repeated attempts to add to the CENTER region (listCommentPane.add(d, BorderLayout.CENTER); ) will end up replacing what was previously there.
You will have to use a different layout manage instead.

Related

How to transfer String from one class to another in Java

I have these two classes:
ConnectionPanel.class
public class ConnectionPanel extends JPanel implements ActionListener,ItemListener, PropertyChangeListener {
private MasterModel m_masterModel;
private JTextField m_keyField;
public ConnectionPanel(MasterModel masterModel) {
m_masterModel = masterModel;
setLayout(new GridLayout(0, 2));
JPanel panel = null;
panel = new JPanel();
panel.add(new JLabel("Type Key:"));
m_keyField = new JTextField(9);
m_keyField.setText("dertfgdertabcdef");
panel.add(m_keyField);
add(panel);
getChatModel().addPropertyChangeListener(this);
getChatModel().setListen(true);
}
public String getEncryptionKey(){
return m_keyField.getText();
}
}
AudioPlayback.class
public class AudioPlayback extends AudioBase {
// and here I want to be able to get
// somehow String key = ConnectionPanel.getEncryptionKey()
// I tried ConnectionPanel panel = new ConnectionPanel(); but does not work
// it messes my graphical interface
// also there is lots of code here too
}
Do you have any ideas how can I get that field input into my audioplayback.class ?
I totally agree with moffeltje & Luke. This question is simple so that I think you can learn something more basic on Java.
But I review your constructor of ConnectionPanel.Excuse me, do you know constructor?
You can find the details here:
https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Now, let's talk about your code. You only give a constructor with one input parameter to ConnectionPanel so that you can't use the constructor without parameters in AudioPlayback.
But the attribute masterModel seems hasn't been called in your ConnectionPanel so that you can roughly use the following code:
// Notice! Don't do this in your production enviroment. It's only for test otherwise you can make sure that you can give the null value to it.
ConnectionPanel panle = new ConnectionPanel(null);
System.out.println(panel.getEncryptionKey());

Methods from external class accessible but GUI Components not

I have a weird Problem with my Java GUI.
I can access the Methods in the Main Class from another Class but i cannot access the Swing Components.
Let me show you how i built the whole thing
Main Class:
public class GUI extends JFrame {
static Code c = new Code();
static Draw panel = new Draw();
JTextArea codelog;
JLabel lblFile;
...
...
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI frame = new GUI();
frame.create();
}
});
}
public void create() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1280,720);
...
...
contentPane = new JPanel();
setContentPane(contentPane);
contentPane.setBackground(Color.DARK_GRAY);
GridBagLayout gbl_contentPane = new GridBagLayout();
setResizable(false);
...
...
panel.setBackground(Color.BLACK);
gbc_panel.fill = GridBagConstraints.BOTH;
gbc_panel.gridx = 1;
gbc_panel.gridy = 1;
contentPane.add(panel, gbc_panel);
codelog = new JTextArea();
codelog.setEditable(true);
JScrollPane scrollPane_1 = new JScrollPane(codelog);
codelog.setLineWrap(true);
scrollPane_1.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
codelog.setVisible(true);
scrollPane_1.setVisible(true);
GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
gbc_scrollPane_1.gridheight = 2;
gbc_scrollPane_1.gridwidth = 4;
gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
gbc_scrollPane_1.gridx = 8;
gbc_scrollPane_1.gridy = 1;
contentPane.add(scrollPane_1, gbc_scrollPane_1);
...
...
}
public void refresh(){
panel.repaint();
}
}
I am using static Code c and static Draw panel to avoid multiple instances as i also have to create Objects of the Main class in other classes.
The other Class named Code
public class Code {
...
...
static GUI g = new GUI();
String test;
...
...
public void hpgl(){
g.codelog.append(test); // gives me nullPointerException !!
g.refresh // works
...
...
}
}
The Problem is that i can access the Methods of the Main Class (GUI) from other classes (such as Code) but i cannot access the Components (such as JTextArea).
The refresh() Method in the Main Class proves it. I can access the Method and in the Main Class the repaint() works. But if i try to repaint from another class using GUI.panel.repaint() it won't work because i would in that case access the panel directly from Code Class.
The Same goes for the JTextArea. I am trying to append codelog from Code but it won't let me do it. If i create a Method in Main Class which appends the Textarea and then call the Method from Code Class it works. But using g.codelog.append(test) gives me a Java null pointer exception
So i can access the Methods but i cannot access the Swing Components.
Can you guys please help me. I don't want to have to write an extra Method in the Main Class for every single Swing Component i want to modify.
Thank You
The UI which is visible on the screen is not the same UI you have created in your Code class. If you want Code to be able to access the UI properties, you will need to pass a reference of the GUI to it.
Having said that, I would be apposed to exposing the UI components directly to any class an instead provide getters and setters (where applicable) to provide access to the information been managed. This prevents rouge classes from making changes to the UI which it should be allowed to do (like remove components)
Depending on what you are doing, an Observer Pattern might be a better choice, where by Code is notified by GUI when something it might be interested in changes. If done through the use of interfaces, this will reduce the coupling between your classes and make it more flexible
Beware static is not a mechanism for providing cross object communication and should be avoid if at all possible, especially in something as dynamic as a GUI.
I was able to solve the Problem following MadProgrammer's Suggestion.
This is what i changed.
I have 3 Classes:
Main Class
Draw
Code
Main Class
public class GUI extends JFrame {
Draw panel = new Draw(this);
Code c = new Code(this);
...
...
}
Code Class
public class Code {
private GUI g;
private Draw b;
public Code(GUI g){
this.g = g;
}
...
...
}
Draw Class
public class Draw extends JPanel{
private GUI x;
private Code c;
public Draw(GUI x){
this.x = x;
}
...
...
}
I removed all the Static declarations. It is now working. I can access the Swing Components in the Main Class now.
Is this the Professional way to do it? or is there still room for improvement. This is the first time i used the passing reference way to do it. Until now i always used static Objects.
Thank You

Access GUI components from another class

I'm new to Java and I've hit a brick wall. I want to access GUI components (that have been created in one class) from another class. I am creating a new GUI class from one class, like so;
GUI gui = new GUI();
and I can access the components in that class, but when I go to a different class I cant. I really just need to access the JTextAreas to update their content. Could someone point me in the right direction please, any help is greatly appreciated.
GUI Class:
public class GUI {
JFrame frame = new JFrame("Server");
...
JTextArea textAreaClients = new JTextArea(20, 1);
JTextArea textAreaEvents = new JTextArea(8, 1);
public GUI()
{
frame.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 3));
...
frame.setVisible(true);
}
}
First respect encapsulation rules. Make your fields private. Next you want to have getters for the fields you need to access.
public class GUI {
private JTextField field = new JTextField();
public GUI() {
// pass this instance of GUI to other class
SomeListener listener = new SomeListener(GUI.this);
}
public JTextField getTextField() {
return field;
}
}
Then you'll want to pass your GUI to whatever class needs to access the text field. Say an ActionListener class. Use constructor injection (or "pass reference") for the passing of the GUI class. When you do this, the GUI being referenced in the SomeListener is the same one, and you don't ever create a new one (which will not reference the same instance you need).
public class SomeListener implements ActionListener {
private GUI gui;
private JTextField field;
public SomeListener(GUI gui) {
this.gui = gui;
this.field = gui.getTextField();
}
}
Though the above may work, it may be unnecesary. First think about what exactly it is you want to do with the text field. If some some action that can be performed in the GUI class, but you just need to access something in the class to perform it, you could just implement an interface with a method that needs to perform something. Something like this
public interface Performable {
public void someMethod();
}
public class GUI implements Performable {
private JTextField field = ..
public GUI() {
SomeListener listener = new SomeListener(GUI.this);
}
#Override
public void someMethod() {
field.setText("Hello");
}
}
public class SomeListener implements ActionListener {
private Performable perf;
public SomeListener(Performable perf) {
this.perf = perf;
}
#Override
public void actionPerformed(ActionEvent e) {
perf.someMethod();
}
}
Several approaches are possible:
The identifier gui is a reference to your GUI instance. You can pass gui to whatever class needs it, as long as you respect the event dispatch thread. Add public accessor methods to GUI as required.
Declarations such as JTextArea textAreaClients have package-private accessibility. They can be referenced form other classes in the same package.
Arrange for your text areas to receive events from another class using a PropertyChangeListener, as shown here.
The best option to access that text areas is creating a get method for them. Something like this:
public JTextArea getTextAreaClients(){
return this.textAreaClients;
}
And the same for the other one.So to access it from another class:
GUI gui = new GUI();
gui.getTextAreaClients();
Anyway you will need a reference for the gui object at any class in which you want to use it, or a reference of an object from the class in which you create it.
EDIT ---------------------------------------
To get the text area from GUI to Server you could do something like this inside of Create-Server.
GUI gui = new GUI();
Server server = new Server();
server.setTextAreaClients(gui.getTextAreaClients());
For this you should include a JTextArea field inside of Server and the setTextAreaClients method that will look like this:
JTextArea clients;
public void setTextAreaClients(JTextArea clients){
this.clients = clients;
}
So in this way you will have a reference to the JTextArea from gui.
here i add a simple solution hope it works good,
Form A
controls
Textfield : txtusername
FormB fb = new FormB();
fb.loginreset(txtusername); //only textfield name no other attributes
Form B
to access FormA's control
public void ResetTextbox(JTextField jf)
{
jf.setText(null); // or you can set or get any text
}
There is actually no need to use a class that implements ActionListener.
It works without, what might be easier to implement:
public class SomeActionListener {
private Gui gui;
private JButton button1;
public SomeActionListener(Gui gui){
this.gui = gui;
this.button1 = gui.getButton();
this.button1.addActionListener(l -> System.out.println("one"));
}
}
and then, like others have elaborated before me in this topic:
public class GUI {
private JButton button = new JButton();
public GUI() {
// pass this instance of GUI to other class
SomeActionListener listener = new SomeActionListener(GUI.this);
}
public JButton getButton() {
return button;
}
}

Multiple Jpanel with buttons in one Jframe on MVC, how do I get the actionlistener in my controler ?

this is a homework btw,
I am asked to make a jframe containing multiple jpanels which have buttons and action listeners attached to them. I have to use the MVC model to do it but, since my buttons/actions are in jpanels instead of the jframe, i do not know how to recover them. I wont put down all of my code but, just what is needed to see what I try to do. I want to get the button "ajouter" from panel 3 first to do whatever action:
So this is pannel 3
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import ca.uqam.inf2120.tp2.modele.GestionAbsenceEmployes;
public class RechercherAbsenceP3 extends JPanel {
private GestionAbsenceEmployes aControleur;
private JButton ajouter, modifier, supprimer, afficher, fermer;
FlowLayout gestionnaireComposant;
RechercherAbsenceP3() {
try {
jbInitP3();
} catch (Exception e) {
e.printStackTrace();
}
ajouter.addActionListener(aControleur);
modifier.addActionListener(aControleur);
supprimer.addActionListener(aControleur);
afficher.addActionListener(aControleur);
fermer.addActionListener(aControleur);
}
private void jbInitP3() throws Exception {
gestionnaireComposant = new FlowLayout(FlowLayout.RIGHT);
this.setLayout(gestionnaireComposant);
ajouter = new JButton("Ajouter");
modifier = new JButton("Modifier");
modifier.setEnabled(false);
supprimer = new JButton("Supprimer");
supprimer.setEnabled(false);
afficher = new JButton("Afficher");
afficher.setEnabled(false);
fermer = new JButton("Fermer");
this.add(ajouter);
this.add(modifier);
this.add(supprimer);
this.add(afficher);
this.add(fermer);
}
public JButton getAjouter() {
return ajouter;
}
}
This is the window
package ca.uqam.inf2120.tp2.interfacegraphique;
import java.awt.BorderLayout;
import ca.uqam.inf2120.tp2.interfacegraphique.RechercherAbsenceP3;
import javax.swing.JFrame;
import javax.swing.JPanel;
import ca.uqam.inf2120.tp2.modele.GestionAbsenceEmployes;
public class CreerRechercherAbsence extends JFrame {
private GestionAbsenceEmployes aControleur;
private JPanel absenceP1, absenceP2, absenceP3;
private BorderLayout gestionnaireComposant;
public CreerRechercherAbsence() {
super("Gestionnaire des employés absents");
try {
jbInit();
} catch (Exception ex) {
ex.printStackTrace();
}
aControleur = new GestionAbsenceEmployes(this);
}
void jbInit() throws Exception {
gestionnaireComposant = new BorderLayout(5, 5);
this.getContentPane().setLayout(gestionnaireComposant);
absenceP1 = new RechercherAbsenceP1();
absenceP2 = new RechercherAbsenceP2();
absenceP3 = new RechercherAbsenceP3();
this.getContentPane().add(absenceP1, BorderLayout.NORTH);
this.getContentPane().add(absenceP2, BorderLayout.CENTER);
this.getContentPane().add(absenceP3, BorderLayout.SOUTH);
}
}
now the not finished controler:
package ca.uqam.inf2120.tp2.modele;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import ca.uqam.inf2120.tp1.partie1.adt.impl.ListeAdtArrayListImpl;
import ca.uqam.inf2120.tp2.interfacegraphique.CreerRechercherAbsence;
public class GestionAbsenceEmployes implements ActionListener{
private AbsenceEmploye modele;
private CreerRechercherAbsence vue;
public GestionAbsenceEmployes(CreerRechercherAbsence uneVue) {
this.modele = new AbsenceEmploye();
vue = uneVue;
}
public AbsenceEmploye getModele() {
return modele;
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if(source == vue.getAjouter()) {
}
}
}
When I add the vue.getAjouter() it does not know what it is !!!
What do I do/get wrong ?
The problem is you are calling getAjouter() on CreerRechercherAbsence JFrame instance in your ActionListener where as you'd want to be calling getAjouter() on RechercherAbsenceP3 JPanel instance.
My solution:
Convert your ActionListener class GestionAbsenceEmployes to accept RechercherAbsenceP3 as the parameter so we can call getAjouter() on its instance like so:
class GestionAbsenceEmployes implements ActionListener {
private AbsenceEmploye modele;
private RechercherAbsenceP3 vue;
public GestionAbsenceEmployes(RechercherAbsenceP3 uneVue) {
this.modele = new AbsenceEmploye();
vue = uneVue;
}
public AbsenceEmploye getModele() {
return modele;
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == vue.getAjouter()) {
}
}
}
you would than do:
aControleur = new GestionAbsenceEmployes(absenceP3);
but in order for the above statement to function you must change this:
private JPanel absenceP1, absenceP2,absenceP3;
in CreerRechercherAbsence class to this:
private JPanel absenceP1, absenceP2;
private RechercherAbsenceP3 absenceP3;
because you extend JPanel to add functionality hence the RechercherAbsenceP3 but by declaring it as JPanel you down cast it, thus it does not have access to the methods of extended JPanel RechercherAbsenceP3 and only those of default JPanel.
Some other suggestions:
Do not extend JFrame class unnecessarily
No need for getContentPane.add(..) as add(..) has been diverted to contentPane
Be sure to create and manipulate Swing components on Event Dispatch Thread
Not sure whether the following approach will be considered MVC, or whether it will result in good marks on your assignment.
My "problem" with your current approach is that the reusability is limited to the model, and that it looks difficult to write a decent test case for this code, unless you are prepared to write tests which include the whole view.
When I need to write a Swing application, it seems that I only end up with 2 classes: a model class defining the data and the operations available on that data, and the view class. The view class functions both as view as well as controller. When I have a button as in your example, I would attach an ActionListener to it (or use an Action) which just retrieves the necessary information from the view without any logic. It passes all that information directly to the model side where all the logic is located.
The two main benefits I see in this approach:
I can re-design my view without any problems. If I decide to remove a JButton and provide the user with another mechanism for that same operation, all my changes are limited to the view. I have no dependency on UI elements except in my view class. I see all the "information gathering and passing it to the model" directly in my view class, and due to the implementation of that view this will not affect other classes. Compare that with your code where you have a source == vue.getAjouter() check in a class outside your view.
I can test the model and all its logic without needing my actual view. So I can skip the whole "firing up a Swing UI" in a unit test and still test all my logic. If I want to test the UI (for example to test whether a certain button is disabled when a field is left blank) I can test this separately in an integration test (as having a UI tends to slow down your tests).
What I found a very interesting article in this regard is The humble dialog box
Here is how I would do it. Make GestionAbsenceEmployes a non-static inner class of CreerRechercherAbsence
public class CreerRechercherAbsence extends JFrame {
private GestionAbsenceEmployes aControleur;
private JPanel absenceP1, absenceP2;
private RechercherAbsenceP3 absenceP3;
// code omitted
public CreerRechercherAbsence() {
super("Gestionnaire des employés absents");
try {
jbInit();
} catch (Exception ex) {
ex.printStackTrace();
}
aControleur = new GestionAbsenceEmployes();
}
// code omitted
class GestionAbsenceEmployes implements ActionListener{
private AbsenceEmploye modele;
public GestionAbsenceEmployes() {
this.modele = new AbsenceEmploye();
}
public AbsenceEmploye getModele() {
return modele;
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if(source == absenceP3.getAjouter()) {
}
}
}
No need to pass this to the constructor and the controller does not need a reference to vue. You get all that for free by making this an inner class. Your controller can access all the member variables of the view. So you can now access the absenseP3 panel with the getAjouter() method.
See http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html for more information on when it makes sense to use inner classes.

Java swing -- Jpanel not rerendering/repainting itself

Im using a JPanel with propertyChangeListener and want it to rerender itself based on whenever a particular variable model changes. My code for the same is as follows --
public class LabelMacroEditor extends JPanel implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
private LabelMacroModel model;
public LabelMacroEditor(LabelMacroModel bean) {
this.model = bean;
model.addPropertyChangeListener(this);
setupComponents();
validate();
setVisible(true);
}
public void setupComponents()
{
Box allButtons = Box.createVerticalBox();
JScrollPane macroModelScroller = new JScrollPane(allButtons);
macroModelScroller.setPreferredSize(new Dimension(300, 200));
for(MacroModel macroModel : model.getMacroModelList())
{
LabelMacroEditorEditableEntity macroEditorEntity = new LabelMacroEditorEditableEntity(macroModel);
Box entityBox = Box.createHorizontalBox();
entityBox.add(macroEditorEntity.getUpButton());
entityBox.add(Box.createHorizontalStrut(15));
entityBox.add(macroEditorEntity.getMacroDetailsButton());
entityBox.add(Box.createHorizontalStrut(15));
entityBox.add(macroEditorEntity.getDownButton());
allButtons.add(entityBox);
}
add(macroModelScroller);
}
#Override
public void propertyChange(PropertyChangeEvent arg0) {
revalidate();
repaint();
}
}
When i use the debug mode in eclipse i can see that whenever there is a change to model it triggers off the call propertyChange and it also runs over revalidate and repaint but only the JPanel display remains the same. It does not seem to be rerendering itself.
Anything fundamental that I'm missing here ?
EDIT :
An example snippet of a property im changing is as follows --
labelMacroModel.addMacroModel(addedMacroModel);
where labelMacroModel is of the type LabelMacroModel and addedMacroModel is of the type Macro
Now the relevant part of LabelMacroModel class that fires off the property change is as follows --
private List<MacroModel> macroModelList;// this is the list of all MacroModels
public void addMacroModel(MacroModel macroModel) {
macroModelList.add(macroModel);
pcs.fireIndexedPropertyChange("LabelMacroModel", macroModelList.size(), null, macroModel);
}
Its not clear how you are changing the components in the panel. If panel is not updated then repaint/revalidate will have no effect. I think you should not need revalidate/repaint to be called explicitly if you are not modifying the way components are laid out. JButton.setText should for example change the label of the button without need of calling repaint.
To expand on the answer by AKJ above, I think you should be reconstructing your components on property change. So doing a remove all then readding is one way to do this. Once you get this working you could be more selective about pushing the model update into the GUI eg if a new entry has been added then just add a new component to reflect this. The remove all / readd is fine for a lot of cases though. HTH.

Categories