Refreshing display of a text panel in a GUI - java

I'm having more "I'm hopeless at programming" problems.
I have a piece of code which uses StringBuilder to display elements of an array in a text panel of a GUI when the program starts. Here's the StringBuilder code:
// memory tab
StringBuilder mList = new StringBuilder();
memLocList = new Memory[MEM_LOCATIONS];
mem = new Memory();
for (int i = 0; i < memLocList.length; i++) {
memLocList[i] = mem;
memLocList[i].setOpCode(00);
mList.append(String.format("%10s %04x %10s %6s", "Address: ", i,
"Value: ", memLocList[i].getOpCode()));
mList.append("\n");
}
JComponent memTab = makeTextPanel(mList.toString());
tabs.addTab("Memory", new JScrollPane(memTab));
}
protected JComponent makeTextPanel(String t) {
text = t;
JPanel panel = new JPanel(false);
JTextPane filler = new JTextPane();
filler.setFont(new Font("Courier", Font.PLAIN, 14));
filler.setText(text);
filler.setAlignmentX(LEFT_ALIGNMENT);
panel.setLayout(new GridLayout(1, 1));
panel.add(filler);
return panel;
}
The GUI also has a text entry panel where a String of hex values can be entered.
On clicking a button, the user is prompted for another value, which corresponds to the position in the array where the first hex value should be inserted.
Once these values have been entered, I'd like the display to be updated / refreshed to reflect this but am unsure of how to go about it.
I found this question here, which is similar but I'm not sure if implementing Observer/Observable pattern is the right way to proceed, and even if it is, how I'd go about it:
Best Way to Constantly Update GUI Elements
My initial approach was to add an "updateDisplay()" method, which I could call after processing the button click and re-call the makeTextPanel method:
public void updateDisplay() {
makeTextPanel(text);
}
I thought this might refresh it but it has no effect of the display.
Any help appreciated.

You hold your array in a model class, and you allow other classes to "listen" to this by giving this class a SwingPropertyChangeSupport object as well as an addPropertyChangeListener(...) method. Then give the array a setXXX(...) method, and in that method fire the SwingPropertyChangeSupport object after updating the array. There are examples of just this sort of thing on this site, some written by me.
For example: here, here, here, ...
By the way, I'm not surprised that your call to makeTextPanel(text) doesn't work. It creates a JPanel, but you don't appear to do anything with the JPanel that is returned from the method. But nor should you. I don't think that creating new JPanels is the solution you want, but rather updating the Strings displayed by a component of some sort such as a JList or JTextArea using the listener framework that I've described above.
If any of this is confusing, please ask for clarification.

Related

Hard coded buttons do not appear in design view, or in the running program

Whenever I choose to hard code an object (so far, I have sampled buttons, text fields and comboboxes), it does not appear on the associated form. Is there a separate piece of code that handles this, or can I use the following? Additionally, are layout bonds strictly necessary?
JButton startButton = new JButton("Start for loop ex");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0){
int start = 1;
int end = 5;
int answer = 0;
for (int i = start; i < end; i++){
answer = answer + i;
}
};
IDEOne showing the entirety of the code:
http://ideone.com/u7CuoG
I think you only created the button, but forgot to put it in the JFrame.
Assuming that this is a subclass of JFrame, you can do this to add the button to the frame:
this.add(startButton);
Also check if you have called setContentPane. If you have not, the button will fill up the whole frame.
It is only natural that dynamically added buttons don't appear in the design view because it would be very slow to compile and run your code every time you open the design view!
EDIT:
I ran the code you gave me and produced this frame. As you can see, the button is on the frame:

How to remove the panel from the panel it attached to in Java Swing?

I have met a serious problem with my Java swing.
This is how I initialize my chart, everything seems fine now, xyChartPanel is declared as a JPanel in the field, I initialize it with the xyChart I just created. When this step is done, I am okay to see the chart (painted to xyChartPanel) centered to the JPanel I am writing code on, see add(xyChartPanel, BorderLayout.CENTER);.
private void initXYChart() {
// Create Chart
xyChart = new XYChartBuilder().width(800).height(800).xAxisTitle(xColName).yAxisTitle("Y").build();
// Customize Chart
xyChart.getStyler().setLegendPosition(LegendPosition.InsideNE);
xyChart.getStyler().setAxisTitlesVisible(true);
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Line);
double[] yCoordArray = new double[xCoordArray.length];
// Loop through the series
for (int i = 0; i < yCoordinates.size(); i++) {
List<Double> yCoordOneSeries = yCoordinates.get(i);
// Convert list to array
for (int j = 0; j < yCoordArray.length; j++) {
yCoordArray[j] = yCoordOneSeries.get(j);
}
xyChart.addSeries(yColNames.get(i), xCoordArray, yCoordArray);
}
xyChartPanel = new XChartPanel<>(xyChart);
add(xyChartPanel, BorderLayout.CENTER);
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Area);
add(xyChartPanel, BorderLayout.CENTER);
}
Now the problem comes, I don't want my chart to be unchanged all the time, actually I want to change the style of my chart responded to my action on the radio buttons.
I just wrote the updateChartPanelStyle(JRadioButton styleButton) method that takes
private void updateChartPanelStyle(JRadioButton styleButton) {
String style = styleButton.getText();
if (styleButton.isSelected()) {
System.out.println(style);
switch (style) {
case "Line":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Line);
break;
case "Area":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Area);
break;
case "Scatter":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Scatter);
}
xyChartPanel = new XChartPanel<>(xyChart);
add(xyChartPanel, BorderLayout.CENTER);
}
}
See in this method, I changed the style of xyChart I initialized in the last function, and reinitialize the xyChartPanel, then add the updated xyChartPanel to the working panel. Interestingly, I didn't see any change in my GUI. I thought this might be a problem with my xyChart whose style could not be changed afterward. But this is not really the case.
Even if I "removed" xyChartPanel with this.remove(xyChartPanel);, the GUI doesn't seems to be changed.
This is really weird, what should I do now?
Every time you add/remove components to swing dynamically, you need to call revalidate(); and then repaint(); on your JPanel (or JFrame if you're adding it straight to that).

Extracting and manipulating data from a multiple interval JList to use in textArea/JOptionPane

As the title says, I have a multiple interval selection JList and i'm having trouble properly manipulating the data. This is my first time using a JList and it's proving difficult for me.
My GUI acts as a ticket ordering interface for a sports team, and the JList i'm referring to holds a list of souvenirs customers can order. Since it's a multiple selection JList, they can select multiple souvenirs if they so choose.
My issue is extracting the items from the JList and properly printing them to a JOptionPane textArea window, which acts as a summary for the user's order. Here is a breakdown of my goals/issues:
Extracting the souvenirs selected, where the names of the souvenirs are stored in a String[] array
Matching a parallel array of prices, stored in a Double[] array
Using the proper methods from the JList event handler to then print the data to the textArea summary
Eliminating duplicates of souvenirs that seem to appear when I try and print the data to the textArea
Here is the creation of my JList:
souvenirList = new JList(itemNames); //itemNames is an array of Strings[] for souvenirs
souvenirList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
souvenirList.setLayoutOrientation(JList.VERTICAL);
scrollPane = new JScrollPane(souvenirList);
scrollPane.setPreferredSize(new Dimension(200,100));
gbc3.gridx = 1;
gbc3.gridy = 1;
centerPanel.add(scrollPane, gbc3);
c.add(centerPanel, BorderLayout.CENTER);
Here is my event handler for the JList:
private class ListHandler implements ListSelectionListener
{
public void valueChanged(ListSelectionEvent le)
{
boolean adjust = souvenirList.getValueIsAdjusting();
if (!adjust)
{
//not sure if/how I should use this
souvIndex = souvenirList.getSelectedIndices();
//I know this is depreciated, I dont know another way
souvItems = souvenirList.getSelectedValues();
for (int i = 0; i < souvItems.length; i++)
{
System.out.println(souvItems[i] + "\n");
//my attempt to save the souvenirs to an accumlator, doesnt work right
souvString += souvItems[i];
}
}
}
}//end List handler
Now, i'm attempting to take what is stored in souvString and print it to the textArea. I have an add to cart JButton which compiles all the data from the GUI to give the user their overall price. I'll focus on the JList since that is what is giving me trouble. Here is the actionEvent() for the add to cart JButton:
else if (ae.getSource() == cartBtn)
{
textArea = new JTextArea(10, 20);
textArea.setFont(f2);
textArea.setLineWrap(true);
textArea.setOpaque(false);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
//appending all the data from the GUI. souvString holds my JList selections
textArea.setText("Team: Tigers" + "\nMeal: " + restaurant
+ "\n\nSeats Ordered: " + seatingType
+ "\nItems Ordered:" + "\n " + souvString);
JOptionPane.showMessageDialog(null, textArea, "OrderReview",
JOptionPane.INFORMATION_MESSAGE,
new ImageIcon(Project7.class.getResource("/tigers.jpg")));
While it prints the souvenirs, weird things happen. I get a combination of null and duplicate souvenirs. I also can't figure out how to use the parallel array of prices that go along with the souvenirs that do print. The parallel array looks like:
private double[] prices = {2.0, 10.0, 15.0, 25.0, 3.0, 5.0, 9.0, 8.0, 12.0, 6.0};
Each price matches w/ it's corresponding souvenir from this array:
private String[] itemNames = {"mug","cap","tee shirt","sweat shirt","pennant","mini stick",
"bobblehead","paper bag","foam paw","thunderstix"};
I've been messing around with this for about 6 hours and can't get it to work, partially bc I don't understand JLists all that well, and partially bc my logic is flawed I feel. I've tried a few different approaches and those didn't work, either. If someone has some suggestions on how I could approach things differently, or even some advice/clarification on how to properly manipulate a JList, i'd be soo appreciative. I really want to understand this! Thanks again stack users :)
Instead of using two arrays i would create a new Class Souvenir in which you save your souvenirs with a subject and a price.
class Souvenir{
String subject;
double price;
}
About the JList i also dont know really much but i thought there is a method you can get a normal List from the JList Object and with this list you could work threw with the indices and put into an ArrayList of Souvenir or something like that.
This is just an idea i can't really give you an example for it so if someone else could verify this i would also be interested :)

Problem in Java swing code

I intend to take the elements of an integer list and add it to a label and print them in downward fashion one after another. I wrote the following code for it.
public static JFrame ListDraw(JFrame frame , ArrayList<Integer> e)
{
for(int i= 0;i<e.size();i++)
{
JLabel j = new JLabel(e.get(i).toString(),JLabel.CENTER);
frame.add(j);
}
return frame;
}
But it just prints the last array element in the label. What am I doing wrong here?
---------------------(update)
This is just a query that I have regarding the same thing. Therefore I am going to ask it here only. Is there any way to print the label items in a stack as in vertical alignment. Right now I get all the values printed in the horizontal fashion.
I guess you need to set layout for your frame, f.ex: frame.setLayout(new FlowLayout());.
Your frame isn't adapting to the new group of elements- the LayoutManager isn't getting a chance to resize the window. At the end of your function, add frame.pack().
You should use setBounds() to define the size of your frame and give it a LayoutManager of your choice.

Collecting data from a large number of Swing text fields

I am currently writing a sudoku solver in Java. What I need now is some kind of Swing GUI to input the known numbers. I created a JFrame, but manually adding 81 text fields from the toolbox seems like a bad solution. I am also able to add with code like this:
this.setLayout(new GridLayout(9, 9));
for (int i = 0; i < 81; i++)
{
this.add(new JTextField("Field"));
}
However, I do not know how to address these text fields afterwards to collect the user input into a two-dimensional array. How can I do that?
A different solution would be to use a JTable. You could allow for the TableModel to maintain the full data solution, as well as a copy of the user's attempts. The CellRenderers and CellEditors could handle the user experience. See this tutorial.
Struggled a bit with this for my own sudoku solver, but ended up going for painting on a JPanel, and adding a mouse listener to that.. Than determine the current field using mouse position with his function:
addMouseListener(new MouseAdapter() {
private int t(int z) {
return Math.min(z / factor, 8);
};
#Override
public void mouseMoved(MouseEvent e) {
setToolTipPossibilities(t(e.getX()), t(e.getY()));
}
#Override
public void mousePressed(MouseEvent e) {
clickColumn = t(e.getX());
clickRow = t(e.getY());
}
});
First you need to declare array of JTextFields.
So just like your array to store user input you do:
private JTextField[] textFields;
After that you can use some math to map your one-dimensional array to your two dimensions.
something like this should work:
floor(index / 9), index % 9
for x,y
Yes that will work to display the array. To read from the array you just need to call the getText method for each element.
JTable is your friend. Use a DefaultTableModel with editable String values.
String[] columnNames = new String[9];
for(int i=0; i<9; i++){columnNames[i]="";}
String[][] data = new String[9][9];
JTable tab = new JTable(columnNames,data);
When they fill it in, check that each string is an appropriate number and prompt for error.
1st way:
You could put the text fields into an array that mirrors the array that your cell values are in.
The problem with this method tho is that when you need to bind a mouseListener or ActionListener to the TextField you will have a hard time figuring out which cell number it corrisponds to.
2nd way:
You could extend the JTextField into a custom class with new instance variables that store cell number in it.
Using this method you can also implement MouseListener or ActionListener on the extended class too and get whatever information about the field you need, without searching through your array. And combining with the first to put them into an array organizes them for quick access.
Just want to post a little update.
I added an array of textfields as a field on my form:
private JTextField[] fields;
Initialized it:
fields = new JTextField[81];
And finally I am adding the fields to my form like this:
private void addComponents()
{
this.setLayout(new GridLayout(9, 9));
for (int i = 0; i < fields.length; i++)
{
fields[i] = new JTextField("" + i);
this.add(fields[i]);
}
}
The result as of now can be seen here:
Image of my textfields

Categories