Hey guys, I have a problem with a code that I've been writing.
I have a JFrame that contains two buttons. Each of these buttons has an action. The problem I'm having is with a JButton called "btnDone" that's supposed to get back to a previous screen. If I I keep pushing the button repeatedly, eventually the "btnDone" would stop doing the logic it's supposed to do. My code is as follows:
For the frame:
public class ItemLocatorPnl extends JPnl
{
private static final long serialVersionUID = 1L;
private Pnl pnl;
private JButton btnDone;
private JButton btnRefreshData;
public void setPnl(Pnl pnl) {
this.pnl = pnl;
}
public ItemLocatorPnl(Pnl pnl)
{
super();
this.pnl=pnl;
initialize();
}
private void initialize()
{
this.setSize(300, 200);
JPanel jContentPane = new JPanel();
jContentPane.setLayout(new MigLayout());
// (1) Remove window frame
setUndecorated(true);
// (3) Set background to white
jContentPane.setBackground(Color.white);
// (5) Add components to the JPnl's contentPane
POSLoggers.initLog.writeDebug("ItemLocator: Adding icon");
jContentPane.add(wmIconLabel, "align left");
POSLoggers.initLog.writeDebug("ItemLocator: Adding global controls");
jContentPane.add(createUpperPanel(), "align right, wrap");
POSLoggers.initLog.writeDebug("ItemLocator: Adding main panel");
jContentPane.add(pnl,"width 100%,height 100%, span 3");
// (6) Attach the content pane to the JPnl
this.setContentPane(jContentPane);
}
private JPanel createUpperPanel()
{
JPanel upperPanel=new JPanel();
MigLayout mig = new MigLayout("align right", "", "");
upperPanel.setLayout(mig);
upperPanel.setBackground(Color.WHITE);
// Create the Done button
btnDone= GraphicalUtilities.getPOSButton("<html><center>Done</center></html>");
btnDone.addActionListener(new ButtonListener());
// Create the Refresh Data button
btnRefreshData = GraphicalUtilities.getPOSButton("<html><center>Refresh<br>Data</center></html>");
btnRefreshData.addActionListener(new ButtonListener());
//Addiing buttons to the Panel
upperPanel.add(btnRefreshData, "width 100:170:200, height 100!");
upperPanel.add(btnDone, "width 100:170:200, height 100!");
return upperPanel;
}
public class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
if (e.getSource() == btnRefreshData) {
Actual.refreshData();
} else if (e.getSource() == btnDone) {
Actual.backToMainScreen();
}
}
catch (Exception ex)
{
}
}
}
}
This is the method that the btnDone button calls upon clicking:
public static void backToMainScreen()
{
frame.setVisible(false);
frame.dispose();
}
This is the code that displays the JFrame:
public static void displayItemLocatorFrame()
{
pnl = new Pnl();
frame = new Frame(pnl);
frame.setVisible(true);
pnl.getSearchCriteria().requestFocus();
}
Please note that the "frame" object is static, and all of my methods are static, and they exist in a static class called Actual.
So in short, I just want to make sure that no matter how many times a user clicks on the button, and no matter how fast the clicks were, the frame should act normally.
Any suggestions? (I tried synchronizing my methods with no luck..)
I would generally prefer to use an Action for what you're trying to do.
So your code might look like this:
btnDone = new JButton(new CloseFrameAction());
...
private class CloseFrameAction extends AbstractAction
{
public CloseFrameAction()
{
super("Done");
}
public void actionPerformed(ActionEvent e)
{
frame.dispose();
setEnabled(false);
}
}
Notice the setEnabled(false) line - this should disable the button and prevent the user clicking on it again. Obviously I don't know what your exact requirements are but this is the general approach I would take.
The problem was with using a static panel that was instantiated with the click of the button each time. Removing "static" has finally fixed my problem! Thanks everyone for the help.
Related
I'm building a UI in Java. I want to create new components, like a JLabel, using a button. So every time I click a button it creates a new JLabel and places them in a specific JPanel.
Then, I want to be able to do some things with the labels based on how the user clicks on them.
With a left mouse press I want them to be able to drag the labels around the screen.
With a right mouse click I want to be open a new window where certain data can be entered, tied to the label (which might involve dynamically creating variables).
I've been toying around with some code I've Googled around for. I can get a button to create new labels in a panel, but when I try to get them to drag, I can only get one label at a time to appear, and after a second button press, moving the label isn't smooth, it jumps around.
I haven't even tried to implement any of the right mouse click things yet. If anyone can point me in the right direction, I'd appreciate it.
public class Testing {
JFrame frame;
//Launch the application.
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Testing window = new Testing();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
//Create the application.
public Testing() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
JPanel area;
JButton btnCreate;
JLabel dragLabel;
frame = new JFrame();
frame.setBounds(100, 100, 511, 542);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setVisible(true);
area = new JPanel();
area.setBounds(10, 11, 477, 404);
frame.getContentPane().add(area);
area.setLayout(new BorderLayout());
btnCreate = new JButton("Create Label");
dragLabel = new JLabel("Drag Me");
btnCreate.setBounds(10, 425, 477, 67);
frame.getContentPane().add(btnCreate);
btnCreate.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
area.add(dragLabel);
area.revalidate();
DragListener drag = new DragListener();
dragLabel.addMouseListener(drag);
dragLabel.addMouseMotionListener(drag);
}
});
}
}
class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me) {
pressed = me;
}
public void mouseDragged(MouseEvent me)
{
if(SwingUtilities.isLeftMouseButton(me)){
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
}
EDIT - I'm fairly certain the primary issue is in how the JLabel itself is being added to the panel. Every time the button is being pushed it's adding the same label over again, and this is gumming up the works.
Unfortunately, I'm not sure how to deal with that. I've done a bit more digging, and since dynamic variables aren't possible, I'm going to have to use an array or a map or some sort. With that, it appears I can declare arrays of components. Would something like that be necessary for my purposes?
Really odd stuff in your code. I don't want to go everything, and I'm not an expert by any stretch of the imagination, but I tried to remove redundant or contradictory stuff. I suspect a part of what you did was just copy pasting bits without really fitting them into the code.
Anyway, you needed to create the label inside the listener, so that it creates a new one everytime you click. Otherwise you only ever create one label and just reuse the same everytime.
I implemented a dialog on right click to enter the label name, don't know what you wanted to do but at least it detects right clicks.
Also in general it's easier to use layout managers instead of hardcoding everything. Here you had a borderlayout but were ignoring it.
class Main {
//Launch the application.
public static void main(String[] args) {
DrageableLabel window = new DrageableLabel();
}
}
public class DrageableLabel {
public DrageableLabel() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
JFrame frame = new JFrame();
Container area = frame.getContentPane();
area.setLayout(new BorderLayout());
JButton btnCreate = new JButton("Create Label");
btnCreate.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
/*
This is where you create your new window
for now I've added a dialog that takes a string parameter and creates a label with that string
I moved the method code to create a new drageable label outside the actionlistener to make it less confusing and reuseable
Either build w-e you want directly in here
or call a method that does it (which I prefer)
*/
String string = JOptionPane.showInputDialog(frame, "Enter your message", "Messages", JOptionPane.CANCEL_OPTION);
addDrageableLabel(string, area);
} else if (SwingUtilities.isLeftMouseButton(e)) {
addDrageableLabel("Drag me", area);
}
}
});
area.add(btnCreate, BorderLayout.SOUTH);
frame.setBounds(100, 100, 511, 542);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
// This is the method that creates and adds a drageable label
public void addDrageableLabel(String labelName, Container container) {
JLabel dragLabel = new JLabel(labelName);
container.add(dragLabel, BorderLayout.CENTER);
container.validate();
DragListener drag = new DragListener();
dragLabel.addMouseListener(drag);
dragLabel.addMouseMotionListener(drag);
}
}
class DragListener extends MouseInputAdapter {
Point location;
MouseEvent pressed;
#Override
public void mousePressed(MouseEvent me) {
pressed = me;
}
#Override
public void mouseDragged(MouseEvent me) {
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
The Buttons in my JPanel don't show up when it's loaded, only when I resize the window or move my mouse over it. In other discussions the use of "validate()" or "repaint()" was suggested, but that doesn't work for me.
I'm using a basic model view controller design and I am pretty sure that I'm doing everything else correctly.
Just in case you wonder, of course more panels will be added to the frame, that's the purpose of the update() and changeCards() methods.
Here's my frame:
public class View extends JFrame {
private MainMenuPanel mainMenu;
private final String MAIN_MENU_CONSTRAINTS = "MAIN_MENU";
public View() {
super();
init();
mainMenu = new MainMenuPanel();
add(mainMenu;MAIN_MENU_CONSTRAINTS);
validate();
repaint(0,0,getWidth(),getHeight());
setVisible(true);
}
private void init() {
setVisible(false);
setTitle("Test");
// set card-layout
setRootPaneCheckingEnabled(false);
CardLayout cl = new CardLayout();
this.setLayout(cl);
// expand frame to whole display size
setExtendedState(MAXIMIZED_BOTH);
// set unclosable
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void update (Mode mode) {
switch (mode) {
case MAIN_MENU:
changeCard(MAIN_MENU_CONSTRAINTS);
break;
}
}
public void changeCard(String card) {
// update cards
CardLayout cl = (CardLayout) getLayout();
cl.show(this, card);
}
}
And here's the Panel:
public class MainMenuPanel extends Panel implements ActionListener{
private JButton startButton;
private JButton quitButton;
private final String START_ACTION_COMMAND = "START";
private final String QUIT_ACTION_COMMAND = "QUIT";
private MainMenuPanelListenerImpl listener;
public MainMenuPanel() {
super();
init();
initComponents();
configureComponents();
configureListeners();
addComponents();
revalidate();
}
private void init() {
setLayout(null);
}
private void initComponents() {
startButton = new JButton();
quitButton = new JButton();
}
private void configureComponents() {
startButton.setText("Start");
quitButton.setText("End");
startButton.setBounds((int)(0.5*getWidth()-200), (int)(0.5*getHeight()-75), 400, 75);
quitButton.setBounds((int)(0.5*getWidth()-200), (int)(0.5*getHeight()+25),400,75);
}
private void configureListeners() {
startButton.addActionListener(this);
startButton.setActionCommand(START_ACTION_COMMAND);
quitButton.addActionListener(this);
quitButton.setActionCommand(QUIT_ACTION_COMMAND);
}
private void addComponents() {
add(startButton);
add(quitButton);
startButton.validate();
quitButton.validate();
}
#Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case START_ACTION_COMMAND:
listener.start();
break;
case QUIT_ACTION_COMMAND:
System.exit(0);
break;
}
}
public void setListener(MainMenuPanelListenerImpl listener) {
this.listener = listener;
}
}
After you paint the elements, you put the setvisible(true) because if you put it before, the Jframe will paint no elements
Well first of all you mix the old AWT-Components like Panel with newer SWING-Components like JFrame. Those don´t really work well together so I would try to fix that first. I would highly recommend using SWING or if you want to learn the newest Java GUI Library then JavaFX.
Don´t use the method repaint in the constructor of your JFrame, actually you shouldn´t use repaint in SWING at all. Nor do you need validate in the constructor. If you want to position your JFrame somewhere you should use something like this this.setLocation(0,0)
And to the main question: The panel probably only shows it´s components after resizing because you add it to the JFrame the wrong way. In SWING there is something called a content pane where you should add all of your stuff onto (except JMenuBar but that is a different story).
Simply set the layout of the content pane to the card layout that you want to use and then add your panel onto the content pane.
Here a link regarding the panel levels: https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html
I have a JPanel holding a JButton and JScrollPane (in turn holding a JTable) and am currently running into two issues which I believe are related:
The JButton listener's actionPerformed() method is not invoked upon click. The only way in which I can get it to be invoked is by calling doClick() on the JButton. The JButton color changes upon hover but no click animation is shown when the mouse is pressed.
Secondly, if a cell is clicked within the JTable, the cell located 2 rows down in the same column registers the click instead. This offset does not occur when clicking in the column headers (i.e. to adjust cell widths), only when within the cell area.
Left-hand panel. Click position circled
public class InventoryPanel extends JPanel {
// Parent Business object reference for communication and JFrame
private Business parent;
private AddItemPanel addItemPanel;
// Inventory table items
private DefaultTableModel inventoryModel;
private JTable inventoryTable;
private JScrollPane inventoryScrollPane;
private JLabel updateLbl;
private JButton addItemBtn;
// Columns for inventory table
private static final String[] INVENTORY_COLUMNS = {"Item","Stock","Restocking Level","Edit"};
public InventoryPanel(Business parent) {
this.parent = parent;
initGUI();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
//doStuff
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(new PrintStream(System.out));
}
}
}
}).start();
}
// INITIALISES GUI
public void initGUI() {
this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
JLabel titleLabel = new JLabel("<html><B>Inventory</B></html>");
this.add(titleLabel);
// Create empty inventory table
inventoryModel = new DefaultTableModel(new Object[3][4],INVENTORY_COLUMNS);
inventoryTable = new JTable(inventoryModel);
inventoryScrollPane = new JScrollPane(inventoryTable);
// Create button to allow items to be added
addItemBtn = new JButton("Add item");
addItemBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("ADD ITEM PRESSED");
}
});
updateLbl = new JLabel("Loading inventory...");
this.add(addItemBtn);
this.add(inventoryScrollPane);
this.add(updateLbl);
}
I've tried removing the table from the panel to see if that solves the JButton issue and visa-versa, but no luck. I've also tried changing the project JDK but no luck there either.
There are other JPanels adjacent to the troublesome one in a JFrame which work perfectly fine. Any ideas?
Edit: I can create a working instance of the InventoryPanel alone in a frame in another project, as mentioned in the comments. However the exact same code (no calls being made to other objects/methods) in the current project now produces ClassCastExceptions. After some googling this seems to be due to non-EDT threads updating the GUI.
However there is no use of the Business class, and all GUI operations are performed using the SwingUtilities.invokeLater() method like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("test");
frame.add(new InventoryPanel());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
Note: the no-argument constructor InventoryPanel() just calls initGUI().
Thanks for the help so far...still very confused by this.
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.
I am making an applet and as part of my applet, I want this to happen: When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
However, I cannot figure out how to add a new component to the applet after it has started. I made the problem simpler by ignoring the removal part (Which I know how to do) and just adding a simple JLabel instead, but even that won't add!
Here is my code so far:
// imports omitted
public class Class extends Applet implements ActionListener
{
Button okButton;
CheckboxGroup radioGroup;
Checkbox radio1;
Checkbox radio2;
Checkbox radio3;
JLabel j;
public void init()
{
setLayout(new FlowLayout());
okButton = new Button("OK");
j = new JLabel("hello");
radioGroup = new CheckboxGroup();
radio1 = new Checkbox("Red", radioGroup,false);
radio2 = new Checkbox("Blue", radioGroup,true);
radio3 = new Checkbox("Green", radioGroup,false);
add(okButton);
add(radio1);
add(radio2);
add(radio3);
okButton.addActionListener(this);
}
public void repaint(Graphics g)
{
if (radio1.getState()) add(j);
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) repaint();
}
}
What am I doing wrong?
You shouldn't override the repaint method, and certainly not add a component in this method. Just remove the radio buttons from the applet (using its remove method) and add the label in the applet in your actionPerformed method, the same way you add them in the init method.
You might have to call validate after.
Add components and then call validate() of your container. In this case yourApplet.validate(). This will trigger repainting and rearranging of all elements.
you could do something like
JFrame fr= new JFrame(); // global variables
JPanel panelToBeAdded = new JPanel();
JPanel initialPanel = new JPanel();
JTextField fieldToBeAdded = new JTextField();
panelToBeAdded.setPreferredSize( new Dimension(400,400));
initialPanel.setPreferredSize( new Dimension(400,400));
initialPanel.setVisible(true);
fr.add(initialPanel);
fr.setVisible(true);
fr.pack();
public void actionPerformed(ActionEvent ae) {
initialPanel.setVisible(false);
//radiobuttons.setVisible(false);---> hide the radio buttons
panelToBeAddedd.add(fieldToBeAddedd);
panelToBeAddedd.setVisible(true);
fr.add(panelToBeAddedd);
}
public void repaint( Graphics g ) {
// do something
}
What am I doing wrong?
Your repaint(Graphics) method is not the same method you are calling in your actionPerformed method.
Also, repaint is a pretty bad name for a method which is adding a new component.
public void swapComponents()
{
if (radio1.getState()) {
remove(radio1);
remove(radio2);
remove(radio3);
add(j);
validate();
}
}
public void actionPerformed(ActionEvent evt)
{
if (evt.getSource() == okButton) {
swapComponents();
}
}
When the user presses "OK", the old components (some radio buttons) are removed, and a new JPanel is added, with a bunch of textfields.
Use a CardLayout, as shown here. It is perfect for situations like this.