Salut,
Rien de bien mirobolant, juste une appli python qui permet de créer des fichiers .desktop pour Linux (Ubuntu).
Le git est là :
https://github.com/diablo76600/Ubuntu-Desktop-File
Salut,
Rien de bien mirobolant, juste une appli python qui permet de créer des fichiers .desktop pour Linux (Ubuntu).
Le git est là :
https://github.com/diablo76600/Ubuntu-Desktop-File
bonjour
coté "linux":
Pourquoi cette liste de catégorie pas standard ?
La liste officielle est ici et à noter que TextEditor n'est qu'une des nombreuses sous-catégories.
Pourquoi parler de ubuntu ?
Ces fichiers sont un standard freedesktop respecté par les bureaux.
Pourquoi écrire un outil en QT alors que ubuntu est gtk (normalement) ? Pour kde ok, mais pour gnome (comme son nom et l'icône l'indique), cela me parait absurde. Mais, ok si c'est pour tout bureau
Choix de l'icône :
Avoir la possibilité de piocher dans le thème actif me semble un minimum !
Lanceur de cette application:
Pourquoi créer un script bash alors qu'il suffit de mettre un shebang à ton fichier main.py ?
--------------
Coté python je n'ai pas regardé en profondeur, juste très surpris de trouver un fichier "model.py" sans le "modèle" des datas de ce fichier.
En fait, tu n'utilises même pas un modèleDu coup, le métier est complètement imbriqué dans la Gui et ce qui entraine que je n'ai même pas envie de lire le code.
Dans le dialogue de sauvegarde, tu pourrais ajouter filter = "Application file (*.desktop)"
Bonjour
Une critique (un conseil): par exemple sur cette fonction (au hasard)...
... pourquoi définir le type de façon textuelle ? C'est tout sauf efficace. Analyser une chaine c'est loooong (relativement aux comparaisons numériques je veux dire). Surtout qu'en plus Qt offre déjà les constantes existantes !!! Pourquoi en redéfinir d'autres qui seront au mieux inutiles ?
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 def display_message(title: str, text: str, type_message: str) -> None: """Display a message box with the specified title, text, and type.""" if type_message == "warning": QMessageBox.warning(None, title, text) else: QMessageBox.information(None, title, text)
Et à l'appel, tu lui passes au choix QMessageBox.Warning ou QMessageBox.Information. Ou (à voir) un autre flag permettant d'afficher un autre type de messageBox (fonction alors à faire évoluer ce qui est assez facile dans la structure match...)
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 def display_message(title: str, text: str, type_message=QMessageBox.Information: int) -> None: """Display a message box with the specified title, text, and type.""" match type_message: case QMessageBox.Warning: box=QMessageBox.warning case QMessageBox.Information: box=QMessageBox.information # match box(None, title, text)
Autre chose: hériter de Qt c'est bien... mais cela ne doit pas faire perdre les avantages des objets d'origine (autrement dit, on préserve les objets et tous leurs paramètres). Surtout...
...que ce n'est franchement pas super compliqué...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class UbuntuDesktopFileCategoriesView(QDialog): """Manage the Ubuntu Desktop File Categories View.""" def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs)
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Il ne faut pas exagérer !Analyser une chaine c'est loooongL'application ne va certainement pas afficher 1000 erreurs en même temps.
mais: je suis tout a fait raccord avec la modification !
@Diablo76
En programmation, il est classique de remplacer les constantes chaines (dupliquées) par des constantes numériques :
- moins de place en mémoire
- plus rapide ...
- surtout pas de risque d'erreur (en gros, tu as presque écrit : getattr(QMessageBox, type_message)(None, title, text))
ps: voir, parfois, si besoin, remplacer par des constantes de type enum
Hello,
Pour display_message,
ça ne fonctionnerait pas ? Car type_message ne semble pas optionnel... la doc me semble pas vraiment utile pour ce genre de méthode, son nom se suffit à elle même.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 def display_message(title: str, text: str, type_message: str) -> None: """Display a message box with the specified title, text, and type.""" getattr(QMessageBox, type_message)(None, title, text)
Mais au final, la question à se poser, c'est qui gagne-t-on comparé à l'utilisation directe de QMessageBox.warning ou QMessageBox.information ?
La structure du projet n'est pas très harmonieuse, mais au final on s'en fou un peu... parce-que c'est un petit projet, et que la maintenabilité est simple et qu'on s'y retrouve sans trop de difficulté.
Et je suis d'accord avec @papajoker, attention aux noms que l'on veut donner surtout quand on veut y apporter un sens, un modèle ou "domain" correspond généralement a la définition des entités métier...
L'esthétisme est bon, si c'est fonctionnel c'est top ! Mais on va pas se leurrer, ce code ne grossissant pas dans le futur, j'ai pas grand chose à en dire, sinon que l'essentiel est là, ça fonctionne !
EDIT :
Sve@r,
Je ne suis pas sûr de comprendre cette phrase, n'est-ce pas l'appel standard d'une fonction ou d'une méthode avec des arguments optionnels (sans les spécifier à nouveau) ?Autre chose: hériter de Qt c'est bien... mais cela ne doit pas faire perdre les avantages des objets d'origine (autrement dit, on préserve les objets et tous leurs paramètres)
Pour démontrer,
Je conserve bien tous les attributs de ma classe mère...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class Test: def __init__(self, parent=None, x=5): # Même configuration que l'initialisation de QDialog (2 args optionnels) self.parent = parent self.x = x class NewTest(Test): def __init__(self, *args, **kwargs): super().__init__() nt = NewTest(2, 3, a=5, d="z") print(nt.parent) # None print(nt.x) # 5
Mais peut-être n'ai je pas compris où tu voulais en venir avec cette remarque ?
En fait, il nous manque une info ! Quelle est la logique derrière ce code ?pas grand chose à en dire, sinon que l'essentiel est là, ça fonctionne !
Si le but est juste qu'il fonctionne, alors ok pour le code
Si le but est de faire un "template" de bon code (je soupçonne avec les noms controleur et modele), alors c'est loupé.
- Qt a son propre système mvc (pour ce strict besoin, pas trop utile ici)
- Bloquer la taille des fenêtreset en plus, tu places les composants de façon statique
Et même si on fixe la taille de l'application/dialogues, dans tous les cas, on place/taille les composants relativement, par rapport au conteneur. On peut attribuer des marges si c'est cela qui te pose problème.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 pushButton_quit.setGeometry(QRect(758, 352, 68, 32)) utton_y = 168 self.gridLayoutWidget.setGeometry(QRect(8, 8, 585, 165)) QRect(int((self.width() / 2) - 34), 352, 68, 32) self.label_icon_application.setGeometry(QRect(758, 274, 68, 68))
Si tu crées un objet qui hérite d'un QDialog (ou de tout autre objet), ce que tu crées doit à minima offrir les mêmes possibilités que l'objet hérité (sinon on ne fait pas d'héritage). Prenons ton Test et NewTest, tu dois pouvoir utiliser NewTest au-moins exactement comme Test (ce qu'il fait en plus ne doit pas enlever ce que fait "Test").
Et justement ton NewTest tel que tu l'as écrit (avec *args et **kwargs) offre la possibilité de l'appeler comme Test et ça c'est bon. Mais si tu enlèves *args et **kwargs, tu es alors obligé de lui mettre des paramètres à l'image de ceux de Test (ce qui freine alors son évolutivité).
Evidemment (tout avantage amène souvent un inconvénient en retour) cela offre la possibilité d'appeler NewTest avec des paramètres non prévus comme dans ton exemple NewTest(2, 3, a=5, d="z"). Dans ce cas c'est Test qui doit checker et refuser "a" et "d" (comme le fera QDialog si tu l'appelles avec des paramètres non attendus).
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Mais on est bien d'accord que QDialog ne prend pas comme argument *args et **kwargs comme paramètres d'initialisation mais deux paramètres nommés et optionnels qui sont parent et f (flag) ?Et justement ton NewTest tel que tu l'as écrit (avec *args et **kwargs) offre la possibilité de l'appeler comme Test et ça c'est bon. Mais si tu enlèves *args et **kwargs, tu es alors obligé de lui mettre des paramètres à l'image de ceux de Test (ce qui freine alors son évolutivité).
Pour aller plus loin dans mon code, voilà ce que je peux être amené à faire sans perdre ni attribut ni méthode de Test.Evidemment (tout avantage amène souvent un inconvénient en retour) cela offre la possibilité d'appeler NewTest avec des paramètres non prévus comme dans ton exemple NewTest(2, 3, a=5, d="z"). Dans ce cas c'est Test qui doit checker et refuser "a" et "d" (comme le fera QDialog si tu l'appelles avec des paramètres non attendus).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class NewTest(Test): def __init__(self, *args, **kwargs): super().__init__() self.arguments = args self.dictionary = kwargs nt = NewTest(2, 3, a=5, d="z") print(nt.parent) # None print(nt.x) # 5 print(nt.arguments) # (2, 3) print(nt.dictionary) # {'a': 5, 'd': 'z'}
Effectivement les termes sont mal choisis, et peut-être qu'il en ressort une incompréhension.Si le but est de faire un "template" de bon code (je soupçonne avec les noms controleur et modele), alors c'est loupé.
Tout à fait d'accord. *args et **kwargs tu le mets dans ton objet (d'ailleurs tu ne les as pas mis dans "Test" mais dans "NewTest" et ma toute première remarque s'appliquait à l'objet "UbuntuDesktopFileCategoriesView" de Diablo76) afin que l'utilisateur de ton objet puisse l'appeler avec les paramètres attendus par QDialog (pour avoir depuis ton objet le comportement de QDialog qu'il est en droit d'espérer).
Et c'est la magie de Python (ou plutôt l'unpacking) qui fait que puisque QDialog attend un paramètre "parent", si tu appelles UbuntuDesktopFileCategoriesView avec un paramètre "parent" ce paramètre sera transmis tel quel à QDialog. Et si tu ne le mets pas (effectivement c'est optionnel) ben il n'y aura pas de paramètre "parent" transmis.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Ok je vois que tu es embêté avec le *args et **kwargs, je le retire
On est bien d'accord que NewTest a un intérêt en y ajoutant des attributs comme il a pu être fait sur la UbuntuDesktopFileCategoriesView ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class NewTest(Test): def __init__(self): super().__init__() self.arguments = (2, 3) self.dictionary = {'a': 5, 'd': 'z'} nt = NewTest() print(nt.parent) # None print(nt.x) # 5 print(nt.arguments) # (2, 3) print(nt.dictionary) # {'a': 5, 'd': 'z'}
Note que Test prend la même configuration qu'un QDialog
je comprends Sve@r , c'est simplement le O du principe SOLID
Mais, ici dans cette appplication, je ne vois pas l'intéret :une entité applicative (classe, fonction, module ...) doit être fermée à la modification directe mais ouverte à l'extension
- c'est une classe finale
- cette classe ne sera jamais surchargée
- surtout, cette classe n'est utilisée que par un seul appel (je suppose donc que le dev a déjà passé tous ces bons paramètres). Et à la limite, si il désire changer un truc, c'est exactement le même travail de modification dans main ou le fichier de cette classe.
Si la classe était utilisée plusieurs fois et peut-être dans un contexte différent, alors oui, il faut l'Ouvrir au maximum.
Perso ? dans ce code, je ne passerais pas kwargs à cette class CategoriesDialog
EDIT:
Nous sommes bien d'accord, c'est un super principe. Mais le problème ici, c'est que tu n'as pas trop donné de raison. Le faire machinalement peut en être une...
Ben non, c'est justement la solution la plus efficace (et que je plébiscite) pour conserver l'héritage !!!
Bien sûr !!! Faire un héritage c'est pour avoir le beurre et l'argent du beurre. Mais il faut tout de même avoir le beurre.
Prends cet exemple: un objet "vehicule" (qui est présumé provenir d'une lib quelconque donc qui n'est pas de toi)
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 class vehicule: def __init__(self, vMax): self.vMax=vMax
Toi ton job est de créer un objet qui va hériter de véhicule (donc rajouter un truc "en plus", on va dire la marque, sans perdre les propriétés du véhicule).
Solution 1
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class voiture(vehicule): def __init__(self, marque, vMax): super().__init__(vMax) self.marque=marque
L'utilisateur: vvv=voiture("marqueX", 200)...
Solution 2
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class voiture(vehicule): def __init__(self, marque, *args, **kwargs): super().__init__(*args, **kwargs) self.marque=marque
L'utilisateur: vvv=voiture("marqueX", 200)...
Les deux solutions fonctionnent et sont utilisables de la même façon (y compris si l'objet de base a des paramètres facultatifs).
Mais la première impose de connaitre l'objet hérité (savoir ce qu'il attend pour reproduire les paramètres attendus dans ton objet). Et n'oublions pas que cet objet peut lui-même hériter d'un objet de plus haut niveau => obligé de tout connaitre pour créer un objet hérité correct.
Alors que la seconde est souple. Tu n'as pas à te préoccuper de "vehicule", tu lui passes "*args" et "**kwargs" sans te faire de noeud au cerveau et roule (c'est le cas de le dire).
Et en plus la seconde permet de suivre l'évolution. Si "vehicule" évolue...
... tu n'as pas besoin de modifier ton objet et c'est ça qui est important.
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class vehicule: def __init__(self, vMin, vMax): self.vMin=vMin self.vMax=vMax
Je pars du principe que Diablo76 nous a demandé un avis, qu'il a envie d'apprendre des trucs qu'il ne sait pas forcément, et qu'il pourra les appliquer demain dans d'autres objets plus critiques. Pour résumer c'est juste "pour le principe"![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Ton exemple ne coïncide pas avec QDialog et ses deux arguments optionnels. vehicule a son initialisation prend un argument obligatoire, on est donc obligé lors de l'héritage de l'utiliser avec super().__init__(vMax=...).
En appelant super().__init__() il appelle la classe mère avec ses deux arguments par défaut, il n'y a pas besoin de les spécifier. C'est comme exécuter une fonction avec des arguments optionnels.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 def test(a=2, b=3): pass test() # pas d'erreur
J'ai précisé que ça fonctionne aussi avec les arguments optionnels. Remplace (dans l'objet d'origine) vMax par vMax=200 par exemple...
Toute la question est là: et s'il veut les spécifier justement ? S'il veut appeler son objet avec un parent (parce que la parenté sous Qt c'est super important et que là il ne s'en préoccupe pas du tout) ???
Le principe est de pouvoir tout offrir, et pas seulement offrir le cas par défaut.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Il me semble que ce choix est un choix délibéré, il veut utiliser les paramètres par défaut pour parent et f.Toute la question est là: et s'il veut les spécifier justement ?
C'est important, mais dans son cas, il n'a pas ce besoin à mon sens. Si on met des valeurs par défaut, c'est justement prévu que si on ne les utilise pas, ça rend tout de même fonctionnel le code. Il semble que ce choix lui convienne...S'il veut appeler son objet avec un parent (parce que la parenté sous Qt c'est super important et que là il ne s'en préoccupe pas du tout) ???
Eh bien je peux l'écrireRemplace (dans l'objet d'origine) vMax par vMax=200 par exemple...
ou comme cela si je sais que ma renault roule à 200 km max
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 class vehicule: def __init__(self, vMax=200): self.vMax=vMax class voiture(vehicule): def __init__(self, marque): super().__init__(vMax=160) self.marque=marque v = voiture("renault") print(v.vMax) # 160
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 class vehicule: def __init__(self, vMax=200): self.vMax=vMax class voiture(vehicule): def __init__(self, marque): super().__init__() self.marque=marque v = voiture("renault") print(v.vMax) # 200
C'est un avis (qui suit celui de papajoker). Je ne peux que te répondre la même chose: je suis parti du postulat que Diablo76 voulait notre avis, je lui ai donné le mien. Toutefois les habitudes ont la vie dure et on peut aussi penser que s'il code ses objets Qt de cette façon ici il les code de la même façon de partout
Je t'invite à aller voir mon exemple Qt n° 6 Construire des widgets en vrac où je crée un objet Qt de mon cru contenant un slider et un lcd associé, puis une fois créé, quand il est devenu tout aussi manipulable et indépendant que tout autre widget Qt, je l'utilise à ma convenance et en place plusieurs dans un gridLayout.
Et donc ton objet "voiture" ne permet pas de lui spécifier une quelconque vMax. C'est aussi une façon de voir les choses mais qui n'est pas la mienne et qui (désolé de le faire remarquer), me semble aller à l'encontre de ta précédente remarque sur les avantages recherchés dans l'héritage (quand tu disais au post #10 que créer un héritage est fait pour avoir des attributs en plus). C'est donc dommage de faire un héritier qui ne permet plus l'accès aux paramètres de l'ancètre.
Et puis (rappel: cette discussion est juste là parce que tu as demandé que je t'explique ma remarque du post 1 donc je te l'explique bien volontiers) moi j'aime bien la souplesse et il me semble que la solution n° 2 à base de *args et **kwargs offre toute la souplesse du monde. Permet de spécifier une vMax si on veut, ou prendre la vMax par défaut...
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class vehicule: def __init__(self, vMax=200): self.vMax=vMax class voiture(vehicule): def __init__(self, marque, *args, **kwargs): super().__init__(*args, **kwargs) self.marque=marque v1 = voiture("renault") print(v1.vMax) # 200 v2 = voiture("bmw", vMax=360) print(v2.vMax) # 360
Et si demain la lib "vehicule v2" rajoute une vMin je n'aurai absolument rien à toucher à mon objet "voiture", il s'y adaptera automatiquement. Seuls les utilisateurs de mon objet devront s'y adapter (mais ça c'est normal quand la lib change).
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Elle a plus de souplesse, le problème n'est pas vraiment là, je comprend ton point de vue, et je pense que @papajoker aussi, je voulais surtout exprimer que l'on peut accepter et croire que le développeur a bien décidé cette manière de faire, c'est lui qui développe son projet. On peut se questionner sur la manière de faire, et proposer une autre manière d'écrire, mais il pourrait ne pas là comprendre, car ce n'est peut-être pas une décision prise à la légère (bénéfice du doute) et surtout comme ça fonctionne, qu'est-ce que ça lui apportera sur un projet qui n'évoluera pas ?Et puis (rappel: cette discussion est juste là parce que tu as demandé que je t'explique ma remarque du post 1 donc je te l'explique bien volontiers) moi j'aime bien la souplesse et il me semble que la solution n° 2 à base de *args et **kwargs offre toute la souplesse du monde.
Bref je t'ai un peu titiller, mais j'aime bien parler POO, j'ai pas pu m'empêcher...![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Salut,
Merci pour vos retours.
Effectivement, ici l'héritage de QDialog ne m'intéresse que pour le mode Modal (mais j'ai pris en compte des remarques et arguments).
Un template de bon code, non, un code qui fonctionne déjà, c'est pas mal. Après, je ne suis pas encore à l'aise avec la notion de MVC (Je vois de tout et de rien sur le net...)
Peux-tu développer : "Qt a son propre système mvc"
C'est une méthode de développement dans laquelle on sépare un projet en 3 grands domaines
- le Modèle (tout ce qui a trait à la sauvegarde des datas => fichier, bdd, ...)
- la Vue (tout ce qui a trait à la saisie et affichage => print, input, IHM, ..)
- le Contrôleur ou Calcul (tout ce qui permet de générer une info Y à partir d'une info X)
En séparant les 3 domaines et en les isolant, on peut généralement plus ou moins facilement en changer (remplacer les fichiers par une bdd, remplacer les print/input par des menus déroulants, ...)
En théorie, Qt c'est une GUI. C'est dans ce but que cet lib a été démarrée. Et GUI c'est juste la partie "Vue" de MVC.
Mais depuis elle s'est développée de façon tentaculaire pour offrir de la gestion de fichier ou de bdd (partie "M") et de la gestion de threads qui peuvent faire la partie "C", et plein d'autres choses encore. Et donc au final on peut faire tout le MVC par Qt.
Perso j'aime pas. Ce n'est jamais bon de mettre tous ses oeufs dans le même panier et l'informatique ne fait pas exception. J'aime Qt pour sa partie V mais moi pour le M et le C j'utilise d'autres libs.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Partager