lundi 14 novembre 2016

Le retour du node graph ! ... en PySide.

Vous vous souvenez que j'avais attaqué y a quelques années la conception d'un node graph view en pyqt parce que impossible de trouver une librairie pyqt/pyside pour faire "facilement"  ce genre de choses...
http://unblogdecolin.blogspot.fr/2013/07/pyqt-qgraphicsview-la-base-pour-un-node.html
  bref j'ai laissé tombé et le projet a était avorté.  
Jusqu'au jour où j'ai discuté avec mon ami Frangipane qui a rencontré le même genre de problématique,  sauf que lui a réussi à se lancer sur la conception d'une lib pyside pour faire des graph views qui claques.  Il a déjà fait une petite base bien rodé mais loin d'être implementable pour le moment et la Frangipane commençait à s'essouffler.  
Du coup je me suis incrusté sur son projet et nous avons décidé de relancer la machine, on a chauffé les github et me voilà  en train de forker de la Frangipane à coup de push request pour faire évoluer ce projet avec lui, parce que bazar nous avons tous besoin d'une bonne lib pyside pour faire des node graph !  

Une petite  preview en image:

mardi 25 octobre 2016

Marilla api update

Petites mises à jour du module gueguetags:
https://github.com/col-one/marilla



Désormais il est possible d'ajouter aux Guerilla tags par défaut les parents des meshs sélectionnés et de choisir la profondeur.
GuegueTags prend comme argument par défaut grp=0, sa valeur précise la profondeur.
-1 infinit
0 pas de parents
1 premier parent
2 premier et second parents
3 premier, second et troisième parent
....

vendredi 21 octobre 2016

Marilla : Alembic Tags Workflow pour Maya / Guerilla Render





Il existe déjà une passerelle maya / guérilla développée par les messieurs de Guerilla, elle fonctionne très bien mais elle est très peu flexible et permet pas d'avoir un workflow de production d'Anim. Heureusement l'alembic est là et le système de référence de guérilla fonctionne très bien.


En utilisant l'outil Marilla nous allons pouvoir mettre en place un workflow de référence entre Maya et Guérilla. Comme celui-là :


   

    L'utilisation des tags a beaucoup d'avantages, cela permet de ne plus être dependant d'objets, de meshs, de fichiers ... mais simplement d'un tag. Comme dans le graph ci-dessus la même série de tags va être utiliser pour shader les alembic du modeling pour le lookdev et les alembics de l'Anim pour le rendu final. Nous utilisons plus des objects mais des etiquettes. Là où dans un workflow classique il aurait fallu réassigner les matériaux aux alembics d'Anim. Un des autres avantages c'est l'utilisation de tags transverses, comme par exemple faire des tags "peaux", "métal", "mate" ou "shiny" ...



 Dans guérilla les préfixes des références peuvent être une manière de donner un espace à nos tags par exemple:


Objet1.abc:

    mesh:
        tags:
            -tete
            -corps
            -peau
            -pied

Objet2.abc:

    mesh:
        tags:
            -tete
            -corps
            -peau
            -pied



    Lorsque l'on importe une référence alembic dans guérilla il propose de le préfixer, par défaut par le nom de du fichier, ici nos nodes auront comme nom Objet1: mesh et Objet2: mesh.

Si on importe des Renders Graph différents mais qu'ils possèdent des tags de mêmes noms il va y avoir conflit, c'est là qu'interviennent les préfixes. 
Dans les proprietes du Render Graph il y a un parametre qui s'appel 'apply on': 'tags' et dans le champs text en dessous il faut preciser le prefix 'Object1:' pour le Render Graph de l'objet 1 et 'Object2:' pour le Render Graph de l'object 2. Ainsi les tags du même nom s'appliqueront bien dans leurs espaces respectifs.
préfixe, attention au :
On peut aussi préciser des tags à la place d'un préfixe, le Render Graph s'appliquera que sur les objets qui possèdent le tag en commun. ex:

Objet1.abc:
    mesh:
        tags:
            -toto
            -tete
            -corps
            -peau
            -pied

Objet2.abc:
    mesh:
        tags:
            -tata
            -tete
            -corps
            -peau
            -pied

Ici pour le Render Graph Objet1 il faudra préciser "Toto" et pour celui d'Objet2 il faudra préciser "Tata"




tag

Encore un autre avantage des tags c'est qu'on peut les combiner et faire des opérations boolean dessus. Un objet qui possède ce genre de combinaison :





    Nous remarquons les signes plus et moins. Dans ce cas l'objet sera trouvé par tous les tags "foot, Head, Tata, Toto" sauf "novisible".
Très utiles pour les retake et tweak de fin de RenderGraph.



Voilà je vous ai presente un workflow et survolle l'utilisation des tags.
Maintenant nous allons voir l'outil Marilla qui permettra d'optimiser l'utilisation des tags de Maya vers guérilla.





Install:

Telecharger le repo Marilla sur github:
https://github.com/col-one/marilla

Placer le dossier marilla dans un répertorie qui sera source par Maya, PYTHONPATH, MAYA_SCRIPTS_PATH...


Dans le dossier marilla nous pouvons trouver un fichier userSetup.py il faut ajouter les lignes de codes presentent dedans a votre propre fichier userSetup.py si nous en avons pas nous pouvons directement copier le userSetup.py dans le bon dossier, par default cela sera:
  • Windows: :\Documents and Settings\\My Documents\maya\\scripts
  • Mac OS X: ~/Library/Preferences/Autodesk/maya//scripts.
  • Linux: ~/maya//scripts.

Le userSetup.py permet d’exécuter du code lors de l'ouverture de maya, ici ca permettra d'ajouter un menu 'marilla' a la main window.

Si tout va bien nous devrions avoir ca:



    Du cote Guerilla, il va falloir copier un fichier lua dans un dossier UserPlugins. Dans le dossier marilla / guerilla nous copions le fichier openPort.lua et le collons dans un dossier UserPlugins. Si nous n'avons pas définit de UserPlugins dans le fichier guerilla.conf nous pouvons le coller dans le dossier plugins de l'install de Guerilla.

    Toutes les fonctionnalités se trouve dans maya. 

Auto Tags, nous sélectionnons l'ensemble de nos géométries (mesh) ou nos cameras et l'exécutons, cela va taguer les transform de nos mesh avec son nom et son top parent. 

Remove All Tags, permet de supprimer tout les tags d'une sélection de mesh.

Add / Remove Tags, permet de venir ajouter des tags custom, comme on a vu plus haut les fameux tags transverses. Il faut rentrer le nom du tag dans le champs text et faire Add ou Remove. Il y a la possibilité d'ajouter ou supprimer plusieurs tags a la fois en séparant les noms par une simple virgule, 'metal,#cccccc,blured...'

Export, permet d'exporter la sélection en alembic avec les tags Guerilla et un ensemble de presets :
    -ogawa
    -world
    -uvs
    -faces groups
Attention pour avoir un bon export il faut sélectionner que des transforms si ils sont dans un group il faudra sélectionner le group. 
Dans le popup nous préciserons nos paramètres d'export. Range Mode, PreRoll... 
Et si nous checkons 'Export to guerilla' cela enverra directement notre alembic dans un Guerilla préalablement ouvert. 


Et pour finir nous avons a disposition une petite API pour les gens qui souhaite ajouter ces fonctionnalités a leur propres pipe / outils ... l'help est dispo en depuis le menu marilla dans maya.





La partie Guerilla est très succincte et mériterai une amélioration comme pouvoir proposer l'export dans un nouveau fichier Guerilla, ou encore pouvoir remplacer la référence si elle existe déjà dans la scène Guerilla...

vendredi 16 octobre 2015

INDICATORZ : Demistification du knob("indicators")





    Hey me voila de retour ! Ca va faire plus d'un an que je n'ai pas ecrit de topic. De plus j'ai plein de suites et correction a ecrire (Blink, NodeGraph...)  mais je suis une grosse feignasse donc ce n'est toujours pas fait...

    Ce topic va traiter du knob indicator qui est present dans tous les nodes nuke et qui permet de gerer les petites vignettes de couleur sur le node comme le V ou le X...

Une vrai guirlande!

    Mais derriere tout ca nous allons surtout comprendre comment marche un systeme de flag comme celui-la et pas que dans Nuke (dans le monde du developpement, tres utilise dans Unity par exemple).


ICI les differentes siginification de chaque indicateur.

Les indicateurs sont generes par un knob de type float (Array_Knob). Si je demande la valeur du knob indicators de ce node :







 
nuke.toNode("NoOp").knob("indicators").value()
# Result:
33.0

Donc nous en concluons que les vignettes V et A correspondent a la valeur 33, si je prend n'importe quel node et que je fais
 
nuke.toNode("Nawak").knob("indicators").setValue(33)

Le node Nawak se verra attribuer ces deux vignettes, si avant il possedait d'autres vignettes elles disparaitront pour etre remplace par V et A.
Attention a chaque knob changed la valeur du knob indicator est reinitialise donc dans notre cas V et A disparaitront.


Nous comprenons que chaque vignette a une valeur definit, voici leur valeur :

A  :  1
E  :  2
M  :  4
C  :  8
X  :  16
V  :  32

Nous remarquons que chaque valeur est une puissances de deux et mieux encore ca nous fait penser a un codage binaire, en bit.

Eh bien ce n'est pas pour rien ! c'est la base du systeme de flags. Dans nuke une vignette/indicateur est un flag.
Grace a ce systeme nous pouvons genere des combinaisons de flag a partir d'une seul valeur. Et meme mieux, nous pouvons tester la presence d'un flag dans cette seul valeur, savoir si l'indicateur V est present sur mon node.

Avant de savoir faire tout ca, nous allons voir en peu de binaire.
Nous allons convertir nos flag en binaire :

Flag  :  Valeur  :  Binaire
A      :       1      :      1
E      :       2      :       10
M     :       4      :       100
C      :      8       :       1000
X      :     16      :       10000
V      :      32     :       100000


Maintenant imaginons que nous voulions un ensemble de flags de type E M X :
(petit rappel 1 + 0 = 1, 0 + 0 = 0, 1 + 1 = 1)

EMX  :   22    :               10
                                     100
                                 10000
                              = 10110

La valeur binaire de la somme de nos flags est 10110.
Grace a cette somme nous allons pouvoir tester la presence d'un flag. Est ce que dans ma somme de flag 22 (EMX mais nous ne sommes pas sense le savoir) il y a present le flag M qui a comme valeur 4 ?
Pour cela nous allons "comparer" notre somme binaire de maniere bit a bit avec la valeur binaire du flag que nous cherchons, a l'inverse d'une somme classique 1 + 0 = 0 des lors qu'il y a le presence d'un 0 la somme sera 0. Pour symboliser cette "comparaison" bit a bit nous utilisons &.

EMX & M
22 & 4
10110 & 100

    10110
& 00100
=  00100

Le resultat est 00100 soit 4 soit notre flag E, il est bien present dans nos flags. Si la sommes bit a bit n'est pas egale (ou = 0) au flag recherche alors il n'est pas present dans notre ensemble de flags.

Autres exemples :
EMX & M
22 & 4
10110 & 1
    10110
& 00001
 = 00000

Le flag A n'est pas present.

En programmation les operateurs bit a bit s'appel bitwise symbolise par & pour la "comparaison". (il existe bien d'autres operateur bitwise mais cela ne nous regarde pas ... ).

Un petit exemple concret d'utilisation dans nuke:
Nous allons chercher tous les nodes qui possedes des knobs de stereos, c'est a dire qui possede l'indicateur V soit la valeur 32.
Attention les & bitwise fonctionnent avec des Integer.

 
stereo_nodes = []
view_flag = 32
for node in nuke.allNodes():
    flags_value = 0
    try:
        flags_value = node.knob("indicators").value()
    except AttributeError:
        print "this node doesnt have indicators"
    if int(flags_value) & view_flag != 0 :
        stereo_nodes.append(node)


Pour etre safe j'ai mis un try except mais sachez que tout les nodes ont un knob indicator, il est meme possible de mettre des indicateurs sur des dot ou des backdrops =))).

STYLAYYYY


















lundi 10 novembre 2014

Nuke Tuto Blink Script, la base.


    Passons a notre premier BlinkScript!

Intro du tuto : http://unblogdecolin.blogspot.fr/2014/11/tuto-blinkscript-intro.html

A travers c'est différents articles nous allons pas innover dans le processing d'image au contraire nous allons voir des choses qui existent déjà mais qui vont nous permettre d'apprendre les bases du BlinKScript pour pouvoir plus tard se prendre la tête sur des nouveaux effets ...

    Pour ce premier BlinkScript nous allons simplement additionner les pixels a une valeurs quelconque. Nous verrons la structure de base, les inputs / outputs et la fonction process().
Nous commençons par créer un nouveau node BlinkScript et nous supprimons l’intégralité du code déjà présent dans l’éditeur de texte.

    Première chose a faire c'est de créer un objet kernel dans le quel nous allons mettre toutes nos instructions. Cet objet dérive de ImageComputationKernel qui possède deux manières de traiter les pixels : eComponentWise et ePixelWise. Pour ce premier BlinkScript nous allons utiliser eComponentWise.
Pour le moment nous avons ça :


    eComponentWise traite tout les channels d'un seul coup. C'est certainement plus performant mais nous ne pourrons pas faire d’opérations sur un channel en particulier. eComponentWise est parfaitement adapte pour notre premier BlinkScript qui est une simple addition.

    Maintenant que nous avons notre kernel, il faut que nous définissions une entrée et une sortie a l’intérieur. Image et ses différents argument sont la pour ça. Le premier argument définit si l'Image est en lecture : eRead ou en écriture : eWrite. Le deuxième définit le type d’accès au pixel, dans notre cas nous avons besoin d'eAccessPoint qui est la manière la plus simple d’accéder aux pixels nous comprendrons pourquoi dans la suite. Il existe trois autres manières d’accéder aux pixels que nous verrons dans des futurs articles. Il reste un dernier argument qui permet la gestion des bords de nos images : eEdgeClamped permet de répéter a l’extérieure de l'image la valeur du pixel le plus proche du bord, eEdgeConstant va répéter des valeurs de pixel noir 0.0 alors que  eEdgeNone  répète rien et est donc l'option la plus performante. Dans notre BlinkScript Additionator nous avons pas besoin de répéter les bords donc on va utiliser eEdgeNone.
Si nous précisons pas d'argument a notre Image les valeurs par default sont eRead, eAccesPoint et eEdgeNone.
Donc nous allons creer une entree src et une sortie dst, c'est les noms choisis par foundry mais nous pouvons les nommer comme bon nous semble.


    Il nous reste plus qu'a dériver une fonction pour que notre BlinkScript soit opérationnel c'est la fonction process() cette fonction va répéter les instructions, présentes dans son bloc, pixel après pixel et ligne après ligne. Le sens de processing des BlinkScript est toujours d'en bas a droite a en haut a gauche.
Nous créons la fonction void process(){ } a la suite de nos Image :


Dans le bloc de la fonction process() nous allons rentrer toutes nos instructions. Dans notre cas tout tiens en une ligne, j'assigne la valeur du pixel de src + une 0.5 au pixel de dst. En eComponentWise pour avoir le pixel de notre src il faut appeler la fonction src() simplement et de même pour avoir le pixel de notre dst nous appelons dst().
Notre instructions sera :


Nous compilons notre BlinkScript en cliquant sur Recompile, nous connectons une image a notre input src, un viewer sur notre BlinkScript  et nous pouvons voir toute notre image être additionne a 0.5, whouaa!.

    Nous le répétons ce BlinkScript ne fait absolument rien de fou mais c'est la meilleur façon de voir comment fonctionne un BlinkScript. En resume, pour que notre BlinkScript fonctionne il lui faut une entre et une sortie et une instruction dans process(). Il faut voir la fonction process() en peu comme une double boucle for :

for(y=0; y‹h; y++){
  for(x=0; x‹w; x++){
    ...
  }
}

Elle va parcourir tout les pixels de l'image et appliquer ses instructions sur chacun d'eux.

    Concrètement pour que notre BlinkScript soit facile utiliser il lui manque un knob pour que l'utilisateur puisse changer la valeur a additionner de manière interactive et non en changent le code. Nous verrons comment procéder dans un prochain article.

a++


C.


Nuke Tuto Blink Script, intro.







English version, here.


     Depuis la version 8 de nuke the foundry nous propose une nouveauté qui est le node de BlinkScript.
 Le node de BlinkScript a comme fonction de "processer" les pixels d'une image, c'est a dire permettre d'appliquer des calculs et des algorithmes sur chaque pixel d'une image a l'aide d'un langage de programmation. Avant l'existence du BlinkScript ce genre de calcul au niveau du pixel était possible, sans passer par le NDK, avec l'utilisation de la fonction sample() en python mais c'était extrêmement couteux en performance. Parcourir une image pixel par pixel en pyhon peut prendre plusieurs dizaines de seconds voir minutes selon l'utilisation des valeurs du pixel et de la taille de l'image. Grâce au BlinkScript les performances sont bien meilleurs.

    Nous allons rapidement voir comment le BlinkScript fonctionne, il possède un éditeur de texte qui lui permet de recevoir le code qui lui fournit les instructions a exécuter. Une fois ce code rentré nous allons demande au BlinkScript de le convertir et de le compiler en cliquant sur le bouton Recompile ainsi il devient utilisable par nuke. Le langage utilisé pour "coder" des BlinkScript est un langage dit "kernel" avec une syntaxe proche de celle du C++ il sera converti dans un langage adapté a l’exécution de ces instructions soit sur le CPU soit sur le GPU (SMID ou OpenCL). Une fois converti et compile le BlinkScript devient aussi performant, voir plus qu'un node classique code en C++ avec le NDK. Le système de Blink a été aussi intégré aux NDK pour pouvoir développer des nodes C++ et profiter de cette nouvelle technologie CPU / GPU.

    Le réel avantage du BlinkScript est donc sa performance mais il possède quelques mauvais points. Il est bon de les savoir pour comprendre les limites de ce node et ne pas perde de temps a essayer de programmer des choses que le BlinkScript ne pourra pas faire.
    Le BlinkScript travail que sur le pixel, il est impossible de travailler sur un autre contexte. Par exemple ce n'est pas possible de paramétrer la taille d'une image, de changer de frame, de changer les connections du BlinkScript ... Il n'agit que sur le pixel.
    Le BlinkScript peut posséder des Knobs mais leurs valeurs peuvent être attribué qu'a la première exécution du BlinkScript. Au final nous pouvons qu'initialiser les valeurs des Knobs. Il est impossible de changer une valeur d'un knob en cour de processing (calcule de l'image) par contre elles peuvent être lues. Si la valeur d'un knob est changé "manuellement" le processing sera relancé automatiquement avec cette nouvelle valeur.
    Le BlinkScript étant assez nouveau la gestion des erreurs de syntaxe ou de compilation sont souvent flous et nous aide pas beaucoup pour trouver d’où vient notre erreur. Il faut se préparer a passer du temps a debugger notre BlinkScript. Une bonne connaissance en C++ peut être un avantage pour corriger et éviter ce genre d'erreurs.
    Le BlinkScript ne travail que sur les channels R, G, B, et A ce qui nous oblige très souvent a faire précéder le BlinkScript d'un Shuffle pour rediriger les Channels souhaité vers RGBA.
    Nous pouvons en déduire que le BlinkScript est a utiliser principalement dans un gizmo entouré d'une panoplie de nodes pour le préparer et agir sur d'autre contexte que celui du pixel.

   Une fois satisfait du code de votre BlinkScript il est possible de le publier, c'est a dire que nuke va préparer le node a une utilisation en production. Nuke va grouper notre BlinkScript et linker ses knobs sur l'interface du group. Nous avons le choix de crypter le code source pour éviter tout plagia si notre souhait est de garder secret nos supers algorithmes, l’éditeur de texte disparaitra. Si nous décidons de ne pas crypter, le code source sera accessible dans l’éditeur de texte du BlinkScript.

    Voila nous avons fait un rapide tour d'horizon de ce nouveaux node. Son fonctionnement, ses avantages et ses désavantages nous paraissent plus clair. Nous sommes prés a nous lancer dans le développement d'un BlinkScript. Dans les prochains articles nous allons voir comment utiliser les différentes fonctions du BlinkScript a travers plusieurs exemples.

Suite du tuto :  http://unblogdecolin.blogspot.fr/2014/11/nuke-tuto-blink-script-suite.html

A++

C.



    Since version 8 of nuke the foundry proposes a novelty that is the node of BlinkScript.
    The node of BlinkScript as function to process the pixels of an image, that is possible to apply calculations and algorithms on each pixel of an image using a programming language. Before its existence such of calculation at the pixel level was possible, without going through the NDK, with the use of the sample() function in python but it was extremely costly in performance. Browsing image pixel a pixel with pyhon may take severals tens of seconds depending using of pixel values and the image size. Thanks to BlinkScript performance is much better.

    Quickly we'll see how the BlinkScript works, it has a text editor that allows it to receive the code which provides instructions to execute. Once the code has been entered we will ask the BlinkScript to convert and compile it by clicking the button Recompile, so it becomes usable by nuke. The language used to "encode" the BlinkScript is a sort of language called "kernel" with a syntax similar to the C++ then it will be converted into a suitable language to the execution of these instructions either on the CPU or on the GPU (MISA or OpenCL ). Once converted and compiled BlinkScript also becomes effective, like a classic node code in C ++ with the NDK. Blink system has also been integrated into the NDK to develop nodes in C ++ and enjoy this new CPU / GPU technology.

    The real advantage is BlinkScript's performance but it has some bad points. It is good to know to understand the limits of this node and not wast our time trying to manage things that BlinkScript can not do.
   The BlinkScript work on the pixel, it is impossible to work on a different context. For example it is not possible to set the size of an image, change frame, change the connections BlinkScript ... It works only on the pixel.
    The BlinkScript may possess Knobs but their values can only be assigned has the first run of the BlinkScript. Finally, we can just initializes the values of the Knobs. It is impossible to change a value of a knob during processing, in contrast they can be read. If the value of a knob is changed "manually" the processing will be restarted automatically with this new value.
    The BlinkScript being fairly new that's why error handling syntax or compilation are often vague and not much help us to find where our error is. We must prepare to spend our time to debug BlinkScript. A good knowledge of C ++ can be a benefit to correct and prevent such errors.  
    The BlinkScript work on the channels R, G, B, A and so we have very often precede the BlinkScript a Shuffle to redirect to the desired RGBA Channels.
     We can deduce that the BlinkScript is to use primarily in a gizmo surrounded by an array of nodes to prepare and act on context other than the pixel.


    Once satisfied with the code of your BlinkScript it is possible to publish it, that nuke will prepare the node has a production use. Nuke will group our  BlinkScript and link knobs to its interface group. We have the choice to encrypt the source code to avoid plagiarism if our desire is to keep our secret algorithms, the text editor will disappear. If we decide not to encrypt the source code will be available in the text editor BlinkScript.

    Here we did a quick tour of this new node. Its operation, its advantages and disadvantages we seem clearer. We are ready to get into the development of a BlinkScript. In future articles we will see how to use the various functions of BlinkScript through several examples.

The next tuto :    http://unblogdecolin.blogspot.fr/2014/11/nuke-tuto-blink-script-suite.html

A++

C.









jeudi 9 janvier 2014

Ajouter des Widget dans des QListWidget et les appeler


    Voila une petite maniere de creer des widgets dans les lignes dune QListWidget et de pouvoir les appeler pour les utiliser.



from PySide.QtGui import *
from PySide.QtCore import *

class Win(QListWidget) : 
    def __init__(self) : 
        super(Win, self).__init__()

        s = QSize(25, 25)

#On met des widget type QCheckBox dans nos ligne
#de notre QListWidget

    #on rajoute 10 ligne
        for i in range(10) : 

        #On instancie un QListWidgetItem qui contiendra 
        #nos QCheckBox et QSpinBox
            item = QListWidgetItem()
            item.setSizeHint(s)

        #on cree nos widgets
            if i % 2 == 0 :
                cb = QCheckBox("Check Box " + str(i))
                cb.setFixedHeight ( 25) 
            else : 
                cb = QSpinBox()
                cb.setSuffix(" : Spinn Box " + str(i))
                cb.setFixedHeight ( 25)

        #On ajoute notre QListWidgetItem dans une ligne
        #grace a addItem() de QListWidget
            self.addItem(item)

        #Et on ajoute nos CheckBox et SpinBox a nos QListWidgetItem
        #Grace a la methode setItemWidget() de QListWidget
        #Le premier arg est le QListWidgetItem, le second arg est notre
        #Widget, pour nous QCheckBox et QSpinBox
            self.setItemWidget(item, cb)


            self.show()

#On recupere nos widget spinbox et checkbox : 

    #liste tous les items present dans le QListWidget
    #dans notre cas se sont des QListWidgetItem 
        widgetItems = []
        for i in range(self.count()) : 
            item = self.item(i)
            widgetItems.append(item)

    #on liste tous nos widget present dans nos QListWidgetItem
    #en passant par la method itemWidget() de QListWidget()
        checkItems = []
        for it in widgetItems : 
            ch = self.itemWidget(it)
            checkItems.append(ch.text())

            
s = Win()