IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PyQt Python Discussion :

Accès Base de données QSqlite3 avec plusieurs Thread.


Sujet :

PyQt Python

  1. #1
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut Accès Base de données QSqlite3 avec plusieurs Thread.
    Bonjour,

    Depuis plusieurs jours je cherche une solution à mon problème d'accès à la BD SQlite3 avec plusieurs threads.
    Ma fonction d'accès à la BD :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    def ouvrecnx(self):
     
        basedonnee = os.path.join(CONFIG_DATABASE_PATH, CONFIG_DATABASE_NAME)
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName(basedonnee)
     
        if not db.open():
            QMessageBox.critical(None, "Problème d'accès à la base de données \n",
                                 "Impossible d'établir une connexion à la base de données.\n"
                                 "Cliquer Annuler pour sortir.",
                                 QMessageBox.Cancel)
            return False
        else:
            return db
    et le code de lancement des threads

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    t1 = threading.Thread(name='Tables Temporaires1', target=self.creation_tables_tmp1)
    t2 = threading.Thread(name='Tables Temporaires2', target=self.creation_tables_tmp2)
     
    t1.start()
    print(t1.name)
     
    t2.start()
    print(t2.name)
    D'après la doc, pour chaque thread = une connexion à la DB, mais d'une par dans www.sqlit.org il y' a la notion de "SQLITE_CONFIG_MULTITHREAD" que je n'ai pas pu l'intégrer dans mon code
    et d'autre par j'ai trouvé un bout de code en C++ qui génère d'une manière automatique la connexion à DB avec un nom différent

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    QSqlDatabase DBUtil::openDataBase()
    {
        quint32 value = QRandomGenerator::global()->generate();
        QSqlDatabase db;
        if ( true == QSqlDatabase::contains(QString::number(value)))
        {
            db = QSqlDatabase::database(QString::number(value));
        }
        else
        {
            db = QSqlDatabase::addDatabase("QSQLITE", QString::number(value));
            db.setDatabaseName("xxx.db");
        }
     
        if (false == db.open())
        {
            qDebug() << db.lastError().text();
        }
        return db;
    }
    Merci de bien m'aider.

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je n'ai peut-être pas bien compris le problème, mais à mon avis, sqlite3 n'est pas multitâche. Pour plusieurs accès simultanées à une même base de données, il faut se tourner vers un vrai serveur (mysql, postgresql, ...).

  3. #3
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour Tyrtamos,

    Ce n'est pas du multitâche que je voudrais, mon souhait est de pouvoir lancer plusieurs requêtes SQL de SELECT en même temps sur une même BD sqlite3.
    C'est une application desktop.

    Et ci-dessous les messages d'erreur qui s'affichent :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Création Tables Temporaires1
    WARNING:
    QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
     
    WARNING:
    QSqlQuery::prepare: database not open
     
    WARNING:
    QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
     
    Création Tables Temporaires2
     
    WARNING:
    QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
    WARNING:
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is Fenetre(0x23689d61960), parent's thread is QThread(0x23686332860), current thread is QThread(0x2369125f5a0)

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 776
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 776
    Par défaut
    Salut,

    Essayez avec des QThreads (et réfléchissez à ce que vous a dit Tyrtamos).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Puisque sqlite3 n'est pas un serveur, il ne faut pas s'attendre à ce qu'il sache répondre à plusieurs requêtes simultanées. Mais si on a une bonne raison d'envoyer plusieurs requêtes à partir de plusieurs threads, il faudrait que ces requêtes soient placées dans une pile FIFO (First In First Out) pour se présenter une à une à sqlite3. Il faudra vérifier que la pile utilisée contient, ou est associée à, un verrou (lock) pour la protéger des collisions d'accès. Une simple "list" avec un verrou et quelques méthodes de traitement prédéfinies conviendrait.

    Peut-être faudrait-il un thread de plus pour assurer cette interface, ce qui permettra de "sérialiser" les requêtes pour sqlite3:
    1- attendre la requête suivante dans la pile s'il en a une
    2- la présenter à sqlite3 et attendre sa réponse
    3- recevoir sa réponse et la renvoyer au demandeur
    4- revenir en 1
    En fait, on fait de façon simplifiée le boulot d'un serveur...

    Ça me fait penser à un truc que j'ai fait il y a longtemps pour assurer des travaux par plusieurs threads. J'avais utilisé une pile de classes, chaque classe contenant en gros:
    - l'identifiant du thread demandeur
    - la requête demandée
    - la place pour la future réponse
    - un drapeau pour indiquer que la réponse est disponible
    - tout autre information pertinente pour le sujet

    Ce qui fait que chaque thread peut mettre sa requête sur la pile commune, attendre quelle soit traitée, et la sortir de la pile pour la suite de son boulot. Cela permet aussi de gérer la file d'attente des requêtes non résolues et, si nécessaire, de "modérer" la vigueur des threads demandeurs...

    En fait, la pile est un objet commun de communication entre les threads.

    Tout cela est assez délicat à mettre au point, mais quand c'est fait, ça marche très bien!

  6. #6
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour wiztricks,

    J'ai utilisé QThread comme ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    t1 = QThread.thread(name='Création Tables Temporaires1', target=self.creation_tables_tmp1)
    t2 = QThread.thread(name='Création Tables Temporaires2', target=self.creation_tables_tmp2)
    Et voici le message d'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    t1 = QThread.thread(name='Création Tables Temporaires1', target=self.creation_tables_tmp1)
    TypeError: thread() takes no keyword arguments
    Mais pour vous Tyrtamos, que comme vous venez de dire "Tout cela est assez délicat à mettre au point, mais quand c'est fait, ça marche très bien!"
    Y a t'il un petit exemple ...
    Merci.

  7. #7
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par noureddine1967 Voir le message
    Mais pour vous Tyrtamos, que comme vous venez de dire "Tout cela est assez délicat à mettre au point, mais quand c'est fait, ça marche très bien!"
    Y a t'il un petit exemple ...
    Le travail que j'avais fait est assez différent du vôtre: un thread fournissait des expressions mathématiques à calculer et 10 threads étaient là pour les calculer et renvoyer le résultat. Les threads étaient en fonctionnement permanent, et allaient chercher du travail quand le précédent était fini. Vous pouvez vous en inspirer. C'est ici:

    https://python.jpvweb.com/python/mes...d_tableaublanc

    Attention: c'est en Python 2. Mais la logique n'a pas changée.

    Quand à choisir entre threading et QThread, ce dernier a un avantage: il permet d'envoyer des messages (.emit()), ce que je n'avais pas en 2008. Quand je développe en PyQt5, j'utilise QThread dans tous les cas.

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 776
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 776
    Par défaut
    Salut,

    Citation Envoyé par noureddine1967 Voir le message
    Et voici le message d'erreur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    t1 = QThread.thread(name='Création Tables Temporaires1', target=self.creation_tables_tmp1)
    TypeError: thread() takes no keyword arguments
    Le plus bizarre est que çà ne râle pas sur ".thread": une lecture diagonale de la documentation me laisse perplexe quant à son existence.
    Si vous êtes sous Python2, quelle version de Qt/pyQt utilisez vous?

    Pour le reste, l'erreur veut simplement dire que vous n'avez pas ouvert la documentation pour savoir quels paramètres passer à.... Et pour moi, pour jouer avec Qt et les threads, il faut déjà savoir un peu se dépatouiller avec la documentation, les recherches d'exemples sur Internet,...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  9. #9
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Merci wiztricks pour votre réponse
    J'utilise python 3 et PyQt5
    Je vais me plonger dans la doc

  10. #10
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 247
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 247
    Par défaut
    hello,
    si tu respectes ces trois règles cela devrait normalement fonctionner :
    You can only access a QSqlDatabase from the thread which created it/in which it lives.
    You need to create one connection per thread directly in the thread where you will use it.
    Don't use same connection name more than once
    Peux-tu nous montrer ton code complet (en particulier le code du thread) ?
    Ami calmant, J.P

  11. #11
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour jurassic pork,

    You can only access a QSqlDatabase from the thread which created it/in which it lives.
    You need to create one connection per thread directly in the thread where you will use it.
    Don't use same connection name more than once
    J'ai bien lu ces contraintes mais, vu que je suis uniquement un amateur en programmation j'ai pas pu mettre en œuvre une solution.
    Mon application, qui pour le moment marche, mais lourdement, avec le traitement séquentiel des fonctions.

    Les fonction de création de l'ensemble des tables temporaires (35) ainsi que, les combobox (11) et tableview (20) dés le lancement de l'application :

    - Création des tables temporaires (tableview).
    - Création des QCombobox
    - Création des Qtableview, chaque tableau est crée à part.

    L'insertion des données dans les tables principales se fait par importation de fichiers .csv

    Est ce que c'est la meilleure solution ? Je ne le sais pas.

    Voila, ci-dessous un bout du code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
     
     
    import csv
    import os
    import sys
     
    from PyQt5 import QtCore, QtWidgets
    from PyQt5.QtCore import Qt, QModelIndex, QSortFilterProxyModel, QRegExp, QThread
    from PyQt5.QtSql import (QSqlDatabase, QSqlQuery, QSqlRelationalTableModel, QSqlRelation, QSqlTableModel)
    from PyQt5.QtWidgets import (QMainWindow, QMessageBox, QFileDialog, QAbstractItemView)
     
    from UI.c2trl_ui import Ui_MainWindow
     
    CONFIG_DATABASE_PATH = "../Data"
    CONFIG_DATABASE_NAME = "releves.db"
     
     
    # ---------------------------------Connexion à la BD------------------------------------
    def ouvrecnx(self):
        basedonnee = os.path.join(CONFIG_DATABASE_PATH, CONFIG_DATABASE_NAME)
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName(basedonnee)
     
        if not db.open():
            QMessageBox.critical(None, "Problème d'accès à la base de données \n",
                                 "Impossible d'établir une connexion à la base de données.\n"
                                 "Cliquer Annuler pour sortir.",
                                 QMessageBox.Cancel)
            return False
        else:
            return db
    # ---------------------------------Déconnexion de la BD-------------------------
    def fermecnx(db):
        if db is not None:
            db.close()
     
    # ---------------------------Menu principal -------------------------------------
    class Fenetre(QMainWindow):
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
            ouvrecnx(self)
    # ---------------------------------------------------------------------------------
     
            t1 = QThread.thread(name='Création Tables Temporaires1, target=self.creation_tables_tmp1)
            t2 = QThread.thread(name='Création Tables Temporaires2', target=self.creation_tables_tmp2)
            t3 = QThread.thread(name='Création Combobox', target=self.cb_periode)
            t4 = QThread.thread(name='Création Tableaux Analyses', target=self.analyse)
     
     
           t1.start()
           print(t1.name)
           t2.start()
           print(t2.name)
           t3.start()
           print(t3.name)
           t4.start()
           print(t4.name)
     
    # ---------------------------------------------------------------------------------
     
        def creation_tables_tmp1(self):
            ...
            ... 
     
        def creation_tables_tmp2(self):
            ...
            ... 
     
     
     
        def cb_periode(self):
     
     
    # ComboBox periode clients
     
            self.liste_periode = QSqlTableModel(self)
            self.liste_periode.setTable('tmp_periode')
            self.liste_periode.select()
            self.ui.cb_periode.setModel(self.liste_periode)
            self.ui.cb_periode.setModelColumn(self.liste_periode.fieldIndex('periode'))
            self.ui.cb_periode.setCurrentIndex(-1)
     
         ...
         ...
     
     
        def analyse(self):
     
            self.model_analyse_clients = QSqlRelationalTableModel(self)
            self.model_analyse_clients.setTable("tmp1")
            self.model_analyse_clients.setEditStrategy(QSqlRelationalTableModel.OnManualSubmit)
            self.model_analyse_clients.select()
     
            self.model_analyse_clients.setHeaderData(0, Qt.Horizontal, "ID")
            self.model_analyse_clients.setHeaderData(1, Qt.Horizontal, "INTITULE")
     
            self.ui.tableView_analyse_clients.setModel(self.model_analyse_clients)
            self.ui.tableView_analyse_clients.setSortingEnabled(True)
            self.ui.tableView_analyse_clients.sortByColumn(1, Qt.AscendingOrder)
     
            self.ui.tableView_analyse_clients.setSortingEnabled(False)
            self.ui.tableView_analyse_clients.resizeColumnsToContents()
            self.ui.tableView_analyse_clients.resizeRowsToContents()
            self.ui.tableView_analyse_clients.hideColumn(0)
            self.model_analyse_clients.setRelation(0, QSqlRelation('tmp_ventes', 'ID', ' '))
     
            # ----------------------------------------------------------------------------------------------
     
            # Affichage Liste Releve par Phases
            self.model_analyse_ventes = QSqlRelationalTableModel(self)
            self.model_analyse_ventes.setTable("tmp_ventes")
            self.model_analyse_ventes.setEditStrategy(QSqlRelationalTableModel.OnManualSubmit)
            self.model_analyse_ventes.select()
            self.model_analyse_ventes.setHeaderData(0, Qt.Horizontal, "ID")
            self.model_analyse_ventes.setHeaderData(1, Qt.Horizontal, "FACTURE")
            self.model_analyse_ventes.setHeaderData(2, Qt.Horizontal, "PERIODE")
            self.model_analyse_ventes.setHeaderData(3, Qt.Horizontal, "MONTANT")
            self.model_analyse_ventes.setSort(0, Qt.AscendingOrder)
     
            self.ui.tableView_ventes.setModel(self.model_analyse_ventes)
            self.ui.tableView_ventes.setSortingEnabled(True)
            self.ui.tableView_ventes.resizeColumnsToContents()
            self.ui.tableView_ventes.resizeRowsToContents()
     
            self.ui.tableView_analyse_clients.selectionModel().currentRowChanged.connect(self.setfilter_ventes)
     
        # ----------------------------------------------------------------------------------------------
        def setfilter_ventes(self, index):
            ident = self.model_analyse_clients.data(self.model_analyse_clients.index(index.row(), 0, QModelIndex()))
            self.model_analyse_ventes.setFilter("ident = {}".format(ident))
     
            while self.model_analyse_ventes.canFetchMore():
                self.model_analyse_ventes.fetchMore()
    J'espère que c'est claire si non, je peut vous envoyé le projet complet sur votre adresse personnelle.

  12. #12
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour wiztricks,

    J'ai bien déniché sur le net et j'ai modifié l'appel du thread comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        self.table_tmp1_thread = QThread()
        self.table_tmp1_thread.started().connect(self.creation_tables_tmp1)
        self.table_tmp1_thread.start()
    Seulement, il y a le message qui s'affiche : TypeError: native Qt signal is not callable

    Y a t'il quelque chose que j'ai omis
    Merci

  13. #13
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 776
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 776
    Par défaut
    Citation Envoyé par noureddine1967 Voir le message
    TypeError: native Qt signal is not callable

    Y a t'il quelque chose que j'ai omis
    Normalement, l'erreur devrait donner l'instruction en défaut.

    Probablement celle qui contient .started().

    Programmer sans comprendre les messages d'erreurs, c'est comme conduire sans savoir lire la signalisation routière...
    Comme pour la conduite, çà se soigne en passant du temps à apprendre (on ne peut pas passer des heures à essayer de vous expliquer ce que vous n'avez pas eu le courage d'aller apprendre par vous même et avec Internet, informations et formations sont à portée de clic).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #14
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour,

    C'est toujours moi avec le fameux QThread. Après avoir arracher le reste de mes cheveux et surfer sur le Net jusqu'à la noyade, j'ai pu comprendre à peu près la notion du QThread.

    Le code ci-dessous fonctionne, mais la progressBarr s'affiche après l'exécution de la fonction chargertables.
    - Où est le problème ?
    - Si je veux exécuter un autre thread, comment faire ? J'ai lu qu'il y a QRunnable et QThreadPool

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    # -------------------------------------------------------------------------------
    class Charger(QDialog):
     
        def __init__(self):
            super(Charger, self).__init__()
            self.ui = Ui_Dialog_Chargement()
            self.ui.setupUi(self)
     
            self.charger_Tables = Charger_Tables(self.chargertables())
     
            self.charger_Tables.moveToThread(self.charger_Tables)
            self.charger_Tables.started.connect(self.charger_Tables.run)
            self.charger_Tables.signalChargement.connect(self.signalChargement)
            self.charger_Tables.chargementFini.connect(self.chargerTables_fini)
            self.charger_Tables.start()
     
        def signalChargement(self, value):
            self.ui.progressBar.setValue(value)
     
        def chargerTables_fini(self):
            QMessageBox.information(self, "Terminé", "Chargement Terminé")
     
        def chargertables(self): # Fonction création des tables temporaires
        ......
        ......
        ......
     
     
    class Charger_Tables(QThread):
     
        signalChargement = pyqtSignal(int)
        chargementFini = pyqtSignal()
     
        def __init__(self, parent=None):
            super(Charger_Tables, self).__init__(parent)
     
        def run(self):
            value = int()
            while True:
                value = 10+value
                print(value)
                time.sleep(1)
                self.signalChargement.emit(value)
            self.chargementFini.emit()
     
    # ----------------------------------------------------------------------------------------------------------------
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        chg = Charger()
        chg.show()
        sys.exit(app.exec_())
    wistricks soyez compréhensif et indulget, je suis un modeste amateur en programmation, je vie dans un pays malheureusement, on a pas de formation en ligne et je ne peut pas m'inscrire à distance pour la simple raison que je peut pas les payer.
    Merci.

  15. #15
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 776
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 776
    Par défaut
    Citation Envoyé par noureddine1967 Voir le message
    Le code ci-dessous fonctionne, mais la progressBarr s'affiche après l'exécution de la fonction chargertables.
    - Où est le problème ?
    Vous appelez cette fonction à la ligne 10... bien avant de démarrer le thread et les mises à jour de l'affichage devraient se faire après l'appel à .exec_().

    Votre code me semble plutôt étrange mais comme on ne peut pas reproduire pas facile d'en dire plus.

    Avant de vouloir utiliser des fonctionnalités que vous maîtriser mal, faites un petit exemple, un cas d'utilisation qui essaie de mimer ce que vous voulez en faire. C'est un bon point de départ et si çà ne marche pas vous avez un exemple à poster qui permet de reproduire ce que vous voyez.

    Citation Envoyé par noureddine1967 Voir le message
    - Si je veux exécuter un autre thread, comment faire ? J'ai lu qu'il y a QRunnable et QThreadPool
    Si vous exécutez un thread qu'est ce qui vous empêche d'en exécuter 2, N.

    Pour QRunnable et QThreadPool ne vous inquiétez pas, çà veut juste dire que vous n'avez pas encore fini d'apprendre à jouer avec les QThreads que vous savez qu'il y a encore des tas de truc à apprendre...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  16. #16
    Membre confirmé
    Homme Profil pro
    Analyste programmeur
    Inscrit en
    Septembre 2015
    Messages
    148
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Algérie

    Informations professionnelles :
    Activité : Analyste programmeur
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2015
    Messages : 148
    Par défaut
    Bonjour wistricks,

    Pour QRunnable et QThreadPool ne vous inquiétez pas, çà veut juste dire que vous n'avez pas encore fini d'apprendre à jouer avec les QThreads que vous savez qu'il y a encore des tas de truc à apprendre...
    Merci pour vos encouragements.

    Votre code me semble plutôt étrange mais comme on ne peut pas reproduire pas facile d'en dire plus.
    Ci-joint un exemple de mon code, prière de l’exécuter

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # Création de la base de données test1.db
     
    PRAGMA foreign_keys = off;
    BEGIN TRANSACTION;
     
    -- Table : table1
    CREATE TABLE table1 (id NUMERIC (15) PRIMARY KEY, nom VARCHAR (50), adresse VARCHAR (50));
    INSERT INTO table1 (id, nom, adresse) VALUES (1, 'A', 'D1');
    INSERT INTO table1 (id, nom, adresse) VALUES (2, 'B', 'D2');
    INSERT INTO table1 (id, nom, adresse) VALUES (3, 'C', 'D3');
     
    -- Table : table2
    CREATE TABLE table2 (id NUMERIC (15) PRIMARY KEY, num_facture NUMERIC (3), montant INT (12, 2));
    INSERT INTO table2 (id, num_facture, montant) VALUES (1, 10, 10000);
    INSERT INTO table2 (id, num_facture, montant) VALUES (2, 20, 15000);
    INSERT INTO table2 (id, num_facture, montant) VALUES (3, 30, 20000);
     
    COMMIT TRANSACTION;
    PRAGMA foreign_keys = on;

    # chargement_ui.py

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    # -*- coding: utf-8 -*-
     
    # Form implementation generated from reading ui file 'Chargement_UI.ui'
    #
    # Created by: PyQt5 UI code generator 5.15.2
    #
    # WARNING: Any manual changes made to this file will be lost when pyuic5 is
    # run again.  Do not edit this file unless you know what you are doing.
     
     
    from PyQt5 import QtCore, QtGui, QtWidgets
     
     
    class Ui_Dialog_Chargement(object):
        def setupUi(self, Dialog_Chargement):
            Dialog_Chargement.setObjectName("Dialog_Chargement")
            Dialog_Chargement.resize(593, 326)
            Dialog_Chargement.setSizeGripEnabled(False)
            self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog_Chargement)
            self.plainTextEdit.setGeometry(QtCore.QRect(20, 20, 531, 241))
            self.plainTextEdit.setFrameShape(QtWidgets.QFrame.StyledPanel)
            self.plainTextEdit.setFrameShadow(QtWidgets.QFrame.Plain)
            self.plainTextEdit.setObjectName("plainTextEdit")
            self.progressBar = QtWidgets.QProgressBar(Dialog_Chargement)
            self.progressBar.setGeometry(QtCore.QRect(20, 270, 571, 31))
            self.progressBar.setProperty("value", 0)
            self.progressBar.setObjectName("progressBar")
     
            self.retranslateUi(Dialog_Chargement)
            QtCore.QMetaObject.connectSlotsByName(Dialog_Chargement)
     
        def retranslateUi(self, Dialog_Chargement):
            _translate = QtCore.QCoreApplication.translate
            Dialog_Chargement.setWindowTitle(_translate("Dialog_Chargement", "Chargement Tables Temporaires"))
    import icons_rc
    chargement_tables.py

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    import os
    import sys
    import time
     
    from PyQt5.QtSql import QSqlQuery, QSqlDatabase
    from PyQt5.QtWidgets import QDialog
    from PyQt5 import QtWidgets
    from PyQt5.QtCore import QThread, pyqtSignal
    from PyQt5.QtWidgets import QMessageBox
     
    from chargement_ui import Ui_Dialog_Chargement
     
    CONFIG_DATABASE_PATH = "D:/chargement/Data"
    CONFIG_DATABASE_NAME = "test1.db"
     
    # ---------------------------------Connexion à la BD------------------------------------
    def ouvrecnx(self):
        basedonnee = os.path.join(CONFIG_DATABASE_PATH, CONFIG_DATABASE_NAME)
        db = QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName(basedonnee)
        if not db.open():
            QMessageBox.critical(None, "Problème d'accès à la base de données \n",
                                 "Impossible d'établir une connexion à la base de données.\n"
                                 "Cliquer Annuler pour sortir.",
                                 QMessageBox.Cancel)
            return False
        else:
            return db
     
     
     
    # ---------------------------------Déconnexion de la BD-------------------------
    def fermecnx(db):
        if db is not None:
            db.close()
     
    # -------------------------------------------------------------------------------
    class Charger(QDialog):
     
        def __init__(self):
            super(Charger, self).__init__()
            self.ui = Ui_Dialog_Chargement()
            self.ui.setupUi(self)
            ouvrecnx(self)
     
            self.charger_Tables = Charger_Tables()
     
            self.chargertables() # Fonction création tables temporaires
     
            self.charger_Tables.moveToThread(self.charger_Tables)
            self.charger_Tables.started.connect(self.charger_Tables.run)
            self.charger_Tables.signalChargement.connect(self.signalChargement)
            self.charger_Tables.chargementFini.connect(self.chargerTables_fini)
            self.charger_Tables.start()
     
     
        def chargertables(self):
            # ----------------------------------------------------------
            # Création des tables temporaires
            # ----------------------------------------------------------
     
            requete = QSqlQuery()
            requete.prepare('''DROP VIEW IF EXISTS vue1''')
            requete.exec_()
            requete = QSqlQuery()
            requete.prepare('''CREATE VIEW vue1 AS SELECT
                    a.id, a.nom, a.adresse, b.num_facture, b.montant
                    from table1 a , table2 b
                    where a.id = b.id''')
            requete.exec_()
            self.ui.plainTextEdit.appendPlainText("Creation table temporaire vue1")
     
     
            requete = QSqlQuery()
            requete.prepare('''DROP VIEW IF EXISTS vue2''')
            requete.exec_()
            requete = QSqlQuery()
            requete.prepare('''CREATE VIEW vue2 AS SELECT
                    a.id, a.nom, a.adresse, b.num_facture, b.montant
                    from table1 a , table2 b
                    where a.id = b.id''')
            requete.exec_()
            self.ui.plainTextEdit.appendPlainText("Creation table temporaire vue2")
     
     
            requete = QSqlQuery()
            requete.prepare('''DROP VIEW IF EXISTS vue3''')
            requete.exec_()
            requete = QSqlQuery()
            requete.prepare('''CREATE VIEW vue3 AS SELECT
                    a.id, a.nom, a.adresse, b.num_facture, b.montant
                    from table1 a , table2 b
                    where a.id = b.id''')
            requete.exec_()
            self.ui.plainTextEdit.appendPlainText("Creation table temporaire vue3")
     
     
     
        def signalChargement(self, value):
            self.ui.progressBar.setValue(value)
     
        def chargerTables_fini(self):
            QMessageBox.information(self, "Terminé", "Chargement Terminé")
     
    # -------------------------------------------------------------------------------
    class Charger_Tables(QThread):
        signalChargement = pyqtSignal(int)
        chargementFini = pyqtSignal()
     
        def __init__(self, parent=None):
            super(Charger_Tables, self).__init__(parent)
     
        def run(self):
            value = int()
            while True:
                value = 10 + value
                print(value)
                time.sleep(1)
                self.signalChargement.emit(value)
            self.chargementFini.emit()
     
    # -------------------------------------------------------------------------------
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        chg = Charger()
        chg.show()
        sys.exit(app.exec_())
    Merci par avance pour votre réponse.

  17. #17
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 776
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 776
    Par défaut
    Citation Envoyé par noureddine1967 Voir le message
    Ci-joint un exemple de mon code, prière de l’exécuter
    ...
    Merci par avance pour votre réponse.
    C'est vous qui programmez.

    Si vous avez un problème, retirer tout ce qui est sans rapport dans votre code... est une façon de se concentrer sur la mécanique de base qui et permettra de trouver...

    Ce boulot là, je ne vais pas le faire à votre place (parce que si programmer est un boulot que vous ne voulez pas prendre le temps d'apprendre...).

    note: je vous ai déjà suggéré de fabriquer des petits exemples. Soit vous l'avez fait avant soit vous partez à coder et vous rencontrez des soucis et vous devez le faire après.

    Ceci dit, vous aurez peut être plus de chances avec d'autres... En ce qui me concerne, au plus vous me montrez du code au moins je comprends ce que vous avez cherché à faire.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Réponses: 3
    Dernier message: 17/02/2017, 21h18
  2. Réponses: 1
    Dernier message: 17/03/2010, 15h33
  3. Réponses: 2
    Dernier message: 14/05/2009, 08h01
  4. hébergement de base de donnée gratuite avec accès par Delphi
    Par dan_lizhot dans le forum Bases de données
    Réponses: 9
    Dernier message: 17/02/2009, 00h40
  5. Accès à une base de données Oracle avec un tunnel ssh
    Par sofiane1111 dans le forum Bases de données
    Réponses: 5
    Dernier message: 14/11/2007, 10h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo