Fenêtre superposant une autre fenêtre

Fermé
Phidippides Messages postés 13 Date d'inscription samedi 29 décembre 2012 Statut Membre Dernière intervention 19 mars 2021 - 22 janv. 2019 à 17:07
Phidippides Messages postés 13 Date d'inscription samedi 29 décembre 2012 Statut Membre Dernière intervention 19 mars 2021 - 31 janv. 2019 à 23:21
Bonjour,

Tout d'abord je n'ai pas beaucoup d'expérience avec Python, cela fait seulement quelques mois que je l'ai découvert.
Je suis en train de développer un solveur de sudoku mais j'ai un problème que je n'arrive pas à résoudre.
J'ai créé une première fenêtre pour ma grille de Sudoku qui est divisée en cellules.
Parfois évidemment, il peut y avoir plusieurs possibilités pour une même cellule jusqu'à ce que l'on déduise le seul chiffre possible.
Pour cela, j'ai créé une petite fenêtre aux dimensions de la cellule qui est elle-même divisée en 9 mini-cellules et dans laquelle l'utilisateur peut entrer les chiffres possibles.
Tout cela marche très bien mais si je clique sur le '-' (en haut à droite) de la fenêtre principale, celle-ci est iconifiée mais pas la ou les petites mini-grilles superposées aux cellules de mon Sudoku (ma fenêtre principale). De la même façon, si je superpose une autre fenêtre (par exemple mon moteur de recherche) à ma grille de Sudoku, cette dernière est effectivement cachée mais pas les petites fenêtres (mini-grilles) qui apparaissent toujours.
J'ai essayé de détecter un 'event' qui est 'Unmap' pour résoudre le problème. Cela marchait effectivement très bien quand j'étais sous Windows 7 mais maintenant que je tourne sous Linux (Ubuntu avec GNOME shell), cela ne marche plus. J'ai essayé des tas d'autres 'events' mais je n'arrive pas à m'en sortir.

Mes questions sont :

1) Quel est l'événement déclenché quand je clique gauche sur le '-' (en haut à droite) de la fenêtre principale, pour iconifier celle-ci ? Et comment récupérer cet événement pour lancer une fonction qui cacherait mes mini-grilles ?
2) Quand je recouvre ma grille de Sudoku (fenêtre principale) par une autre fenêtre (extérieure à mon logiciel), comment faire en sorte que mes mini-grilles soient aussi recouvertes ?

Je serais vraiment reconnaissant à ceux qui pourraient me donner un coup de pouce.

1 réponse

Yoan Messages postés 11795 Date d'inscription mardi 1 février 2005 Statut Modérateur Dernière intervention 10 décembre 2023 2 327
22 janv. 2019 à 22:53
Après une recherche sur le terme Unmap, j'en déduis que vous utilisez Tkinter, ce qui est primordial à préciser.

Si vous lisez l'anglais et cette discussion, il semble que le terme "unmap" n'a pas le même sens sous Linux, et en particulier ce n'est pas l'événement qui ce déclenche en cliquant sur le "-".

Sur la même discussion, une solution avec wmctrl et xprop est proposée, mais vous allez vous retrouver avec du code non portable (différent selon s'il est sous Linux ou Windows).

Pour déterminer si un autre événement pourrait vous intéresser, je vous suggère de créer un petit programme tout simple qui imprime tous les événements reçus 1 fois par seconde. Vous cliquez sur - et vous regarder ce qui a été affiché à l'écran.

Je n'ai pas bien compris comment était organisée votre interface graphique et vos mini grilles. Elles sont de quelles classes vos mini grilles ? Classe Tk ?
0
Phidippides Messages postés 13 Date d'inscription samedi 29 décembre 2012 Statut Membre Dernière intervention 19 mars 2021
Modifié le 23 janv. 2019 à 18:34
Bonjour Yoan

Je n'ai pas pu détecter l'"event" quand on clique sur le '-' pour iconifier la fenêtre principale.
J'ai en fait essayer d'afficher les "events" quand on clique gauche au niveau de la fenêtre Tk mais rien n'est affiché quand on clique sur le '-'. Par contre il m'affiche bien tous les "events" quand je clique n'importe où dans la fenêtre. Je vous donne un code de test ci-dessous :

import tkinter as tk
from tkinter.font import Font
from collections import namedtuple

RC = namedtuple('RC', 'rows columns')
BBox = namedtuple('BBox', 'x y width height')


class HintWindow(tk.Toplevel):        # fenêtre utilisée pour afficher les mini-grilles

    def __init__(self, bbox, bg='yellow', alpha=0.3, state='normal'):
        super().__init__(bg=bg)
        if state == 'withdrawn':
            self.withdraw()
        self.overrideredirect(True)
        self.geometry("%dx%d+%d+%d" % (bbox.width, bbox.height, bbox.x, bbox.y))
        self.wm_attributes('-alpha', alpha)

class Cell:        # Tout ce qui concerne les 81 (= 9 x 9) cellules de la grille de Sudoku
    _iid = None
    _square_cfg = dict(fill='white', width=1, outline='white',
                       activeoutline='red', activewidth=3, tag='cell')
    _hintcell = None

    @property
    def iid(self):
        return self._square

    def __init__(self, canvas, rc, coords, text_color='black'):
        self.canvas = canvas
        self.rc = rc
        self.coords = coords
        self.center = (coords[0] + coords[2]) // 2, (coords[1] + coords[3]) // 2
        self._square = canvas.create_rectangle( coords, self._square_cfg)
        self._label = canvas.create_text(self.center, fill=text_color, text='', font=canvas.font, tag='cell')
        self.value = 0

    def set_value(self, value):
        itemconfig = self.canvas.itemconfigure
        s = str(value) if value else ''
        itemconfig(self._label, text=s)
        self.value = value

    def create_hintcell(self, values):     # crée la fenêtre et la mini-grille incluse dans celle-ci
        '''hint as reusable toplevel'''
        w = None
        if self._hintcell is None:
            bbox = self.canvas.root_bbox(self.iid, 1, 1)
            w = HintWindow(bbox, bg='white', alpha=0.7)
            hints = self._hintcell = HintsGrid(w, self)
            hints.pack(fill='both', padx=2, pady=2)
        self._hintcell.load(values)
        return w

class Grid(tk.Canvas):         # classe parent de la grille SudokuGrid et de la mini-grille HintsGrid qui effectue 
                                                    tout ce qui est commun aux 2 classes filles 
    _cfg = None
    cellsize = None
    font = None
    RC = None
    SPACING = None
    font_config = None

    def __init__(self, parent=None):
        self._cfg['width'] = self.RC[0] * (self.cellsize + self.SPACING)
        self._cfg['height'] = self.RC[1] * (self.cellsize + self.SPACING)
        super().__init__(parent, self._cfg)

        self.font = Font(**self.font_config)
        self._cells = {} # maps (r, c) to cell

        for r in range(self.RC.rows):
            y0 = r * (self.cellsize + self.SPACING)
            y1 = y0 + self.cellsize
            for c in range(self.RC.columns):
                x0 = c * (self.cellsize + self.SPACING)
                x1 = x0 + self.cellsize
                rc = (r+1, c+1)
                self._cells[rc] = self.create_cell(rc, (x0, y0, x1, y1))

    def cell(self, r, c):
        if (r, c) in self._cells:
            return self._cells[(r, c)]

    def root_bbox(self, iids, dx=0, dy=0):
        if not isinstance(iids, list):
            iids = (iids,)
        x0, y0, x1, y1 = self.bbox(*iids)
        w = x1 - x0
        h = y1 - y0
        x = self.winfo_rootx() + x0
        y = self.winfo_rooty() + y0
        return BBox(x+dx, y+dy, w-dx, h-dy)

class SudokuGrid(Grid):     # ma grille de Sudoku
    _cfg = dict(bd=0, highlightthickness=False, background='grey')
    cellsize = 63
    RC = RC(9, 9)
    SPACING = 2
    font_config = dict(family='Helvetica', size=(cellsize // 3))
    _toplevel = None
    _model = None

    def __init__(self, parent):

        self.create_cell = lambda rc, coords: Cell(self, rc, coords)
        super().__init__(parent)
        self._hints = []

    def load(self, initial_values):
        for r, values in enumerate(initial_values, 1):
            [ self.cell(r, c).set_value(v) for c, v in enumerate(values, 1) if v ]

    def update(self):
        toplevel = self.toplevel
        toplevel.bind('<Unmap>', self.on_minimize, '+')     # c'est ici que cela coince
        super().update()

    @property
    def toplevel(self):
        if self._toplevel is None:
            self._toplevel = self.winfo_toplevel()
        return self._toplevel

    def on_minimize(self, event):
        for h in self._hints:
            h.withdraw()

    def hint_cell(self, r, c, values):
        self._hints.append(self.cell(r, c).create_hintcell(values))

class HintsGrid(Grid):     # ma mini-grille incluse dans ma fenêtre HintWindow
    _cfg = dict(bd=0, highlightthickness=False, background='white')
    cellsize = 17
    RC = RC(3, 3)
    SPACING = 4
    font_config = dict(family='Helvetica', size=11)

    def __init__(self, parent, cell, values=None):
        self.create_cell = lambda rc, coords: Cell(self, rc, coords, text_color='blue')
        self._cell = cell
        super().__init__(parent)
        if values:
            self.load(values)

    def load(self, values):
        z = 1
        for r in range(self.RC.rows):
            for c in range(self.RC.columns):
                cell = self.cell(r+1, c+1)
                if z in values:
                    cell.set_value(z)
                else:
                    cell.set_value(0)
                z += 1

if __name__ == '__main__':

    G = [ (0, 2, 0,  5, 0, 1,  0, 9, 0),
          (8, 0, 0,  2, 0, 3,  0, 0, 6),
          (0, 3, 0,  0, 6, 0,  0, 7, 0),

          (0, 0, 1,  0, 0, 0,  6, 0, 0),
          (5, 4, 0,  0, 0, 0,  0, 1, 9),
          (0, 0, 2,  0, 0, 0,  7, 0, 0),

          (0, 9, 0,  0, 3, 0,  0, 8, 0),
          (2, 0, 0,  8, 0, 4,  0, 0, 7),
          (0, 1, 0,  9, 0, 7,  0, 6, 0),
      ]

    app = tk.Tk()
    app.resizable(False, False)
    app.tk_focusFollowsMouse()
    grid = SudokuGrid(app)
    grid.load(initial_values=G)

    grid.pack(fill='both')
    grid.update()

    grid.hint_cell( 1, 1, (1, 2, 5, 6))

    app.mainloop()
0
Bonjour.

Les fenêtres toplevel dont les bordures ont été enlevées ne peuvent plus être gérées via le gestionnaire de fenêtre du système d'exploitation.

https://www.tcl.tk/man/tcl8.4/TkCmd/wm.htm#M37

Il serait donc sans doute plus simple d'insérer ces toplevels dans le canvas avec create_window pour ne pas se compliquer la vie.
0
Phidippides Messages postés 13 Date d'inscription samedi 29 décembre 2012 Statut Membre Dernière intervention 19 mars 2021 > jokler
26 janv. 2019 à 16:12
Merci jokler

Je vais tester pour voir si ça me satisfait.
0
Phidippides Messages postés 13 Date d'inscription samedi 29 décembre 2012 Statut Membre Dernière intervention 19 mars 2021 > jokler
31 janv. 2019 à 23:21
Voilà j'ai fini de modifier et de tester et c'est parfait.
Encore grand merci à toi jokler.
0