First time posting. I feel this should be rather straight-forward, but after searching and trying, I've been left without a solution. I re-created my problem in a very simple MVC program - it's behaving the same in both this sample application and in my actual application; I'm clearly making the same mistake in both places.
In my Java desktop application, I have the GUI code in a "View" class. This class is strictly responsible for the appearance of the GUI, ensuring all viewable objects are laid out on the screen/window. The "Controller" is handling all the program flow, and is responsible for listening for the user events, such as a button click, and then calling the necessary View methods to either retrieve or put data from/to the GUI.
The classes, below, do this in a very simple way - all it does is draw a small JFrame window containing a JPanel with 4 objects, 3 JButtons and a JTextField. When any of the 3 buttons is pressed, the number of that button, 1, 2, or 3, is to be displayed in the text field. Only, the field isn't updating. I have a method in the View that calls the repaint() and revalidate() methods of the JFrame, called from the controller right after it updates the text field after a button press. I have a print statement that writes the text to the console, so I know that part works. I also believe the updating of the text field works as I have a message dialog display its value. My understanding is JFrame.repaint(); is supposed to repaint the frame and all its descendants (objects within), it just, isn't.
Thanks in advance for helping. Here's my sample code:
Model.java (currently empty)
package com.techbybryan;
public class Model {
}
View.java
package com.techbybryan;
import javax.swing.*;
import java.awt.*;
public class View {
JButton button1 = new JButton( "One" );
JButton button2 = new JButton( "Two" );
JButton button3 = new JButton( "Three" );
JTextField jTextField = new JTextField();
JPanel jPanel = new JPanel();
JFrame jFrame = new JFrame( "Gui Test" );
public View(){
jPanel.add( button1 );
jPanel.add( button2 );
jPanel.add( button3 );
jPanel.add( jTextField );
jFrame.add( jPanel );
jFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
jFrame.setSize(new Dimension( 500, 100 ) );
jFrame.setLocationRelativeTo( null );
jFrame.setResizable( false );
jFrame.setVisible( true );
}
public JButton getButton1() {
return button1;
}
public void setButton1( JButton button1 ) {
this.button1 = button1;
}
public JButton getButton2() {
return button2;
}
public void setButton2( JButton button2 ) {
this.button2 = button2;
}
public JButton getButton3() {
return button3;
}
public void setButton3( JButton button3 ) {
this.button3 = button3;
}
public JTextField getjTextField() {
return jTextField;
}
public void setJTextField( JTextField jTextField ) {
this.jTextField = jTextField;
}
public void repaint(){
jFrame.revalidate();
jFrame.repaint();
JOptionPane.showMessageDialog( null, jTextField );
}
}
Controller.java
package com.techbybryan;
import javax.swing.*;
public class Controller {
Model model;
View view;
Controller controller;
public Controller( Model model, View view ){
this.model = model;
this.view = view;
}
public void init(){
view.getButton1().addActionListener( e -> setOutputText( "One" ) );
view.getButton2().addActionListener( e -> setOutputText( "Two" ) );
view.getButton3().addActionListener( e -> setOutputText( "Three" ) );
}
public void setOutputText( String textToDisplay ){
System.out.println( textToDisplay );
view.setJTextField( new JTextField( textToDisplay ) );
view.repaint();
}
}
GuiText.java
package com.techbybryan;
public class GuiTest {
public static void main(String[] args) {
Model model = new Model();
View view = new View();
Controller controller = new Controller( model, view );
controller.init( );
}
}
Thank you so much for any constructive advice you may have; I appreciate your feedback.
This code in your controller is not right:
view.setJTextField( new JTextField( textToDisplay ) );
The controller should not be adding components to the view, but rather that method, the actionlistener, should be changing the state of the model, something that you can't do since your model class is inexplicably empty.
In short, you're doing things backwards -- you should get your model working first, and then wire the control and the view to work with the model first and foremost. Your model should notify the view when it changes (a PropertyChangeListener would work well here), and then the view should update the display in the currently displayed JTextField (not adding a new JTextField --sorry to be blunt, but that's plum crazy), based on the model's state.
Also, get rid of all those repaints and revalidates as that code will not help your basic problem and is unnecessary.
Note also that I would get rid of this code:
public void setJTextField( JTextField jTextField ) {
this.jTextField = jTextField;
}
Instead do something more like:
public void setJTextFieldText(String text) {
this.jTextField.setText(text);
}
don't go adding components unnecessarily but instead change the state of the components that you already have
Related
This is my first time learning Java Swing and I had a label and setLocation wasn't working. Someone told me it's because you have to set the layout to null, otherwise they're set to default locations and sizes. So I did, and now my label isn't appearing
import java.util.*;
import javax.swing.*;
public class School {
private ArrayList <String> Usernames = new ArrayList <> ();
private ArrayList <String> Passwords = new ArrayList <> ();
public void registerUser(){
JFrame Register = new JFrame("Register");
JLabel Username = new JLabel("Username: ");
Username.setBounds(50, 50, 100, 30);
Register.add(Username);
Register.setVisible(true);
Register.setSize(500, 500);
Register.setLayout(null);
Register.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main (String [] args){
School example = new School();
example.registerUser();
}
}
Here's a simple example where I corrected a few issues.
I'm using the default layouts, not null. The defaults work well if you learn how to use them.
I use a JPanel instead of adding components directly to the JFrame. JFrames actually use a rather confusing layout, it's best to just put stuff in a panel which makes the layout more intuitive.
I'm using vertical boxes and horizontal boxes and nesting them (putting one inside the other). When I first started this was an easy way to make simple formatted layouts.
I put the labels and text fields in a loop so you could see how to make several components in a loop and still lay them out.
I changed several of your variable names to conform to the Java coding conventions (use lower case for local variables and fields).
I added a more conventional sequence for displaying a window for the first time.
I also kicked off your Swing code on the Event Dispatch Thread. You should do this for all Swing code.
Lightly tested:
package stackoverflow;
import java.util.*;
import javax.swing.*;
public class BasicWindow {
private ArrayList<String> userNames = new ArrayList<>();
private ArrayList<String> passwords = new ArrayList<>();
public void registerUser() {
JFrame register = new JFrame( "Register" );
JPanel panel = new JPanel();
Box vbox = Box.createVerticalBox();
for( int i = 0; i < 4; i++ ) {
Box hbox = Box.createHorizontalBox();
JLabel username = new JLabel( "Username: " );
hbox.add( username );
JTextField input = new JTextField( 25 );
hbox.add( input );
vbox.add( hbox );
}
panel.add( vbox );
register.add( panel );
register.setSize( 500, 500 );
register.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
register.setLocationRelativeTo( null ); // center on screen
register.setVisible( true );
}
public static void main( String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
BasicWindow example = new BasicWindow();
example.registerUser();
}
});
}
}
I have a fully functional console-based database which I need to add GUIs to. I have created a tab page (currently only one tab) with a button "Display All Student" which when triggered will display a list of students inside a JTextArea which of course is in its own class and not inside the button's action listener class. Problem is, the JTextArea is not recognised inside button's action listener. If I add parameter into the action listener, more errors arise. Help?
I have searched Stack Overflow for similar problems but when I tried it in my code, doesn't really do the trick? Or maybe I just need a nudge in the head. Anyways.
Here is my code so far:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class StudDatabase extends JFrame
{
private JTabbedPane tabbedPane;
private JPanel studentPanel;
private static Scanner input = new Scanner(System.in);
static int studentCount = 0;
static Student studentArray[] = new Student[500];
public StudDatabase()
{
setTitle("Student Database");
setSize(650, 500);
setBackground(Color.gray);
JPanel topPanel = new JPanel();
topPanel.setLayout( new BorderLayout() );
getContentPane().add( topPanel );
// Create the tab pages
createStudentPage();
// more tabs later...
// Create a tab pane
tabbedPane = new JTabbedPane();
tabbedPane.addTab( "Student Admin", studentPanel );
topPanel.add( tabbedPane, BorderLayout.CENTER );
}
public void createStudentPage()
{
studentPanel = new JPanel();
studentPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
JButton listButton = new JButton("List All Student(s)");
listButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(studentCount > 0)
{
for(int i=0; i<studentCount; i++)
{
// print out the details into JTextArea
// ERROR! textDisplay not recognised!!!
textDisplay.append("Student " + i);
}
System.out.printf("\n");
}
else // no record? display warning to user
{
System.out.printf("No data to display!\n\n");
}
}
});
studentPanel.add(listButton);
JTextArea textDisplay = new JTextArea(10,48);
textDisplay.setEditable(true); // set textArea non-editable
JScrollPane scroll = new JScrollPane(textDisplay);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
studentPanel.add(scroll);
}
public static void main(String[] args)
{
StudDatabase mainFrame = new StudDatabase();
mainFrame.setVisible(true);
}
Your code isn't working for the same reason this wouldn't work:
int j = i+5;
int i = 4;
You have to declare variables before using them in Java.
Secondly, in order to use a variable (local or instance) from inside an inner class - which is what your ActionListener is - you need to make it final.
So, the below code will compile and run:
final JTextArea textDisplay = new JTextArea(10,48);
...
listButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
...
textDisplay.append("Student " + i);
I have a JTreeTable and have successfully implemented a MouseMotionListener to show a tooltip whenever the mouse is over one of the cells. However when clicking on the cell the tooltip does not show up. I've tried several things like setting the text on the mouseClicked and mouseReleased events but that doesn't work. I found this code -
Action toolTipAction = treeTable.getActionMap().get("postTip");
if(toolTipAction != null){
ActionEvent postTip = new ActionEvent(treeTable,ActionEvent.ACTION_PERFORMED, "");
toolTipAction.actionPerformed(postTip);
}
to use in the mouseReleased method, which does make the tooltip popup, but it's then in the wrong position. So next i tried overriding the getTooltipLocation method on the JTreeTable, and this works fine for mouseMoved events but doesn't get called with the above method. Can anyone shed some light on how to do this?
Thanks
Andy
You can use the following approach to show the tooltip (there will be a slight delay). Then you can override the getToolTipLocation() method since a MouseEvent will now be generated:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToolTipOnRelease extends JPanel
{
public ToolTipOnRelease()
{
JLabel label = new JLabel( "First Name:" );
add( label );
JTextField textField = new JTextField(15);
add( textField );
MouseListener ml = new MouseAdapter()
{
public void mouseReleased(MouseEvent e)
{
JComponent component = (JComponent)e.getSource();
component.setToolTipText("Mouse released on: " + component.getClass().toString());
MouseEvent phantom = new MouseEvent(
component,
MouseEvent.MOUSE_MOVED,
System.currentTimeMillis(),
0,
0,
0,
0,
false);
ToolTipManager.sharedInstance().mouseMoved(phantom);
}
};
label.addMouseListener( ml );
textField.addMouseListener( ml );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("ToolTipOnRelease");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new ToolTipOnRelease() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
org.apache.jorphan.gui.JTreeTable extends javax.swing.JComponent
javax.swing.JComponent#setToopTipText() doesn't work?
I do realize that you want to use Action but for tooltips? I would use Action when multiple UI actions would need to share it.
I need to put a value in to my class from UI (Swing) and then start my method by clicking a button. What should I do?
Getting started with swing
Here's a super simple example of a text field and a button that, when clicked, will get the text value then you can all the method you'd like to pass that value to.
public class ButtonExample extends JPanel
{
private JTextField _text;
public ButtonExample()
{
_text = new JTextField();
setLayout( new BorderLayout() );
add( _text, BorderLayout.NORTH );
add( new JButton( new CaptureTextAction() ), BorderLayout.SOUTH );
}
private class CaptureTextAction extends AbstractAction
{
private CaptureTextAction()
{
super( "Click Me" );
}
#Override
public void actionPerformed( ActionEvent ae )
{
String textToCapture = _text.getText();
// do something interesting with the text
}
}
}
Swing is just the user interface you provide to to your app.
it works like this....
you have buttons, panels and all the stuff you need for providing a proper interface, which means if you need to take text input you'll put textfield or textArea in your UI
swing applications are based on events, thats the basic difference between console based and window based applications, a console based application is sequential it compiles and then executes code sequentially it has no regard of how you interact with it.
a swing application on the other hand is event based, until any event is fired and caught it won't do anything, in java you just handle the event, which means what happens after an event occurs is decided by the programmer.
suppose there is a button click event fires and there is a listener attached to the element then the actionPerformed function gets called and it is executed
suppose you want to get the user name from the app
JButton btnSubmit = new JButton("Submit");
JTextField txtName = new JTextField("", 4);
btnSubmit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String name = txtName.getText();//see below for explanation
printInfo();//write the function call statements here if you want them to be executed when button is clicked
}
});
whenever button is clicked or more generally any event occurs on the button then it creates a string object in the string pool and assigns to it the value of the text field at the time when the button was clicked
I'm writing a Java application that will have an on-screen number pad available for touch-input. Normal key input will also be available, but I'd like the keypad there for tablets and such. I've made a class that extends JPanel. It has 10 buttons laid out in the normal keypad configuration. Now I'm trying to figure out how to make it act like a regular keypad.
I just don't know how to issue KeyEvents. Here's what I've tried so far:
I tried adding a new KeyListener. In the JPanel, when a button was pressed, the action listener called a method that created a new KeyEvent and sent it to all the KeyListeners that were added to the JPanel. However, no matter how many times I added KeyListeners, the didn't seem to be any associated with the panel.
Another thing I tried was passing the target JTextField to the JPanel and setting a member object to the JTextField. But every time I try to append text to it, the member object is null. It's really perplexing to me.
I'm hoping someone could point me in the correct direction with how to implement this keypad to make it as modular is possible so it can be used inside several different screens.
Thanks in advance!
Brent
You dont need the KeyListener you can associate yourself the outcome effect of pressing a button (its not a key) on the JTextField.
Maybe something like:
New JButton button = new JButton(new KeyPressedAction(mTextField,"0"));
Where
public class KeyPressedAction extends Action{
JTextField tf;
String num;
public KeyPressedAction(JTextField textField,String num){
this.tf = textField;
this.num = num;
}
public void actionPerformed(ActionEvent e){
textField.setText(textField.getText+num);
}
}
I'm writing a Java application that
will have an on-screen number pad
available for touch-input.
So I assume that when the button is "touched" an ActionEvent will be generated. Then I assume you will want to add the character related to the button to a text field. If so, then the following examples should get you started. You don't need to generated KeyEvents, you just respond to the ActionEvents:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonCalculator extends JFrame implements ActionListener
{
private JButton[] buttons;
private JTextField display;
public ButtonCalculator()
{
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
buttons = new JButton[10];
for (int i = 0; i < buttons.length; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( this );
button.setMnemonic( text.charAt(0) );
buttons[i] = button;
buttonPanel.add( button );
}
getContentPane().add(display, BorderLayout.NORTH);
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
setResizable( false );
}
public void actionPerformed(ActionEvent e)
{
JButton source = (JButton)e.getSource();
display.replaceSelection( source.getActionCommand() );
}
public static void main(String[] args)
{
ButtonCalculator frame = new ButtonCalculator();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
If that doesn't solve your problem, then you should be looking into Key Bindings instead of using KeyEvents.