MVC - is this correct? - java

I'm trying to use the MVC Pattern for the first time.
And I'm not sure if i do it the right way:
Main Class:
public class DBEditorMain
{
public static void main(String[] args)
{
DBEditorController control = new DBEditorController(new DBEditorView());
}
}
DBEditorController constructor:
public DBEditorController(DBEditorView view)
{
this.view = view;
addListeners ();
view.setVisible (true);
}
DBEditorController addListeners():
private void addListeners()
{
view.addWindowListener (new WindowAdapter ()
{
#Override
public void windowClosing(WindowEvent e)
{
terminate ();
}
});
view.addActionListeners (this);
}
DBEditorView Constructor:
public DBEditorView()
{
super ("Database");
setSize (800, 600);
setResizable (false);
initGUI ();
}
DBEditorView addActionListeners():
public void addActionListeners(ActionListener l)
{
closeButton.setActionCommand ("close");
saveButton.setActionCommand ("save");
closeButton.addActionListener (l);
saveButton.addActionListener (l);
}
DBEditorController actionPerformed():
#Override
public void actionPerformed(ActionEvent e)
{
switch (e.getActionCommand ())
{
case ("save"):
save();
break;
case ("close"):
terminate();
break;
}
}
I think i did it right since the View and Model (not implemented yet) have no references to the Controller or to each other.
Is this a good start or have I missed something.
I know this is a dumb "question" ._.

Related

How to close a JFrame while opening another JFrame? [duplicate]

This question already has answers here:
The Use of Multiple JFrames: Good or Bad Practice? [closed]
(9 answers)
Closed 4 years ago.
I have a frame (main). There are two buttons: Items and Sale.
When I click button Items it opens a frame (Items)
and I want to, when I click on button Sale, it should close the Items and open Sale.
This is Items frame:
public class Items extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Items frame = new Items();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
UPDATE :- here is my sale class
public class Sale extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Sale frame = new Sale();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Just close the previous Item JFrame with dispose() method.
salesframe.setVisible(true);
itemframe.dispose();
In your case, I think you should also add an ActionListener to the button.
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
frameToClose.dispose();
}
});
You should .dispose(); the frame in the ActionListener of the button and since you are extending JFrame in you class it means you .dispose(); the instance itself. Something like this:
public class Main extends JFrame {
public Main() {
Sale sale = new Sale();
Items item = new Items();
JButton btnSale = new JButton("Sale");
getContentPane().add(btnSale, BorderLayout.WEST);
JButton btnItems = new JButton("Items");
getContentPane().add(btnItems, BorderLayout.CENTER);
btnSale.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sale.setVisible(true);
if(item.isVisible()) {
item.dispose();
}
}
});
btnItems.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
item.setVisible(true);
if(sale.isVisible()) {
sale.dispose();
}
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

Cant use dispose(); method, Java Gui form

I have some problems with using dispose() method in my GUI project.
I' am making a GUI swing application for some kind of Elections in IntelliJ.
My problem is, by clicking a button(Confirm1, or 2 or 3) I want to open new JFrame which is checking the age of voter and closes the current JFrame where this button is located by calling dispose().
But frame.dispose(); doesn't work.
I have my JFrame declared in public static main().
Should I make reference for it in my ActionListener? I have been looking for solution, but I couldn't find any.
Here is a code:
import javax.swing.*; //another libraries
public class ElectionGUI {
private JPanel labelElection; // another texfields or etc.
private JButton Confirm1;
private JButton Confirm3;
private JButton Confirm2;
private JPanel Elections;
public VotesGUI(){
Votes votes = new Votes("...","...",0);
listX.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()){
NrX.setText(listX.getSelectedValue().toString());
}
}
});
listY.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()){
NrY.setText(listY.getSelectedValue().toString());
}
}
});
listZ.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()){
NrZ.setText(listZ.getSelectedValue().toString());
}
}
});
Confirm1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
votes.VotesX();
votes.countVotes();
CheckAge age = new CheckAge();
age.Check(); /// referention, to my next //Jframe called psvm Check();
}
});
Confirm2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
votes.VotesY();
votes.countVotes();
CheckAge age = new CheckAge();
age.Check();
}
});
Confirm3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
votes.VotesZ();
votes.countVotes();
CheckAge age = new CheckAge();
age.Check();
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("Elentions");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setContentPane(new ElectionGUI().labelElection);
frame.pack();
}
}

How can i wait for a frame to perform an action before the code execute the next line?

I want to initialize a Graphical User Interface (GUI) for the user to input a form. After this is accomplished i want to open a new GUI, but as soon as the first GUI pops-up the next one is initialized to.
Is there any way to solve this without using waits and notifies?
here is an example of my code:
public static void main(String[] args) {
new GUIForm();
// wait until the user inputs the complete form
new GUIWelcome();
}
It is really simple I woild like to keep it that way.
Create an Interface OnActionListener
public interface OnActionListener {
public void onAction();
}
Add these code in GUIForm class
private OnActionListener listener;
private JButton action;
public GUIForm(OnActionListener listener) {
this.listener = listener;
action = new JButton("Action");
action.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
GUIForm.this.listener.onAction();
}
});
}
Now you can achieve that
new GUIForm(new OnActionListener() {
#Override
public void onAction() {
new GUIWelcome();
}
});
You need to use some sort pub/sub mechanism. This in a nutshell is what you need:
public class PubSub {
public static void main(String[] args) {
JFrame frame1 = new JFrame("GUIForm");
frame1.setSize(640, 480);
JButton button = new JButton("User Input");
JFrame frame2 = new JFrame("Welcome");
frame2.setSize(320, 240);
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
button.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
#Override
public void mouseClicked(MouseEvent e) {
frame2.setVisible(true);
}
});
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.add(button);
frame1.setVisible(true);
}
}
This version uses JFrame's listeners, but you could implement your on callback mechanism to accomplish the same

changing the value of a text field as another is changed and the same but reversed causing an error

I am making a simple Miles-Kilometers converter that updates automatically as you type. The problem is that is that an error is thrown somewhere. I believe that this is because as i change one of the fields it handles the event and changes the other field but since that also has an event handler for when it is changed it tries to change the other field itself and they keep firing events back and forth until something somewhere explodes. Any idea how I can fix this or is there a different problem completely ?
Here's my code:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
public class Book extends JFrame{
private JTextField jtfKilometers = new JTextField(10);
private JTextField jtfMiles = new JTextField(10);
public Book(){
setLayout(new BorderLayout(10, 0));
JPanel jlblPanel = new JPanel(new GridLayout(2, 0, 50, 5));
jlblPanel.add(new JLabel("Kilometers"));
jlblPanel.add(new JLabel("Miles"));
add(jlblPanel, "West");
JPanel jtfPanel = new JPanel(new GridLayout(2, 0, 5, 5));
jtfPanel.add(jtfKilometers);
jtfPanel.add(jtfMiles);
add(jtfPanel, "Center");
jtfKilometers.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
if(jtfKilometers.getText().equals("")){
jtfMiles.setText("");
}else{
jtfMiles.setText(Double.parseDouble(jtfKilometers.getText()) * 0.621371 + "");
}
}
#Override
public void removeUpdate(DocumentEvent e) {
insertUpdate(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
insertUpdate(e);
}
});
jtfMiles.getDocument().addDocumentListener(new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
if(jtfMiles.getText().equals("")){
jtfKilometers.setText("");
}else{
jtfKilometers.setText(Double.parseDouble(jtfMiles.getText()) * 1.60934 + "");
}
}
#Override
public void removeUpdate(DocumentEvent e) {
insertUpdate(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
insertUpdate(e);
}
});
}
public static void main(String[] args){
Book f = new Book();
f.setDefaultCloseOperation(MyFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
You need to add additional guard on the focus of the text fields, so that you will be modifying only the other text field, not recursively both of them.
jtfKilometers.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
if (jtfKilometers.hasFocus()) { // ADD THIS LINE
if (jtfKilometers.getText().equals("")) {
jtfMiles.setText("");
} else {
jtfMiles.setText(Double.parseDouble(jtfKilometers.getText()) * 0.621371 + "");
}
}
}
and similarly
jtfMiles.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
if (jtfMiles.hasFocus()) { // ADD THIS LINE
if (jtfMiles.getText().equals("")) {
jtfKilometers.setText("");
} else {
jtfKilometers.setText(Double.parseDouble(jtfMiles.getText()) * 1.60934 + "");
}
}
}
An easy fix for this is checking if the frame has focus when the event is triggered. This will prevent the event from triggering back and forth like is happening to you now.
See the adjusted code snippet from your sample below...
public void insertUpdate(DocumentEvent e) {
if(jtfMiles.hasFocus()){//Check for focus here....repeat same check on your other "insertUpdate" method for your other frame.
if(jtfMiles.getText().equals("")){
jtfKilometers.setText("");
}else{
jtfKilometers.setText(Double.parseDouble(jtfMiles.getText()) * 1.60934 + "");
}
}
}
Hope this helps!

My Swing application is likely not thread-safe - not sure why, though

Edited at the request of commenters. I hope this is compliant.
First post! Trying to understand why my Swing application will not advance from one panel to the next. Here is the general flow of the code :
public class MainWindow {
JFrame mainFrame;
ChangeablePanel currentScreen; // abstract and extends JPanel, has getters &
setters for a Timer (swing timer), a String (nextScreen), and an Image
(background image). also has a close(AWTEvent e) method that simply calls
"this.setVisible(false);"
public MainWindow() {
mainFrame = new JFrame("New Arcana");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitleFrame();
} // MainFrame constructor
public void changeFrame(String frameType, String frameName) {
switch (frameType) {
case "Title":
setTitleFrame();
break;
case "Town":
setTownFrame(frameName);
break;
case "Movie":
setMovieFrame(frameName);
break;
default:
break;
} // switch
} // changeFrame
private void setTitleFrame() {
currentScreen = new TitlePanel();
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
} // setTitleFrame
private void setTownFrame(String townName) {
currentScreen = new TownPanel(townName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(townScreenLength, townScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setTownFrame
private void setMovieFrame(String movieName) {
currentScreen = new MoviePanel(movieName);
currentScreen.addComponentListener(new ScreenChangeListener());
...
mainFrame.setContentPane(currentScreen);
mainFrame.setSize(titleScreenLength, titleScreenHeight); // put constants here if you want
mainFrame.setVisible(true);
} // setMovieFrame
private class ScreenChangeListener implements ComponentListener {
#Override
public void componentHidden(ComponentEvent e) {
gotoNextScreen(e);
}
public void componentMoved(ComponentEvent e) {}
public void componentResized(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
} // ScreenChangeListener
public void gotoNextScreen(ComponentEvent e) {
changeFrame(currentScreen.getNextScreen(), null);
}
} // MainWindow
public class Start {
...
public static void main(String[] args) {
initialize();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainWindow();
}
});
} // main
...
} // Start
public class TitlePanel extends ChangeablePanel implements ActionListener {
JButton newGame, continueGame;
public TitlePanel() {
setFocusable(true);
...
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setNextScreen("Movie");
close(e);
}
});
add(newGame);
add(continueGame);
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
drawTitleScreen(g2d);
} // paintComponent
private void drawTitleScreen(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
newGame.setLocation(170, 550);
continueGame.setLocation(605, 550);
} // drawTitleScreen
} // TitlePanel
public class MoviePanel extends ChangeablePanel implements ActionListener {
public MoviePanel(String movieName) {
setFocusable(true);
addKeyListener(new AnyKeyActionListener());
...
createTimer(10, this);
getTimer().start();
} // TitlePanel constructor
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
drawMovie(g2d);
} // paintComponent
private void drawMovie(Graphics2D g2d) {
g2d.drawImage(getBGImage(), 0, 0, null);
} // drawTitleScreen
private class AnyKeyActionListener extends KeyAdapter {
public void keyTyped(KeyEvent e) {
setNextScreen("Town");
close(e);
} // keyPressed
} // listener to check for keystrokes
} // MoviePanel
The MainFrame is to be populated with more frames as the application advances based on user-input (currently, only MoviePanel and TownPanel are coded), and their code is fairly analogous to this one -- I pasted MoviePanel as well.
Execution breaks down after the KeyAdapter-based listener above. However, when I run my application in Debug mode in Eclipse with breakpoints, this indeed does what it's supposed to do and advances from the MoviePanel to the TownPanel. It is because of this that I suspect threading is the culprit here. Note that I did try many different combinations of the SwingUtilities.invokeLater() technique on the code-blocks above, but it didn't change anything. Any help would be appreciated; thanks!
Do the following:
invokeLater for creation ont the GUI Event Dispatch Thread
No repaint() during construction
setVisible last
Especially on event listeners again use invokeLater, to let buttons and such be responsive, and have then actions being taken with response too.
public static void main(String[] args) {
...
SwingUtilities.invokeLater() {
#Override()
new Runnable() {
new MainFrame().setVisible(true);
}
};
}
Code review
In TitlePanel.TitlePanel better use an absolute layout (that means null), instead of using setLocation in the painting code.
setLayout(null);
newGame = new JButton("New Game");
continueGame = new JButton("Continue");
newGame.setBounds(170, 550, 120, 24);
continueGame.setBounds(605, 550, 120, 24);
In ChangeablePanel.close ensure also timer.stop().
In MainWindow use invokeLater:
public void gotoNextScreen(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
changeFrame(currentScreen.getNextScreen(), null);
}
});
}
In MoviePanel I cannot see that addKeyListener could function; maybe the left-out code? Or is this maybe the error you saw?
Furthermore I find a simple repaint() dubious; would have expected something like:
public void actionPerformed(ActionEvent e) {
invalidate();
repaint(10L);
}

Categories