I know there are already 1000 threads out there that deal with this, but I've tried everything and nothing has worked so far. I am making a little app that lets me log work hours, so I have an array of strings that contains all of the hours that I work. I am trying to update the array, then update the JList that has the text, then update the JScrollPane that has the list on it. This way I can see the hours I added directly after I add them on a window off to the side.
I've tried revalidate() and repaint() on every object, I've tried the removeAll() method on the list as well as the scroll pane, and nothing seems to work! The only thing I CAN do is change the color of the border on the scrollpane!! I don't know why the layout is so easy to update but not the text on the pane!
Thanks for any help you can give! If you want to see the code, I can post it but it's a little confusing as this is just a very small part of the whole.
I try to sort you out from it.
As you trying to add time string in Jlist then want to update your Jscroll pane.
I will go through simple
Just create your design view like:
Jpanel1(card layout)
|
----> Jscrollpane1
|
------>Jpanel2
|
--------> Your Jlist will be here on dynamic runtime
and you can manage panels instead of Jlist.
But here I go with list
public void getUpdateOldWorkTimeList()
{
List<String> workTimeList;
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
workTimeList=getMyTimeList(); // here you put your work time array
Thread.sleep(100);
return null;
}
};
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
jPanel2.removeAll();
jPanel2.revalidate();
jPanel2.repaint();
for (int i = 0; i < workTimeList.size(); i++) {
jPanel2.add(new ModelJList()).setVisible(true);
}
}
}
});
jPanel3.setLayout(new model.WrapLayout(FlowLayout.CENTER, 1, 0));
jPanel1.setBackground(new Color(0, 0, 0, 0));
jScrollPane1.setBackground(new Color(0, 0, 0, 0));
i
jScrollPane1.getVerticalScrollBar().setUnitIncrement(16);
int remainScroll=jScrollPane1.getVerticalScrollBar().getMaximum()- jScrollPane1.getVerticalScrollBar().getModel().getExtent();
jScrollPane1.getVerticalScrollBar().setValue(remainScroll);
jPanel1.removeAll();
jPanel1.add(jScrollPane1);
jPanel1.revalidate();
jPanel1.repaint();
}
2 things must remind:
list model class: You need to implement.(As your look n feel you want).
getMyTimeList() method to array to list conversion.
I already had implement it for chat application to add chat for sender and receiver side.
All the best
Related
I am currently working on a Black Jack game in Java.
I am trying to work with Swing and I am stuck right now:
I made this method
private void addImage(String path) {
JLabel imgLabel = new JLabel();
imgLabel.setIcon(new ImageIcon(getClass().getResource(path)));
add(imgLabel);
display.pack();
}
I want to have a reset button to restart after a round ends, how can I remove these unspecific JLabels? Should I give them an identifier? If yes how?
Thanks in advance.
You can do this by creating a list that contains all the labels.
List<JLabel> labelsList = new ArrayList<JLabel>();
Make sure to declare this outside of the addImages method so that it can be accessed in other methods. Then, every time an image label is created you can add it to the list by using:
labelsList.add(imgLabel)
To remove the cards, you could implement a reset method that loops through the labels list and removes each component, making sure to also remove it from the labelsList:
public void resetLabels()
{
for (JLabel label : labelsList) {
remove(label);
labelsList.remove(label);
}
}
I think learning about collections would be very helpful in this case, keep up the good work!
EDIT: After a closer look, you shouldn't modify the list as you go through the loop, instead:
public void resetLabels()
{
for (JLabel label : labelsList) {
remove(label);
}
labelsList.clear();
}
I'm attempting to create dynamic interface that essentially creates a grid of a growing number of panels that look similar to the picture below. I've got some rough code to achieve that. I have an issue in regards to handling events for the JButtons that i've added to an ArrayList. I'm aware that creating inner class event handlers is best practise, how would I handle events for a scaling number of buttons that are stored in an ArrayList?
Currently i've resulted to getting the objects source to achieve this.
Global Variables:
ArrayList<JButton> buttons = new ArrayList<JButton>();
Adding buttons to the panel:
for (int i = 0; i < 2; i ++) {
int xTotal = 150;
if (i == 0) {
xTotal = 132;
}
else {
xTotal = 308;
}
xTotal = xTotal + xTotal;
JButton currentButton = new JButton("+");
currentButton.setBounds(xTotal , 375, 45, 25);
currentButton.setFont(currentButton.getFont().deriveFont(14f));
currentButton.addActionListener(new AddHandler());
buttons.add(currentButton);
panel.add(currentButton);
}
Event handler:
class AddHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == buttons.get(0)) {
System.out.println("hello");
}
else {
System.out.println("it worked");
}
}
}
It looks to me like you're creating more than just a collection of JButtons. Instead you appear to be wanting to create (and correct me if I'm wrong), a collection of images/text with JButton. This suggests that you want to create a class that encapsulates one (?) menu item, that holds a JLabel for the image, a JLabel perhaps for the text, perhaps other components, and a JButton that the user can press to select the menu item. This component would be a JPanel that (important here) uses layout managers to intelligently arrange all of its constituent components. I would recommend not using ActionListeners but rather create a separate stand along class that extends AbstractAction, that you can use to set each JButton's Action, either via the JButton's constructor or via its setAction(...) method. Then you could place a collection of these JPanels in a master JPanel that uses perhaps a GridLayout, and have it held in a JScrollPane.
The details of my suggestions and the code would of course depend on the details of your GUI and your current code.
Other "side" recommendations:
Don't use null layouts and setBounds(...). Often newbie Swing programmers feel that this is the easiest way to create complex GUI's, and in the short term it may be, but in the long term, when it comes time to maintain, upgrade and enhance your GUI, it isn't. Also the GUI's so created may look OK on one platform and screen resolution, but they look terrible on all others. Learn about and use the layout managers.
Maybe you want a collection of Actions or the JButtons, but I'm not sure you need this. If the button's Action knows what to do, then no collection is needed. The Action could have a constructor that passes in references to the name and price of the menu item.
Even though youve already accepted another answer, I want to share what I have on my mind.
The idea of my idea is to store a number (maybe an ID) on the button by creating a subclass of JButton.
(ID could be, perhaps the ID of the food item this button is currently linked to)
class FoodButton extends JButton{
long id;
public FoodButton(String text, long id){
super(text);
this.id = id;
}
//Perhaps more constructors
public long getId(){
return id;
}
}
Then writing a single actionListener that gets the source of the event (even though you seem to think thats bad practice, I think it makes sense in this example), Observe:
ActionListener al = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
FoodButton btn = (FoodButton) e.getSource();
long id = btn.getId();
//Do something now that you know what button was clicked (id)
}
}
Let me note again that this actionListener is created before your loop, so you only need one, and you'll assign the same one to all your buttons.
Then inside your loop instead of creating a normal JButton, you create a FoodButton:
ActionListener al = new ActionListener(){...};
for (int i = 0; i < 2; i ++) {
//...
//Assigning id 'i' here, but you could pick something else
JButton currentButton = new FoodButton("+", i);
//...
currentButton.addActionListener(al);
buttons.add(currentButton);
panel.add(currentButton);
}
I hope this makes some sense to you.
Also, as someone who used to use null layouts too, once you get accustomed to using layoutmanagers, im sure you will like them.
I've looked for the answer to this on SO and elsewhere but can't find an answer. Is it possible to select an entire jlist rather than a specific item? For example if a user were to click on the white area of a jlist I could call a method which would put that jlist's name in a HashMap or call another method to alter the list as a whole. Hopefully the code gives you an idea. Any info would be helpful. Thanks.
final JList list_1 = new JList(list1);
list_1.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent arg0) {
//make entire list disappear when selected
list_1.setVisible(false);
}
});
GridBagConstraints gbc_list_1 = new GridBagConstraints();
gbc_list_1.gridheight = 3;
gbc_list_1.insets = new Insets(0, 0, 5, 5);
gbc_list_1.fill = GridBagConstraints.BOTH;
gbc_list_1.gridx = 5;
gbc_list_1.gridy = 0;
panel.add(list_1, gbc_list_1);
Is it possible to select an entire jlist rather than a specific item?
Yes, as long as the ListSelectionModel allows you to do that. See Selecting Items in a List.
For example if a user were to click on the white area of a jlist...
Better than that is to have a "Select All" kind of button and work with the ListSelectionModel so you don't have to mess with the focus subsystem at all. For example:
final JList list = new JList();
...
Action selectAllAction = new AbstractAction("Select All") {
#Override
public void actionPerformed(ActionEvent e) {
list.getSelectionModel().setSelectionInterval(0, list.getModel().getSize() - 1);
}
};
...
JButton selectAllButton = new JButton(selectAllAction);
...I could call a method which would put that jlist's name in a HashMap or call another method to alter the list as a whole.
I don't have any idea what do you mean alter the list as whole or why do you want to put that jlist's name in a HashMap, so I'm not able to help you any further. For better help please include a SSCE
I am currently learning Swing and am trying to create a simple program that stores information about different sports teams.
I have created multiple tabbed panels which all hold various information about each team. I would like to be able to have a button that when press displays each tabbed panel say every 10 seconds or so - sort of a slide show effect.
I have read up on action listeners but have not spent a lot of time on them as of yet so i am having trouble implementing this. I would be very grateful if anyone could maybe help me or just give me a push in the right direction. I have posted a snippet of code that i have atempted but i am at a loss about what to actually put inside the loop to achieve this.
slides.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent actionEvent){
for(int i = 0; i<arrayList.size(); i++)
{
//code that changes the tabbed panels every few seconds.
}
}
});
I have created multiple tabbed panels which all hold various various information about each team.
Rather you should focus on creating a JPanel that can display team stats, and not so much JTabbedPanes. The JPanel can then be displayed in a JTabbedPane if desired.
I would use a CardLayout to swap JPanels, and then a Swing Timer to do the swapping. However if you use a single JPanel to display the stats, then you could even display one single JPanel and simply change the model (Team Stats information) that is displayed in it rather than swap JPanels.
As to what to put in your ActionListener, it will not be a for loop at all, but rather a Swing Timer, and you can read about it here: Swing Timer Tutorial.
e.g.,
slides.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent){
int timerDelay = 10 * 1000; // 10 seconds
new Timer(timerDelay, new ActionListener() {
private int count = 0;
public void actionPerformed(ActionEvent evt){
if (count < maxCount) {
// code to show the team data for the count index
count++;
} else {
((Timer) evt.getSource()).stop(); // stop timer
}
}
}).start();
}
});
A very similar question has been asked here, and while I acknowledge it, the question's solution doesn't quite solve my question. A JList, when clicked on, will select the index list item closest to the mouse click. A JList will also do this for every click+drag event fire.
I would like to prevent my JList from selecting items during click+drag events when the click+drag location is outside the visible list. How would I go about this?
I had considered overriding a different method, one involved in the click+drag events of selecting list items. I thought to try the setSelectionInterval() method.
JList<String list = new JList<String>(){
private static final long serialVersionUID = 1L;
#Override
public int locationToIndex(Point location) {
int index = super.locationToIndex(location);
if (index != -1 && !getCellBounds(index, index).contains(location)) {
clearSelection();
return -1;
//an excellent click-only solution to prohibit the selecting of
//items from beyond the visible list
}
else {
return index;
}
}
#Override
public void setSelectionInterval(int anchor, int lead) {
super.setSelectionInterval(anchor, lead);
System.out.println("setSelectionInterval");
}
};
I found that each time I click+drag anywhere on the displayed JList, I get the System.out message of "setSelectionInterval" that I added to the method above. I don't know where to go from here in terms of overriding methods. Maybe that is not how I should approach this. In the source code for setSelectionInterval() I got lost trying to find my way through to a whatever listener is involved, so I came here. :p
I'd greatly appreciate any pointers to where I should be looking or a solution altogether. Thanks in advance!
This is an SSCCE example that is close to how I am set up. As it is, the list will not select an item when a click-only event is fired away from the list items themselves. I would like this same effect to happen when click+drag events are fired away from the list items.
import java.awt.BorderLayout;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
public class TestMain {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel content = new JPanel(new BorderLayout());
String[] data = {"Luke", "Jeff", "Bryce"};
JList<String> list = new JList<String>(data){
private static final long serialVersionUID = 1L;
#Override
public int locationToIndex(Point location) {
System.out.println("location to index");
int index = super.locationToIndex(location);
if (index != -1 && !getCellBounds(index, index).contains(location)) {
clearSelection();
return -1;
}
else {
return index;
}
}
}
content.add(list, BorderLayout.CENTER);
frame.setContentPane(content);
frame.setSize(200,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
If disabling the whole dragging feature is acceptable, then the following should help:
#Override
protected void processMouseMotionEvent(MouseEvent e) {
if(MouseEvent.MOUSE_DRAGGED != e.getID()) {
super.processMouseMotionEvent(e);
}
}
I would like to prevent my JList from selecting items during click+drag events when the click+drag location is outside the visible list.
Not sure I understand the requirement. Lets start with the first row being selected.
If you click on the first row and then continue to drag to the second the 2nd row gets highlighted. Continue dragging and the 3rd row gets highlighted. Continue dragging past the 3rd row and what do you want to happen?
Are you saying that you want the first row to be selected because that is where you started? If this is what you are asking, then you would need to look at the BasicListUI. This is where the mouse listeners are added to the JList. You would somehow need to handle the mousePressed event to save the currently selected row. You would then somehow need to override the default behaviour of the mouseDragged code to reset the selected row when you start to drag outside the last row.
I have no idea how to do all this.
I get the System.out message of "setSelectionInterval" that I added to the method above
Trying to override the code in that method is too late. The selection will continue to be updated as you drag the mouse. You don't know if this method is being called because the mouse is really on the last row or past the last row because you don't have access to the mouse point.
I suppose you could try to use the MouseInfo class to determine where the mouse is when this method is invoked, but then somehow you will still need to know that dragging originally started when the first row was selected. I have no idea how to do this either.