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 :

Coquille vide pour un sudoku


Sujet :

PyQt Python

  1. #1
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut Coquille vide pour un sudoku
    Bonsoir,
    non, non je ne me lance pas dans un concours d'haïku.

    Est-ce que quelqu'un a dans ses codes une coquille vide pour afficher
    une grille de type Sudoku ? Pour la résolution, pas de souci j'ai un code.

    Dans le cas contraire, j'essaierais de trouver un peu de temps pour le
    faire mais c'est un peu compliqué côté temps pour moi en ce moment.

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour rambc,

    Sur le web, j'ai au moins trouvé ça: http://lionel.textmalaysia.com/sudok...l#.UK3Dm9fQvwM.

    Si ça ne te convient pas et si tu n'as pas d'autres réponses, je te proposerais un échange: je te fabrique ta coquille, et tu me passes tes codes de résolution. La coquille, en PyQt4, ne devrait pas être très compliquée en utilisant QTableWidget, et la structure de données sous forme de liste de listes du genre matrice devrait permettre la recherche récursive dans un arbre.

    Il y a une dizaine d'années, je m'étais amusé à coder les algorithmes de résolution en... Lisp (="Lots of Insipid and Stupid Parentheses" ), y compris dans les cas complexes nécessitant des retours en arrière sur des tentatives infructueuses. C'était très amusant à faire, et ça marchait très bien (en console). C'est également intéressant de savoir fabriquer des grilles de sudoku à résoudre selon différents niveaux de complexité.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Merci pour le lien.

    Côté résolution, rien de bien original. J'ai des idées pour la création de
    grilles. C'est dans le cadre d'une formation dans l'Éducation Nationale.

    Je mettrais le code final en ligne en Mars normalement (trop peu de
    temps libre cette année). Si d'ici là je ne t'ai pas contacté, relances-moi.

    Citation Envoyé par tyrtamos Voir le message
    Lisp ="Lots of Insipid and Stupid Parentheses"
    J'aime beaucoup !

  4. #4
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Comment pourrait-on faire pour obtenir les fonctionnalités suivantes visibles dans cette page et cette autre ?
    1. Chaque case non renseignée se remplira par un simple clic dessus puis une saisie au clavier.
    2. Chaque case non renseignée pourra, ou non, afficher des possibilités (toutes ou justes certaines).
    3. Chacune des possibilités affichées dans une case pourra avoir une petite mise en forme spécifique : encadrement et couleur de fond.
    4. J'aimerais dessiner des cercles et des traits par dessus la grille pour aider le joueur ou indiquer une résolution pas à pas.

    Mes questions sont de pures questions de mise en forme car j'ai presque fini mon "solveur" à quelques détails près.

    PS : le lien donné ci-dessus semble mort...

  5. #5
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour rambc,

    Je n'ai pas le temps pour l'instant de te terminer la coquille, je suis assez pris jusqu'à 1/2 mars.

    Cependant, je peux te confirmer que tout ce que tu souhaites est parfaitement réalisable. Voilà quelques éléments de principe:

    Grille utilisée: QTableWidget.

    Petit code de base pour créer la grille 9x9:

    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
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
    # Python 2.7
     
    import sys
    from copy import deepcopy
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    class Fenetre(QtGui.QWidget):
     
        # =======================================================================
        def __init__(self, parent=None):
            super(Fenetre, self).__init__(parent)
     
            # crée la grille 9x9
            self.table = QtGui.QTableWidget(self)
            self.nbrow, self.nbcol = 9, 9
            self.table.setRowCount(self.nbrow)
            self.table.setColumnCount(self.nbcol)
     
            # cache les entêtes horizontale et verticale
            self.table.horizontalHeader().hide()
            self.table.verticalHeader().hide()
     
            # définit les cases carrées 50 pixels x 50 pixels
            for row in xrange(0, self.nbrow):
                self.table.setRowHeight(row, 50)
                for col in xrange(0, self.nbcol):
                    self.table.setColumnWidth(col, 50)
     
            # remplit la grille avec des QTableWidgetItem
            for row in xrange(0, self.nbrow):
                for col in xrange(0, self.nbcol):
                    item = QtGui.QTableWidgetItem()
                    item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
                    self.table.setItem(row, col, item)
     
            # définit la police de caractère par défaut de la table 
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(16)
            self.table.setFont(font)
     
            # taille de la fenêtre
            self.resize(53*9, 53*9)
     
            # positionne la table dans la fenêtre
            posit = QtGui.QGridLayout()
            posit.addWidget(self.table, 0, 0)
            self.setLayout(posit)
     
            # grille de base
            self.g0 =  [[0,0,0,0,2,0,9,0,1],
                        [0,0,0,0,0,0,0,0,3],
                        [0,8,0,3,0,0,4,5,0],
                        [0,4,7,0,0,5,0,8,0],
                        [0,0,0,0,0,0,0,0,0],
                        [0,2,0,9,0,0,7,4,0],
                        [0,9,5,0,0,2,0,3,0],
                        [6,0,0,0,0,8,0,0,0],
                        [7,0,4,0,6,0,0,0,0]]
     
            # intégre le delegate pour lignes en gras et les cases en couleur
            #self.delegate = MonDelegate(self.table)
            #self.table.setItemDelegate(self.delegate)
     
            # redessine les lignes en gras et les cases de couleur
            #self.delegate.grilleinit(self.g0)
     
            # initialise la grille courante
            self.g = deepcopy(self.g0)
     
            # affiche la grille courante
            self.affiche(self.g)
     
            # place le focus
            self.table.setFocus()
            self.table.setCurrentCell(0, 0)
     
        # =======================================================================
        def affiche(self, g):
     
            for row in xrange(0, len(g[0])):
                for col in xrange(0, len(g)):
                    if g[row][col]==0:
                        self.table.item(row, col).setText(u"")
                        self.table.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable)
                    else:
                        self.table.item(row, col).setText(unicode(g[row][col]))
                        self.table.item(row, col).setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
     
            couleur = QtGui.QColor(160, 255, 160, 255) # vert clair
            self.table.item(2, 4).setBackgroundColor(couleur)
     
            couleur = QtGui.QColor(255, 160, 160, 255) # rouge clair
            self.table.item(6, 3).setBackgroundColor(couleur)
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = Fenetre()
        fen.show()
        sys.exit(app.exec_())
    Cela donne déjà une grille complète, mais il reste à dessiner les lignes en gras pour séparer visuellement les groupes de cases 3x3. On peut aussi mettre les cases de départ ayant des chiffres en couleur (ici, en gris).

    Pour faire ça, je n'ai pas trouvé plus simple que de sous-classer QItemDelegate, et de surcharger sa méthode paint. Voilà comment on peut faire ça:

    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
    #############################################################################
    def couleurcase(painter, option, couleur):
        """met le fond de la case dans la couleur demandée"""
        r = option.rect
        x, y, w, h = r.x()+1, r.y()+1, r.width()-2, r.height()-2
        if isinstance(couleur, (str, unicode)):
            coul = QtGui.QColor(couleur)
        elif isinstance(couleur, (list, tuple)):
            if len(couleur) == 3:
                r, g, b = couleur
                t = 255
            else:
                r, g, b, t = couleur
            coul = QtGui.QColor(r, g, b, t)
        painter.fillRect(x, y, w, h, coul)
     
    #############################################################################
    def bordurecase(painter, option, ligne):
        """met en gras la bordure d'une case d'un QTableWidget dans le paint d'un 
           delegate: ligne 'h'=haute, 'g'=gauche, 'd'=droite, 'b'=basse
        """
        r = option.rect
        x, y, w, h = r.x(), r.y(), r.width(), r.height()
        if ligne=='h':
            x1, y1, x2, y2 = x, y, x+w, y
        elif ligne=='d':
            x1, y1, x2, y2 = x+w, y, x+w, y+h
        elif ligne=='b':
            x1, y1, x2, y2 = x+w, y+h, x, y+h
        elif ligne=='g':
            x1, y1, x2, y2 = x, y+h, x, y
        else:
            return
        pen = QtGui.QPen()
        pen.setWidth(2)
        painter.setPen(pen)
        painter.drawLine(x1, y1, x2, y2)
     
    #############################################################################
    class MonDelegate(QtGui.QItemDelegate):
     
        #========================================================================
        def __init__(self, parent=None):
            super(MonDelegate, self).__init__(parent)
     
        #========================================================================
        def grilleinit(self, g):
            self.g0 = g
     
        #========================================================================
        def paint(self, painter, option, index):    
            """appelé case par case pour en dessiner le contenu"""        
     
     
            row, col = index.row(), index.column() 
            if row==0 or row==3 or row==6:
                if col in[0,3,6]:
                    bordurecase(painter, option, 'g')
                    bordurecase(painter, option, 'h')
                elif col==8:
                    bordurecase(painter, option, 'd')
                    bordurecase(painter, option, 'h')
                else:
                    bordurecase(painter, option, 'h')
            elif row in [1,2,4,5,7]:
                if col in [0,3,6]:
                    bordurecase(painter, option, 'g')
                elif col==8:
                    bordurecase(painter, option, 'd')
            elif row==8:
                if col in[0,3,6]:
                    bordurecase(painter, option, 'g')
                    bordurecase(painter, option, 'b')
                elif col==8:
                    bordurecase(painter, option, 'd')
                    bordurecase(painter, option, 'b')
                else:
                    bordurecase(painter, option, 'b')    
     
            # mettre la couleur souhaitée dans les cases de départ ayant un numéro 
            if self.g0[row][col]!=0:
                couleurcase(painter, option, [200,200,200])
     
            QtGui.QItemDelegate.paint(self, painter, option, index)
    Et dans la classe Fenetre, on fait à l'initialisation (les lignes y sont déjà, il suffit de les dé-commenter):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            # intégre le delegate pour lignes en gras et les cases en couleur
            self.delegate = MonDelegate(self.table)
            self.table.setItemDelegate(self.delegate)
     
            # redessine les lignes en gras et les cases de couleur
            self.delegate.grilleinit(self.g0)
    Et voilà ce que ça donne:



    Les cases grises qui ont un chiffre au départ sont sélectionnables, mais en lecture seule.

    La case bleue est la case qui a le focus.

    J'ai mis à titre d'exemple des cases roses et vertes pour remplacer les dessins fournis (rond vert et croix rouge) parce que c'est plus simple à programmer. Si ça ne va pas, on peut trouver autre chose.

    Pour le reste:

    Il est possible de mettre dans une case en tout petit les chiffres permis, il suffit de placer à la volée un QTextEdit au lieu du QTableWidgetItem, et d'écrite en "richtext", c'est à dire en html (syntaxe réduite cependant). Ce ne sera peut-être pas facile à mettre au point, mais ça marchera. Et puisqu'il s'agit de html, on devrait pouvoir mettre une image en option.

    Voilà le départ! Pour le reste, il faudra attendre un peu...

    A+
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  6. #6
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Merci,
    cela fait un bon départ. Je vais étudier cela. Va juste falloir que je me remette à PyQt.

    Un grand merci.

    PS : je posterais ici mes avancés, s'il y en a...

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,
    Citation Envoyé par rambc Voir le message
    cela fait un bon départ. Je vais étudier cela. Va juste falloir que je me remette à PyQt.
    Vu le type de rendu montré à l'URL mentionnée, il semblerait plus judicieux de passer par des "canvas". Comme je ne vois pas trop l'intérêt d'utiliser Qt quand on a peu de temps, je me suis amusé à faire une "estimation"/"réalisation" de la chose avec Tk.
    J'étais parti sur une estimation d'une poignée d'heures en plusieurs itérations.
    C'était correct sur la partie réalisation du rendu proposé:

    Avec la mise en place d'une API semblable:
    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
        app = tk.Tk()
        grid = SudokuGrid(app)
        grid.load(initial_values=G)
     
        grid.pack(fill='both')
        grid.update() # update grid to get real position from xxx_bbox
        grid.focus_set()
     
        grid.highlight_cell(2,8)
        grid.highlight_row(8)
        grid.highlight_column(5)
        grid.highlight_rectangle((4,1), (6,3))
        grid.circle_cell(5, 2)
        grid.cross_cell(8,1)
        grid.hint_cell( 1, 1, (3, 4, 6, 7))
    Une fois le "joujou" réalisé, j'ai passé autant de temps à y intégrer ce "solveur".
    Normal! Découvrir comment "adapter" les sorties avec l'interface et boucher des trous imprévus prend du temps.

    Au cas où le code est en PJ.

    - W
    PS: Le code est assez brouillon, il faut le faire évoluer en fonction des cas d'utilisation à y intégrer. Difficile de savoir "à priori" ce qui doit être factorisé ou pas, les différents objets, leurs relations ne sont pas encore "stables".
    Fichiers attachés Fichiers attachés
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  8. #8
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Je suis allergique à Tk. Pas propre du tout à utiliser. Je n'aime pas
    du tout la logique de Tk. Qt a une certaine cohérence de mon point de vue.

    De plus, j'ai envie de le faire comme un grand mais étant pressé je suis venu
    ici cherché de l'aide pour les points techniques, pour gagner du temps.

    J'ai regardé, le rendu est pas mal.

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    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 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par rambc Voir le message
    Je suis allergique à Tk. Pas propre du tout à utiliser. Je n'aime pas du tout la logique de Tk. Qt a une certaine cohérence de mon point de vue.
    Il est fort dommage que la flexibilité de Tk vous donne des boutons.
    J'aime bien Qt aussi mais c'est un peu compliqué à mettre en œuvre.
    On se retrouve à programmer en Python avec un background C++ pour comprendre les pièges et les astuces.

    De plus, j'ai envie de le faire comme un grand mais étant pressé je suis venu ici cherché de l'aide pour les points techniques, pour gagner du temps.

    J'ai regardé, le rendu est pas mal.
    L'API que vous avez donné était suffisamment claire pour être réalisée rapidement: un Canvas et quelques méthodes pour le décorer. Le canvas sous Qt est construit avec QGraphicsScene, une ou des QGraphicsView et des QGraphicsItems. C'est la même chose, seul l'emballage change.

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

  10. #10
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Côté solveur, je pense bientôt mettre mon code en ligne (au plus tard le 14 mars). Il faut que je finalise des trucs.

    Bonne nouvelle : le code est assez structuré et scindé pour appréhender au mieux ce que j'ai fait, enfin je l'espère...

  11. #11
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Salut wiztricks tyrtamos.

    Je suis en train de compléter un peu ton code. J'arrive à ce qui suit. J'utilise PySide car il s'installe très facilement sous Mac.

    Deux soucis.
    1. Les lignes épaisses pour visualiser les carrés sont tracées en dessous des cases. Peut-on utiliser l'équivalent d'un z-index pour pallier à cela ?
    2. J'aimerais garder la dimension de la fenêtre tout en centrant le tableau. Il me semble qu'il faut faire appel à des ressorts. Je ne connais plus le terme exact.


    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
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    #! /usr/bin/env python2.7
    # -*- coding: utf-8 -*-
     
    from __future__ import division
     
    import sys
    from copy import deepcopy
     
    from PySide import QtCore, QtGui
     
    def cellColor(painter, option, color):
        """met le fond de la case dans la color demandée"""
        r = option.rect
        x, y, w, h = r.x()+1, r.y()+1, r.width()-2, r.height()-2
        if isinstance(color, (str, unicode)):
            coul = QtGui.QColor(color)
        elif isinstance(color, (list, tuple)):
            if len(color) == 3:
                r, g, b = color
                t = 255
            else:
                r, g, b, t = color
            coul = QtGui.QColor(r, g, b, t)
        painter.fillRect(x, y, w, h, coul)
     
    def bordurecase(painter, option, ligne):
        """met en gras la bordure d'une case d'un QTableWidget dans le paint d'un
           delegate: ligne 'h'=haute, 'g'=gauche, 'd'=droite, 'b'=basse
        """
        r = option.rect
        x, y, w, h = r.x(), r.y(), r.width(), r.height()
        if ligne=='h':
            x1, y1, x2, y2 = x, y, x+w, y
        elif ligne=='d':
            x1, y1, x2, y2 = x+w, y, x+w, y+h
        elif ligne=='b':
            x1, y1, x2, y2 = x+w, y+h, x, y+h
        elif ligne=='g':
            x1, y1, x2, y2 = x, y+h, x, y
        else:
            return
        pen = QtGui.QPen()
        pen.setWidth(4)
        painter.setPen(pen)
        painter.drawLine(x1, y1, x2, y2)
     
    class MonDelegate(QtGui.QItemDelegate):
        def __init__(self, parent=None):
            super(MonDelegate, self).__init__(parent)
     
        def grilleinit(self, g):
            self.g0 = g
     
        def paint(self, painter, option, index):
            """appelé case par case pour en dessiner le contenu"""
            row, col = index.row(), index.column()
     
            if row==0 or row==3 or row==6:
                if col in[0,3,6]:
                    bordurecase(painter, option, 'g')
                    bordurecase(painter, option, 'h')
     
                elif col==8:
                    bordurecase(painter, option, 'd')
                    bordurecase(painter, option, 'h')
     
                else:
                    bordurecase(painter, option, 'h')
     
            elif row in [1,2,4,5,7]:
                if col in [0,3,6]:
                    bordurecase(painter, option, 'g')
     
                elif col==8:
                    bordurecase(painter, option, 'd')
     
            elif row==8:
                if col in[0,3,6]:
                    bordurecase(painter, option, 'g')
                    bordurecase(painter, option, 'b')
     
                elif col==8:
                    bordurecase(painter, option, 'd')
                    bordurecase(painter, option, 'b')
     
                else:
                    bordurecase(painter, option, 'b')
     
    # mettre la color souhaitée dans les cases de départ ayant un numéro
            if self.g0[row][col]!=0:
                cellColor(painter, option, [200,200,200])
     
            QtGui.QItemDelegate.paint(self, painter, option, index)
     
    class MainWindow(QtGui.QWidget):
        def __init__(
            self,
            parent = None
        ):
            super(MainWindow, self).__init__(parent)
     
    # General grid
            self.table = QtGui.QTableWidget(self)
            self.nbrow, self.nbcol = 9, 9
            self.table.setRowCount(self.nbrow)
            self.table.setColumnCount(self.nbcol)
     
    # Each cell has dimension 50 pixels x 50 pixels
            for row in range(0, self.nbrow):
                self.table.setRowHeight(row, 50)
     
                for col in range(0, self.nbcol):
                    self.table.setColumnWidth(col, 50)
     
    # Each cell contains one single QTableWidgetItem
            for row in range(0, self.nbrow):
                for col in range(0, self.nbcol):
                    item = QtGui.QTableWidgetItem()
                    item.setTextAlignment(
                        QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter
                    )
     
                    self.table.setItem(row, col, item)
     
    # header formatting
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(12)
            self.table.horizontalHeader().setFont(font)
            self.table.verticalHeader().setFont(font)
     
    # Font used
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(20)
            self.table.setFont(font)
     
    # Global Size
            self.resize(60*9, 60*9 + 20)
     
    # Layout of the table
            layout = QtGui.QGridLayout()
            layout.addWidget(self.table, 0, 0)
            self.setLayout(layout)
     
    # Initial grid (to test)
            self.g0 =  [[0,0,0,0,2,0,9,0,1],
                        [0,0,0,0,0,0,0,0,3],
                        [0,8,0,3,0,0,4,5,0],
                        [0,4,7,0,0,5,0,8,0],
                        [0,0,0,0,0,0,0,0,0],
                        [0,2,0,9,0,0,7,4,0],
                        [0,9,5,0,0,2,0,3,0],
                        [6,0,0,0,0,8,0,0,0],
                        [7,0,4,0,6,0,0,0,0]]
     
            # intégre le delegate pour lignes en gras et les cases en color
            self.delegate = MonDelegate(self.table)
            self.table.setItemDelegate(self.delegate)
     
            # redessine les lignes en gras et les cases de color
            self.delegate.grilleinit(self.g0)
     
    # Initialization of the actual grid
            self.g = deepcopy(self.g0)
     
    # Display the grid.
            self.update(self.g)
     
    # Set the focus in the first cell
            self.table.setFocus()
            self.table.setCurrentCell(0, 0)
     
        def update(self, g):
            for row in range(0, len(g[0])):
                for col in range(0, len(g)):
                    if g[row][col]==0:
                        font = QtGui.QFont()
                        font.setFamily(u"DejaVu Sans")
                        font.setPointSize(12)
                        self.table.item(row, col).setFont(font)
     
                        color = QtGui.QColor(0, 0,  255, 255) # bleu
                        self.table.item(row, col).setForeground(color)
     
                        self.table.item(row, col).setText(
                            u"1 2 3\n4 5 6\n7 8 9"
                        )
                        self.table.item(
                            row, col
                        ).setFlags(
                            QtCore.Qt.ItemIsEnabled |
                            QtCore.Qt.ItemIsSelectable |
                            QtCore.Qt.ItemIsEditable
                        )
     
                    else:
                        self.table.item(row, col).setText(unicode(g[row][col]))
                        self.table.item(
                            row, col
                        ).setFlags(
                            QtCore.Qt.ItemIsEnabled |
                            QtCore.Qt.ItemIsSelectable
                        )
     
            color = QtGui.QColor(160, 255, 160, 255) # vert clair
            self.table.item(2, 4).setBackground(color)
     
            color = QtGui.QColor(255, 160, 160, 255) # rouge clair
            self.table.item(6, 3).setBackground(color)
     
     
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = MainWindow()
        fen.show()
        sys.exit(app.exec_())

  12. #12
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour rambc,

    Citation Envoyé par rambc Voir le message
    Salut wiztricks.

    Je suis en train de compléter un peu ton code.
    Compte tenu du code que tu montres, tu voulais peut-être dire "Salut Tyrtamos"?
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  13. #13
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Oh le boulet que je fais !!! Je corrige le message de suite. J'ai confondu avec le code tkinter. J'espère que tu ne vas pas trop m'en vouloir.

  14. #14
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par rambc Voir le message
    J'espère que tu ne vas pas trop m'en vouloir.
    Mais non, ne t'inquiète pas, ça me fait plutôt rigoler.

    Je regarde si je peux répondre à tes questions.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  15. #15
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Cela fait un baille que je n'utilise plus PySide et du coup je pense que j'ai râté un truc important.

    Attention ! Sous PySide, je dois utiliser setBackground et non setBackgroundColor.

  16. #16
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    La coquille se remplit. Le code ci-dessous gère en plus le déplacement et la saisie des valeurs là où c'est autorisé. Voici ce que j'aimerais ajouter dans un 1er temps.

    1. (rappel) Les lignes épaisses pour visualiser les carrés sont tracées en dessous des cases. Peut-on utiliser l'équivalent d'un z-index pour pallier à cela ?
    2. (rappel) J'aimerais garder la dimension de la fenêtre tout en centrant le tableau. Il me semble qu'il faut faire appel à des ressorts. Je ne connais plus le terme exact.
    3. (nouveau) J'aimerais faire apparaître une mini-table de 9 sur 9 au-dessus de la case qui a le focus. Pourquoi ? Ce serait pour permettre au joueur de réduire les possibilités dans une case. Concrètement, le joueur choisit une case et taper sur R par exemple et hop la mini-table apparait.

    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
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    #! /usr/bin/env python2.7
    # -*- coding: utf-8 -*-
     
    # Source : http://www.developpez.net/forums/d1281788/autres-langages/python-zope/gui/pyside-pyqt/coquille-vide-sudoku/#post7181230
     
    from __future__ import division
     
    import sys
    from copy import deepcopy
     
    from PySide import QtCore, QtGui
     
     
    def cellColor(painter, option, color):
        """
        ???
        """
        r = option.rect
        x, y, w, h = r.x() + 1, r.y() + 1, r.width()-2, r.height()-2
     
        if isinstance(color, (str, unicode)):
            color = QtGui.QColor(color)
     
        elif isinstance(color, (list, tuple)):
            if len(color) == 3:
                r, g, b = color
                alpha   = 255
     
            else:
                r, g, b, alpha = color
     
            color = QtGui.QColor(r, g, b, alpha)
     
        painter.fillRect(x, y, w, h, color)
     
    def cellBorder(painter, option, where):
        """
        ???
        """
        r = option.rect
        x, y, w, h = r.x(), r.y(), r.width(), r.height()
     
        if where == 'up':
            x1, y1, x2, y2 = x, y, x + w, y
     
        elif where == 'bottom':
            x1, y1, x2, y2 = x + w, y + h, x, y + h
     
        elif where == 'right':
            x1, y1, x2, y2 = x + w, y, x + w, y + h
     
        elif where == 'left':
            x1, y1, x2, y2 = x, y + h, x, y
     
        else:
            return None
     
        pen = QtGui.QPen()
        pen.setWidth(4)
        painter.setPen(pen)
        painter.drawLine(x1, y1, x2, y2)
     
     
    class SudokuDelegate(QtGui.QItemDelegate):
        def __init__(self, parent=None):
            super(SudokuDelegate, self).__init__(parent)
     
        def initGrid(self, grid):
            self.grid_0 = grid
     
        def paint(self, painter, option, index):
            """
            ???
            """
            row, col = index.row(), index.column()
     
            if row == 0 or row == 3 or row == 6:
                if col in[0,3,6]:
                    cellBorder(painter, option, 'left')
                    cellBorder(painter, option, 'up')
     
                elif col == 8:
                    cellBorder(painter, option, 'right')
                    cellBorder(painter, option, 'up')
     
                else:
                    cellBorder(painter, option, 'up')
     
            elif row in [1,2,4,5,7]:
                if col in [0,3,6]:
                    cellBorder(painter, option, 'left')
     
                elif col == 8:
                    cellBorder(painter, option, 'right')
     
            elif row == 8:
                if col in[0,3,6]:
                    cellBorder(painter, option, 'left')
                    cellBorder(painter, option, 'bottom')
     
                elif col == 8:
                    cellBorder(painter, option, 'right')
                    cellBorder(painter, option, 'bottom')
     
                else:
                    cellBorder(painter, option, 'bottom')
     
    # Background color for initial known cells
            if self.grid_0[row][col]!=0:
                cellColor(painter, option, [200,200,200])
     
            QtGui.QItemDelegate.paint(self, painter, option, index)
     
    class MainWindow(QtGui.QWidget):
        def __init__(
            self,
            parent = None
        ):
            super(MainWindow, self).__init__(parent)
     
    # General grid
            self.table = QtGui.QTableWidget(self)
            self.nbrow, self.nbcol = 9, 9
            self.table.setRowCount(self.nbrow)
            self.table.setColumnCount(self.nbcol)
     
    # Each cell has dimension 50 pixels x 50 pixels
            for row in range(0, self.nbrow):
                self.table.setRowHeight(row, 50)
     
                for col in range(0, self.nbcol):
                    self.table.setColumnWidth(col, 50)
     
    # Each cell contains one single QTableWidgetItem
            for row in range(0, self.nbrow):
                for col in range(0, self.nbcol):
                    item = QtGui.QTableWidgetItem()
                    item.setTextAlignment(
                        QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter
                    )
     
                    self.table.setItem(row, col, item)
     
    # Header formatting
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(12)
            self.table.horizontalHeader().setFont(font)
            self.table.verticalHeader().setFont(font)
     
    # Font used
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(20)
            self.table.setFont(font)
     
    # Global Size
            self.resize(60*9, 60*9 + 20)
     
    # Layout of the table
            layout = QtGui.QGridLayout()
            layout.addWidget(self.table, 0, 0)
            self.setLayout(layout)
     
    # Initial grid (to test)
            self.grid_0 =  [
                [0,0,0, 0,2,0, 9,0,1],
                [0,0,0, 0,0,0, 0,0,3],
                [0,8,0, 3,0,0, 4,5,0],
    #
                [0,4,7, 0,0,5, 0,8,0],
                [0,0,0, 0,0,0, 0,0,0],
                [0,2,0, 9,0,0, 7,4,0],
    #
                [0,9,5, 0,0,2, 0,3,0],
                [6,0,0, 0,0,8, 0,0,0],
                [7,0,4, 0,6,0, 0,0,0]
            ]
     
    # Use of the delegate so to use thicker lines.
            self.delegate = SudokuDelegate(self.table)
            self.table.setItemDelegate(self.delegate)
            self.delegate.initGrid(self.grid_0)
     
    # Initialization of the actual grid
            self.grid = deepcopy(self.grid_0)
     
    # Display the grid.
            self.update(self.grid)
     
    # ??
            self.cellToFill = []
     
            for row in range(9):
                for col in range(9):
                    if self.grid_0[row][col] == 0:
                        self.cellToFill.append((row, col))
     
    # Set the focus in the first cell
            self.table.setFocus()
            self.table.setCurrentCell(0, 0)
            self.table.keyPressEvent = self.keyPressEvent
     
        def keyPressEvent(self, event):
            row, col = self.table.currentRow(), self.table.currentColumn()
     
    # One digit
            if ord('1') <= event.key() <= ord('9'):
                if (row, col) in self.cellToFill:
                    font = QtGui.QFont()
                    font.setFamily(u"DejaVu Sans")
                    font.setPointSize(20)
                    self.table.item(row, col).setFont(font)
     
                    color = QtGui.QColor(0, 0, 0)
                    self.table.item(row, col).setForeground(color)
     
                    self.table.item(row, col).setText(chr(event.key()))
    # Arrow moving
            elif event.key() == QtCore.Qt.Key_Up:
                self.table.setCurrentCell((row - 1) % 9, col)
     
            elif event.key() == QtCore.Qt.Key_Down:
                self.table.setCurrentCell((row + 1) % 9, col)
     
            elif event.key() == QtCore.Qt.Key_Left:
                self.table.setCurrentCell(row, (col - 1) % 9)
     
            elif event.key() == QtCore.Qt.Key_Right:
                self.table.setCurrentCell(row, (col + 1) % 9)
     
        def update(self, g):
            for row in range(0, len(g[0])):
                for col in range(0, len(g)):
                    if g[row][col] == 0:
                        font = QtGui.QFont()
                        font.setFamily(u"DejaVu Sans")
                        font.setPointSize(12)
                        self.table.item(row, col).setFont(font)
     
                        color = QtGui.QColor(0, 0,  255, 255) # bleu
                        self.table.item(row, col).setForeground(color)
     
                        self.table.item(row, col).setText(
                            u"1 2 3\n4 5 6\n7 8 9"
                        )
                        self.table.item(
                            row, col
                        ).setFlags(
                            QtCore.Qt.ItemIsEnabled
                            | QtCore.Qt.ItemIsSelectable
    #                        | QtCore.Qt.ItemIsEditable
                        )
     
                    else:
                        self.table.item(row, col).setText(unicode(g[row][col]))
                        self.table.item(
                            row, col
                        ).setFlags(
                            QtCore.Qt.ItemIsEnabled
                            | QtCore.Qt.ItemIsSelectable
                        )
     
    # Just for testing !
            color = QtGui.QColor(160, 255, 160, 255) # Light green
            self.table.item(2, 4).setBackground(color)
     
            color = QtGui.QColor(255, 160, 160, 255) # Light red
            self.table.item(6, 3).setBackground(color)
     
     
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = MainWindow()
        fen.show()
        sys.exit(app.exec_())

  17. #17
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Bonjour rambc,

    J'ai quelques solutions à te proposer.

    Je n'ai pas repris la totalité de ton code, pour que les solutions que tu cherches ne soient pas noyées.

    Je crois avoir amélioré l'esthétique de la grille. Voilà ce que ça donne:



    Voilà le code qui fait ça (les commentaires sont à la suite):

    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
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    from __future__ import division
     
    import sys, os
     
    from PyQt4 import QtCore, QtGui
     
    #############################################################################
    def cellColor(painter, option, color):
        """ peint la case dans la couleur demandée (appel par le delegate)"""
        r = option.rect
        x, y, w, h = r.x() + 1, r.y() + 1, r.width()-2, r.height()-2
     
        if isinstance(color, (str, unicode)):
            color = QtGui.QColor(color)
        elif isinstance(color, (list, tuple)):
            if len(color) == 3:
                r, g, b = color
                alpha   = 255
            else:
                r, g, b, alpha = color
            color = QtGui.QColor(r, g, b, alpha)
        painter.fillRect(x, y, w, h, color)
     
    #############################################################################
    class CouleurCase(object):
     
        #========================================================================
        def __init__(self):
            self.cases = []
     
        #========================================================================
        def couleur(self, row, col):
            """si la case existe, retourne la couleur, sinon None"""
            for (r, c, coul) in self.cases:
                if row==r and col==c:
                    return coul
            return None
     
        #========================================================================
        def metcouleur(self, row, col, couleur=u"white"):
            """si la case est déjà dans la liste, change sa couleur. 
               sinon, ajoute case et couleur
            """
            for i, (r, c, coul) in enumerate(self.cases):
                if row==r and col==c:
                    self.cases[i][2] = couleur
                    return
            # la case n'est pas là: on l'ajoute avec sa couleur 
            self.cases.append([row, col, couleur])
     
    #############################################################################
    # variable globale        
    couleurCase = CouleurCase()
     
    #############################################################################
    class SudokuDelegate(QtGui.QItemDelegate):
        """delegate qui redessine chaque case"""
     
        #========================================================================
        def __init__(self, parent=None):
            super(SudokuDelegate, self).__init__(parent)
     
        #========================================================================
        def paint(self, painter, option, index):
            global couleurCase
     
            # sauvegarde la config de painter
            painter.save() 
     
            # récup des coordonnées de la case en cours
            row, col = index.row(), index.column()
     
            # récup des données (en pixels) du rectangle de la case 
            r = option.rect
            x, y, w, h = r.x()-1, r.y()-1, r.width()+1, r.height()+1
     
            # initialise le crayon gras
            pen = QtGui.QPen(QtCore.Qt.SolidLine)
            pen.setWidth(3)
            painter.setPen(pen)
     
            # dessine le côté gauche en gras
            if col in [3, 6]: 
                x1, y1, x2, y2 = x, y + h, x, y
                painter.drawLine(x1, y1, x2, y2)
     
            #dessine le côté haut en gras
            if row in [3, 6]: 
                x1, y1, x2, y2 = x, y, x + w, y
                painter.drawLine(x1, y1, x2, y2)
     
            # dessine le côté droit en gras
            if col in [2, 5]: 
                x1, y1, x2, y2 = x + w, y, x + w, y + h
                painter.drawLine(x1, y1, x2, y2)
     
            # dessine le côté bas en gras
            if row in [2, 5]: 
                x1, y1, x2, y2 = x + w, y + h, x, y + h
                painter.drawLine(x1, y1, x2, y2)
     
            # essai d'appel pour mettre les cases en couleur
            couleurCase.metcouleur(4, 1, [160, 255, 160]) # vert clair])
            couleurCase.metcouleur(6, 5, [255, 160, 160]) # rouge clair])
            couleur = couleurCase.couleur(row, col)
            if couleur != None:
                cellColor(painter, option, couleur)
     
            # restaure la config initiale de painter
            painter.restore() 
     
            # redonne la main à la méthode normale pour la suite des opérations
            QtGui.QItemDelegate.paint(self, painter, option, index)
     
    #############################################################################
    class MainWindow(QtGui.QWidget):
     
        #========================================================================
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            global couleurCase
     
            # General grid
            self.table = QtGui.QTableWidget(self)
            self.nbrow, self.nbcol = 9, 9
            self.table.setRowCount(self.nbrow)
            self.table.setColumnCount(self.nbcol)
     
            # cache les entêtes horizontale et verticale
            self.table.horizontalHeader().hide()
            self.table.verticalHeader().hide()
     
            # Each cell has dimension 50 pixels x 50 pixels
            for row in range(0, self.nbrow):
                self.table.setRowHeight(row, 50)
                for col in range(0, self.nbcol):
                    self.table.setColumnWidth(col, 50)
     
            # Each cell contains one single QTableWidgetItem
            for row in range(0, self.nbrow):
                for col in range(0, self.nbcol):
                    item = QtGui.QTableWidgetItem()
                    item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
                    self.table.setItem(row, col, item)
     
            # Header formatting
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(12)
            self.table.horizontalHeader().setFont(font)
            self.table.verticalHeader().setFont(font)
     
            # Font used
            font = QtGui.QFont()
            font.setFamily(u"DejaVu Sans")
            font.setPointSize(20)
            self.table.setFont(font)
     
            # Use of the delegate so to use thicker lines.
            self.delegate = SudokuDelegate(self.table)
            self.table.setItemDelegate(self.delegate)
            #self.delegate.initGrid(self.grid_0)
     
            # met un entourage de 3 px pour le widget QTableWidget
            self.table.setStyleSheet("QTableWidget {border: 3px solid black;} ")
     
            # calcule la taille de la grille (6=2*largeur du trait de 3 px)
            w = self.table.horizontalHeader().length()+6
            h = self.table.verticalHeader().length()+6
     
            # redimensionne le widget avec la taille de la grille
            self.table.setMinimumSize(QtCore.QSize(w, h))
            self.table.setMaximumSize(QtCore.QSize(w, h))
     
            # taille de la fenêtre
            self.resize(w+100, h+100)
     
            # placement du QTableWidget dans la fenêtre avec un QGridLayout
            layout = QtGui.QGridLayout()
            layout.addWidget(self.table, 0, 0)
            self.setLayout(layout)
     
            # Set the focus in the first cell
            self.table.setFocus()
            self.table.setCurrentCell(0, 0)
     
            # essai pour mettre les cases en couleur
            #couleurCase.metcouleur(3, 2, u"red")
            couleurCase.metcouleur(3, 5, [200,200,200])
     
            self.table.item(1, 6).setToolTip(u"1  \n45 \n7 9")
            #self.table.item(1, 6).setToolTip(u"")
     
    #############################################################################
    if __name__ == "__main__":
        app = QtGui.QApplication(sys.argv)
        fen = MainWindow()
        fen.show()
        sys.exit(app.exec_())
    Commentaires:

    Pour mettre la grille au centre de la fenêtre, y compris avec le redimensionnement, il suffit:
    - de fixer les dimensions de la grille en mini et en maxi
    - et de la placer dans un QGridLayout

    Pour mettre de la couleur dans une case, on peut soit le faire à partir de delegate, soit à partir du QTableWidget. Mais à partir du QTableWidget, la couleur a tendance à "manger" un peu d'encadrement. Alors j'ai essayé de passer systématiquement par le delegate: cela explique la classe "CouleurCase" qui gère une liste de coordonnées comme [ligne, colonne, couleur].

    Pour avoir sur demande une petite fenêtre avec les nombres permis dans la case en question, j'ai pensé à 2 solutions:

    - utiliser les bulles qui existent dans chaque case. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    self.table.item(1, 6).setToolTip(u"1  \n45 \n7 9")
    Pour annuler, il suffit de redonner l'instruction avec une chaine vide.

    - utiliser la barre de status en bas de la fenêtre, mais cela demande à prendre la fenêtre QMainWindow au lieu de QWidget.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  18. #18
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Cela a l'air zoli !

    Je teste cela avec PySide en fin de semaine car je croûle sous le boulot en retard.

    Serais-tu partant pour mettre le code sur pypi et github ? Je te mettrais en tant que concepteur associé de l'interface ou sous un autre titre.

    On pourrait aussi le mettre bien entendu sur ce site.

  19. #19
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 461
    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 461
    Points : 9 248
    Points
    9 248
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par rambc Voir le message
    Serais-tu partant pour mettre le code sur pypi et github ? Je te mettrais en tant que concepteur associé de l'interface ou sous un autre titre.

    On pourrait aussi le mettre bien entendu sur ce site.
    Pas de problème pour moi: tu pilotes! Mais avant la publication, j'aimerais simplement vérifier que ma partie est ok sur le produit final.

    Je peux te proposer, si ça te manque, une jolie fenêtre pour l'inévitable "à propos" et le copyright.

    Je peux aussi essayer d'en faire une version binaire avec cx_freeze, voire avec l'installeur "innosetup" pour Windows.

    Je peux aussi te proposer de le mettre dans la barre de notification (tray), pour que les gens qui font le sudoku au boulot puisse le faire discrètement .
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  20. #20
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Tout ce que tu me proposes est intéressant modulo innosetup car je suis librophile et windophobe...

    Je regarde donc ta proposition ce weekend tranquillement.

    Merci pour ta collaboration, c'est génial !

Discussions similaires

  1. Coquille vide pour un snake
    Par rambc dans le forum PyQt
    Réponses: 7
    Dernier message: 19/03/2013, 13h59
  2. Sélection d'une valeur vide pour un select
    Par Tiaps dans le forum Struts 1
    Réponses: 2
    Dernier message: 30/06/2006, 10h20
  3. [Tableaux] Tableau valeur vide pour une clé
    Par hisy dans le forum Langage
    Réponses: 3
    Dernier message: 17/01/2006, 11h49
  4. Réponses: 4
    Dernier message: 12/09/2005, 09h21

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