Adding multiple Panels and events to a GUI - java

I'm new to java and working on a GUI assignment and I'm running into some issues. The premise is a simple GUI window that has a few mouse events and a few keyboard events.
I put together a window with some mouse events and once that was working started to add a couple JTextFields to the window but they're not showing up on the window and I'm not exactly sure why.
Here is the problem now. I created a new panel (panel2) to add the JTextFields to the window and I now see the JTextFields but it overtakes the entire window and the Mouse Events do not work with it. If I add the JTF to the panel above the Mouse Events then the JTF do not show up and the Mouse Events work.......
code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class EventDemo extends JFrame {
private JPanel mousePanel;
private JPanel panel1;
private JPanel panel2;
private JPanel panel3;
private JLabel statusBar;
private JLabel directions1;
private JLabel directions2;
private JLabel directions3;
private JTextField textField1;
private JTextField textField2;
public EventDemo() {
super("EVENT DEMO PROGRAM");
panel1 = new JPanel();
panel2 = new JPanel();
//Add directions for the events to top of the window.
directions1 = new JLabel("Enter & Leave window." +
" Press & hold, release, drag, move cursor to display a message in statusbar." +
" Clicking in one spot will display coordinates.");
panel1.add(directions1);
add(panel1, BorderLayout.PAGE_START);
//Add mouse and statusBar to panel.
mousePanel = new JPanel();
mousePanel.setBackground(Color.WHITE);
add(mousePanel, BorderLayout.CENTER);
statusBar = new JLabel("Default");
add(statusBar, BorderLayout.SOUTH);
//Create handler object for Mouse events
TheHandler handler = new TheHandler();
mousePanel.addMouseListener(handler);
mousePanel.addMouseMotionListener(handler);
textField1 = new JTextField(10);
panel2.add(textField1, BorderLayout.SOUTH);
textField2 = new JTextField("Enter Text Here");
panel2.add(textField2, BorderLayout.SOUTH);
add(panel2);
TheHandler handlerJTF = new TheHandler();
textField1.addActionListener(handlerJTF);
textField2.addActionListener(handlerJTF);
}
private class TheHandler implements MouseListener, MouseMotionListener {
public void mouseClicked(MouseEvent event) {
statusBar.setText(String.format("YOU CLICKED THE MOUSE AT %d, %d", event.getX(), event.getY()));
}
public void mousePressed(MouseEvent event) {
statusBar.setText("YOU HAVE PRESSED THE MOUSE BUTTON.");
}
public void mouseReleased(MouseEvent event) {
statusBar.setText("YOU HAVE RELEASED THE MOUSE BUTTON.");
}
public void mouseEntered(MouseEvent event) {
statusBar.setText("YOU HAVE ENTERED THE WINDOW THE BACKGROUND CHANGES TO RED.");
mousePanel.setBackground(Color.RED);
}
public void mouseExited(MouseEvent event) {
statusBar.setText("EXITING THE WINDOW, BACKGROUND CHANGES BACK TO WHITE.");
mousePanel.setBackground(Color.WHITE);
}
//Mouse Motion events.
public void mouseDragged(MouseEvent event) {
statusBar.setText("YOU ARE DRAGGING THE MOUSE.");
}
public void mouseMoved(MouseEvent event) {
statusBar.setText("YOU ARE MOVING THE MOUSE AROUND.");
}
}
public void actionPerformed(ActionEvent event) {
textField1.getText();
textField2.getText();
}
public static void main(String[] args) {
EventDemo go = new EventDemo();
go.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
go.setSize(960, 300);
go.setVisible(true);
new EventDemo();
}
}

TheHandler does not implement ActionListener which is the required type of JTextField#addActionListener. See How to Write an Action Listeners and How to Use Text Fields for more details
Your actionPerformed method isn't actually defined in TheHandler class, but is a method of the EventDemo class
You should use the #Override annotation when you think you're overriding methods (or implementing methods from an interface) as this will cause a compiler error when you're wrong (for some reason)
Your fields aren't appearing for two reasons, first, textField is added to panel2 which is never added to anything and textField2 is been added to the frame (at the default position of BorderLayout.CENTER), but is been overriden/circumvented by add(mousePanel, BorderLayout.CENTER);, so it's actually never laid out by the frames BorderLayout. Have a look at How to Use Borders for more details

Related

dispatching mouse events to the deepest visible JComponent

There are a transparent JPanel on top of the screen, and a background JPanel and a JButton added to it(All are visible and have mouse listeners)
After handling mouse events in the transparent panel's listeners, they should be dispatched to the next deeper component(i.e. background panel or its button)
Clicking on background panel is OK but clicking on the button cause an unwanted ClassCastException.
example:
//making frame
frame=new JFrame();
frame.setVisible(true);
//making layered pane
layeredPane = new JLayeredPane();
frame.add(layeredPane);
//transparent panel on top
frontPanel = new JPanel();
frontPanel.setOpaque(false);
layeredPane.add(frontPanel,Integer.valueOf(1));
//background panel containing a button
backPanel = new JPanel();
JButton button = new JButton();
backPanel.add(button);
layeredPane.add(backPanel,Integer.valueOf(0));
//listeners
button.addMouseListener(new MouseListener()...a blank listener...);
backPanel.addMouseListener(new MouseListener()...a blank listener...);
frontPanel.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.getDeepestComponentAt(backPanel, e.getX(), e.getY()).dispatchEvent(e);
}
#Override
public void mousePressed(MouseEvent e) {
SwingUtilities.getDeepestComponentAt(backPanel, e.getX(), e.getY()).dispatchEvent(e);
}
#Override
public void mouseReleased(MouseEvent e) {
SwingUtilities.getDeepestComponentAt(backPanel, e.getX(), e.getY()).dispatchEvent(e);
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
//setting dimensions
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frontPanel.setSize(screenSize);
backPanel.setSize(screenSize);
frame.setSize(screenSize);
//now clicking on the button cause a ClassCastException: JPanel cannot be cast to javax.swing.AbstractButton. why?
You can't just dispatch the old event. The old event contains information about the original event (ie. the component source).
You need to create a new MouseEvent before dispatching it.
For example see the GlassPaneDemo from the Swing tutorial on How to Use Root Panes.

how to use action listener on a button in a different class

I'm fairly new to GUIs and am having trouble with this assignment. Basically we have eight classes total and have to use three panel classes three different ways, one way using only the TopPanel and InitialPanel classes, one using only the BottomPanel and and InitialPanel class, and one using only the InitialPanel class. The goal is to make a button in the bottom panel display info about a football player when the button in the top panel is pressed. `
public class BottomPanel extends JPanel implements ActionListener
{
public JButton b1;
public BottomPanel(final JPanel topPanel)
{
super();
setBackground(Color.pink);
//setLayout(new GridLayout(3,1));
b1 = new JButton("When the user clicks on the button in the UPPER panel, displays the football player's position here" );
add(b1);
}
public void actionPerformed(ActionEvent event)
{
Object obj = event.getSource();
if(obj == b1)
{
b1.setText(fp1.getPosition());
}
}
}
public class InitialPanel extends JPanel
{
public InitialPanel()
{
super();
setBackground(Color.gray);
setLayout(new BorderLayout());
TopPanel p1 = new TopPanel();
add(p1,"North");
BottomPanel p2 = new BottomPanel(p1);
add(p2,"Center");
}
}`
public class TopPanel extends JPanel
{
public TopPanel()
{
super();
setBackground(Color.yellow);
footballPlayer fp1 = new footballPlayer("Mark","Allen",22, "IST", 5.6f, 180, "Junior","Running Back");
// the whatsUp of this student has to shown in the other panel
JButton jl1 = new JButton(fp1.getInfo());
add(jl1);
}
}`
I think i got the only TopPanel and InitialPanel running, but am stuck on what do to for the other two. Also, getInfo() is the method to call when setting the text of the bottom button, and we CANNOT create another footballplayer object other than the one being used in TopPanel. Any help will be appreciated!
You already added jl1 button to the TopPanel, now you should add a listener to that button: you can add it at the BottomPanel class.
You receive a reference to topPanel in the BottomPanel constructor so you can keep him as a member and create the listener, something like this:
public class BottomPanel extends JPanel implements ActionListener
{
public JButton b1;
/** added member to topPanel **/
private JPanel mTopPanel;
public BottomPanel(final JPanel topPanel)
{
super();
setBackground(Color.pink);
this.mTopPanel = topPanel;
b1 = new JButton("When the user clicks on the button in the UPPER
panel, displays the football player's position here" );
add(b1);
/** the topPanel jli button listener **/
this.mTopPanel.jl1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
/** edit your button with the info of the player **/
b1.setText("player info added here");
}
});
}
public void actionPerformed(ActionEvent event)
{
Object obj = event.getSource();
if(obj == b1)
{
b1.setText(fp1.getPosition());
}
}
}
You should register the bottom panel as a Listener of the button in the top panel. To achieve this, you should make a list storing all the listeners to the button in your TopPanel class. And once the button is pressed, the current player's information will be broadcast to all the listeners. And what you need to do is to make ButtonPanel class implement the Listener which here I call it DisplayPlayerInfoListener.
class TopPanel extends JPanel {
JButton displayButton = new JButton("show player info");
FootballPlayer currentPlayer = new FootballPlayer();
List<DisplayPlayerInfoListener> listeners = new ArrayList<>();
public TopPanel() {
add(displayButton);
displayButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
displayButtonPressed();
}
});
}
void displayButtonPressed() {
for (DisplayPlayerInfoListener listener : listeners) {
listener.displayPlayer(currentPlayer);
}
}
public void addDisplayPlayerInfoListener(DisplayPlayerInfoListener listener) {
listeners.add(listener);
}
}
interface DisplayPlayerInfoListener {
void displayPlayer(FootballPlayer player);
}
class BottomPanel extends JPanel implements DisplayPlayerInfoListener {
#Override
public void displayPlayer(FootballPlayer player) {
// show the player's information on your bottom panel's UI
}
}
somewhere in your code, you will need to add the bottom panel as a listener to the top panel's button.
topPanel.addDisplayPlayerInfoListener(bottomPanel);
By doing this, you can register as many listeners as you want since this information might need to be broadcast to other UI components as well. Also, it separates the two panels, you don't need to get the information by access one of the other panels fields on methods. The information will be handled when the it's ready to send. The TopPanel only sees the BottomPanel as a DisplayPlayerInfoListener instance thus there's less coupling.

JLabel ToolTip interferes with MouseListener

I have Java Swing application ToolTipMouseTest
The critical line is label.setToolTipText("label" + i);. Once it is commented out very click on a label produces 2 mousePressed in console. With this line enabled click on labels would produce nothing.
Is this expected behaviour or a bug? My goal is to show tooltips without disabling MouseListener from working.
Almost SSCCE, but without imports:
public class ToolTipMouseTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ToolTipMouseTest();
}
});
}
public ToolTipMouseTest() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
JLayeredPane lpane = new JLayeredPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
};
MouseAdapter1 mouseAdapter1 = new MouseAdapter1();
lpane.addMouseListener(mouseAdapter1);
frame.add(lpane);
JPanel panel1 = new JPanel();
panel1.setSize(new Dimension(600, 400));
panel1.setOpaque(false);
lpane.add(panel1, JLayeredPane.PALETTE_LAYER);
JPanel panel2 = new JPanel();
for (int i = 0; i < 5; i++) {
JLabel label = new JLabel("Label " + i);
panel2.add(label);
label.setToolTipText("label" + i); //HERE!!
}
JScrollPane spane = new JScrollPane(panel2) {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
};
MouseAdapter2 mouseAdapter2 = new MouseAdapter2();
spane.addMouseListener(mouseAdapter2);
panel1.add(spane);
frame.pack();
frame.setVisible(true);
}
private class MouseAdapter1 extends MouseAdapter {
#Override
public void mousePressed (MouseEvent me) {
System.out.println("1 mousePressed");
}
}
private class MouseAdapter2 extends MouseAdapter {
#Override
public void mousePressed (MouseEvent me) {
System.out.println("2 mousePressed");
}
}
}
It is working as intended. Let me explain why.
When a component has no listener, the mouse events will be propagated.
When any component has at least one MouseListener set on it - it will consume any mouse enter/exit/click/press/release events from going down in the components hierarchy.
It's the same for any listener such as MouseMotionListener with
mouse dragged/moved.
When you are adding a tooltip to a component (JLabel in your case), the component automatically receive a new MouseListener and a MouseMotionListener from ToolTipManager. The registerComponent method from ToolTipManager class do this (it's invoked by setToolTipText) :
public void registerComponent(JComponent component) {
component.removeMouseListener(this);
component.addMouseListener(this);
component.removeMouseMotionListener(moveBeforeEnterListener);
component.addMouseMotionListener(moveBeforeEnterListener);
component.removeKeyListener(accessibilityKeyListener);
component.addKeyListener(accessibilityKeyListener);
}
In your case - JLabels are consuming mouse events and mouse motion events, and as such prevents from propagating the events to the JLayeredPane because ToolTipManager listener added itself when the tooltip is set (setToolTipText) on the component.
In order to work around this, register a listener that will pass events down. You can add that listener to every component with a tooltip that should pass mouse events down (e.g to a JLayeredPane, a JScrollPane, etc).
Here is a small example of how that could be done:
var destinationComponent = // the JLayeredPane, JScrollPane, etc with mouse listeners
componentWithToolTip.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
destinationComponent.dispatchEvent(
SwingUtilities.convertMouseEvent(
event.getComponent(), // the component with the tooltip
event,
destinationComponent
)
);
}
// implements other mouse* handlers as required.
});
In that setup componentWithToolTip will have 2 listeners, the one from the ToolTipManager and the propagating one. When componentWithToolTip all its listeners will be triggered, and the propagating listener will dispatch to the declared destination component destinationComponent. So that destinationComponent listeners receive the mouse events as well.

buttons resizing them selves?

Me and a friend are trying to make an mp3 player with buttons in java, however once the first button is clicked it resizes all butttons on the second menu.
Any information on how to keep the buttons from rezising would be greatly appreciated.
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class Player extends JFrame {
class CustomPanel extends JPanel{ //create image
public void paintComponent (Graphics painter){
Image pic = Toolkit.getDefaultToolkit().getImage("playerBase.jpg");
if(pic != null) painter.drawImage(pic, 0, 0, this);
}
}
public static void main(String[] args) {
Player gui = new Player();
gui.go();
}
public void go() {
JFrame frame = new JFrame("MP3 Player."); //Creates window.
CustomPanel base = new CustomPanel(); //Makes the image into a panel.
JButton button1 = new JButton("Artists");
JButton button2 = new JButton("Genres");
JButton button3 = new JButton("Songs");
JButton button4 = new JButton("TEST");
JButton button5 = new JButton("TEST");
button1.setHorizontalAlignment(SwingConstants.LEFT);
button2.setHorizontalAlignment(SwingConstants.LEFT);
button3.setHorizontalAlignment(SwingConstants.LEFT);
button4.setHorizontalAlignment(SwingConstants.LEFT);
button5.setHorizontalAlignment(SwingConstants.LEFT);
button1.addActionListener(new Button1Listener());
button2.addActionListener(new Button2Listener());
button3.addActionListener(new Button3Listener());
button4.addActionListener(new Button4Listener());
button5.addActionListener(new Button5Listener());
base.add(button1);
base.add(button2);
base.add(button3);
base.add(button4);
base.add(button5);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setSize(304, 360);
frame.setResizable(false);
frame.add(base);
frame.setVisible(true);
button1.setSize(280, 30);
button1.setLocation(10,10);
button1.setBackground(Color.BLACK);
button1.setForeground(Color.white);
button2.setSize(280, 30);
button2.setLocation(10,40);
button2.setBackground(Color.BLACK);
button2.setForeground(Color.white);
button3.setSize(280, 30);
button3.setLocation(10,70);
button3.setBackground(Color.BLACK);
button3.setForeground(Color.white);
button4.setSize(280, 30);
button4.setLocation(10,100);
button4.setBackground(Color.BLACK);
button4.setForeground(Color.white);
button5.setSize(280, 30);
button5.setLocation(10,130);
button5.setBackground(Color.BLACK);
button5.setForeground(Color.white);
}
//These are the actions for the 5 buttons.
//Need to get buttons straight once first button is clicked
class Button1Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
if (event.getSource() instanceof JButton) {
JButton clickedButton = (JButton) event.getSource();
clickedButton.setSize(280, 30);
clickedButton.setLocation(10,10);
clickedButton.setBackground(Color.BLACK);
clickedButton.setForeground(Color.white);
String buttonText = clickedButton.getText();
if (buttonText.equals("Artists")) {
System.out.println("Artists");
clickedButton.setText("Back");
}
else if (buttonText.equals("Back")) {
System.out.println("Back");
}
}
}
}
//these are just place holders for the other buttons.
class Button2Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("Genres");
}
}
class Button3Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("Songs");
}
}
class Button4Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("TEST");
}
}
class Button5Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("TEST");
}
}
}
Set the layout Manager to null on your CustomPanel base.
base.setLayout(null);
If you want to force the size and location of your components (using setBounds()), then you need to remove the layout manager.
However, LayoutManagers provide better UI experience across different platforms as they will adapt to differences. LayoutManager's perform the sizing and positionning of the components based on preferredSize and constraints. If you have never used them or heard from them, you should really consider looking into them: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
well, I didn't see a menu code. However, by default, the Layout manager for Panel is Flow Layout. Since you did not specify any layout, Flow Layout is assumed, and any sizing you specify will largely be ignored.
So, as Guillaume suggests, set it to null, so you can position things absolutely. Or use more complex layouts depending on your needs. Have a look at how to use layout managers in the swing tutorial. GridBagLayout is the most complex (difficult to use), unless you use some sort of gui builder. Other candidates are BorderLayout, GridLayout among others. Read through the examples to see which one fits your case.

MouseEvents for a JTabbedPane Tab component are not bleeding through

I have a JTabbedPane with a custom tab component. That component contains a JLabel (To display the tab title) and a JButton (A close button). When I change the text in the JLabel the JLabel stops receiving mouse events and I can no longer select that tab when I click directly on the label instead if I click around the label then I can select the tab. Any ideas?
A snippet of the code:
class ShellPanelTabComponent extends JPanel implements ActionListener{
private ShellPanel panel;
private JLabel label;
public ShellPanelTabComponent(final ShellPanel panel){
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
this.panel = panel;
setOpaque(false);
label = new JLabel(panel.getTitle());
label.setFocusable(false);
add(label);
label.setBorder(BorderFactory.createEmptyBorder(2,0,0,5));
//now the button
CloseButton closeButton = new CloseButton(panel);
add(closeButton);
closeButton.addActionListener(this);
}
public void actionPerformed(ActionEvent ae) {
panel.getShell().removeShellPanel(panel);
}
/**
* #return the label
*/
public JLabel getLabel() {
return label;
}
}
I don't recall seeing such a problem in the TabComponentsDemo, discussed in How to Use Tabbed Panes. You might compare your code with that example as a reference.
Addendum: Re-factoring ButtonTabComponent to include getLabel(), this version of runTest() in TabComponentsDemo adds a button that evinces the desired behavior. In particular, each time the button is pressed, the tabs are redrawn to display the enlarged title.
Update: Modify correct tab component after pane.remove().
public void runTest() {
pane.removeAll();
for (int i = 0; i < tabNumber; i++) {
final int titleIndex = i;
String title = "Tab " + titleIndex;
final JButton button = new JButton("Relabel tab");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int index = pane.indexOfComponent(button);
ButtonTabComponent btc = (ButtonTabComponent)
pane.getTabComponentAt(index);
JLabel label = btc.getLabel();
pane.setTitleAt(index, label.getText() + titleIndex);
label.invalidate();
pane.repaint();
}
});
pane.add(title, button);
initTabComponent(i);
}
tabComponentsItem.setSelected(true);
pane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
scrollLayoutItem.setSelected(false);
this.setPreferredSize(new Dimension(500, 200));
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
I seem to remember a question like this recently although I can't find the posting. I believe the problem is that the "custom component" receives the mouse event so it is not passed on to the tabbed pane. The solution suggested was to use the dispatchEvent(...) method to redispatch the mouse event to the proper tab.
The problem is related to the one that I posted here after I did more digging: Workaround for setToolTipText consuming mouse events?

Categories