Zapis i odczyt danych. Jak to ugryźć ?

0

Cześć,

Robię swoją pierwszą Apkę w Javie(to tak w formie nauki). Wygląda ona tak:
user image

I teraz opiszę jak to ma funkcjonować...

Po kliknięciu przycisku DODAJ, pola 1 i 2 zapisują się. Tekst z pola 1 pokazuję się w ListView(numer 3). Teraz załóżmy, że włączyłem moją apkę i zapisałem np. 100 pozycji. Chciałbym, aby one wczytywały mi się do ListView, przy każdym ponownym włączeniu aplikacji.

Próbowałem wielu metod(Jestem początkującym programistą Javy, więc pewnie wszystkiego nie zdołałem spróbować) dlatego chciałbym , abyście mi podsunęli pomysł, jak to ugryźć. Nie chcę tutaj gotowych rozwiązań, ale może ktoś mnie jakoś naprowadzi na właściwe tory ?(Na koniec dodam, że fileChooser odpada. Przy zapisywaniu tychże pól, nie chciałbym, aby użytkownik, wybierał sobie nazwę pliku i miejsca, gdzie ma się to zapisać, nie mówiąc już o załadowaniu takiego pliku, gdzie trzeba go szukać właśnie poprzez fileChooser - Chciałbym, aby to działo się... automatycznie, bądź po kliknięciu na odpowiedni BUTTON).

0

Masz kilka możliwości

a) baza zdalna:
stawiasz bazę na jednym serwerze w Internecie i tam trzymasz dane każdego użytkownika

  • jedna centralna baza dla wszystkich
  • łatwość zarządzania
    b) baza lokalna
    tak samo jak baza zdalna, z tym że każdy użytkownik będzie miał bazę danych u siebie lokalnie.
    c) pliki - chyba najlepsze rozwiązanie na początek
    Możesz stworzyć jakiś ukryty folder w katalogu domowym użytkownika (np. http://stackoverflow.com/questions/585534/what-is-the-best-way-to-find-the-users-home-directory-in-java) i tam trzymać jego plik konfiguracyjny i wszystkie dane. Możesz je trzymać w plain text, możesz również serializować sobie to do jsona lub xmla - twój wybór.

Jak masz jakieś pytania to wal śmiało - możesz również na PW.

0

Postanowiłem załatwić sprawę za pomocą serializacji. Jednak utknąłem... czy ktoś poradzi coś na mój wyjątek ?

    public void loadDream(ActionEvent event)
    {
        String fileName = "C:\"Users\"pstan\"workspace\"DreamNote\"sen.txt"; // probowalem rowniez z fileName = "sen.txt"

        Dream dream = null;

        try(
                FileInputStream fis = new FileInputStream(fileName);
                ObjectInputStream ois = new ObjectInputStream(fis); //TUTAJ JEST BLAD
                ) {


        	dream = (Dream) ois.readObject();

        } catch (FileNotFoundException e) {
            System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
            e.printStackTrace();
        } catch (IOException e) {
        	 System.out.println("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"); //TEN BŁĄD SIĘ POJAWIA
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
        	 System.out.println("ccccccccccccccccccccccccccccccccccccc");
            e.printStackTrace();
        }

Jakieś propozycję co może być nie tak ?

Konsola pokazuje mi cos takiego:
java.io.StreamCorruptedException: invalid stream header: 73656E6E

1
  1. Co to
String fileName = "C:\"Users\"pstan\"workspace\"DreamNote\"sen.txt";

za cudo? Zamień na

String fileName = "C:/Users/pstan/workspace/DreamNote/sen.txt";
//lub
String fileName = "C:\\Users\\pstan\\workspace\\DreamNote\\sen.txt";
  1. Pokaż jak zapisujesz.
0
  1. Zamieniłem tak jak napisałeś, ale błąd pozostał identyczny.

Resztę już pokazuję...

  1. Zapisuję tak:
    public static void save(Dream dream)
    {
    	String title = dream.getTitle(); //Klasa Dream ma pola(String) title oraz content. Chcialbym, aby zapisywany plik mial nazwe taka jak tytul, ktory wpisal uzytkownik

    	title+=".txt";
	    try{
	    // Create file
	    FileWriter fstream = new FileWriter(title);
	    BufferedWriter out = new BufferedWriter(fstream);

	    //get the CONTENT from dream
	    String cont = dream.getContent();
	    out.write(cont); //zapisuje sam kontent w pliku ktory nazywa sie tak jak tytul ktory podal uzytkownik

	    //Close the output stream
	    out.close();
	    }catch (Exception e){//Catch exception if any
	    System.err.println("Error: " + e.getMessage());
	    }
    }

Struktura:

user image

1

Jak odbierasz

ObjectInputStream

to wysłanie powinno odbyć się za pomocą ObjectOutputStream

0

Wszystko działa :) Dziękuję za pomoc :). Nie mam pojęcia czemu tego nie zauważyłem...

Ale teraz trafiam na kolejny problem^^. Obiekty klasy Dream, zapisuję do ObservableList<Dream>, aby je wyświetlać w ListView. Po wyłączeniu aplikacji pliki(czyli w moim przypadku obiekty klasy Dream) są zapisane i z tego się niezmiernie cieszę, ale chciałbym teraz żeby te pliki(ich zawartość) "wskakiwały" do mojej listy po ponownym włączeniu apki.

Przy moim obecnym poziomie wiedzy ;] jakoś nie widzę rozwiązania innego niż zastosowanie tutaj fileChoosera(Nie chciałbym, żeby użytkownik musiał wybierać manualnie pliki do wczytania).

Macie jakieś pomysły ?

Z góry dziękuję

0

Po prostu wraz ze starem apki wczytaj ten plik z dysku i powypełniaj danymi z niego co tam sobie chcesz.

0

Czyli dopisywać wszystko do jednego pliku tekstowego i później bawić się operacjami na tekście ?

0

Ok to zabieram sie do pracy. Tylko jeszcze jedno pytanie. Czy jest mozliwosc zapisania/odczytania List do pliku za pomocą serializacji?

1

Można też pisać element po elemencie:

List lista = new Vector<MojaKlasa>();
...
ObjectOutputStream oos = ...;
for(MojaKlasa obiekt:lista)
{
    if(obiekt spełnia warunek)
    {
       oos.write(obiekt);
    }
}
0

Opiszę kolejny problem. zrobiłem 2 okna w mojej apce(po kliknieciu na jakis button otwiera się drugie okno). Na tym pierwszym mam moje listView a na drugim mam przycisk DODAJ, ktory dodaje coś do listView w innym oknie(tym startowym). Przycisk oraz listView są w dwóch odrębnych klasach. Bawiłem się troche polami Static, ale nie udało się tego zrobić bez błędu :/. Czy jest możliwość listView zrobić statyczne, w taki sposób, abym dodawał do niego cos z innej klasy(w moim przypadku jeszcze z innego okna apki) ? Nie mam możliwości podrzucenia kodu. Zrobię to później jeśli nie da się pomóc bez zajrzenia do niego :).

1

Tworząc drugie okno przekaż referencję do pierwszego okna, coś w rodzaju:

DrugieOkno drugie = new DrugieOkno(this);
drugie.setVisible(true);

W konstruktorze drugiego okno zapamiętaj przekazana referencję w polu klasy

    private PierwszeOkno pierwsze = null;
    ...
    public DrugieOkno(PierwszeOkno pierwsze)
    {
        this.pierwsze = pierwsze;

W obsłudze przycisku DODAJ możesz wtedy użyć kodu

pierwsze.listView.add(...);
//lub - zależnie od modyfikatora dostępu do pola listView
pierwsze.getListView().add(...);
0

Troszkę tego nie ogarniam. Nowe okno otwieram tak:

   public void newWindow(ActionEvent event) throws IOException {
		Stage stage = new Stage();
		stage.setTitle("Apka");

		Parent root1 = FXMLLoader.load(getClass().getResource("/fxml/nazwa.fxml"));


/**************************************************************************/
		//SCENA
		Scene scene = new Scene(root1,600,400);
		stage.setScene(scene);
		stage.showAndWait();
    }

i teraz mam dwa pliki .fxml jeden w ktorym jest

    @FXML // fx:id="dreamHistoryList"
	public ListView<String> dreamHistory; // Value injected by FXMLLoader
//oraz
.
.
.
public ArrayList<Dream> listDreams = new ArrayList<Dream>();

do mojego listView pakuje sobie pola w ten sposob:

dreamHistory.getItems().add(title);
//title to pole String z klasy Dream

a w tym drugim pliku .fxml(czyli nowym oknie) mam przycisk ADD(musi wysylac moje *title *do dreamHistory).

    @FXML
    void ADD(ActionEvent event) {

    	}

Zabrać się za otwieranie nowego okna inaczej ?

1

Przekaz do metody newWindow dwa argumenty

public void newWindow(ActionEvent event, PierwszeOkno okno) throws IOException
0

z tym też mam problemy, ale rozwiązałem to inaczej :) ustawilem** ListDreams** na static i w drugim oknie dopisuje obiekty do mojej listy + zapisuje je w pliku. Aby wczytać je do ListView ustawiłem na drugim oknie

stage.setOnCloseRequest(e -> loadDream());
loadDream()

ładuje mi obiekty z pliku do ListView. Obejście problemu długim łukiem, ale to moja pierwsza apka, więc proszę o wyrozumiałość.

Dziękuję wam za udzielanie się w temacie !

0

Posiedziałem dzisiaj nad kolejnym problemem dobrych kilka godzin, ale nie udało mi się go rozwiązać. Mój program wygląda tak:

user image

Pole zaznaczone na zółto to w pliku FXML coś takiego:

<BorderPane>
<center>
.
.
.
</center>
</BorderPane> 

Po kliknięciu w przycisk w przycisk chciałbym, aby moje CENTER uległo zmianie. Robię to tak:

			  contentID.getChildren().clear();//contentID to ID do VBox który chcę zmienić
			  contentID.getChildren().add(FXMLLoader.load(getClass().getResource("/fxml/showDreamFXML.fxml")));

To mi się udało, ale mój nowy plik FXML nie jest responsywny... mianowicie buttony itp które zawiera nie są umiejscowione tak jakbym chciał. Pokazuję screena z nowego pliku FXML(otwartym w Scene Builderze)

user image

Strzałka pokazuję gdzie chciałbym, aby button się przykleił. Jak włączam program na full screen to button jest mniej więcej na środku wysokości okna programu. Jakieś pomysły ? podać kod źródłowy ?

1 użytkowników online, w tym zalogowanych: 0, gości: 1