As a seminar, I was asked to implement a phone book on a file and use a design pattern. I chose the observer. The implementation is a client-server. I created a server class that manages the file. The client communicate to the server, and the client thread registered to the observer. My goal is to whenever there is an update of the file (deletion, adding etc.) all the clients's GUI refresh.
I would like for help.
The server class:
public class Server extends Application implements Observer {
//implements Observer
private TextArea ta = new TextArea();
private int clientNo = 0;
private int flag = 0;
private int lockId;
private RandomAccessFile raf;
#SuppressWarnings("rawtypes")
private ArrayList<HandleAClient> clients;
private HandleAClient clientThread;
//Specify the size of five string fields in the record
final static int NAME_SIZE = 32;
final static int STREET_SIZE = 32;
final static int CITY_SIZE = 20;
final static int STATE_SIZE = 2;
final static int ZIP_SIZE = 5;
final static int RECORD_SIZE = (NAME_SIZE + STREET_SIZE
+ CITY_SIZE + STATE_SIZE + ZIP_SIZE);
private int[] fromToSortChoices =
{ 0, NAME_SIZE, NAME_SIZE + STREET_SIZE ,
NAME_SIZE + STREET_SIZE + CITY_SIZE ,
NAME_SIZE + STREET_SIZE + CITY_SIZE + STATE_SIZE,
NAME_SIZE + STREET_SIZE + CITY_SIZE + STATE_SIZE + ZIP_SIZE
};
private Socket socket;
private ServerSocket serverSocket;
final static String fileName0 = "address0";
public static void main(String[] args)
{ launch(args);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
public void start(Stage primaryStage){
// Open or create a random access file
try
{
raf = new RandomAccessFile(fileName0 + ".dat", "rw");
raf.setLength(0);
this.clients = new ArrayList<Server.HandleAClient>();
}
catch (IOException e1)
{ System.out.print("Error: " + e1);
System.exit(0);
}
// Create a scene and place it in the stage
Scene scene = new Scene(new ScrollPane(ta), 450, 200);
primaryStage.setTitle("Server"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
primaryStage.setAlwaysOnTop(true);
primaryStage.setOnCloseRequest(e->{
try{
socket.close();
serverSocket.close();
Platform.exit();
System.exit(0);
}
catch(Exception e1){
}});
new Thread( () ->{
try {
serverSocket = new ServerSocket(8000);
Platform.runLater(() ->
ta.appendText("Server started at " + new Date() + '\n'));
while(true){
socket = serverSocket.accept();
clientNo++;
Platform.runLater(() ->
ta.appendText("Starting thread for client " + clientNo + " at " + new Date() + '\n'));
InetAddress clientInetAddress = socket.getInetAddress();
Platform.runLater(() ->{
ta.appendText("Client " + clientNo + "'s host name is " + clientInetAddress.getHostName() + "\n");
ta.appendText("Client " + clientNo + "'s IP Address is " + clientInetAddress.getHostAddress() + "\n");
});
clientThread =
new HandleAClient(socket,clientNo);
Thread t = new Thread(clientThread);
clientThread.addObserver(Server.this);
clients.add(clientThread);
t.start();
}
}
catch(IOException ex) {
System.err.println(ex);
}
}).start();
}
class HandleAClient extends Observable implements Runnable {
//extends Observable
private Socket connectToClient;
private int id;
private long currentPosition = 0;
DataInputStream FromClient;
DataOutputStream ToClient;
public HandleAClient(Socket socket,int id) {
this.connectToClient = socket;
this.id = id;
}
public void run() {
try {
// Create data input and output streams
FromClient =
new DataInputStream(connectToClient.getInputStream());
ToClient =
new DataOutputStream(connectToClient.getOutputStream());
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
long fromPosition = raf.getFilePointer() - 2 * RECORD_SIZE;
long numberOfRecordsToCopy =
(raf.length()- fromPosition) / (2 * RECORD_SIZE);
long numberOfRecords;
while (true) {
System.out.println("server wait");
// synchronized (Thread.class) {
ToClient.writeLong(raf.length());
ToClient.flush();
String type = FromClient.readUTF();
switch (type) {
case ("Clear"):
{
raf.setLength(0);
setChanged();
notifyObservers();
}
break;
case ("Add"):
{
writeAddress(raf.length());
//currentPosition = raf.getFilePointer();
setChanged();
notifyObservers();
ToClient.writeLong(currentPosition);
}
break;
case ("First"):
{
System.out.println("server start first");
if (raf.length() > 0) readAddress(0);
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
System.out.println("server done first");
}
break;
case ("Next"):
{
currentPosition = FromClient.readLong();
if (currentPosition < raf.length()) {
readAddress(currentPosition);}
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
}
break;
case ("Previous"):
{
currentPosition = FromClient.readLong();
if (currentPosition - 2 * 2 * RECORD_SIZE > 0)
readAddress(currentPosition - 2 * 2 * RECORD_SIZE);
else if (raf.length() > 0) readAddress(0);
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
}
break;
case ("Last"):
{
long lastPosition = raf.length();
ToClient.writeLong(lastPosition);
if (lastPosition > 0)
readAddress(lastPosition - 2 * RECORD_SIZE);
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
}
break;
case ("Midst"):
{
numberOfRecords = (raf.length()) / (2 * RECORD_SIZE);
ToClient.writeLong(numberOfRecords);
if (numberOfRecords > 0)
readAddress((numberOfRecords/2)*(2*RECORD_SIZE));
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
}
break;
case "Update":
{
currentPosition = FromClient.readLong();
if (currentPosition > 0) {
currentPosition = currentPosition - 2*RECORD_SIZE;
ToClient.writeLong(currentPosition);}
writeAddress(currentPosition);
//currentPosition = raf.getFilePointer();
setChanged();
notifyObservers();
ToClient.writeLong(currentPosition);
}
break;
case "Delete":
{
currentPosition = FromClient.readLong();
numberOfRecords = (raf.length()) / (2 * RECORD_SIZE);
ToClient.writeLong(numberOfRecords);
if (numberOfRecords == 0) {
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
return;
}
else if (numberOfRecords == 1)
{
raf.setLength(0);
currentPosition = raf.getFilePointer();
ToClient.writeLong(currentPosition);
return;
}
fromPosition = currentPosition;
long toPosition = fromPosition - 2*RECORD_SIZE;
numberOfRecordsToCopy = (raf.length()- fromPosition) / (2 * RECORD_SIZE);
ToClient.writeLong(numberOfRecordsToCopy);
for (int i=0; i < numberOfRecordsToCopy; i++ )
{
readAddress(fromPosition);
writeAddress(toPosition);
fromPosition += 2*RECORD_SIZE;
toPosition += 2*RECORD_SIZE;
}
raf.setLength(raf.length() - 2*RECORD_SIZE);
ToClient.writeLong(raf.length());
readAddress(0);
currentPosition = raf.getFilePointer();
setChanged();
notifyObservers();
ToClient.writeLong(currentPosition);
}
break;
case "Insert":
{
currentPosition = FromClient.readLong();
if (raf.length() == 0)
{
writeAddress(raf.length());
ToClient.writeLong(raf.getFilePointer());
return;
}
fromPosition = currentPosition-2*RECORD_SIZE;
long currentFrom = raf.length() - 2*RECORD_SIZE;
numberOfRecordsToCopy = (raf.length()- fromPosition) / (2 * RECORD_SIZE);
ToClient.writeLong(numberOfRecordsToCopy);
for (int i=0; i < numberOfRecordsToCopy; i++ )
{
readAddress(currentFrom);
writeAddress(currentFrom + 2*RECORD_SIZE);
currentFrom -= 2*RECORD_SIZE;
}
writeAddress(fromPosition);
raf.setLength(raf.length() - 2*RECORD_SIZE);
readAddress(0);
currentPosition = raf.getFilePointer();
setChanged();
notifyObservers();
ToClient.writeLong(currentPosition);
}
break;
case "Duplicate":
{
numberOfRecords = (raf.length()) / (2 * RECORD_SIZE);
ToClient.writeLong(numberOfRecords);
for (int i=0; i < numberOfRecords; i++ )
{
readAddress(i*2*RECORD_SIZE);
writeAddress(raf.length());
}
if (numberOfRecords>0) readAddress(0);
setChanged();
notifyObservers();
ToClient.writeLong(currentPosition);
}
break;
case "Sort":
{
sortFile();
if (raf.length() > 0)
{
readAddress(0);
}
setChanged();
notifyObservers();
}
break;
}
//}
Platform.runLater(() ->{
ta.appendText("Done operation for client "+ this.id + "\n");
});
}
}
catch(IOException e) {
System.err.println(e);
}
}
private void sortFile() {
try {
int size = (int) (raf.length() / RECORD_SIZE / 2);
int ascORdes, from, to, idx;
raf.seek(0);
if (raf.length() == 0) return ;
ascORdes = FromClient.readBoolean() ? -1 : 1;
String fileToSort[];
fileToSort = new String[size];
for (int i = 0; i < size;i++)
{
fileToSort[i] =
FixedLengthStringIO.readFixedLengthString(RECORD_SIZE, raf);
}
idx = FromClient.readInt();
from = fromToSortChoices[idx];
to = fromToSortChoices[idx+1];
HeapSortaORd.heapSortaORd(fileToSort, ascORdes, from, to);
raf.seek(0);
for (int i = 0; i < size;i++)
{
FixedLengthStringIO.writeFixedLengthString(
fileToSort[i], RECORD_SIZE, raf);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
private void readAddress(long position) {
try {
raf.seek(position);
String name =
FixedLengthStringIO.readFixedLengthString(NAME_SIZE, raf);
String street =
FixedLengthStringIO.readFixedLengthString(STREET_SIZE, raf);
String city =
FixedLengthStringIO.readFixedLengthString(CITY_SIZE, raf);
String state =
FixedLengthStringIO.readFixedLengthString(STATE_SIZE, raf);
String zip =
FixedLengthStringIO.readFixedLengthString(ZIP_SIZE, raf);
ToClient.flush();
ToClient.writeUTF(name);
ToClient.flush();
ToClient.writeUTF(street);
ToClient.flush();
ToClient.writeUTF(city);
ToClient.flush();
ToClient.writeUTF(state);
ToClient.flush();
ToClient.writeUTF(zip);
ToClient.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void writeAddress(long position) {
try
{ raf.seek(position);
String name = FromClient.readUTF();
String street = FromClient.readUTF();
String city = FromClient.readUTF();
String state = FromClient.readUTF();
String zip = FromClient.readUTF();
FixedLengthStringIO.writeFixedLengthString(name
== null ? " " : name, NAME_SIZE, raf);
FixedLengthStringIO.writeFixedLengthString(street
== null ? " " : street, STREET_SIZE, raf);
FixedLengthStringIO.writeFixedLengthString(city
== null ? " " : city, CITY_SIZE, raf);
FixedLengthStringIO.writeFixedLengthString(state
== null ? " " : state, STATE_SIZE, raf);
FixedLengthStringIO.writeFixedLengthString(zip
== null ? " " : zip, ZIP_SIZE, raf);
}
catch (IOException e1)
{ e1.printStackTrace();
}
}
}
#Override
public void update(Observable observable, Object object) {
this.flag = 0;
for (int i = 0; i < clients.size(); i++) {
System.out.println("File changed. Client " + clients.get(i).id + " back to first");
clients.get(i).currentPosition = 0;
}
}
}
The client class:
public class Client extends Application
//extends Observable
{ // IO streams
DataOutputStream toServer = null;
DataInputStream fromServer = null;
Socket socket;
//Specify the size of five string fields in the record
final static int NAME_SIZE = 32;
final static int STREET_SIZE = 32;
final static int CITY_SIZE = 20;
final static int STATE_SIZE = 2;
final static int ZIP_SIZE = 5;
final static int RECORD_SIZE = (NAME_SIZE + STREET_SIZE
+ CITY_SIZE + STATE_SIZE + ZIP_SIZE);
final static String fileName0 = "address0";
// Text fields
private TextField jtfName = new TextField();
private TextField jtfStreet = new TextField();
private TextField jtfCity = new TextField();
private TextField jtfState = new TextField();
private TextField jtfZip = new TextField();
// Buttons
private Button jbtAdd = new Button("Add");
private Button jbtFirst = new Button("First");
private Button jbtNext = new Button("Next");
private Button jbtPrevious = new Button("Previous");
private Button jbtLast = new Button("Last");
private Button jbtMidst = new Button("Midst");
private Button jbtUpdate = new Button("Update");
private Button jbtDelete = new Button("Delete");
private Button jbtInsert = new Button("Insert");
private Button jbtClear = new Button("Clear");
private Button jbtDuplicate = new Button("Duplicate");
private Button jbtDoSort = new Button("Perform Sort");
private GridPane jpSortPanel;
private RadioButton jrbSortDecsend;
private RadioButton jrbSortAcsend;
private ToggleGroup bgSortType;
private ObservableList<String> sortChoices =
FXCollections.observableArrayList(
"Name", "Street", "City", "State", "Zip");
private GridPane mainPane =new GridPane();
#SuppressWarnings("rawtypes")
private ComboBox jcbSortChoices;
private DataOutputStream ToServer;
private DataInputStream FromServer;
private long fileLength;
private long currentPosition;
private long numberOfRecords;
private long numberOfRecordsToCopy;
private TextArea ta = new TextArea();
private int flag = 0;
#Override // Override the start method in the Application class
public void start(Stage primaryStage)
{
/** Make scene and add to Application **/
jtfName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
jtfStreet.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
jtfCity.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
jtfState.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
jtfZip.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
// Panel jpAddress for holding labels & text fields
GridPane jpAddress = new GridPane();
String LabelColumn[]={"Name","Street","City"};
Label l[]=new Label[LabelColumn.length];
for(int i=0;i<LabelColumn.length;i++)
{
l[i] = new Label(LabelColumn[i]);
l[i].setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
}
jpAddress.addColumn(0,l);
// Panel jpStateZip for holding state and zip
GridPane jpStateZip = new GridPane();
jpStateZip.addRow(0, new Label("State"),jtfState,new Label("Zip"),jtfZip);
// Panel p3 for holding jtfCity and jpStateZip
GridPane p3 = new GridPane();
p3.addRow(0, jtfCity,jpStateZip);
growChildren(jpStateZip);
growChildren(p3);
jpAddress.addColumn(1, jtfName, jtfStreet,p3);
// Set the panel with line border
jpAddress.getStyleClass().add(
"{ -fx-border-color: black;-fx-border-width: 5;}");
growChildren(jpAddress);
// Add buttons to a panel
GridPane jpButton = new GridPane();
HBox hb = new HBox();
hb.getChildren().addAll(jbtAdd,jbtFirst,jbtNext,jbtPrevious,jbtLast,jbtMidst,jbtUpdate,jbtDelete,jbtInsert,jbtClear,jbtDuplicate);
jpButton.addRow(0, hb);
growChildren(jpButton);
// Add jpAddress and jpButton to the mainPane
mainPane.addColumn(0, jpAddress,jpButton,ta);
/* ============ sort Panel ============ */
jpSortPanel = new GridPane();
jrbSortAcsend = new RadioButton("Ascending");
jrbSortAcsend.setSelected(true);
jrbSortDecsend = new RadioButton("descending");
jcbSortChoices = new ComboBox<String>(sortChoices);
jcbSortChoices.getSelectionModel().selectFirst();
bgSortType = new ToggleGroup();
bgSortType.getToggles().addAll(jrbSortAcsend,jrbSortDecsend);
jpSortPanel.addColumn(0, jrbSortAcsend,jrbSortDecsend,jcbSortChoices);
growChildren(jpSortPanel);
/* ========== end of sort panel ======= */
jbtDoSort.setMaxWidth(Double.MAX_VALUE);
mainPane.addColumn(1, jpSortPanel,jbtDoSort);
growChildren(mainPane);
try {
socket = new Socket("localhost", 8000);
// Create an input stream to receive data from the server
FromServer = new DataInputStream(socket.getInputStream());
// Create an output stream to send data to the server
ToServer = new DataOutputStream(socket.getOutputStream());
currentPosition = FromServer.readLong();
primaryStage.setOnCloseRequest(e->{
try{
socket.close();
Platform.exit();
System.exit(0);
}
catch(Exception e1){
e1.printStackTrace();
}});
}
catch (IOException ex) {
ex.printStackTrace();
}
jbtClear.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Clear");
clearTextFields();
currentPosition = 0;
} catch (Exception e1) {
e1.printStackTrace();
}
System.out.println("client done clear");
});
jbtAdd.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Add");
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
currentPosition = FromServer.readLong();
System.out.println("client done add");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtFirst.setOnAction(e ->
{
System.out.println("client start first");
try {
first();
System.out.println("client done first");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtNext.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Next");
ToServer.writeLong(currentPosition);
if (currentPosition < fileLength) {
readAddress();}
currentPosition = FromServer.readLong();
System.out.println("client done next");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtPrevious.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Previous");
ToServer.writeLong(currentPosition);
if (currentPosition - 2 * 2 * RECORD_SIZE > 0)
readAddress();
else if (fileLength > 0) readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done previous");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtLast.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Last");
long lastPosition = FromServer.readLong();
if (lastPosition > 0)
readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done last");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtMidst.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Midst");
numberOfRecords = FromServer.readLong();
if (numberOfRecords > 0)
readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done midst");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtUpdate.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Update");
ToServer.writeLong(currentPosition);
if (currentPosition > 0)
currentPosition = FromServer.readLong();
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
currentPosition = FromServer.readLong();
System.out.println("client done update");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtDelete.setOnAction(e ->
{ try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Delete");
ToServer.writeLong(currentPosition);
numberOfRecords = FromServer.readLong();
if (numberOfRecords == 0) {
currentPosition = FromServer.readLong();
return;
}
else if (numberOfRecords == 1)
{
clearTextFields();
currentPosition = FromServer.readLong();
return;
}
numberOfRecordsToCopy = FromServer.readLong();
for (int i=0; i < numberOfRecordsToCopy; i++ )
{
readAddress();
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
}
fileLength = FromServer.readLong();
readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done delete");
}catch (Exception e1) {
e1.printStackTrace();
}
});
jbtInsert.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Insert");
ToServer.writeLong(currentPosition);
if (fileLength == 0)
{
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
currentPosition = FromServer.readLong();
System.out.println("client done insert");
return;
}
String recordToInsert[] = { jtfName.getText(), jtfStreet.getText(), jtfCity.getText(),
jtfState.getText(), jtfZip.getText()};
numberOfRecordsToCopy = FromServer.readLong();
for (int i=0; i < numberOfRecordsToCopy; i++ )
{
readAddress();
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
}
//readAddress();
jtfName.setText(recordToInsert[0]);
jtfStreet.setText(recordToInsert[1]);
jtfCity.setText(recordToInsert[2]);
jtfState.setText(recordToInsert[3]);
jtfZip.setText(recordToInsert[4]);
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done insert");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtDuplicate.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Duplicate");
//ToServer.writeLong(currentPosition);
numberOfRecords = FromServer.readLong();
for (int i=0; i < numberOfRecords; i++ )
{
readAddress();
ToServer.writeUTF(jtfName.getText());
ToServer.writeUTF(jtfStreet.getText());
ToServer.writeUTF(jtfCity.getText());
ToServer.writeUTF(jtfState.getText());
ToServer.writeUTF(jtfZip.getText());
}
if (numberOfRecords>0) readAddress();
currentPosition = FromServer.readLong();
System.out.println("client done duplicate");
} catch (Exception e1) {
e1.printStackTrace();
}
});
jbtDoSort.setOnAction(e ->
{
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("Sort");
ToServer.writeBoolean(jrbSortDecsend.isSelected());
ToServer.writeInt(jcbSortChoices.getSelectionModel().getSelectedIndex());
} catch (Exception e1) {
e1.printStackTrace();
}
if (fileLength > 0) readAddress();
System.out.println("client done sort");
});
/** Add to details and run Application **/
Scene scene = new Scene (mainPane, -100, -100);
primaryStage.setTitle("Complex Address System"); // Set the window title
primaryStage.setScene(scene); // Place the scene in the window
primaryStage.setAlwaysOnTop(true);
primaryStage.show(); // Display the window
primaryStage.setOnCloseRequest( new EventHandler<WindowEvent>(){
public void handle(WindowEvent event){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
System.exit(0);
}
});
}
private void first() {
try {
fileLength = FromServer.readLong();
ToServer.writeUTF("First");
ToServer.flush();
if (fileLength > 0) readAddress();
currentPosition = FromServer.readLong();
} catch (Exception e1) {
e1.printStackTrace();
}
}
#SuppressWarnings("static-access")
private void growChildren(GridPane pane)
{ pane.getChildren().forEach(chiled ->
{ pane.setHgrow(chiled, Priority.ALWAYS);
pane.setVgrow(chiled, Priority.ALWAYS);
});
}
private void readAddress() {
try {
String name = FromServer.readUTF();
String street = FromServer.readUTF();
String city = FromServer.readUTF();
String state = FromServer.readUTF();
String zip = FromServer.readUTF();
jtfName.setText(name);
jtfStreet.setText(street);
jtfCity.setText(city);
jtfState.setText(state);
jtfZip.setText(zip);
} catch (IOException e) {
e.printStackTrace();
}
}
private void clearTextFields() {
jtfName.setText(null);
jtfStreet.setText(null);
jtfCity.setText(null);
jtfState.setText(null);
jtfZip.setText(null);
}
public static void main(String[] args)
{ launch(args);
}
}
Related
I'm using Xamarin.Forms.Map and I want to show pins on my map with already expanded window message(without click on them). Something like screenshot. By default window message show only after I clicked on them. How can I do this?
I did a test based on this sample:sample
The thing I do is override the GetViewForAnnotation method.
I add a subview and set it's position based on pin's position.
Here is relative code:
[assembly:ExportRenderer(typeof(CustomMap),typeof(CustomMapRenderer))]
namespace My_Forms_Test3.iOS
{
public class CustomMapRenderer:MapRenderer
{
UIView customPinView;
List<CustomPin> customPins;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
var nativeMap = Control as MKMapView;
nativeMap.GetViewForAnnotation = null;
nativeMap.CalloutAccessoryControlTapped -= OnCallourAccessoryControlTapped;
nativeMap.DidSelectAnnotationView -= OnDidSelect;
nativeMap.DidDeselectAnnotationView -= OnDidDeSelect;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
var nativeMap = Control as MKMapView;
customPins = formsMap.CustomPins;
nativeMap.GetViewForAnnotation = GetViewForAnnotation;
nativeMap.CalloutAccessoryControlTapped += OnCallourAccessoryControlTapped;
nativeMap.DidSelectAnnotationView += OnDidSelect;
nativeMap.DidDeselectAnnotationView += OnDidDeSelect;
}
}
private void OnDidDeSelect(object sender, MKAnnotationViewEventArgs e)
{
if (!e.View.Selected)
{
customPinView.RemoveFromSuperview();
customPinView.Dispose();
customPinView = null;
}
}
private void OnDidSelect(object sender, MKAnnotationViewEventArgs e)
{
throw new NotImplementedException();
}
private void OnCallourAccessoryControlTapped(object sender, MKMapViewAccessoryTappedEventArgs e)
{
throw new NotImplementedException();
}
protected override MKAnnotationView GetViewForAnnotation(MKMapView mapView, IMKAnnotation annotation)
{
MKAnnotationView annotationView = null;
if (annotation is MKUserLocation)
return null;
var customPin = GetCustomPin(annotation as MKPointAnnotation);
if (customPin == null)
{
throw new Exception("not found");
}
annotationView = mapView.DequeueReusableAnnotation(customPin.Name);
if (annotationView == null)
{
annotationView = new CustomMKAnnotationView(annotation, customPin.Name);
annotationView.Image = UIImage.FromFile("pin.png");
annotationView.CalloutOffset = new CGPoint(0, 0);
annotationView.LeftCalloutAccessoryView = new UIImageView(UIImage.FromFile("monkey.png"));
annotationView.RightCalloutAccessoryView = UIButton.FromType(UIButtonType.DetailDisclosure);
((CustomMKAnnotationView)annotationView).Name = customPin.Name;
customPinView = new UIView();
var Label = new UILabel();
Label.Text = "Samsung";
Label.Frame=new CGRect(annotationView.GetFrame().X+35,annotationView.GetFrame().Y,100,50);
var Label2 = new UILabel();
Label2.Text = "20:20";
Label2.Frame = new CGRect(annotationView.GetFrame().X + 35, annotationView.GetFrame().Y+20, 100, 50);
customPinView.Frame= new CGRect(annotationView.GetFrame().X+40, annotationView.GetFrame().Y-20, 100, 50);
customPinView.AddSubview(Label);
customPinView.AddSubview(Label2);
Label.BaselineAdjustment = UIBaselineAdjustment.AlignBaselines;
customPinView.BackgroundColor = UIColor.White;
customPinView.Layer.CornerRadius = 5;
customPinView.Alpha = (nfloat)0.8;
customPinView.Layer.MasksToBounds = true;
annotationView.AddSubview(customPinView);
}
annotationView.CanShowCallout = true;
return annotationView;
}
CustomPin GetCustomPin(MKPointAnnotation annotation)
{
var position = new Position(annotation.Coordinate.Latitude, annotation.Coordinate.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{ return pin; }
}
return null;
}}
result:
I have a created a custom Picker with downarrow image at right side using UITextFied in Xamarin ios. When I click the downarrow, the picker is not opening. But when the click centre of the UITextField, the picker is opening. How to open the pickerview when click of downarrow?
[assembly: ExportRenderer(typeof(CustomMonthPicker), typeof(CustomMonthPickerRenderer))]
namespace AMS.iOS.CustomRenderer
{
public class CustomMonthPickerRenderer : ViewRenderer<CustomMonthPicker, UITextField>
{
private DateTime _selectedDate;
private UITextField _dateLabel;
private PickerDateModel _pickerModel;
protected override void OnElementChanged(ElementChangedEventArgs<CustomMonthPicker> e)
{
try
{
base.OnElementChanged(e);
_dateLabel = new UITextField();
var dateToday = Element.Date;
SetupPicker(new DateTime(dateToday.Year, dateToday.Month, 1));
SetNativeControl(_dateLabel);
Control.EditingChanged += ControlOnEditingChanged;
Element.PropertyChanged += Element_PropertyChanged;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void ControlOnEditingChanged(object sender, EventArgs e)
{
if (Element.Date.ToString().Equals(DateTime.MinValue.ToString()))
{
_dateLabel.Text = "";
}
else
{
var monthName = SetMonthNumberToMonthName(Element.Date.Month);
var currentDate = $"{monthName} | {Element.Date.Year}";
if (_dateLabel.Text != currentDate)
{
_dateLabel.Text = currentDate;
}
}
}
protected override void Dispose(bool disposing)
{
Element.PropertyChanged -= Element_PropertyChanged;
base.Dispose(disposing);
}
private void SetupPicker(DateTime date)
{
var datePicker = new UIPickerView();
_pickerModel = new PickerDateModel(datePicker, date);
datePicker.ShowSelectionIndicator = true;
_selectedDate = date;
_pickerModel.PickerChanged += (sender, e) =>
{
_selectedDate = e;
};
datePicker.Model = _pickerModel;
//_pickerModel.MaxDate = Element.MaxDate ?? DateTime.MaxValue;
//_pickerModel.MinDate = Element.MinDate ?? DateTime.MinValue;
var toolbar = new UIToolbar
{
BarStyle = UIBarStyle.Default,
Translucent = true
};
toolbar.SizeToFit();
var doneButton = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done,
(s, e) =>
{
Element.Date = _selectedDate;
if (_selectedDate == DateTime.MinValue)
{
Element.Date = DateTime.Now;
}
var monthNameText = SetMonthNumberToMonthName(Element.Date.Month);
_dateLabel.Text = $"{monthNameText} | {Element.Date.Year}";
MessagingCenter.Send<App>((App)Xamarin.Forms.Application.Current, "PreferredDateChanged");
_dateLabel.ResignFirstResponder();
});
toolbar.SetItems(new[] { new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace), doneButton }, true);
Element.Date = _selectedDate;
var monthName = SetMonthNumberToMonthName(Element.Date.Month);
//if (Element.Date.Equals(DateTime.MinValue.ToString()))
//{
// _dateLabel.Text = "";
//}
//else
if (Element.Date.Year == 1)
{
_dateLabel.Text = "";
}
else
_dateLabel.Text = $"{monthName} | {Element.Date.Year}";
_dateLabel.InputAccessoryView = toolbar;
_dateLabel.TextColor = Element.TextColor.ToUIColor();
_dateLabel.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
_dateLabel.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
_dateLabel.TextAlignment = (UITextAlignment)TextAlignment.Center;
var downarrow = UIImage.FromBundle("brandIcon.png");
CGSize iconSize = downarrow.Size;
if (20 > -1)
iconSize = new CGSize((float)20, (float)20);
UIView paddingView = new UIView(new CGRect(0, 0, iconSize.Width + 8, iconSize.Height + 8));
UIImageView sideView = new UIImageView(new CGRect(0, 4, iconSize.Width, iconSize.Height));
sideView.Image = downarrow;
paddingView.AddSubview(sideView);
paddingView.UserInteractionEnabled = true;
_dateLabel.RightViewMode = UITextFieldViewMode.Always;
_dateLabel.RightView = paddingView;
//var gesture = new UITapGestureRecognizer(()=> {
// if (datePicker != null)
// {
// //datePicker.Hidden = !datePicker.Hidden;
// _dateLabel.InputView.Hidden = !_dateLabel.InputView.Hidden;
// //_dateLabel.AccessibilityRespondsToUserInteraction = true;
// }
//});
//paddingView.AddGestureRecognizer(gesture);
_dateLabel.RightView.UserInteractionEnabled = true;
// _dateLabel.RightView.AddGestureRecognizer(gesture);
_dateLabel.InputView = datePicker;
}
private void Element_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
try
{
if (e.PropertyName == CustomMonthPicker.MaxDateProperty.PropertyName)
{
_pickerModel.MaxDate = Element.MaxDate ?? DateTime.MinValue;
}
else if (e.PropertyName == CustomMonthPicker.MinDateProperty.PropertyName)
{
_pickerModel.MinDate = Element.MinDate ?? DateTime.MaxValue;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
How to open the pickerview when click of downarrow?
As ToolmakerSteve mentioned , we can add a tap gesture on the icon to focus the textfiled and it will open picker view automacially .
Try the following code
UIView paddingView = new UIView(new CGRect(0, 0, iconSize.Width + 8, iconSize.Height + 8));
UIImageView sideView = new UIImageView(new CGRect(0, 4, iconSize.Width, iconSize.Height));
sideView.Image = downarrow;
paddingView.AddSubview(sideView);
paddingView.UserInteractionEnabled = true;
_dateLabel.RightViewMode = UITextFieldViewMode.Always;
_dateLabel.RightView = paddingView;
//add this
sideView.UserInteractionEnabled = true;
UITapGestureRecognizer tap = new UITapGestureRecognizer(()=> {
_dateLabel.BecomeFirstResponder();
});
paddingView.AddGestureRecognizer(tap);
In one of the apps I'm working on I require the use of custom map pins and I've followed the guide on Xamarin https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/map/customized-pin/ as well as borrowed their sample code to try and make my own example.
It works to a degree in such that the info window is actually updated to the custom layout but the map pin never changes.
My CustomMapRenderer:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
using WorkingWithMaps.Droid.Renderers;
using WorkingWithMaps;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace WorkingWithMaps.Droid.Renderers
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
{
GoogleMap map;
List<CustomPin> customPins;
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
map.InfoWindowClick -= OnInfoWindowClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
((MapView)Control).GetMapAsync(this);
}
}
void IOnMapReadyCallback.OnMapReady(GoogleMap googleMap)
{
map = googleMap;
map.SetInfoWindowAdapter(this);
map.InfoWindowClick += OnInfoWindowClick;
this.NativeMap = googleMap;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("VisibleRegion") && !isDrawn)
{
map.Clear();
foreach (var pin in customPins)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
marker.SetTitle(pin.Pin.Label);
marker.SetSnippet(pin.Pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
map.AddMarker(marker);
}
isDrawn = true;
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
if (changed)
{
isDrawn = false;
}
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Id == "Xamarin")
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Pin.Position == position)
{
return pin;
}
}
return null;
}
}
}
and my map page, also heavily borrowed from Xamarin's working with maps guide
using Plugin.Geolocator;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Xaml;
namespace WorkingWithMaps
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
CustomMap map;
Geocoder geoCoder;
String navAdd;
public MainPage()
{
InitializeComponent();
var maplocator = CrossGeolocator.Current;
maplocator.DesiredAccuracy = 1;
geoCoder = new Geocoder();
map = new CustomMap
{
HeightRequest = 100,
WidthRequest = 960,
VerticalOptions = LayoutOptions.FillAndExpand,
IsShowingUser = true
};
map.MapType = MapType.Street;
map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(55.237208, 10.479160), Distance.FromMeters(500)));
map.IsShowingUser = true;
var street = new Button { Text = "Street" };
var hybrid = new Button { Text = "Hybrid" };
var satellite = new Button { Text = "Satellite" };
street.Clicked += HandleClickedAsync;
hybrid.Clicked += HandleClickedAsync;
//satellite.Clicked += OnReverseGeocodeButtonClicked;
var segments = new StackLayout
{
Spacing = 30,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Orientation = StackOrientation.Horizontal,
Children = { street, hybrid, satellite }
};
Content = new StackLayout
{
HorizontalOptions = LayoutOptions.Center,
Children = { map, segments }
};
Device.BeginInvokeOnMainThread(async () =>
{
try
{
//var currentpos = await maplocator.GetPositionAsync(1000);
//map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(currentpos.Latitude, currentpos.Longitude), Distance.FromMeters(500)));
if (!maplocator.IsListening)
{
await maplocator.StartListeningAsync(1000, 50, true);
}
}
catch (Exception ex)
{
Debug.WriteLine("Fail" + ex);
}
});
var pin = new CustomPin
{
Pin = new Pin
{
Type = PinType.Place,
Position = new Position(55.240121, 10.469895),
Label = "Testing Pins"
}
};
map.CustomPins = new List<CustomPin> { pin };
map.Pins.Add(pin.Pin);
map.PropertyChanged += (sender, e) =>
{
Debug.WriteLine(e.PropertyName + " just changed!");
if (e.PropertyName == "VisibleRegion" && map.VisibleRegion != null)
CalculateBoundingCoordinates(map.VisibleRegion);
};
maplocator.PositionChanged += (sender, e) =>
{
var position = e.Position;
map.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(position.Latitude, position.Longitude), Distance.FromKilometers(2)));
};
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//async void OnReverseGeocodeButtonClicked(object sender, EventArgs e)
//{
// var possibleAddresses = await geoCoder.GetAddressesForPositionAsync(pin.Position);
// navAdd += possibleAddresses.ElementAt(0) + "\n";
// switch (Device.OS)
// {
// case TargetPlatform.iOS:
// Device.OpenUri(new Uri(string.Format("http://maps.apple.com/?q={0}", WebUtility.UrlEncode(navAdd))));
// break;
// case TargetPlatform.Android:
// Device.OpenUri(new Uri(string.Format("geo:0,0?q={0}", WebUtility.UrlEncode(navAdd))));
// break;
// case TargetPlatform.Windows:
// case TargetPlatform.WinPhone:
// Device.OpenUri(new Uri(string.Format("bingmaps:?where={0}", Uri.EscapeDataString(navAdd))));
// break;
// }
//}
void HandleClickedAsync(object sender, EventArgs e)
{
var b = sender as Button;
switch (b.Text)
{
case "Street":
map.MapType = MapType.Street;
break;
case "Hybrid":
map.MapType = MapType.Hybrid;
break;
case "Satellite":
map.MapType = MapType.Satellite;
break;
}
}
static void CalculateBoundingCoordinates(MapSpan region)
{
var center = region.Center;
var halfheightDegrees = region.LatitudeDegrees / 2;
var halfwidthDegrees = region.LongitudeDegrees / 2;
var left = center.Longitude - halfwidthDegrees;
var right = center.Longitude + halfwidthDegrees;
var top = center.Latitude + halfheightDegrees;
var bottom = center.Latitude - halfheightDegrees;
if (left < -180) left = 180 + (180 + left);
if (right > 180) right = (right - 180) - 180;
Debug.WriteLine("Bounding box:");
Debug.WriteLine(" " + top);
Debug.WriteLine(" " + left + " " + right);
Debug.WriteLine(" " + bottom);
}
}
}
On top of the mentioned issue the implementation has also caused IsShowingUser = True to no longer function as well as
var currentpos = await maplocator.GetPositionAsync(1000);
to throw an exception.
Github repository: https://github.com/Mortp/CustomMapPinsXamarin
First of all I would like to provide 2 links that helped me to understand the problem. Thank you guys.
Xamarin.Forms.Maps 2.3.4 custom MapRenderer disables everything and https://forums.xamarin.com/discussion/92565/android-ionmapreadycallback-forms-2-3-4
Latest Xamarin Maps broke OnElementPropertyChanged with VisibleRegion. They defined that MapRenderer now implements IOnMapReadyCallback and that broke somehow OnElementPropertyChanged (I didn't investigate how and why). As you can see in link I provided there are 2 methods you can go. To keep your renderer implementing IOnMapReadyCallback or not. When I kept IOnMapReadyCallback I started to get 2 pins - one of top another - our custom pin and regular pin. I didn't dig more how that happens and removed IOnMapReadyCallback. After that things became really simple because if you let Xamarin handle it and create NativeMap you can remove some code and make renderer simpler.
Before I post the code I also want to mention that when I fixed it the app started crashing with OutOfMemory exception and I found out that your pin image is 2000 pixels width. I changed it to 40. Below is the code:
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter//, IOnMapReadyCallback
{
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
NativeMap.InfoWindowClick -= OnInfoWindowClick;
}
}
bool isMapReady;
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (!isMapReady && (NativeMap != null))
{
NativeMap.SetInfoWindowAdapter(this);
NativeMap.InfoWindowClick += OnInfoWindowClick;
isMapReady = true;
}
if (e.PropertyName.Equals("VisibleRegion") && !isDrawn)
{
NativeMap.Clear();
foreach (var pin in ((CustomMap)Element).CustomPins)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
marker.SetTitle(pin.Pin.Label);
marker.SetSnippet(pin.Pin.Address);
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.pin));
NativeMap.AddMarker(marker);
}
isDrawn = true;
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
if (changed)
{
isDrawn = false;
}
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Id == "Xamarin")
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in ((CustomMap)Element).CustomPins)
{
if (pin.Pin.Position == position)
{
return pin;
}
}
return null;
}
}
The issue I am having is with the "Office" String. I get this: java.lang.NumberFormatException: For input string: "Office:" I feel like I need to do something else with the parseline down in the tokenizer section? Am I on the right track? I am basically trying to read from a file than I will calculate total sales and write to another file. This is the error I get even when I try to display my people.txt file to an output screen on my GUI. I just need a little advice to where to look to fix this. I have looked up many things but have not came close.
public class PersonReader {
public static void main(String args[]) throws IOException {
PersonReader reader = new PersonReader();
List<person> people = reader.readPeople("people.txt");
System.out.println(people);
}
public List<person> readPeople(String filename) throws IOException {
File f = new File(filename);
FileReader reader = new FileReader(f);
BufferedReader breader = new BufferedReader(reader);
List<person> people = new ArrayList<person>();
String line = breader.readLine();
while (line != null) {
person p = null;
try {
p = parseLine(line);
} catch (Exception e) {
e.printStackTrace();
}
if (p == null) {
System.out.println("This row is bad." + line);
} else {
people.add(p);
}
line = breader.readLine();
}
return people;
}
private static person parseLine(String line) {
int repID;
String firstName;
String lastName;
double books;
double paper;
double office;
String district;
String contact;
String next;
StringTokenizer st = new StringTokenizer(line, ", ");
repID = Integer.parseInt(st.nextToken().trim());
firstName = st.nextToken().trim();
lastName = st.nextToken().trim();
books = Double.parseDouble(st.nextToken().trim());
parseLine(line);
paper = Double.parseDouble(st.nextToken().trim());
parseLine(line);
office = Double.parseDouble(st.nextToken().trim());
parseLine(line);
district = st.nextToken().trim();
parseLine(line);
contact = st.nextToken().trim();
parseLine(line);
if (repID < 1) {
return null;
}
if (firstName.length() == 0) {
return null;
}
if (lastName.length() == 0) {
return null;
}
if (books < 1) {
return null;
}
if (paper < 1) {
return null;
}
if (office < 1) {
return null;
}
if (district.length() == 0) {
return null;
}
if (contact.length() == 0) {
return null;
}
person p = new person();
p.setRepID(repID);
p.setFirstName(firstName);
p.setLastName(lastName);
p.setBooks(books);
p.setPaper(paper);
p.setOffice(office);
p.setDistrict(district);
p.setContact(contact);
return p;
}
}
I'm asking for your help.
I'm developing an application in JavaFX who "scan" Mp3 files to get ID3tag.
Here is my problem. I did a foreach loop of a list for every .mp3 found but I'd like to increment a label which inform the progression of the list.
Here is my code
private ArrayList checkMp3File(ArrayList<String> lsMp3file, String sDir) throws UnsupportedTagException, InvalidDataException, IOException
{
this.currentData = 1;
int size = lsMp3file.size();
ArrayList<DataSong> lsds = new ArrayList<>();
for(String mp3file : lsMp3file)
{
this.labelUpdate.setText(this.current++ + " of " + " size");
DataSong ds = new DataSong();
Mp3File mp3 = new Mp3File(mp3file);
ds.setLenghtOfMp3inSec(mp3.getLengthInSeconds());
ds.setBitRateOfMp3(mp3.getBitrate());
ds.setSampleRate(mp3.getSampleRate());
ds.setVbrOrCbr(mp3.isVbr());
}
Actually, when the loop progress my window interface is completely freeze.
And only when the loop is finished, the label updated.
Someone can explain why ?
I already thank you for your answers.
EDIT :
Here is my fully code
public class LaunchOption extends Pane {
private final HBox launchAndSend = new HBox();
private final HBox browseAndField = new HBox();
private final HBox jsonAndAdvance = new HBox();
private ArrayList<DataSong> lsWithData = new ArrayList<>();
private String sendJson;
private File selectedDirectory;
private User user;
private int currentData;
private final ProgressIndicator pi = new ProgressIndicator(0);
private final VBox containerElement = new VBox();
private final TextArea displayJson = new TextArea();
private final TextField pathDir = new TextField();
private final TextField nbrOfData = new TextField();
private final Button btnScan = new Button();
private final Button btnSend = new Button();
private final Button btnCheckJson = new Button();
private final Button btnDirectoryBrowser = new Button();
private final Label nbMp3 = new Label();
public Label listAdvance = new Label();
private final Stage home;
public LaunchOption(Stage home){
this.home = home;
configureBtnCheckJson();
configureBtnScan();
configureBtnSend();
configureLabelMp3();
configureBtnDirectoryBrowser();
configureTextAreaDisplayJson();
configureTextFieldPathDir();
configureTextFieldNbDataMp3();
configureHBoxlaunchSend();
configureHBoxBrowseAndField();
configureHBoxJsonAndAdvance();
configureContainer();
this.getChildren().addAll(containerElement,launchAndSend);
}
private void configureLabelMp3()
{
nbMp3.setText("MP3");
}
private void configureBtnScan(){
btnScan.setText("Scan");
btnScan.setOnAction(event->{
ArrayList<String> Mp3FileData;
Mp3FileData = mapFilesMp3(selectedDirectory.getAbsolutePath());
System.out.println("ListSize = " + Mp3FileData.size());
nbrOfData.setText(String.valueOf(Mp3FileData.size()));
try {
lsWithData = checkMp3File(Mp3FileData, selectedDirectory.getAbsolutePath());
} catch (UnsupportedTagException ex) {
Logger.getLogger(MusiScanMp3agic.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidDataException ex) {
Logger.getLogger(MusiScanMp3agic.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MusiScanMp3agic.class.getName()).log(Level.SEVERE, null, ex);
}
pi.setProgress(1);
});
}
private void configureBtnDirectoryBrowser(){
btnDirectoryBrowser.setText("Browse ...");
btnDirectoryBrowser.getStyleClass().add("round-red");
btnDirectoryBrowser.setOnAction(event-> {
DirectoryChooser dc = new DirectoryChooser();
selectedDirectory = dc.showDialog(home);
pi.setProgress(0.35);
if(selectedDirectory == null)
{
pathDir.setText("No directory selected");
}
else
{
pathDir.setText(selectedDirectory.getAbsolutePath());
String Text = pathDir.getText();
System.out.println(Text.toString());
}
});
}
private static String regexMp3()
{
return "^.*\\.(mp3)$";
}
private ArrayList mapFilesMp3(String sDir){
ArrayList<String> ls = new ArrayList<>();
printFnames(sDir,ls);
return ls;
}
private static void printFnames(String sDir, ArrayList<String> ls)
{
File[] faFiles = new File(sDir).listFiles();
for(File file : faFiles)
{
if(file.getName().matches(regexMp3()))
{
// System.out.println(file.getAbsolutePath());
ls.add(file.getAbsolutePath());
}
if(file.isDirectory())
{
printFnames(file.getAbsolutePath(), ls);
}
}
}
private ArrayList checkMp3File(ArrayList<String> lsMp3file, String sDir) throws UnsupportedTagException, InvalidDataException, IOException
{
this.currentData = 1;
int size = lsMp3file.size();
ArrayList<DataSong> lsds = new ArrayList<>();
for(String mp3file : lsMp3file)
{
System.out.println(this.currentData++);
DataSong ds = new DataSong();
Mp3File mp3 = new Mp3File(mp3file);
ds.setLenghtOfMp3inSec(mp3.getLengthInSeconds());
ds.setBitRateOfMp3(mp3.getBitrate());
ds.setSampleRate(mp3.getSampleRate());
ds.setVbrOrCbr(mp3.isVbr());
if(mp3 != null){
ds.setAbsoluteLocation(mp3.getFilename());
ds.setLocation(removeSDir(mp3.getFilename(), sDir));
if(mp3.hasId3v2Tag())
{
ID3v2 id3v2Tag = mp3.getId3v2Tag();
if(!(id3v2Tag.getArtist() == null))
{
ds.setArtist(id3v2Tag.getAlbumArtist());
}
if(!(id3v2Tag.getAlbum() == null))
{
ds.setAlbum((id3v2Tag.getAlbum()));
}
if(!(id3v2Tag.getTitle() == null))
{
ds.setTitle(id3v2Tag.getTitle());
}
if(!(id3v2Tag.getTrack() == null))
{
ds.setTrackOnAlbum(id3v2Tag.getTrack());
}
if(!(id3v2Tag.getYear() == null) && !(id3v2Tag.getYear().isEmpty()))
{
ds.setYearReleased(id3v2Tag.getYear());
}
if(!(id3v2Tag.getGenreDescription() == null))
{
ds.setGenre(id3v2Tag.getGenreDescription());
}
if(!(id3v2Tag.getComposer() == null))
{
ds.setComposer(id3v2Tag.getComposer());
}
if(!(id3v2Tag.getPublisher() == null))
{
ds.setPublisher(id3v2Tag.getPublisher());
}
if(!(id3v2Tag.getOriginalArtist() == null))
{
ds.setOriginArtist(id3v2Tag.getOriginalArtist());
}
if(!(id3v2Tag.getAlbumArtist() == null))
{
ds.setAlbumArtString(id3v2Tag.getAlbumArtist());
}
if(!(id3v2Tag.getCopyright() == null))
{
ds.setCopyright(id3v2Tag.getCopyright());
}
if(!(id3v2Tag.getUrl() == null))
{
ds.setUrl(id3v2Tag.getUrl());
}
}
}
lsds.add(ds);
}
return lsds;
}
I presume that what I should do is to make my checkMp3File method into a Task method which will do a background thread ?
There is not enough code to be sure but I think you are probably calling your method on the JavaFX application thread which then blocks your UI.
You should read the documentation about concurrency in JavaFX.
https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm