How can I save pattern changes to a loaded midi? - java

I am working on a school coding project, which involves using the JFugue library in Java. However, I am having significant difficulty saving loaded and edited patterns to a file. So far, I have tried both the player.saveMidi (which is not recognized) and MidiFileManager.savePatternToMidi functions, but the edits do not save.
Here is a snippet of the aforementioned code:
Pattern pattern = new Pattern(MidiFileManager.loadPatternFromMidi(new File(filePath.getText())));
TextField midiData = new TextField(pattern.toString());
midiData.setFont(Font.font(14));
pattern = new Pattern(midiData.getText());
Button save = new Button("Save Edits");
Pattern finalPattern = pattern;
save.setOnAction(e -> {
try {
MidiFileManager.savePatternToMidi(finalPattern, new File(filePath.getText()));
Load.playAndEdit(filePath);
} catch (Exception ex) {
ex.printStackTrace();
}
});
Any help would certainly be appreciated!

Although your suspicion is that this is an issue with JFugue, the underlying issue is in the JavaFX pieces of the code.
The main issue is that the way the code is written, it looks like the expectation is that the TextField will be displayed, the user will make a change, and the code will remember that change in "pattern = new Pattern(midiData.getText())". That's not how the JavaFX TextField works. UI elements are not sequential like this; instead, they work with actions (or in JavaFX, you can "bind" the value of a UI component with a data element). If you get the text from the TextField in the action that triggers when the user presses the Save button, you will have the most recent data from the text field. As the code is written, the user's change is never placed into a variable.
Two other notes:
In your first line, MidiFileManager.loadPatternFromMidi returns a Pattern, so you don't need to put it into a "new Pattern()".
There is no need to say "Pattern finalPattern = pattern". That just creates a new variable that points to the same data as the existing variable. You can just save "pattern", if it has the information you expect from the text field (but again, this isn't the right place to say it, so it won't have the information that you're expecting).
One way to test that this is not a JFugue issue is to create a simple program that does, for example:
Pattern pattern = MidiFileManager.loadPatternFromMidi(new File(filePath.getText()));
pattern.add(" C D E");
MidiFileManager.savePatternToMidi(pattern, new File(filePath.getText()));
Then you would see that the resulting pattern has three new notes added to the end.

Related

Java swing requestFocusInWindow()

I know there are many questions on how to focus on a certain text field and so on, but it seems that the issue I am facing is a bit different. So, I have a JTextField which has functionality to autocomplete the text if something that is currently in it has been typed before by the user. I also have a set of buttons that perform insertion of some predefined portion of text into the text field when pressed. The problem is that every time any new text appears in the text field, the autocomplete can trigger and append the text that was used by the user previously. In order to it more friendly, I decided to select the part appended by the autocomplete. All the code is executed in the ED thread. Consider the case when the text field was not in focus :
Both code samples are in the actionPerformed method of the button.
// does not work
if (textField.requestFocusInWindow()) {
textField.getDocument().insertString(...);
}
The insertString() is overriden and has all the logic to select appended string by the autocomplete. So, the only thing I need is that the text field is selected before the string is inserted.
I tried :
// does work
textField.requestFocusInWindow();
SwingUtilities.invokeLater(() -> {
textField.getDocument().insertString(...);
});
The official doc says :
The call to the requestFocusInWindow method initiates the focus transfer, but it does not immediately move the focus ...
This sort of makes sense, since to acquire the focus, a call must be made to the window manager of the clients operating system (that's how I understand that, correct me if I am wrong).
Is the second example working mainly because both events (getting focus and inserting the string) are added to the event queue and the insertion appears after the focus request (actually at the end of the queue) or am I missing something? Is it a valid solution? Can it be done better?
Note: simply adding a listener to the text field ( to react when it is in focus) is not a solution, since the logic I described here is only a part of the whole functionality used.

Filter text in JTextPane

I am learning java (just finished reading of Head First Java book) and I've started to write app (for mine and learning purposes), which would read log file and changed fond of the line according to defined rules/filters.
I have some prototype, but now I am stuck with design ... coding is not a big deal but I still have problem to think in OOP and to create good design.
What I currently have are 3 classes.
public class App {
//... contains main method, frame, button for file load, etc...
}
public class FileTail {
//... open/read file, and create thread where file is checked for
//changes and in case that file is changed, reads new lines
}
public class logText extends JTextPane {
//... where the text -> file output appears
}
What I would like to do next, is to have other components on the frame, where I would say e.g.:
filter out all lines which contains "INFO"
lines which contains string "ERROR" will be red
etc...
I cannot come up with design, like should I add this functionality to logText class? I know, that this is small app and probably everything could be in one class, but as one of the reasons is learning purpose, I would like to do it right.
I was thinking about create new class patern, which would contain searched string, Font and Color. Then in main class I would create ArrayList<Patern> and each before each new line is to be added to JTextPane, I would somehow search through ArrayList<Patern> for match.
I suggest you create a method that takes an argument of what ever you want to search for, and compares against a set of records, listing the records that records in some sort of list and returns the list.
good luck

How do you append both pre-established text and user responses into a text area in Java?

I will do my best to explain-- I am trying to make a choose-your-own-adventure type game while using a TextField and a TextArea, where what is written in the TextField is appended into the TextArea (this I know how to do via ActionListener).
However, I need to have the TextArea start with a pre-written 'intro', which asks the user at the end if they want to continue or not. Therefore, I need it to be able to scan the user's response ('yes' or 'no') and choose the appropriate selection of pre-written text to follow.
I don't want to overwrite what is already in the TextArea, I want to add to it. I suppose what I'm confused about it how I'm supposed to lay out the entire file so that it functions properly, because the different choices for the adventure span different methods. Having
"String text = textField.getText();" only within the actionPerformed method means I can't use 'text' elsewhere, but moving that line up with my other variables tells me it can't reference the field before it's defined.
I am fairly new to Java and am working on this as a project for a non-programming school course. I've been through many iterations thus far and this is what seems to be my final attempt, as I've remade it repeatedly and don't have much time left. :(
Your questions/comments and my attempts to answer:
I am trying to make a choose-your-own-adventure type game while using a TextField and a TextArea, where what is written in the TextField is appended into the TextArea (this I know how to do via ActionListener).
As per my comment, be sure to create a Swing GUI which would use a JTextField and a JTextArea. You would then add your java.awt.event.ActionListener to the JTextArea, and the ActionListener would respond whenever the user pressed <ENTER> within the JTextField.
However, I need to have the TextArea start with a pre-written 'intro', which asks the user at the end if they want to continue or not. Therefore, I need it to be able to scan the user's response ('yes' or 'no') and choose the appropriate selection of pre-written text to follow.
This can be done easily, but sounds as if you may be trying to shoe-horn a linear console type program into a GUI. If so, consider reconsidering your program design since what works best for one often doesn't work well for another. If you do re-write, then you should consider redoing most including your program flow, but excepting perhaps the "model" portion of your previous program, the "business logic" that underlies everything.
I don't want to overwrite what is already in the TextArea, I want to add to it. I suppose what I'm confused about it how I'm supposed to lay out the entire file so that it functions properly, because the different choices for the adventure span different methods. Having "String text = textField.getText();" only within the actionPerformed method means I can't use 'text' elsewhere, but moving that line up with my other variables tells me it can't reference the field before it's defined.
Again as per comments a JTextArea has an append(String text) method that will add new text to existing text that is already displayed in your JText Area. So on that note, your ActionListener's actionPerformed method could be very simple and look something like:
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
textArea.append(text):
}
Although you may need to add line feeds, "\n" either before and/or after the text you are going to append.

Java - JFormattedTextField does not allow input on first attempt

I am making a little Sudoku game with a GUI and use a MaskFormatter for the JFormattedTextFields:
formatter = new MaskFormatter(s);
formatter.setValidCharacters("123456789");
But my problem is that when the window opens and i click into one of those fields, it is not possible to type something,
it only works on second try, namely when I click into another field and then back to the first one.
Is it like it has to lose focus first to activate?
If some of my code is necessary please let me know.
Here's what it looks like
EDIT: The problem was here:
if (guessMatrix[i][j] == 0) {
tfM[j][i].setBackground(Color.yellow);
tfM[j][i].setText("");
Without the setText("") it works perfectly fine.
I think you have problem in create object of MaskFormatter.
you create object with pattern of masking and then after set valid characters.
MaskFormatter formatter = new MaskFormatter("#");
formatter.setValidCharacters("123456789");
JFormattedTextField txt = new JFormattedTextField(formatter);
This work perfectly, when you click on textfield and type any number(1-9 only) it allow but you type any non-number then not allow.
Thanks,
Jignesh Gothadiya

Java Swing Threading Problem

so here's the problem. I have a JDialog box that consists of 3 combo boxes, a text field, a few buttons and a JTable. The JTable information is filtered based on the text field and combo boxes, so for instance it starts with all of the data and gets shrunk down to only the data that starts with any string value the user decides.
What's happening though is that while the values filter correctly, if I click in the JTable (in the white space, where there are no rows) then the rows that were deleted show up, like they were invisible until I clicked on them. I've tried almost everything:
I've tried re-creating the table every time filter is clicked (bad hack that didn't even work), I've called all of the repaint, revalidate, firechanged methods, I rewrote the dialog from scratch to make sure I didn't do any stupid mistakes (if I made one I didn't find it at least), and I've tried putting them on separate threads. The only fix I haven't tried is using a swing worker, but that's because my filtering was a little too complicated for me to figure out what goes where and how to extend the swing worker correctly. The GUI is generated by netbeans (bleh), and has worked in my other dozen or so JDialogs just fine (perfectly in fact). Here's the method that doest the filtering, if any of you can help it would be greatly appreciated.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
nameFilter = "task1";
javax.swing.table.DefaultTableModel dm = (javax.swing.table.DefaultTableModel)jTable1.getModel();
tempParameters = parameters;
String currentString;
int rowNumber = 0;
while (dm.getRowCount()>rowNumber){
currentString = (String)(jTable1.getValueAt(rowNumber,1));
if(!nameFilter.equalsIgnoreCase(currentString.substring(0,nameFilter.length()))){
dm.removeRow(rowNumber);
parameters--;
}
else rowNumber++;
}
parameters = numOfRows;
}
Update, I also implemented the filter from the comment below, and while it filtered out the correct data, it had the exact same problem. In the future I will probably use this filter feature though, so thanks.
Another update, the code is still failing even after removing everything but this chunk, and all (at least I believe..) I am doing here is doing a simple remove row call. Hope this helps a bit.
Have you tried creating a new Model every time you want to filter, instead of clearing it by deleting rows? Create new model, copy relevant rows to new Model, set new Model in table. Really shouldn't be necessary, but it might be a quick fix.
Also, I really have to wonder why you're calling toLowerCase on two strings when you're using equalsIgnoreCase to compare them.
So long as this method is called from the EDT I don't think there would be a threading problem. Try using
SwingUtilties.isEventDispatchThread()
to make sure.
If you look at the API for DefaultTableModel, updates are being sent to your JTable which will repaint itself, so I don't think that is the problem.
I would guess that it is a logic problem. If you can extract the logic into separate methods it will be easier to test and verify whether it is updating the model as you expect.
Couple of observations:
If the filter happens to be larger than the string content of the row, it'll throw in the substring call
Calling the dm.removerow is generating a bunch of tablerowsdeleted events.
You're asking for a rowcount from the model, yet are getting the value through the table (a little inconsistent, if the model gets wrapped around another model you might be acting upon different rows), so instead of jtable1.getvalueat, use the dm.getvalueat.
I think what might be happening is that as the events get fired I see there are repaint and revalidate events fired in the JTable, these can be trampling over each other as they get enqueued in the EDT.
What I would suggest is to create a new datamodel, add the rows that you want to keep, and then reassign it to your jTable1.setModel(newDm);
Also to watch for is if someone else is modifying the model while you're in your eventlistener.
Hope this helps

Categories