2017-07-13 6 views
0

J'ai une application JavaFX standard qui étend l'application. La première page que je montre est un tableau de bord avec des boutons pour ouvrir d'autres applications. Tout va bien, la première application est une page admin appelée AdminController qui permet à l'utilisateur de faire des opérations CRUD sur les objets du modèle - utilisateur, contacts, produits chaque entité est un onglet sur la vue admin - donc dans mon Admin FXML principal (Utilisation de SceneBuilder) J'inclus les autres pages fxml en utilisant fx: inclure l'onglet utilisateurs, l'onglet contacts et l'onglet produits. Encore une fois ces inclus sont tous dans un Admin.fxml avec son propre contrôleur.Ordre d'initialisation du contrôleur JavaFx - Base de données appelée plusieurs fois

<Tab fx:id="contactsTab" onSelectionChanged="#goToContacts" text="Contact"> 
    <content> 
    <fx:include source="/fxml/manager_contacts_tab.fxml" fx:id="contact" /> 
    </content 
<Tab/> 

Mon idée était de charger les ressources chaque page aura besoin, les utilisateurs/contacts/produits dans la AdminController sorte que chaque fx: include je peut utiliser ces mêmes objets. Comme certains des onglets ont besoin de toutes ces ressources, comme les utilisateurs pour gérer les associations et d'autres onglets comme les produits, il suffit d'une liste de produits. Mon contrôleur principal ressemble à ceci Je

public class AdminController { 
    @FXML 
    UserController userController; 
    @FXML 
    ProductController productController; 
    @FXML 
    ContactController contactController; 

@FXML 
public void initialize 
    // at this point userController already ran, and called DB so it calls it again here 
    if (users == null) { 
     this.users = FXCollections.observableArrayList(userDao.getAllWithProductsAndContacts()); 
    } 
    if (products == null) { 
     this.products = FXCollections.observableArrayList(productDao.getAll()); 
    } 
    if (contacts == null) { 
     this.contacts = FXCollections.observableArrayList(contactDao.getAll()); 
    } 
    contactController.setContacts(contact); 
    // set other resources, like products 
} 

Logiquement dans ma tête, je pense que la méthode initialize pour AdminController va se lancer d'abord qui permettrait mon de mettre tous les objets qui je dois dans les contrôleurs de l'enfant depuis que je peux accéder à eux, mais ce qui se passe est que les contrôleurs enfants sont exécutés en premier, ex. avec ContactController

public class ContactController { 
    @FXML 
    public void initialize() { 
     if (contacts == null) { 
      this.contacts = FXCollections.observableArrayList(contactDao.getAll()); 
     } 
    } 

donc mes applications initialize exécuter des méthodes dans l'ordre dans lequel ils ont été inclus dans le Je pense que UserController de admin.fxml, contactController, enfin ProductController

ma question se résume à comment puis-je partager des objets entre l'enfant les contrôleurs de sorte que lorsqu'un nouvel onglet est cliqué qui a eu la même liste de ressources que le précédent, un nouvel appel de base de données n'est pas lancé - dans mon exemple, cela se produit lorsque je charge la page utilisateur, liste de contacts et liste de produits mais ContactController & ProductController a besoin de ces mêmes listes, il ne devrait pas être nécessaire de faire un autre appel DB.

+0

Pour moi, ce n'est pas clair à 100% exactement ce que vous demandez ici. Que voulez-vous dire par un appel à une base de données? En règle générale, vous interrogez uniquement une base de données (à moins que vous ne la modifiez) et cela ne devrait prendre que ms pour se terminer. Sinon (si la base de données est suffisamment petite), vous pouvez le charger en mémoire lorsque votre programme démarre et ne pas le récupérer du tout dans vos contrôleurs. Par base de données, voulez-vous dire un tas de fichiers que vous avez sérialisés ou parlez-vous d'une base de données SQL? –

+0

Ce que je fais typiquement avec un petit stockage est de définir une classe appelée "Data" et d'y stocker des ArrayLists qui contiennent des objets de base de données (comme des utilisateurs, des produits, etc.). Je charge ces ArrayLists quand mon programme commence. De cette façon, vos contrôleurs peuvent simplement appeler quelque chose comme Data.getContacts(); saisir tous les contacts. Si nous parlons d'une énorme base de données, les requêtes SQL doivent être exécutées pour récupérer l'information. –

+0

Désolé devrait avoir clearified - c'est une base de données SQL, je pense que ma question est de savoir où faire l'appel à la base de données pour obtenir la liste des éléments que je travaille - ma première pensée était de faire tous les appels de base de données dans AdminController définir les ChildControllers, mais les contrôleurs enfants sont initialisés avant AdminController, donc l'appel doit avoir été fait et les contrôleurs enfants partageant la même liste de données ne sont pas visibles les uns par rapport aux autres, ex Contact/Admin Controllers - ContactController a besoin de contacts , mais aussi UserController (pour montrer les associations entre les deux). –

Répondre

1

Dans votre cas, si vous chargez "tous" les contacts en même temps, j'appellerais probablement la base de données AVANT d'initialiser un seul contrôleur.

package main; 

import javafx.application.Application; 
import javafx.stage.Stage; 

public class Main extends Application { 

    public void start(Stage window) throws Exception { 
     // Database call goes here! 
     DatabaseManager.initialize(); 


     Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); 
     // Whatever window initialization stuff you need to do 
     window.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

maintenant pour votre classe DatabaseManager

package sample; 

public class DatabaseManager { 

    public static void initialize() { 
     // Query the database for your information. 
     // Little pseudo code here 
     Data.setUsers(Database.userQuery); 
     Data.setContacts(Database.contactQuery); 
     Data.setProducts(Database.productQuery); 
    } 

} 

Maintenant, la classe de données

package sample; 

public class Data { 

    public static ArrayList<User> getUsers() { 
     return users; 
    } 

    public static void setUsers(ArrayList<User> users) { 
     this.users = users; 
    } 

    public static ArrayList<Contact> getContacts() { 
     return contacts; 
    } 

    public static void setContacts(ArrayList<Contact> contacts) { 
     this.contacts = contacts; 
    } 

    public static ArrayList<Product> getProducts() { 
     return products; 
    } 

    public static void setProducts(ArrayList<Product> products) { 
     this.products = products; 
    } 

    private static ArrayList<User> users = new ArrayList<User>(); 
    private static ArrayList<Contact> contacts = new ArrayList<Contact>(); 
    private static ArrayList<Product> products = new ArrayList<Product>(); 

} 

Maintenant vos contrôleurs ne doivent appeler

this.contacts = FXCollections.observableArrayList(Data.getContacts()); 

et cela aura votre arraylist du cont agit prêt à partir.

Notez également que c'est ce qu'on appelle "chargement en mémoire". Un autre mot que vous stockez toutes ces informations dans la mémoire de l'ordinateur et y accéder à partir de là. Cela ne fonctionnera pas pour une base de données ÉNORME parce que votre ordinateur n'aura tout simplement pas l'espace du cerveau. Quoi qu'il en soit, j'espère que cela aidera.

+0

Merci! À l'heure actuelle, mon application est assez petite pour que cela fonctionne - mais le plan est qu'il deviendra une grande application, avez-vous des suggestions sur des applications plus grandes? Idéalement, je voudrais le charger uniquement lorsque cela est nécessaire, mais l'initialisation du contrôleur @FXML me perturbe et ne fonctionne pas dans l'ordre attendu. Mes attentes où -> AdminController - Charger ce qui est nécessaire pour les vues afin que les vues pertinentes pour ce contrôleur i.e ContactController puissent avoir accès aux contacts AdminControllers - seul ContactController est initialisé en premier. –

+0

Eh bien, pour être honnête avec vous, je n'ai jamais aimé la méthode "initialiser" des contrôleurs. C'était un peu bancal pour moi aussi. Je ne suis pas sûr de la façon dont votre programme est exécuté mais pour moi ce que j'ai fait dans tous mes projets FX est de créer une classe "Controller" et d'étendre tous mes autres contrôleurs de cette classe et j'ai une méthode publique start() que je me suis inventé dans cette classe parent et chaque fois que je charge un contrôleur, j'appelle la méthode start(). Tous les contrôleurs étendus remplacent la méthode start(). –

+0

Merci Phillip, j'apprécie les réponses - je vais bidouiller un peu plus et voir ce que je peux faire. –