Workbench creation/fr: Difference between revisions

From FreeCAD Documentation
No edit summary
No edit summary
(29 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<languages/>
<languages/>
This page will show you how to add a new workbench to the FreeCAD interface. [[Workbenches|Workbenches]] are containers for FreeCAD commands. They can be coded in python, in C++, or in a mix of both, which has the advantage to ally the speed of C++ to the flexibility of python. In all cases, though, your workbench will be launched by a set of two python files.
Cette page vous montrera comment ajouter un nouvel atelier à l'interface FreeCAD. Les [[Workbenches|ateliers]] sont des conteneurs pour les commandes FreeCAD. Ils peuvent être codés en python, en C++ ou en un mélange des deux, ce qui a l’avantage d’allier la vitesse de C++ à la souplesse de python. Dans tous les cas, cependant, votre atelier sera lancé par un ensemble de deux fichiers python.


=== La structure Atelier ===
== La structure Atelier ==


Basically it is simple: You need a folder, with any name you like, placed in the Mod directory, with an '''Init.py''' file, and, optionally an '''InitGui.py''' file. The Init file is executed when FreeCAD starts, always, and the InitGui.py file is executed immediately after, but only when FreeCAD starts in GUI mode, not in console mode. That's all it needs for FreeCAD to find your workbench at startup and add it to its interface.
En gros, c'est simple : vous avez besoin d'un dossier, avec le nom de votre choix, placé dans le répertoire Mod, avec un fichier '''Init.py''' et, éventuellement, un fichier '''InitGui.py'''. Le fichier Init est toujours exécuté au démarrage de FreeCAD, et le fichier InitGui.py est exécuté immédiatement après, mais uniquement lorsque FreeCAD démarre en mode interface graphique, pas en mode console. C'est tout ce dont FreeCAD a besoin pour trouver votre atelier au démarrage et l'ajouter à son interface.


Dans ces fichiers, vous pouvez faire ce que vous voulez. Ils sont généralement utilisés comme ceci :
Inside those files you can do whatever you want. Usually they are used like this:


* Dans le fichier Init.py, vous ajoutez simplement quelques éléments utilisés même lorsque FreeCAD fonctionne en mode console, par exemple les importateurs et les exportateurs de fichiers
* In the Init.py file you just add a couple of things used even when FreeCAD works in console mode, for example the file importers and exporters


* Dans le fichier InitGui.py, vous définissez généralement un atelier, qui contient un nom, une icône et une série de commandes FreeCAD (voir ci-dessous). Cet atelier définit également les fonctions exécutées lors du chargement de FreeCAD (essayez d'en faire le moins possible à ce niveau, afin de ne pas ralentir le démarrage). Un autre est exécuté lorsque l'atelier est activé (c'est là que vous ferez le plus du travail) et un troisième lorsque l'atelier est désactivé (vous pouvez donc supprimer des éléments si nécessaire).
* In the InitGui.py file you usually define a workbench, which contains a name, an icon, and a series of FreeCAD commands (see below). That workbench also defines functions that are executed when FreeCAD loads (you try to do as little as possible there, so you don't slow down the startup), another that gets executed when the workbench is activated (that's where you'll do most of the work), and a third one when the workbench is deactivated (so you can remove things if needed).


=== La structure d'atelier C++ ===
=== La structure d'atelier C++ ===


If you are going to code your workbench in python, you don't need to take special care, and can simply place your other python files together with your Init.py and InitGui.py files. When working with C++, however, you should take greater care, and start with respecting one fundamental rule of FreeCAD: The separation of your workbench between an App part (that can run in console mode, without any GUI element), and a Gui part, which will only be loaded when FreeCAD runs with its full GUI environment. So when doing a C++ workbench, you will actually most likely be doing two modules, an App and a Gui. These two modules must of course be callable from python. Any FreeCAD module (App or Gui) consists, at the very least, of a module init file. This is a typical AppMyModuleGui.cpp file:
Si vous voulez coder votre atelier en python, vous n'avez pas besoin de faire très attention, vous pouvez simplement placer vos autres fichiers python avec vos fichiers Init.py et InitGui.py. Toutefois, lorsque vous travaillez avec C++, vous devez faire preuve d'une plus grande prudence et commencer par respecter une règle fondamentale de FreeCAD : la séparation de votre atelier entre une partie d'application (pouvant s'exécuter en mode console, sans aucun élément d'interface graphique) et une partie d'interface graphique qui ne sera chargé que lorsque FreeCAD s’exécutera avec son environnement graphique complet. Ainsi, lorsque vous construirez un atelier C++, vous élaborerez probablement deux modules, une application et une interface graphique. Ces deux modules doivent bien entendu être appelables depuis python. Tout module FreeCAD (App ou Gui) consiste à minima en un fichier init de module. Voici un fichier typique AppMyModuleGui.cpp :
{{Code|code=
{{Code|code=
extern "C" {
extern "C" {
Line 50: Line 50:


=== Le fichier Init.py ===
=== Le fichier Init.py ===
{{code|code=
{{code|# FreeCAD init script of XXX module
"""FreeCAD init script of XXX module"""


#***************************************************************************
# ***************************************************************************
#* Copyright (c) 2015 John Doe john@doe.com *
# * Copyright (c) 2015 John Doe john@doe.com *
#* *
# * *
#* This file is part of the FreeCAD CAx development system. *
# * This file is part of the FreeCAD CAx development system. *
#* *
# * *
#* This program is free software; you can redistribute it and/or modify *
# * This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
# * as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
# * the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
# * for detail see the LICENCE text file. *
#* *
# * *
#* FreeCAD is distributed in the hope that it will be useful, *
# * FreeCAD is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Lesser General Public License for more details. *
# * GNU Lesser General Public License for more details. *
#* *
# * *
#* You should have received a copy of the GNU Library General Public *
# * You should have received a copy of the GNU Library General Public *
#* License along with FreeCAD; if not, write to the Free Software *
# * License along with FreeCAD; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
# * USA *
#* *
# * *
#***************************************************************************/
# ***************************************************************************/


FreeCAD.addImportType("My own format (*.own)","importOwn")
FreeCAD.addImportType("My own format (*.own)", "importOwn")
FreeCAD.addExportType("My own format (*.own)","importOwn")
FreeCAD.addExportType("My own format (*.own)", "importOwn")
print "I am executing some stuff here when FreeCAD starts!"}}
print("I am executing some stuff here when FreeCAD starts!")
}}
You can choose any license you like for your workbench, but be aware that if you wish
Vous pouvez choisir la licence de votre choix pour votre atelier, mais sachez que si vous souhaitez que votre atelier soit intégré et distribué avec le code source de FreeCAD à un moment donné, il doit être LGPL2+, comme dans l'exemple ci-dessus. Voir [[Licence/fr|Licence]].
to see your workbench integrated into and distributed with the FreeCAD source code at

some point, it needs to be LGPL2+ like the example above.
Les fonctions {{incode|FreeCAD.addImportType()}} et {{incode|addEXportType()}} vous permettent de fournir le nom et l'extension d'un type de fichier, ainsi qu'un module python responsable de son importation. Dans l'exemple ci-dessus, un module {{incode|importOwn.py}} gérera les fichiers {{incode|.own}}. Voir [[Code snippets/fr|Extraits de codes]] pour plus d'exemples.
The FreeCAD.addImportType() and addEXportType() functions allow you to give the name
and extension of a file type, and a python module responsible for its import. In the
example above, an "importOwn.py" module will handle .own files. See [[Code snippets]]
for more examples.


=== Ateliers Python ===
=== Ateliers Python ===
{{Code|code=
<syntaxhighlight>class MyWorkbench (Workbench):
class MyWorkbench (Workbench):


MenuText = "My Workbench"
MenuText = "My Workbench"
Line 94: Line 93:


def Initialize(self):
def Initialize(self):
"This function is executed when FreeCAD starts"
"""This function is executed when FreeCAD starts"""
import MyModuleA, MyModuleB # import here all the needed files that create your FreeCAD commands
import MyModuleA, MyModuleB # import here all the needed files that create your FreeCAD commands
self.list = ["MyCommand1, MyCommand2"] # A list of command names created in the line above
self.list = ["MyCommand1, MyCommand2"] # A list of command names created in the line above
Line 102: Line 101:


def Activated(self):
def Activated(self):
"This function is executed when the workbench is activated"
"""This function is executed when the workbench is activated"""
return
return


def Deactivated(self):
def Deactivated(self):
"This function is executed when the workbench is deactivated"
"""This function is executed when the workbench is deactivated"""
return
return


def ContextMenu(self, recipient):
def ContextMenu(self, recipient):
"This is executed whenever the user right-clicks on screen"
"""This is executed whenever the user right-clicks on screen"""
# "recipient" will be either "view" or "tree"
# "recipient" will be either "view" or "tree"
self.appendContextMenu("My commands",self.list) # add commands to the context menu
self.appendContextMenu("My commands",self.list) # add commands to the context menu
Line 118: Line 117:
return "Gui::PythonWorkbench"
return "Gui::PythonWorkbench"
Gui.addWorkbench(MyWorkbench())</syntaxhighlight>
Gui.addWorkbench(MyWorkbench())
}}
Other than that, you can do anything you want: You could put your whole workbench code
En dehors de cela, vous pouvez faire ce que vous voulez : Vous pouvez insérer tout votre code d'atelier dans le fichier InitGui.py si vous le souhaitez, mais il est généralement plus pratique de placer les différentes fonctions de votre atelier dans des fichiers séparés. Ainsi ces fichiers sont plus petits et plus faciles à lire. Ensuite, vous importerez ces fichiers dans votre fichier InitGui.py. Vous pouvez organiser ces fichiers comme bon vous semble, un bon exemple est en avoir un pour chaque commande FreeCAD que vous ajoutez.
inside the InitGui.py if you want, but it is usually more convenient to place the different

functions of your workbench in separate files. So those files are smaller and easier to
==== Préférences ====
read. Then you import those files into your InitGui.py file. You can organize those files

the way you want, a good example is one for each FreeCAD command you add.
Vous pouvez ajouter une page Préférences pour votre atelier Python. Les pages Préférences recherchent une icône de préférence avec un nom spécifique dans le système de ressources Qt. Si votre icône ne se trouve pas dans le système de ressources ou si son nom n'est pas correct, votre icône n'apparaîtra pas sur la page Préférences.

Ajouter votre icône d'atelier :
* l’icône des préférences doit être nommée "preferences-" + "nom du module" + ".svg" (en minuscules)
* créez un fichier qrc contenant les noms de tous les icônes
* dans le répertoire *.py principal, exécutez pyside-rcc -o myResources.py myqrc.qrc
* dans InitGui.py, ajouter importer myResource(.py)
* mettre à jour votre référentiel (git) avec myResources.py et myqrc.qrc

Vous devrez refaire les étapes si vous ajoutez/modifiez des icônes.

@kbwbe a créé un joli script pour compiler des ressources pour l'atelier A2Plus. Voir ci-dessous.

Ajouter votre/vos page(s) de préférence :
* Vous devez compiler le plugin Qt Designer qui vous permet d’ajouter des paramètres de préférence avec [[Compile on Linux/Unix/fr#Plugin_Qt_designer|Qt Designer]]
* Créer un widget vide dans Qt Designer (sans boutons ni quoi que ce soit)
* Concevez votre page de préférences, de nombreux paramètres qui doivent être enregistrés (préférences) doivent être l’un des widgets Gui::Pref* ajoutés par le plug-in)
* Dans ces cas-là, veillez à renseigner PrefName (le nom de votre valeur de préférence) et PrefPath (ex: Mod/MyWorkbenchName), qui sauvegardera votre valeur sous BaseApp/Preferences/Mod/MyWorkbebchName
* Enregistrez le fichier d'interface utilisateur dans votre atelier, assurez-vous qu'il est géré par cmake.
* Dans votre atelier, par exemple dans le fichier InitGui, dans la méthode Initialize (mais tout autre endroit fonctionne également), ajoutez : FreeCADGui.addPreferencePage ("/path/to/myUiFile.ui", "MyGroup"), "MyGroup" étant l'un des groupes de préférences de la gauche. FreeCAD recherchera automatiquement un fichier "preferences-mygroup.svg" dans ses emplacements connus (que vous pouvez étendre avec FreeCADGui.addIconPath())
* Assurez-vous que la méthode addPreferencePage() n’est appelée qu’une fois, sinon votre page de préférence sera ajoutée plusieurs fois


=== Ateliers C++ ===
=== Ateliers C++ ===


Si vous voulez coder votre atelier en C++, vous souhaiterez probablement coder aussi sa définition elle-même en C++ (bien que cela ne soit pas nécessaire : vous pouvez également coder uniquement les outils en C++, et laisser la définition de de l'atelier en python). Dans ce cas, le fichier InitGui.py devient très simple : il peut contenir une seule ligne :
If you are going to code your workbench in C++, you will probably want to code the
workbench definition itself in C++ too (although it is not necessary: You could also
code only the tools in C++, and leave the workbench definition in python). In that case,
the InitGui.py file becomes very simple: It might contain just one line:
{{Code|code=import MyModuleGui}}
{{Code|code=import MyModuleGui}}
where MyModule is your complete C++ workbench, including the commands and workbench
MyModule est votre atelier C++ complet, incluant les commandes et la définition de l'atelier.
definition.


Le codage des ateliers C++ fonctionne de manière assez similaire. Il s'agit d'un fichier Workbench.cpp typique à inclure dans la partie interface graphique de votre module :
Coding C++ workbenches works in a pretty similar way. This is a typical Workbench.cpp
file to include in the Gui part of your module:
{{Code|code=
{{Code|code=
namespace MyModuleGui {
namespace MyModuleGui {
Line 156: Line 171:
}
}
}}
}}

==== Préférences ====

Vous pouvez également ajouter une page de préférences pour les ateliers C++. Les étapes sont similaires à celles de Python.



== Commandes FreeCAD ==
== Commandes FreeCAD ==


Les commandes FreeCAD constituent le bloc de construction de base de l'interface FreeCAD. Ils peuvent apparaître sous la forme d'un bouton dans les barres d'outils et d'une entrée de menu dans les menus. Mais c'est la même commande. Une commande est une simple classe python, qui doit contenir un couple attributs et fonctions prédéfinis, définissant le nom de la commande, son icône et l'action à effectuer lorsque la commande est activée.
FreeCAD commands are the basic building block of the FreeCAD interface. They can appear
as a button on toolbars, and as a menu entry in menus. But it is the same command. A
command is a simple python class, that must contain a couple of predefined attributes
and functions, that define the name of the command, its icon, and what to do when the
command is activated.


=== Définition des commandes Python ===
=== Définition des commandes Python ===
Line 177: Line 193:


def Activated(self):
def Activated(self):
"Do something here"
"""Do something here"""
return
return


Line 190: Line 206:
=== Définition des commandes C++ ===
=== Définition des commandes C++ ===


Similarly, you can code your commands in C++, typically have a Commands.cpp file in your Gui module. This is a typical Commands.cpp file:
De la même manière, vous pouvez coder vos commandes en C++. Vous avez généralement un fichier Commands.cpp dans votre module d'interface graphique. Ceci est un fichier Commands.cpp typique :
{{Code|code=DEF_STD_CMD_A(CmdMyCommand);
{{Code|code=DEF_STD_CMD_A(CmdMyCommand);


Line 228: Line 244:
}}
}}



== "Compiler" votre fichier ressources ==
compileA2pResources.py depuis l'atelier A2Plus :
{{Code|code=#!/usr/bin/env python
# -*- coding: utf-8 -*-
#***************************************************************************
#* *
#* Copyright (c) 2019 kbwbe *
#* *
#* Portions of code based on hamish's assembly 2 *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU Library General Public License for more details. *
#* *
#* You should have received a copy of the GNU Library General Public *
#* License along with this program; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#***************************************************************************

# This script compiles the A2plus icons for py2 and py3
# For Linux only
# Start this file in A2plus main directory
# Make sure pyside-rcc is installed

import os, glob

qrc_filename = 'temp.qrc'
if os.path.exists(qrc_filename):
os.remove(qrc_filename)

qrc = '''<RCC>
\t<qresource prefix="/">'''
for fn in glob.glob('./icons/*.svg'):
qrc = qrc + '\n\t\t<file>%s</file>' % fn
qrc = qrc + '''\n\t</qresource>
</RCC>'''

print(qrc)

f = open(qrc_filename,'w')
f.write(qrc)
f.close()

os.system(
'pyside-rcc -o a2p_Resources2.py {}'.format(
qrc_filename
)
)
os.system(
'pyside-rcc -py3 -o a2p_Resources3.py {}'.format(
qrc_filename
)
)

os.remove(qrc_filename)
}}
[[Category:Hubs/fr]]
[[Category:Hubs/fr]]
[[Category:Poweruser Documentation/fr]]
[[Category:Poweruser Documentation/fr]]

Revision as of 09:33, 20 November 2019

Cette page vous montrera comment ajouter un nouvel atelier à l'interface FreeCAD. Les ateliers sont des conteneurs pour les commandes FreeCAD. Ils peuvent être codés en python, en C++ ou en un mélange des deux, ce qui a l’avantage d’allier la vitesse de C++ à la souplesse de python. Dans tous les cas, cependant, votre atelier sera lancé par un ensemble de deux fichiers python.

La structure Atelier

En gros, c'est simple : vous avez besoin d'un dossier, avec le nom de votre choix, placé dans le répertoire Mod, avec un fichier Init.py et, éventuellement, un fichier InitGui.py. Le fichier Init est toujours exécuté au démarrage de FreeCAD, et le fichier InitGui.py est exécuté immédiatement après, mais uniquement lorsque FreeCAD démarre en mode interface graphique, pas en mode console. C'est tout ce dont FreeCAD a besoin pour trouver votre atelier au démarrage et l'ajouter à son interface.

Dans ces fichiers, vous pouvez faire ce que vous voulez. Ils sont généralement utilisés comme ceci :

  • Dans le fichier Init.py, vous ajoutez simplement quelques éléments utilisés même lorsque FreeCAD fonctionne en mode console, par exemple les importateurs et les exportateurs de fichiers
  • Dans le fichier InitGui.py, vous définissez généralement un atelier, qui contient un nom, une icône et une série de commandes FreeCAD (voir ci-dessous). Cet atelier définit également les fonctions exécutées lors du chargement de FreeCAD (essayez d'en faire le moins possible à ce niveau, afin de ne pas ralentir le démarrage). Un autre est exécuté lorsque l'atelier est activé (c'est là que vous ferez le plus du travail) et un troisième lorsque l'atelier est désactivé (vous pouvez donc supprimer des éléments si nécessaire).

La structure d'atelier C++

Si vous voulez coder votre atelier en python, vous n'avez pas besoin de faire très attention, vous pouvez simplement placer vos autres fichiers python avec vos fichiers Init.py et InitGui.py. Toutefois, lorsque vous travaillez avec C++, vous devez faire preuve d'une plus grande prudence et commencer par respecter une règle fondamentale de FreeCAD : la séparation de votre atelier entre une partie d'application (pouvant s'exécuter en mode console, sans aucun élément d'interface graphique) et une partie d'interface graphique qui ne sera chargé que lorsque FreeCAD s’exécutera avec son environnement graphique complet. Ainsi, lorsque vous construirez un atelier C++, vous élaborerez probablement deux modules, une application et une interface graphique. Ces deux modules doivent bien entendu être appelables depuis python. Tout module FreeCAD (App ou Gui) consiste à minima en un fichier init de module. Voici un fichier typique AppMyModuleGui.cpp :

extern "C" {
    void MyModuleGuiExport initMyModuleGui()  
    {
         if (!Gui::Application::Instance) {
            PyErr_SetString(PyExc_ImportError, "Cannot load Gui module in console application.");
            return;
        }
        try {
            // import other modules this one depends on
            Base::Interpreter().runString("import PartGui");
            // run some python code in the console
            Base::Interpreter().runString("print('welcome to my module!')");
        }
        catch(const Base::Exception& e) {
            PyErr_SetString(PyExc_ImportError, e.what());
            return;
        }
        (void) Py_InitModule("MyModuleGui", MyModuleGui_Import_methods);   /* mod name, table ptr */
        Base::Console().Log("Loading GUI of MyModule... done\n");
    
        // initializes the FreeCAD commands (in another cpp file)
        CreateMyModuleCommands();
    
        // initializes workbench and object definitions
        MyModuleGui::Workbench::init();
        MyModuleGui::ViewProviderSomeCustomObject::init();
    
         // add resources and reloads the translators
        loadMyModuleResource();
    }
}

Le fichier Init.py

"""FreeCAD init script of XXX module"""

# ***************************************************************************
# *   Copyright (c) 2015 John Doe john@doe.com                              *   
# *                                                                         *
# *   This file is part of the FreeCAD CAx development system.              *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
# *   as published by the Free Software Foundation; either version 2 of     *
# *   the License, or (at your option) any later version.                   *
# *   for detail see the LICENCE text file.                                 *
# *                                                                         *
# *   FreeCAD is distributed in the hope that it will be useful,            *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
# *   GNU Lesser General Public License for more details.                   *
# *                                                                         *
# *   You should have received a copy of the GNU Library General Public     *
# *   License along with FreeCAD; if not, write to the Free Software        *
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
# *   USA                                                                   *
# *                                                                         *
# ***************************************************************************/

FreeCAD.addImportType("My own format (*.own)", "importOwn")
FreeCAD.addExportType("My own format (*.own)", "importOwn")
print("I am executing some stuff here when FreeCAD starts!")

Vous pouvez choisir la licence de votre choix pour votre atelier, mais sachez que si vous souhaitez que votre atelier soit intégré et distribué avec le code source de FreeCAD à un moment donné, il doit être LGPL2+, comme dans l'exemple ci-dessus. Voir Licence.

Les fonctions FreeCAD.addImportType() et addEXportType() vous permettent de fournir le nom et l'extension d'un type de fichier, ainsi qu'un module python responsable de son importation. Dans l'exemple ci-dessus, un module importOwn.py gérera les fichiers .own. Voir Extraits de codes pour plus d'exemples.

Ateliers Python

class MyWorkbench (Workbench):

    MenuText = "My Workbench"
    ToolTip = "A description of my workbench"
    Icon = """paste here the contents of a 16x16 xpm icon"""

    def Initialize(self):
        """This function is executed when FreeCAD starts"""
        import MyModuleA, MyModuleB # import here all the needed files that create your FreeCAD commands
        self.list = ["MyCommand1, MyCommand2"] # A list of command names created in the line above
        self.appendToolbar("My Commands",self.list) # creates a new toolbar with your commands
        self.appendMenu("My New Menu",self.list) # creates a new menu
        self.appendMenu(["An existing Menu","My submenu"],self.list) # appends a submenu to an existing menu

    def Activated(self):
        """This function is executed when the workbench is activated"""
        return

    def Deactivated(self):
        """This function is executed when the workbench is deactivated"""
        return

    def ContextMenu(self, recipient):
        """This is executed whenever the user right-clicks on screen"""
        # "recipient" will be either "view" or "tree"
        self.appendContextMenu("My commands",self.list) # add commands to the context menu

    def GetClassName(self): 
        # this function is mandatory if this is a full python workbench
        return "Gui::PythonWorkbench"
       
Gui.addWorkbench(MyWorkbench())

En dehors de cela, vous pouvez faire ce que vous voulez : Vous pouvez insérer tout votre code d'atelier dans le fichier InitGui.py si vous le souhaitez, mais il est généralement plus pratique de placer les différentes fonctions de votre atelier dans des fichiers séparés. Ainsi ces fichiers sont plus petits et plus faciles à lire. Ensuite, vous importerez ces fichiers dans votre fichier InitGui.py. Vous pouvez organiser ces fichiers comme bon vous semble, un bon exemple est en avoir un pour chaque commande FreeCAD que vous ajoutez.

Préférences

Vous pouvez ajouter une page Préférences pour votre atelier Python. Les pages Préférences recherchent une icône de préférence avec un nom spécifique dans le système de ressources Qt. Si votre icône ne se trouve pas dans le système de ressources ou si son nom n'est pas correct, votre icône n'apparaîtra pas sur la page Préférences.

Ajouter votre icône d'atelier :

  • l’icône des préférences doit être nommée "preferences-" + "nom du module" + ".svg" (en minuscules)
  • créez un fichier qrc contenant les noms de tous les icônes
  • dans le répertoire *.py principal, exécutez pyside-rcc -o myResources.py myqrc.qrc
  • dans InitGui.py, ajouter importer myResource(.py)
  • mettre à jour votre référentiel (git) avec myResources.py et myqrc.qrc

Vous devrez refaire les étapes si vous ajoutez/modifiez des icônes.

@kbwbe a créé un joli script pour compiler des ressources pour l'atelier A2Plus. Voir ci-dessous.

Ajouter votre/vos page(s) de préférence :

  • Vous devez compiler le plugin Qt Designer qui vous permet d’ajouter des paramètres de préférence avec Qt Designer
  • Créer un widget vide dans Qt Designer (sans boutons ni quoi que ce soit)
  • Concevez votre page de préférences, de nombreux paramètres qui doivent être enregistrés (préférences) doivent être l’un des widgets Gui::Pref* ajoutés par le plug-in)
  • Dans ces cas-là, veillez à renseigner PrefName (le nom de votre valeur de préférence) et PrefPath (ex: Mod/MyWorkbenchName), qui sauvegardera votre valeur sous BaseApp/Preferences/Mod/MyWorkbebchName
  • Enregistrez le fichier d'interface utilisateur dans votre atelier, assurez-vous qu'il est géré par cmake.
  • Dans votre atelier, par exemple dans le fichier InitGui, dans la méthode Initialize (mais tout autre endroit fonctionne également), ajoutez : FreeCADGui.addPreferencePage ("/path/to/myUiFile.ui", "MyGroup"), "MyGroup" étant l'un des groupes de préférences de la gauche. FreeCAD recherchera automatiquement un fichier "preferences-mygroup.svg" dans ses emplacements connus (que vous pouvez étendre avec FreeCADGui.addIconPath())
  • Assurez-vous que la méthode addPreferencePage() n’est appelée qu’une fois, sinon votre page de préférence sera ajoutée plusieurs fois

Ateliers C++

Si vous voulez coder votre atelier en C++, vous souhaiterez probablement coder aussi sa définition elle-même en C++ (bien que cela ne soit pas nécessaire : vous pouvez également coder uniquement les outils en C++, et laisser la définition de de l'atelier en python). Dans ce cas, le fichier InitGui.py devient très simple : il peut contenir une seule ligne :

import MyModuleGui

où MyModule est votre atelier C++ complet, incluant les commandes et la définition de l'atelier.

Le codage des ateliers C++ fonctionne de manière assez similaire. Il s'agit d'un fichier Workbench.cpp typique à inclure dans la partie interface graphique de votre module :

namespace MyModuleGui {
    class MyModuleGuiExport Workbench : public Gui::StdWorkbench
    {
        TYPESYSTEM_HEADER();

    public:
        Workbench();
        virtual ~Workbench();

        virtual void activated();
        virtual void deactivated();

    protected:
        Gui::ToolBarItem* setupToolBars() const;
        Gui::MenuItem*    setupMenuBar() const;
    };
}

Préférences

Vous pouvez également ajouter une page de préférences pour les ateliers C++. Les étapes sont similaires à celles de Python.


Commandes FreeCAD

Les commandes FreeCAD constituent le bloc de construction de base de l'interface FreeCAD. Ils peuvent apparaître sous la forme d'un bouton dans les barres d'outils et d'une entrée de menu dans les menus. Mais c'est la même commande. Une commande est une simple classe python, qui doit contenir un couple attributs et fonctions prédéfinis, définissant le nom de la commande, son icône et l'action à effectuer lorsque la commande est activée.

Définition des commandes Python

class My_Command_Class():
    """My new command"""

    def GetResources(self):
        return {'Pixmap'  : 'My_Command_Icon', # the name of a svg file available in the resources
                'Accel' : "Shift+S", # a default shortcut (optional)
                'MenuText': "My New Command"
                'ToolTip' : "What my new command does"}

    def Activated(self):
        """Do something here"""
        return

    def IsActive(self):
        """Here you can define if the command must be active or not (greyed) if certain conditions
        are met or not. This function is optional."""
        return True

FreeCADGui.addCommand('My_Command',My_Command_Class())

Définition des commandes C++

De la même manière, vous pouvez coder vos commandes en C++. Vous avez généralement un fichier Commands.cpp dans votre module d'interface graphique. Ceci est un fichier Commands.cpp typique :

DEF_STD_CMD_A(CmdMyCommand);

CmdMyCommand::CmdMyCommand()
  :Command("My_Command")
{
  sAppModule    = "MyModule";
  sGroup        = QT_TR_NOOP("MyModule");
  sMenuText     = QT_TR_NOOP("Runs my command...");
  sToolTipText  = QT_TR_NOOP("Describes what my command does");
  sWhatsThis    = QT_TR_NOOP("Describes what my command does");
  sStatusTip    = QT_TR_NOOP("Describes what my command does");
  sPixmap       = "some_svg_icon_from_my_resource";
}

void CmdMyCommand::activated(int iMsg)
{
    openCommand("My Command");
    doCommand(Doc,"print('Hello, world!')");
    commitCommand();
    updateActive();
}

bool CmdMyCommand::isActive(void)
{
  if( getActiveGuiDocument() )
    return true;
  else
    return false;
}

void CreateMyModuleCommands(void)
{
    Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
    rcCmdMgr.addCommand(new CmdMyCommand());
}


"Compiler" votre fichier ressources

compileA2pResources.py depuis l'atelier A2Plus :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#***************************************************************************
#*                                                                         *
#*   Copyright (c) 2019 kbwbe                                              *
#*                                                                         *
#*   Portions of code based on hamish's assembly 2                         *
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU Lesser General Public License (LGPL)    *
#*   as published by the Free Software Foundation; either version 2 of     *
#*   the License, or (at your option) any later version.                   *
#*   for detail see the LICENCE text file.                                 *
#*                                                                         *
#*   This program is distributed in the hope that it will be useful,       *
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#*   GNU Library General Public License for more details.                  *
#*                                                                         *
#*   You should have received a copy of the GNU Library General Public     *
#*   License along with this program; if not, write to the Free Software   *
#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
#*   USA                                                                   *
#*                                                                         *
#***************************************************************************

# This script compiles the A2plus icons for py2 and py3
# For Linux only
# Start this file in A2plus main directory
# Make sure pyside-rcc is installed

import os, glob

qrc_filename = 'temp.qrc'
if os.path.exists(qrc_filename):
    os.remove(qrc_filename)
    

qrc = '''<RCC>
\t<qresource prefix="/">'''
for fn in glob.glob('./icons/*.svg'):
    qrc = qrc + '\n\t\t<file>%s</file>' % fn
qrc = qrc + '''\n\t</qresource>
</RCC>'''

print(qrc)

f = open(qrc_filename,'w')
f.write(qrc)
f.close()

os.system(
    'pyside-rcc -o a2p_Resources2.py {}'.format(
        qrc_filename
        )
    )
os.system(
    'pyside-rcc -py3 -o a2p_Resources3.py {}'.format(
        qrc_filename
        )
    )

os.remove(qrc_filename)