Hi everyone, I was wondering if anyone has a simple program that can read each line of a txt-file and edit a specific line if you want to.
Thank you to everyone who can help!
here is a basic Sketch to load and save text
you cannot edit text really, except for Backspace
- it’s originally a few tabs, joined into one Sketch now
// ********************************************************************************
// joined pde-file of folder
// ********************************************************************************
// ********************************************************************************
// tab: Editor1.pde main file (file name is folder name)
// Editor
// Demo for Editor and Save and load handling
// SEE 3 buttons lower right corner !!!!!!!!!!!!!!!!!!!!!!!!
// SKETCH EXPECTS A SUB FOLDER texts in the Sketch folder, see: final String pathFolder = "texts";
//
//
// from https : // forum.processing.org/two/discussion/comment/112902/#Comment_112902
// editor path and file extension
final String pathFolder = "texts";
final String fileExtension = ".txt";
// editor content
String str = "Test ";
// states of the program:
// unique constants:
final int normal = 0;
final int save = 1;
final int load = 2;
///current state (must be one of them)
int state=normal;
// blinking cursor:
boolean blinkIsOn=true;
// Paths (returned by 'callback' functions)
String savePath="";
String loadPath="";
// ------------------------------------------------
// Core functions of processing
void setup() {
size(900, 900);
}//func
void draw() {
switch (state) {
case normal:
drawForStateNormal() ;
break;
case save:
// wait for Save Dialog
waitForSaveDialog();
break;
case load:
// wait for Load Dialog
waitForLoadDialog();
break;
default:
//Error
println("Error: 4711");
exit();
break;
//
}//switch
//
}//func
//
// ********************************************************************************
// tab: InputsKeys.pde
// keep it simple
void keyPressed() {
if (state!=normal)
return;
// for the editor:
if ( keyCode == DELETE || keyCode == BACKSPACE ) {
if ( str.length() > 0 ) {
str = str.substring(0, str.length()-1);
}
} else {
if ( key != CODED ) {
str += key;
}
}
}
//
// ********************************************************************************
// tab: InputsMouse1.pde
//
void mousePressed() {
if (state!=normal)
return;
// for the buttons
if ( overSave() ) {
initSave();
}
//---
else if ( overLoad() ) {
initLoad();
}
//---
else if ( overNew() ) {
str="";
}
//
}//func
// ----------------------------------------------------------
// functions to register if mouse is over buttons
boolean overSave() {
return( mouseX > width-40 &&
mouseY > height-20 );
}
boolean overLoad() {
return( mouseX > width-40 &&
mouseY > height-50 &&
mouseY < height-50+25 );
}
boolean overNew() {
return( mouseX > width-40 &&
mouseY > height-80 &&
mouseY < height-80+25 );
}
//
// ********************************************************************************
// tab: SaveLoad.pde
// Save and load
// 4 blocks with 2 functions each, for save and load
void initSave() {
// init save process
// reset
savePath="";
// make date time stamp (the expression nf(n,2) means leading zero: 2 becomes 02)
String dateTimeStamp = year()
+ nf(month(), 2)
+ nf(day(), 2)
+ "-"
+ nf(hour(), 2)
+ nf(minute(), 2)
+ nf(second(), 2);
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()
+ "//"
+ pathFolder
+ "//"
+ dateTimeStamp
+ fileExtension);
// open the dialog
selectOutput("Select a file to write to", "fileSelectedSave", fileDescription);
// set state to wait
state=save;
}
void initLoad() {
// init load process
// reset
loadPath="";
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()+"//"+pathFolder+"//"+"*" + fileExtension );
// open the dialog
selectInput("Select a file to load", "fileSelectedLoad", fileDescription);
// set state to wait
state=load;
}
// --------------------------------------------------------------------
void fileSelectedSave(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
savePath=selection.getAbsolutePath();
}
}
void fileSelectedLoad(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
loadPath=selection.getAbsolutePath();
}
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
state=normal;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
state=normal;
}
}
// ----------------------------------------------------
void saveIt() {
// save
// split at line break and make array (to save it)
String[] strs = split ( str, "\n" );
// check if file extension (fileExtension, e.g. .txt) is there
int len = savePath.length();
if (len<4 || !savePath.substring( len-4 ).equals(fileExtension)) {
// file Extension is not present, we have to add it
savePath += fileExtension; // add the file Extension
}
// save
println("Saved: " + savePath);
saveStrings( savePath, strs );
}
void loadIt() {
// load
String[] strs = loadStrings( loadPath );
str = join(strs, "\n");
}
//
// ********************************************************************************
// tab: States.pde
void drawForStateNormal() {
background(0);
textSize(14);
// title
fill(255, 2, 2);
text("My Little Editor",
width-133, 20,
130, 422);
// show the text the user entered
fill(255);
text(str+blink(),
20, 20, width-177, height-20);
// ----------------------
// buttons
textSize(11);
fill(128);
if ( overSave() ) {
fill(196);
}
rect(width-40, height-20, 40, 20);
fill(255);
text("Save",
width-40+7, height-9+5);
// ---
fill(128);
if ( overLoad() ) {
fill(196);
}
rect(width-40, height-50, 40, 20);
fill(255);
text("Load",
width-40+7, height-50+9+5);
// ---
fill(128);
if ( overNew() ) {
fill(196);
}
rect(width-40, height-80, 40, 20);
fill(255);
text("New",
width-40+7, height-80+9+5);
}
// ********************************************************************************
// tab: Tools.pde
// Misc
String blink() {
// toggle blinkIsOn
if (frameCount%17 == 0)
blinkIsOn=!blinkIsOn;
// depending from blinkIsOn
if (blinkIsOn)
return "|";
else return "";
}
//
// End of joined file. ********************************************************************************
To read a table I can just use loadStrings without any problems, but the problem I am having now is instead of editing the specific file I need to make a new txt-file that can replace the old one with the text i want.
Thank you for the previous answers
Another option would be to use JTextArea in a Swing app. Downside is you have to do your own event handling to add ‘Open’ and ‘Save’ buttons. Also draw() is non-functional with this approach.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
javax.swing.JFrame frame;
java.awt.Canvas canvas;
JTextArea txtArea;
final int _wndW = 600;
final int _wndH = 600;
void textArea() {
txtArea = new JTextArea();
JScrollPane scrlPane = new JScrollPane(txtArea);
scrlPane.setBounds(0, 40, _wndW, _wndH);
frame.add(scrlPane);
txtArea.setEditable(true);
// txtArea.setFont(new Font("Menlo", Font.BOLD, 16));
txtArea.setLineWrap(false);
txtArea.setWrapStyleWord(true);
txtArea.repaint();
}
void buildWnd(){
textArea();
}
void setup() {
frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
frame.setBounds(500, 300, _wndW, _wndH);
frame.remove(canvas);
surface.setTitle("JTextArea Demo");
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
buildWnd(); // Builds components on EventDispatchThread
}
}
);
}
Honestly, I feel that using Java 's File API is the only thing worthy of use here.
What I should tell you, though, is that this would require a lot of learning and some practice.
I myself learnt to use the File API pretty recently, so I consider myself worthy enough to write this ‘little’ guide.
What I write here in this answer assumes that you first learn about the previous topic I mentioned, so you could be following this in a sort of step-by-step manner later on.
More than enough talk. Here’s the real deal:
The first thing I recommend you to do use another IDE (such as VSCode), and write a few Java programs for File I/O. That should help you learn much faster.
java.io
classes such as BufferedReader
will help you here.
Here is a JavaDoc! Read a few methods’ names to know what you can do with this class, :D!
Here’s a StackOverflow answer to help you start: How to use BufferedReader in Java - Stack Overflow
The idea, is to make a File
object (File file = new File("file_name.txt")
). This is basically a way to hold a path to a file, not actually make a file!
You would usually check if the file already exists with the .exists()
method, else use .createNewFile()
!
You should then make a BufferedReader
to read the file. However, a BufferedReader
cannot do that alone - you need to feed it a FileReader()
first (welcome to the OOP mess, :P)
…that’s what BufferedReader reader = new BufferedReader(new FileReader(file));
is.
“Time for some theory!~”
In C
- the programming language the world runs on, we have standard library functions (stuff that comes built into every programming language) for File I/O. The way these work, is by loading a file into memory (RAM), and then proceeding to read each character in it. (Note that modern operating systems of course, will still load the file in small chunks for performance.)
You are then supposed to make changes in the file the way you want to. Once you’re done, you “close the file stream”: this tells the OS to change the contents of the data stored on the disk, to whatever you did to its copy in RAM.
I’m sorry if this sounded like tech jargon and wasn’t understood by you… Anyway, this should tell you the very important things it has to:
- Yes, Java has a way to read files byte-by-byte (
FileInputStream
for bytes!). - Yes,
BufferedReader
is supposed to make your work easier by giving you lines to read, rather than giving you justchar
s, orbyte
s. - You have to remember to “close the file stream”!
Now - making objects from File I/O classes in Java can throw exceptions.
You could make a try { } catch(Exception e) { }
block to deal with that.
However, there exists a utility for just this stuff: the “try-with-resources” block! The essence of these, is that they .close()
the readers etc. automatically. (Though you would be doing that yourself sometimes. Try doing it manually in those cases!)
…you should go read about it :D!
Having gathered all that information, hopefully, this code should make sense!:
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
// The condition in the loop here simply states that `line` should not be `null`.
// However, before we do that, we simply assign the next line in our file to it.
// Operators can be used inside round brackets / parenthesis,
// ..just like the ternary operator can!
// (The `variable = condition? trueVal : falseVal` thing).
for (String line; (line = reader.readLine()) != null;
// Do something like counting the number of lines here!
) { // Loop begins:
println(line);
//...
}
}
Next up - classes for writing to the file:
There really are two primary ways: new BufferedWriter(FileWriter(file))
, or, as the Processing reference also shows you: new PrintWriter(file)
.
The difference, is that PrintWriter
gives you built-in functionality for formatting (such as automatically inserting the newline character using its println()
method).
BufferedWriter
, lets you handle exceptions yourself. PrintWriter
‘eats’ them!
…which one to use?!
BufferedWriter
.
Even though it only has only one method that can write strings (which you’ll probably have to read the docs for every time), it is faster.
There’s nothing wrong with PrintWriter
either, I guess. But speed is nice for larger files!
The important part!:
Note that though you can do both reading and writing at the same time, we won’t need to do that, yay!
How? Using a StringBuilder
! (And not a StringBuffer
!)
StringBuilder text = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
for (String line; (line = reader.readLine()) != null;)
builder.append(line);
}
Using deleteCharAt()
, it is possible to edit parts of a line, etcetera, easily.
But we work with Processing!
Using this function, you should be able to write just data/filename
for your file locations, and it might work. I have never tested this!
Processing also gives you createReader()
and createWriter()
.
You may want to use Andreas Schlegel’s “controlP5” library to make things easier for a UI.
Also, since Java strings are ‘immutable’ (AKA they remain in memory even when no variable stores them), you would want to use a StringBuilder
instead of just a String
to hold data. If the file data is too long, it’ll cause memory issues.
controlP5 gives probably gives you the text in another thread (there is a callback function for that!), so you could be using a StringBuffer
instead. But apparently, that callback gets a String
, which is already sorta’ doing things to memory, so… you could just use that string…
…thanks for reading!
Here is a new version based on my previous one.
You can still load and save but you now have an Editor from the g4p library (also a GUI library).
Again, Sketch is in one part, but you can split it up into tabs.
[NEW VERSION BELOW]
// ********************************************************************************
// joined pde-file of folder
// ********************************************************************************
// ********************************************************************************
// tab: Editor2.pde main file (file name is folder name)
// Editor ::: using G4P : GTextArea as Editor Element
// Demo for Editor and Save and load handling
// SEE 3 buttons lower right corner !!!!!!!!!!!!!!!!!!!!!!!!
// SKETCH EXPECTS A SUB FOLDER texts in the Sketch folder, see: final String pathFolder = "texts";
//
//
// from https : // forum.processing.org/two/discussion/comment/112902/#Comment_112902
import g4p_controls.*;
GTextArea txaSample;
// editor path and file extension
final String pathFolder = "texts";
final String fileExtension = ".txt";
// editor content
// String str = "Test ";
// states of the program:
// unique constants:
final int normal = 0;
final int save = 1;
final int load = 2;
///current state (must be one of them)
int state=normal;
// blinking cursor:
boolean blinkIsOn=true;
// Paths (returned by 'callback' functions)
String savePath="";
String loadPath="";
// ------------------------------------------------
// Core functions of processing
void setup() {
size(900, 900);
// Create a text area with both horizontal and
// vertical scrollbars that automatically hide
// when not needed.
txaSample = new GTextArea(this,
20, 20,
width-200, height-60,
G4P.SCROLLBARS_BOTH | G4P.SCROLLBARS_AUTOHIDE);
txaSample.setText("Hello", 310);
// Set some default text
// txaSample.setPromptText("Please enter some text");
}//func
void draw() {
switch (state) {
case normal:
drawForStateNormal() ;
break;
case save:
// wait for Save Dialog
waitForSaveDialog();
break;
case load:
// wait for Load Dialog
waitForLoadDialog();
break;
default:
//Error
println("Error: 4711");
exit();
break;
//
}//switch
//
}//func
//
// ********************************************************************************
// tab: InputsKeys.pde
// keep it simple
void keyPressed() {
if (state!=normal)
return;
// for the editor:
//if ( keyCode == DELETE || keyCode == BACKSPACE ) {
// if ( str.length() > 0 ) {
// str = str.substring(0, str.length()-1);
// }
//} else {
// if ( key != CODED ) {
// str += key;
// }
//}
}
//
// ********************************************************************************
// tab: InputsMouse1.pde
//
void mousePressed() {
if (state!=normal)
return;
// for the buttons
if ( overSave() ) {
initSave();
}
//---
else if ( overLoad() ) {
initLoad();
}
//---
else if ( overNew() ) {
// str="";
txaSample.setText("Hello", 310);
}
//
}//func
// ----------------------------------------------------------
// functions to register if mouse is over buttons
boolean overSave() {
return( mouseX > width-40 &&
mouseY > height-20 );
}
boolean overLoad() {
return( mouseX > width-40 &&
mouseY > height-50 &&
mouseY < height-50+25 );
}
boolean overNew() {
return( mouseX > width-40 &&
mouseY > height-80 &&
mouseY < height-80+25 );
}
//
// ********************************************************************************
// tab: SaveLoad.pde
// Save and load
// 4 blocks with 2 functions each, for save and load
void initSave() {
// init save process
// reset
savePath="";
// make date time stamp (the expression nf(n,2) means leading zero: 2 becomes 02)
String dateTimeStamp = year()
+ nf(month(), 2)
+ nf(day(), 2)
+ "-"
+ nf(hour(), 2)
+ nf(minute(), 2)
+ nf(second(), 2);
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()
+ "//"
+ pathFolder
+ "//"
+ dateTimeStamp
+ fileExtension);
// open the dialog
selectOutput("Select a file to write to", "fileSelectedSave", fileDescription);
// set state to wait
state=save;
}
void initLoad() {
// init load process
// reset
loadPath="";
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()+"//"+pathFolder+"//"+"*" + fileExtension );
// open the dialog
selectInput("Select a file to load", "fileSelectedLoad", fileDescription);
// set state to wait
state=load;
}
// --------------------------------------------------------------------
void fileSelectedSave(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
savePath=selection.getAbsolutePath();
}
}
void fileSelectedLoad(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
loadPath=selection.getAbsolutePath();
}
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
state=normal;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
state=normal;
}
}
// ----------------------------------------------------
void saveIt() {
// save
// split at line break and make array (to save it)
// get the data from the text Area
String[] strs = split(txaSample.getText(), "\n" );
// check if file extension (fileExtension, e.g. .txt) is there
int len = savePath.length();
if (len<4 || !savePath.substring( len-4 ).equals(fileExtension)) {
// file Extension is not present, we have to add it
savePath += fileExtension; // add the file Extension
}
// save
println("Saved: " + savePath);
saveStrings( savePath, strs );
}
void loadIt() {
// load
String[] strs = loadStrings( loadPath );
String str1 = join(strs, "\n");
txaSample.setText(str1, 310);
}
//
// ********************************************************************************
// tab: States.pde
void drawForStateNormal() {
background(0);
textSize(14);
// title
fill(255, 2, 2);
text("My Little Editor",
width-133, 20,
130, 422);
// show the text the user entered
//fill(255);
//text(str+blink(),
// 20, 20, width-177, height-20);
// ----------------------
// buttons
textSize(11);
fill(128);
if ( overSave() ) {
fill(196);
}
rect(width-40, height-20, 40, 20);
fill(255);
text("Save",
width-40+7, height-9+5);
// ---
fill(128);
if ( overLoad() ) {
fill(196);
}
rect(width-40, height-50, 40, 20);
fill(255);
text("Load",
width-40+7, height-50+9+5);
// ---
fill(128);
if ( overNew() ) {
fill(196);
}
rect(width-40, height-80, 40, 20);
fill(255);
text("New",
width-40+7, height-80+9+5);
}
// ********************************************************************************
// tab: Tools.pde
// Misc
String blink() {
// toggle blinkIsOn
if (frameCount%17 == 0)
blinkIsOn=!blinkIsOn;
// depending from blinkIsOn
if (blinkIsOn)
return "|";
else return "";
}
//
// End of joined file. ********************************************************************************
NEW VERSION
new version with button class, better button handling
// ********************************************************************************
// joined pde-file of folder Editor2
// ********************************************************************************
// ********************************************************************************
// tab: Editor2.pde main file (file name is folder name)
// Editor ::: using G4P : GTextArea as Editor Element
// Demo for Editor and Save and load handling
// SEE 3 buttons !!!!!!!!!!!!!!!!!!!!!!!!
// SKETCH EXPECTS A SUB FOLDER texts in the Sketch folder, see: final String pathFolder = "texts";
//
//
// from https : // forum.processing.org/two/discussion/comment/112902/#Comment_112902
import g4p_controls.*;
GTextArea txaSample;
// editor path and file extension
final String pathFolder = "texts";
final String fileExtension = ".txt";
// states of the program:
// unique constants:
final int normal = 0;
final int save = 1;
final int load = 2;
///current state (must be one of them)
int state=normal;
// blinking cursor:
boolean blinkIsOn=true;
// Paths (returned by 'callback' functions after using save and load)
String savePath="";
String loadPath="";
// list of buttons
ArrayList<Button> listButton = new ArrayList();
// ------------------------------------------------
// Core functions of processing
void setup() {
size(900, 900);
// Create a text area with both horizontal and
// vertical scrollbars that automatically hide
// when not needed.
txaSample = new GTextArea(this,
20, 20,
width-200, height-60,
G4P.SCROLLBARS_BOTH | G4P.SCROLLBARS_AUTOHIDE);
txaSample.setText("Hello", 310);
// Set some default text
// txaSample.setPromptText("Please enter some text");
// init buttons
int i=0;
listButton.add(new Button ("Save", width-70, 60+i*40, 50, 25));
i++;
listButton.add(new Button ("Load", width-70, 60+i*40, 50, 25));
i++;
listButton.add(new Button ("New", width-70, 60+i*40, 50, 25));
i++;
}//func
void draw() {
switch (state) {
case normal:
drawForStateNormal() ;
break;
case save:
// wait for Save Dialog
waitForSaveDialog();
break;
case load:
// wait for Load Dialog
waitForLoadDialog();
break;
default:
//Error
println("Error: 4777");
exit();
break;
//
}//switch
//
}//func
//
// ********************************************************************************
// tab: classButton.pde
class Button {
String textButton;
PVector position = new PVector();
float sizeW, sizeH;
// constructor
Button ( String s1_,
float x_, float y_,
float sizeW_, float sizeH_ ) {
position.set(x_, y_);
sizeW = sizeW_;
sizeH = sizeH_;
textButton=s1_;
}// constructor
// ------------------------------------------
// methods
void display() {
// show button
// rect
stroke(200);
//noFill();
fill(255);
if (checkMouse())
fill(255, 0, 0);
if (checkMouse()&&mousePressed)
fill(255, 0, 120);
rect(position.x, position.y,
sizeW, sizeH);
// text
fill(0);
text(textButton,
position.x+5, position.y+17);
}// method
boolean checkMouse() {
// returns true when inside
return
mouseX > position.x &&
mouseX < position.x + sizeW &&
mouseY > position.y &&
mouseY < position.y + sizeH;
} // method
//
}//class
//
// ********************************************************************************
// tab: InputsKeys.pde
// keep it simple
void keyPressed() {
if (state!=normal)
return;
}
//
// ********************************************************************************
// tab: InputsMouse1.pde
//
void mousePressed() {
if (state!=normal)
return;
String command="";
// for the buttons
for (Button currentButton : listButton) {
if (currentButton.checkMouse()) {
command=currentButton.textButton;
break;
}
}//for
if (command.equals(""))
return;
switch(command) {
case "Load":
initLoad();
break;
case "Save":
initSave();
break;
case "New":
txaSample.setText("Hello", 310);
break;
default:
// Error
println("unknown command "+command);
exit();
break;
}//switch
//
} //func
//
// ********************************************************************************
// tab: SaveLoad.pde
// Save and load
// 4 blocks with 2 functions each, for save and load
// --------------------------------------------------------------------
// the two init functions
void initSave() {
// init save process
// reset
savePath="";
// make date time stamp (the expression nf(n,2) means leading zero: 2 becomes 02)
String dateTimeStamp = year()
+ nf(month(), 2)
+ nf(day(), 2)
+ "-"
+ nf(hour(), 2)
+ nf(minute(), 2)
+ nf(second(), 2);
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()
+ "//"
+ pathFolder
+ "//"
+ dateTimeStamp
+ fileExtension);
// open the dialog
selectOutput("Select a file to write to", "fileSelectedSave", fileDescription);
// set state to wait
state=save;
}
void initLoad() {
// init load process
// reset
loadPath="";
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()+"//"+pathFolder+"//"+"*" + fileExtension );
// open the dialog
selectInput("Select a file to load", "fileSelectedLoad", fileDescription);
// set state to wait
state=load;
}
// --------------------------------------------------------------------
// the two 'callback' functions
void fileSelectedSave(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
savePath=selection.getAbsolutePath();
}
}
void fileSelectedLoad(File selection) {
// the 'callback' function
if (selection == null) {
// println("Window was closed or the user hit cancel.");
// go back
state=normal;
} else {
// println("User selected " + selection.getAbsolutePath());
loadPath=selection.getAbsolutePath();
}
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
state=normal;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
state=normal;
}
}
// ----------------------------------------------------
// executing save and load
void saveIt() {
// save
// split at line break and make array (to save it)
// get the data from the text Area
String[] strs = split(txaSample.getText(), "\n" );
// check if file extension (fileExtension, e.g. .txt) is there
int len = savePath.length();
if (len<4 || !savePath.substring( len-4 ).equals(fileExtension)) {
// file Extension is not present, we have to add it
savePath += fileExtension; // add the file Extension
}
// save
println("Saved: " + savePath);
saveStrings( savePath, strs );
}
void loadIt() {
// load
String[] strs = loadStrings( loadPath );
String str1 = join(strs, "\n");
txaSample.setText(str1, 310);
}
//
// ********************************************************************************
// tab: States.pde
void drawForStateNormal() {
background(0);
textSize(14);
// title
fill(255, 2, 2);
text("My Little Editor",
width-133, 20,
130, 422);
// buttons
for (Button currentButton : listButton) {
currentButton.display();
} //for
//
}
//
// End of joined file. ********************************************************************************
The following miniEditor uses Swing components:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.io.File;
javax.swing.JFrame frame;
java.awt.Canvas canvas;
JTextArea txtArea;
JButton open;
JButton save;
JButton saveAs;
JButton clearBtn;
File file;
final int _wndW = 600;
final int _wndH = 600;
void clearAction(){
String s = "";
txtArea.setText(s);
}
void saveAs(){
JFileChooser fileChooser = new JFileChooser();
int option = fileChooser.showSaveDialog(frame);
if(option == JFileChooser.APPROVE_OPTION){
file = fileChooser.getSelectedFile();
println("file = ",file);
} else {
println("SaveAs canceled.");
exit();
}
try {
String content = txtArea.getText();
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file) ;
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (IOException e) {
//e.printStackTrace();
JOptionPane.showMessageDialog(saveAs, e);
}
}
void openBtn() {
open = new JButton("Open");
open.setBounds(20, 10, 80, 24);
frame.add(open);
// **** Open Action **** //
open.addActionListener( new ActionListener() {
void actionPerformed(ActionEvent event) {
JFileChooser fileChooser = new JFileChooser();
int option = fileChooser.showOpenDialog(fileChooser);
if (option == JFileChooser.APPROVE_OPTION) {
file = fileChooser.getSelectedFile();
try {
BufferedReader buffer = new BufferedReader(new FileReader(file));
String s1 = "", s2 = "";
while ((s1 = buffer.readLine())!= null) {
s2 += s1 + "\n";
}
txtArea.setText(s2);
buffer.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(open,e);
}
}
}
}
);
open.repaint();
}
void saveBtn() {
save = new JButton("Save");
save.setBounds(110, 10, 80, 24);
frame.add(save);
// **** Save Action **** //
save.addActionListener( new ActionListener() {
void actionPerformed(ActionEvent event) {
println("Save hit.", file);
if (file != null) {
try {
String content = txtArea.getText();
FileWriter fw = new FileWriter(file) ;
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (IOException e) {
// e.printStackTrace();
JOptionPane.showMessageDialog(save,e);
}
} else {
saveAs(); // file has no name; show save dialog to give it one.
}
}
}
);
save.repaint();
}
void saveAsBtn() {
saveAs = new JButton("SaveAs...");
saveAs.setBounds(200, 10, 80, 24);
frame.add(saveAs);
// **** SaveAs Action **** //
saveAs.addActionListener( new ActionListener() {
void actionPerformed(ActionEvent event) {
println("SaveAs hit.");
saveAs();
}
}
);
saveAs.repaint();
}
void clearBtn() {
clearBtn = new JButton("Clear");
clearBtn.setBounds(290, 10, 80, 24);
frame.add(clearBtn);
// **** Clear Action **** //
clearBtn.addActionListener( new ActionListener() {
void actionPerformed(ActionEvent event) {
println("Clear hit.");
clearAction();
}
}
);
clearBtn.repaint();
}
void textArea() {
txtArea = new JTextArea();
JScrollPane scrlPane = new JScrollPane(txtArea);
scrlPane.setBounds(10, 40, _wndW-20, _wndH - 80);
frame.add(scrlPane);
txtArea.setEditable(true);
// txtArea.setFont(new Font("Menlo", Font.BOLD, 16));
txtArea.setLineWrap(true);
txtArea.setWrapStyleWord(true);
txtArea.repaint();
}
void buildWnd() {
textArea();
openBtn();
saveBtn();
saveAsBtn();
clearBtn();
}
void setup() {
frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
frame.setBounds(500, 300, _wndW, _wndH);
frame.remove(canvas);
surface.setTitle("miniEditor");
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
buildWnd(); // Builds components on EventDispatchThread
}
}
);
}
My take on the problem -
A Line based Text File Editor
User requirements
- The text is edited on a line by line basis
- When a file is selected the original is copied to make a backup
- The user can traverse the file forwards and backwards through the file
- Lines can be edited in any order.
- Line changes are automatically remembered
- User can commit all changes to the original file (overwriting it)
- Popup dialogs warnings to prevent user going passed beginning and end of file
- Popup warning before committing changes allowing original file to be unchanged
Java Swing is not used instead this sketch uses the G4P library (install from Contributions Manager).
import g4p_controls.*;
// GUI controls
GTextField txfLine;
GButton btnFirst, btnPrev, btnNext, btnLast, btnSave, btnOpen;
GLabel lblTitle, lblGuide, lbl0, lbl1, lblLineNo, lblNbrLines;
// File editing variables
String fname;
String[] lines;
int ln = 0, nbrLines = 0;
public void setup() {
size(600, 300, JAVA2D);
createGUI();
}
public void draw() {
background(230);
}
void openFile() {
fname = G4P.selectInput("Text file to edit", "txt", "text files");
if (fname != null) {
lines = loadStrings(fname);
saveStrings(fname + ".copy", lines);
ln = 1;
nbrLines = lines.length;
displayLineCounter();
showCurrentLine();
}
}
void saveChanges() {
int reply = G4P.selectOption(this, "This will overwrite the original file",
"Do you wish to continue?", G4P.WARN_MESSAGE, G4P.OK_CANCEL);
if (reply == G4P.CANCEL || reply == G4P.CLOSED) {
println("Cancelled");
return;
}
keepEditedLine();
saveStrings(fname, lines);
}
void nextLine() {
if (ln == nbrLines) {
G4P.showMessage(this, "Currently showing last line",
"No next line", G4P.WARN_MESSAGE);
return;
}
keepEditedLine();
ln++;
displayLineCounter();
showCurrentLine();
}
void prevLine() {
if (ln == 1) {
G4P.showMessage(this, "Currently showing first line",
"No previous line", G4P.WARN_MESSAGE);
return;
}
keepEditedLine();
ln--;
displayLineCounter();
showCurrentLine();
}
void firstLine() {
if (ln > 1) {
keepEditedLine();
ln = 1;
displayLineCounter();
showCurrentLine();
}
}
void lastLine() {
if (ln < nbrLines) {
keepEditedLine();
ln = nbrLines;
displayLineCounter();
showCurrentLine();
}
}
void keepEditedLine() {
lines[ln - 1] = txfLine.getText();
}
void showCurrentLine() {
txfLine.setText(lines[ln - 1]);
}
void displayLineCounter() {
lblLineNo.setText("" + ln);
lblNbrLines.setText("" + nbrLines);
}
// G4P event handlers
public void gotoPrevLine(GButton source, GEvent event) {
prevLine();
}
public void gotoNextLine(GButton source, GEvent event) {
nextLine();
}
public void saveChanges(GButton source, GEvent event) {
saveChanges();
}
public void openFile(GButton source, GEvent event) {
openFile();
}
public void gotoFirst(GButton source, GEvent event) {
firstLine();
}
public void gotoLast(GButton source, GEvent event) {
lastLine();
}
public void createGUI(){
G4P.messagesEnabled(false);
G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
G4P.setMouseOverEnabled(false);
G4P.setDisplayFont("Arial", G4P.PLAIN, 14);
G4P.setInputFont("Arial", G4P.PLAIN, 14);
surface.setTitle("Sketch Window");
txfLine = new GTextField(this, 10, 140, 580, 36, G4P.SCROLLBARS_HORIZONTAL_ONLY | G4P.SCROLLBARS_AUTOHIDE);
txfLine.setOpaque(false);
lblTitle = new GLabel(this, 10, 10, 490, 30);
lblTitle.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
lblTitle.setText("Line by Line File Editor");
lblTitle.setOpaque(true);
btnPrev = new GButton(this, 10, 180, 110, 30);
btnPrev.setText("Previous");
btnPrev.addEventHandler(this, "gotoPrevLine");
btnNext = new GButton(this, 130, 180, 110, 30);
btnNext.setText("Next");
btnNext.addEventHandler(this, "gotoNextLine");
btnSave = new GButton(this, 510, 210, 80, 80);
btnSave.setText("Save Changes");
btnSave.setLocalColorScheme(GCScheme.RED_SCHEME);
btnSave.addEventHandler(this, "saveChanges");
btnOpen = new GButton(this, 510, 10, 80, 120);
btnOpen.setText("Open File to Edit");
btnOpen.setLocalColorScheme(GCScheme.GREEN_SCHEME);
btnOpen.addEventHandler(this, "openFile");
lblGuide = new GLabel(this, 10, 40, 490, 90);
String guide = "Click on the green button to select the file to edit. ";
guide += "A copy of the original file will be created with a '.code' extension. \n";
guide += "You can move forward and backwards through the file making changes but ";
guide += "these will not overwrite the original file unless you click on the ";
guide += "'Save Changes' button.";
lblGuide.setText(guide);
lblGuide.setOpaque(false);
lbl0 = new GLabel(this, 440, 180, 40, 20);
lbl0.setTextAlign(GAlign.RIGHT, GAlign.MIDDLE);
lbl0.setText("Line ");
lbl0.setOpaque(false);
lblLineNo = new GLabel(this, 480, 180, 40, 20);
lblLineNo.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
lblLineNo.setText("?");
lblLineNo.setOpaque(true);
lblNbrLines = new GLabel(this, 550, 180, 40, 20);
lblNbrLines.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
lblNbrLines.setText("?");
lblNbrLines.setOpaque(true);
lbl1 = new GLabel(this, 520, 180, 30, 20);
lbl1.setTextAlign(GAlign.CENTER, GAlign.MIDDLE);
lbl1.setText("of");
lbl1.setOpaque(false);
btnFirst = new GButton(this, 10, 220, 50, 20);
btnFirst.setText("First");
btnFirst.addEventHandler(this, "gotoFirst");
btnLast = new GButton(this, 190, 220, 50, 20);
btnLast.setText("Last");
btnLast.addEventHandler(this, "gotoLast");
}
…and an Editor without any libraries…
joined as one file, you may split it back into several tabs
— EDITOR —
- This editor does work only with java (default) and not with P2D or P3D / opengl.
- Use mouse to place cursor
- Type normal text, use Backspace, Delete and Return
- Use Cursor up/down, left/right
- Use Pos1, End
- Ctrl-Pos1, Ctrl-End
- Pg up, Pg Down
- ctrl-y - delete current line
- Ctrl-1 - test text
no scrollbars
// ********************************************************************************
// joined pde-file of folder Editor4
// ********************************************************************************
// ********************************************************************************
// tab: Editor4.pde main file (file name is folder name)
// Editor: using OWN class as Editor. NO libraries used.
// The core is the class TextBoxEditor.
//
// Demo for Editor and Save and load handling
// SEE 3 buttons.
// SKETCH EXPECTS A SUB FOLDER texts in the Sketch folder, see: final String pathFolder = "texts";
//
//
// from https : // forum.processing.org/two/discussion/comment/112902/#Comment_112902
// imports ---
// NONE
// classes ---
// Editor
TextBoxEditor textBoxEditor;
// Toolbox save / load
ClassSaveLoadTools classSaveLoadTools = new ClassSaveLoadTools();
// list of buttons
ArrayList<Button> listButton = new ArrayList();
// consts und vars ---
// Help
final String helpText = "--- EDITOR ---\n"
+"This editor does work only with java (default) and not with P2D or P3D / opengl.\n"
+"Use mouse to place cursor\nType text, use Backspace, Delete and Return\nUse Cursor up/down, left/right\nPos1, End\nCtrl-Pos1, Ctrl-End\nPg up, Pg Down\nctrl-y - delete current line\nCtrl-1 - test text";
// states of the program:
final int normal = 0; // unique constants
final int save = 1;
final int load = 2;
///current state (must be one of them)
int state=normal;
// ------------------------------------------------
// Core functions of processing
void setup() {
size(1800, 900);
this.registerMethod("keyEvent", this);
println(helpText.replace("\n", "\n * "));
// Create a text area (without horizontal and
// vertical scrollbars)
final String textToStart = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.\n"
+"Aenean commodo ligula eget dolor.\nAenean massa.\nCum sociis natoque penatibus et magnis\ndis parturient montes,\nnascetur ridiculus mus";
textBoxEditor = new TextBoxEditor( textToStart,
20, 20, // x, y
width-200, height-60, // width, height of the textBoxEditor
0300 << 030, color(255), // textColor, backgroundColor
color(-1, 0100), color(#FF00FF, 0200)); // bordColor, slctColor
// init buttons
String[] buttonTitles = {"Save", "Load", "New" };
int i=0;
for (String buttonTitle : buttonTitles) {
listButton.add(new Button (buttonTitle, width-70, 60+i*40, 50, 25));
i++;
}//for
}//func
void draw() {
switch (state) {
case normal:
//normal
drawForStateNormal() ;
break;
case save:
// wait for Save Dialog
classSaveLoadTools.waitForSaveDialog();
break;
case load:
// wait for Load Dialog
classSaveLoadTools.waitForLoadDialog();
break;
default:
//Error
println("Error: 4777");
exit();
break;
//
}//switch
//
}//func
//
// ********************************************************************************
// tab: classButton.pde
class Button {
String textButton;
PVector position = new PVector();
float sizeW, sizeH;
// constructor
Button ( String s1_,
float x_, float y_,
float sizeW_, float sizeH_ ) {
position.set(x_, y_);
sizeW = sizeW_;
sizeH = sizeH_;
textButton=s1_;
}// constructor
// ------------------------------------------
// methods
void display() {
// show button
// rect
stroke(200);
fill(255);
if (checkMouse())
fill(255, 0, 0);
if (checkMouse()&&mousePressed)
fill(255, 0, 120);
rect(position.x, position.y,
sizeW, sizeH);
// text
fill(0);
// text is centered
textAlign(CENTER);
text(textButton,
position.x+sizeW/2, position.y+17);
//reset
textAlign(LEFT);
}// method
boolean checkMouse() {
// returns true when inside
return
mouseX > position.x &&
mouseX < position.x + sizeW &&
mouseY > position.y &&
mouseY < position.y + sizeH;
} // method
//
}//class
//
// ********************************************************************************
// tab: classSaveLoad.pde
// Save and load
// the two 'callback' functions MUST BE OUTSIDE THE CLASS
// 3 blocks with 2 functions each, for save and load
class ClassSaveLoadTools {
// editor path and file extension
final String pathFolder = "texts";
final String fileExtension = ".txt";
// Paths (returned by 'callback' functions after using save and load)
String savePath="";
String loadPath="";
// no constr
// --------------------------------------------------------------------
// the two init functions
void initSave() {
// init save process
// reset
savePath="";
// make date time stamp (the expression nf(n,2) means leading zero: 2 becomes 02)
String dateTimeStamp = year()
+ nf(month(), 2)
+ nf(day(), 2)
+ "-"
+ nf(hour(), 2)
+ nf(minute(), 2)
+ nf(second(), 2);
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()
+ "//"
+ pathFolder
+ "//"
+ dateTimeStamp
+ fileExtension);
// open the dialog
selectOutput("Select a file to write to", "fileSelectedSave", fileDescription);
// set state to wait
state=save;
}
void initLoad() {
// init load process
// reset
loadPath="";
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()+"//"+pathFolder+"//"+"*" + fileExtension );
// open the dialog
selectInput("Select a file to load", "fileSelectedLoad", fileDescription);
// set state to wait
state=load;
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
state=normal;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
state=normal;
}
}
// ----------------------------------------------------
// executing save and load
void saveIt() {
// save
// split at line break and make array (to save it)
// get the data from the text Area
String[] strs = split(textBoxEditor.getText(), "\n" );
// check if file extension (fileExtension, e.g. .txt) is there
int len = savePath.length();
if (len<4 || !savePath.substring( len-4 ).equals(fileExtension)) {
// file Extension is not present, we have to add it
savePath += fileExtension; // add the file Extension
}
// save
println("Saved: " + savePath);
saveStrings( savePath, strs );
}
void loadIt() {
// load
String[] strs = loadStrings( loadPath );
String str1 = join(strs, "\n");
textBoxEditor.setText(str1);
}
//
}//class
//
// ********************************************************************************
// tab: classTextBoxEditor.pde
// Editor
class TextBoxEditor {
// debug
String testText = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
+"Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a. "+
"venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, "
+"eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur "
+"ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus. sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, "
+"hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit "
+"amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc";
boolean ctrlIsDown=false;
color textColor, textBoxBackgroundColor,
borderColor, // not in use
selectedColor; // not in use
int x, y,
w, h;
// this is the entire text of the editor text area
String[] editorArray = new String[220];
// whether the blinking line is currently on or off
boolean showCursorAsLine=true;
// for cursor movements:
// When we use CRS up and down currentLine changes;
// for CRS left and right currentColumn changes.
int currentColumn = 0; // x-value measured in characters
int currentLine = 0; // y-value measured in lines
// when working within one line by CRS left and right, by backspace and by delete,
// the line is internally split up into 2 strings, which are left and right from the
// cursor. Thus it's easy to do backspace / delete within a line etc.
// See initNewLine() and others.
String leftText="", rightText="";
// ------------------------------------------------------
// constr
TextBoxEditor(String textIn_,
int xxIn_, int yyIn_,
int wwIn_, int hhIn_,
color textColorIn_, color textBoxBackgroundColorIn_,
color bordColorIn_, color slctColorIn_) { // not in use
x = xxIn_;
y = yyIn_;
w = wwIn_;
h = hhIn_;
textColor = textColorIn_;
textBoxBackgroundColor = textBoxBackgroundColorIn_;
// not in use
borderColor = bordColorIn_;
selectedColor = slctColorIn_;
setText(textIn_);
PGraphics dummy = new PGraphics();
// int keyCodePos1; int keyCodeEnd; int keyCodePageUp; int keyCodePageDown;
if (dummy.is3D()) {
// BAD
println("This editor does work only with java (default) and not with P2D or P3D / opengl. ");
exit();
} else {
//Good
}//else
} // constr
// ------------------------------------------------------
void setText(String text1_) {
editorArray = split(text1_, "\n");
currentLine=0;
initNewLine();
} // func
String getText() {
return
join(editorArray, "\n");
} // func
// ------------------------------------------------------
void display() {
// display Editor text box
// draw box
rectMode(CORNER);
noStroke();
fill(textBoxBackgroundColor);
rect(x, y, w, h);
// draw lines
textSize(14);
fill(textColor);
float textx=x+3;
float texty=y+2;
for (int i = 0; i < editorArray.length; i++) {
if (i==currentLine) {
// this is the current line of the cursor
text(leftText + rightText,
textx, texty,
w, h);
blinkingCursor(textx, texty);
} else {
// other lines
text(editorArray[i],
textx, texty,
w, h);
}
//next line
texty+=13;
}//for
//
}//method
// ------------------------------------------------------
// Inputs Keyboard and mouse
void keyPressedInClassEditor() {
if (key==CODED) {
// Coded
checkCodedKeys();
} else {
// NOT Coded
checkNotCodedKeys();
} // NOT Coded
//
} //func
void keyReleasedInClassEditor() {
final int keyCodeCtrl=17;
if (keyCode==keyCodeCtrl) {
ctrlIsDown=false;
}//if
} // func
void mouseInClassEditor() {
// use mouse to set cursor to a position
if (! overEditor() )
return;
textSize(14);
boolean done1=false;
boolean done2=false;
//currentColumn = 0;
//currentLine = 0;
// find currentLine of cursor position
int texty = y+2;
for (int i = 0; i < editorArray.length; i++) {
if (mouseY>texty &&
mouseY<texty+13) {
currentLine = i;
if (currentLine<0)
currentLine=0;
done1 = true;
break;
}//if
//next line
texty+=13;
}//for
if (! done1) // something went wrong
return;
// find currentColumn of cursor position
String currentText="";
for (int i = 0; i < editorArray[currentLine].length(); i++) {
// we check the width of the text letter by letter
float leftWidth = x+textWidth(currentText);
currentText += editorArray[currentLine].charAt(i);
float newWidth = x+textWidth(currentText);
if (mouseX > leftWidth &&
mouseX < newWidth) {
currentColumn = i;
initNewLine(); // currentColumn
done2=true;
break;
}//if
}//for
// when we didn't find a place to insert, we assume the end of the line
if (! done2) {
currentColumn = editorArray[currentLine].length();
initNewLine(); // currentColumn
}//if
//
}//method
// -----------------------------------------------------------------
// smaller funcs for keyboard
void checkNotCodedKeys() {
// not coded......
if (ctrlIsDown) {
// with control
if (key == '1') {
// Ctrl-1
testText=testText.replace(". ", ".\n");
setText(testText);
} else if (keyCode == 'Y') {
// Ctrl-y
deleteLine();
} else {
//
}
//
} else {
// without control
if (key == BACKSPACE) {
if (leftText.length()>0) {
leftText = leftText.substring(0, leftText.length()-1);
currentColumn--;
writeLineBackInArray();
} else {
// we are at start of line and with Backspace we move the entire current line to the end of the last line
currentColumn=0;
if (currentLine==0)
return;
int prevLengthPrevLine=editorArray[currentLine-1].length();
editorArray[currentLine-1]+=editorArray[currentLine];
deleteLine();
currentColumn = prevLengthPrevLine;
currentLine--;
initNewLine();
}
} else if (key == ENTER || key == RETURN) {
doReturnKey();
} else if (key == TAB) {
leftText += " ";
currentColumn+=4;
writeLineBackInArray();
} else if (key == DELETE) {
doDeleteKey();
} else if (key >= ' ') {
// Normal typing of text
leftText += str(key);
currentColumn++;
writeLineBackInArray();
}
// ----
}//else without CTRL
}//method
void checkCodedKeys() {
// Coded
// CODED from now on.....
if (ctrlIsDown) {
// with control key
if (keyCode==36) {
// "Ctrl-Pos1"
writeLineBackInArray();
if (currentLine!=0)
currentLine=0;
else currentColumn=0;
initNewLine();
} else if (keyCode==35) {
// "Ctrl-End"
writeLineBackInArray();
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
// If we are not in last line
if (currentLine!=editorArray.length-1) {
currentLine=editorArray.length-1; // set current line to last line
} else {
currentColumn=editorArray[currentLine].length(); // if we are there already, set the column to end of line
}
initNewLine();
} else if (keyCode==33) {
//text1 = "Ctrl-Pg Up";
} else if (keyCode==34) {
//text1 = "Ctrl-Pg Down";
}
} else {
// without control key
if (keyCode == LEFT) {
decreaseCurrentColumn();
} else if (keyCode == RIGHT) {
increaseCurrentColumn();
} else if (keyCode == UP) {
// previous line in text
writeLineBackInArray();
currentLine--;
if (currentLine<0)
currentLine=0;
initNewLine(); // currentColumn
} else if (keyCode == DOWN) {
// next line in text
writeLineBackInArray();
currentLine++;
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
initNewLine(); // currentColumn
}
//---
else if (keyCode==36) {
// text1 = "Pos1";
currentColumn=0;
initNewLine();
} else if (keyCode==35) {
// text1 = "End";
currentColumn=editorArray[currentLine].length();
initNewLine();
} else if (keyCode==33) {
// text1 = "Pg Up";
currentLine-=4;
if (currentLine<0)
currentLine=0;
initNewLine();
} else if (keyCode==34) {
// text1 = "Pg Down";
currentLine+=4;
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
initNewLine();
}
//
}//else without control key
}//func
void doReturnKey() {
editorArray[currentLine]=leftText;
String[] newLineArray=new String[1];
newLineArray[0] = rightText;
// Splice one array of values into another
editorArray = splice(editorArray, newLineArray, currentLine+1);
currentLine++;
currentColumn = 0;
initNewLine();
}
void doDeleteKey() {
// Do delete key
if (rightText.length()-1>=0) {
// Delete char right of the cursor (normal situation)
rightText = rightText.substring(1); // remove 1st char in rightText
writeLineBackInArray();
} else {
//
writeLineBackInArray();
// rightText += editorArray[currentLine+1];
int prevLengthPrevLine=editorArray[currentLine].length();
if (editorArray.length<=1)
return;
if (currentLine+1>=editorArray.length)
return;
editorArray[currentLine] += editorArray[currentLine+1];
// writeLineBackInArray();
currentLine++;
deleteLine();
writeLineBackInArray();
currentLine--;
currentColumn=prevLengthPrevLine;
initNewLine();
// writeLineBackInArray();
}//else
//
}//method
// -------------------------------------------------------------------
boolean overEditor() {
if (mouseX >= x &&
mouseX <= x+w &&
mouseY >= y &&
mouseY <= y+h) {
return true;
} else {
return false;
}
} // method
void spliceNewTextIntoEditor (String[] newArray) {
// Splice one array of values into another.
// (This can be used when we load a second file and insert it in the editor at cursor position.)
// Not in use.
editorArray = splice(editorArray, newArray, currentLine);
} // method
void initNewLine() {
// when entering a new line
// we set left and right String leftText and rightText
// when column # too small, fix it
if (currentColumn<0) {
currentColumn=0;
}
// when no text is present, we make an empty text
if (editorArray.length<=0) {
editorArray=new String[1];
editorArray[0]="";
}
//if line number is too high, fix it
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
// column is too low, fix it
if (currentLine<0)
currentLine=0;
if (currentColumn > editorArray[currentLine].length()) {
currentColumn=editorArray[currentLine].length(); //-1? ???
if (currentColumn<0)
currentColumn=0;
}
// set left and right String
leftText = editorArray[currentLine].substring( 0, currentColumn);
rightText = editorArray[currentLine].substring( currentColumn );
//
} // method
void writeLineBackInArray() {
// when leaving a line, the leftText + rightText needs to go back in the array
editorArray[currentLine] = leftText + rightText;
} // method
void decreaseCurrentColumn() {
currentColumn--;
if (currentColumn<0)
currentColumn=0;
initNewLine();
} // method
void increaseCurrentColumn() {
currentColumn++;
if (currentColumn>editorArray[currentLine].length())
currentColumn=editorArray[currentLine].length();
// initNewLine();
leftText = editorArray[currentLine].substring( 0, currentColumn);
rightText = editorArray[currentLine].substring( currentColumn );
} // method
void blinkingCursor( float textx, float texty) {
if ((frameCount%11) == 0) {
showCursorAsLine= ! showCursorAsLine;
}
if (showCursorAsLine) {
float leftWidth = textWidth(leftText);
stroke(255, 0, 0);
strokeWeight(1);
line(textx+leftWidth, texty,
textx+leftWidth, texty+19);
stroke(0);
}
} // method
void newText() {
// New
// editorArray = split(text1, "\n");
editorArray = split("Hello", "\n");
currentLine=0;
currentColumn=0;
initNewLine();
} // method
void deleteLine() {
// delete line
writeLineBackInArray();
String[] before = (String[]) subset(editorArray, 0, currentLine);
String[] after = (String[]) subset(editorArray, currentLine+1);
editorArray = (String[]) concat(before, after);
initNewLine();
} // method
//
}//class
//
// ********************************************************************************
// tab: InputsKeys.pde
// Inputs Keyboard
void keyPressed() {
switch (state) {
case normal:
if (key==ESC) {
key=0; // kill
}
// editor codes !
textBoxEditor.keyPressedInClassEditor();
break;
case save:
case load:
// ignore
break;
default:
// Error
println("Error 975: "+"unknown state "+(state));
exit();
break;
}//switch
//
} //func
public void keyEvent(KeyEvent ke) {
if (ke.getAction() == KeyEvent.PRESS) {
textBoxEditor.ctrlIsDown = (ke.getModifiers() & KeyEvent.CTRL) == KeyEvent.CTRL;
}
}
void keyReleased() {
if (state!=normal)
return;
// editor codes !
textBoxEditor.keyReleasedInClassEditor();
} // func
// ********************************************************************************
// tab: InputsMouse1.pde
// Inputs mouse
void mousePressed() {
if (state!=normal)
return;
String command="";
// for the buttons
for (Button currentButton : listButton) {
if (currentButton.checkMouse()) {
command=currentButton.textButton;
break;
}//if
} //for
// found a mouse button like save/load/new
if (! command.equals("")) {
// execute
doCommand(command);
} else {
// editor :
textBoxEditor.mouseInClassEditor();
}//else editor
//
} //func
// --------------------------------------------------------------------------------
void doCommand(String command) {
//
if (command.equals(""))
return;
switch(command) {
case "Load":
classSaveLoadTools.initLoad();
break;
case "Save":
classSaveLoadTools.initSave();
break;
case "New":
textBoxEditor.newText();
break;
default:
// Error
println("unknown command "+command);
exit();
break;
}//switch
//
} //func
//
// ********************************************************************************
// tab: States.pde
// The states of the program
void drawForStateNormal() {
background(0);
// title
fill(255, 2, 2);
textSize(14);
text("Little Editor",
width-133, 20,
130, 422);
// buttons
for (Button currentButton : listButton) {
currentButton.display();
} //for
// show Editor Text Box
textBoxEditor.display();
textSize(24);
//
}
//
// ********************************************************************************
// tab: ToolsSaveLoad.pde
// the two 'callback' functions MUST BE OUTSIDE THE CLASS
// this tab is an addition to the class
void fileSelectedSave(File selection) {
// the 'callback' function
if (selection == null) {
// Window was closed or the user hit cancel
// go back
state=normal;
} else {
// User selected selection.getAbsolutePath()
classSaveLoadTools.savePath=selection.getAbsolutePath();
}
}
void fileSelectedLoad(File selection) {
// the 'callback' function
if (selection == null) {
// Window was closed or the user hit cancel
// go back
state=normal;
} else {
// User selected selection.getAbsolutePath()
classSaveLoadTools.loadPath=selection.getAbsolutePath();
}
}
//
// End of joined file. ********************************************************************************
This is the sample code I was looking for.
Thank you.
Very nice source code.