Macro Express Placement/de

Express-Platzierung

Beschreibung
Zeigt die Platzierungskoordinaten eines ausgewählten Objekts direkt oder über Ausdrücke an und bearbeitet sie schnell.

Versionsmakro : 1.0
Datum der letzten Änderung : 2023-08-01
FreeCAD version : Erstellt und getestet in 0.21
Herunterladen : Express-Platzierung
Autor: screeneroner
Autor
screeneroner
Herunterladen
Express-Platzierung
Links
Macro-Version
1.0
Datum der letzten Änderung
2023-08-01
FreeCAD-Version(s)
Erstellt und getestet in 0.21
Standardverknüpfung
None
Siehe auch
None

Beschreibung

Das Makro Express Placement ist ein FreeCAD-GUI-Addon. Es ermöglicht die schnelle Bearbeitung der X-, Y- und Z-Platzierungskoordinaten für das aktuell ausgewählte Objekt.

Unterschiede und Vorteile

Standard vs Express

Ein Doppelklick zum Bearbeiten der Objektplatzierung statt vier aufeinanderfolgender Klicks – Man kann viermal schneller arbeiten!

Standard-FreeCAD-Platzierung (in Rot)

Der standardmäßige integrierte Editor von FreeCAD erfordert viele zusätzliche Mausklicks, bevor man tatsächlich mit der Bearbeitung der Parameter beginnen kann, insbesondere wenn man parametrische Ausdrücke zur Positionierung des Objekts verwenden:

  1. Im Eigenschaften-Anansicht auf den Eintrag Basis/Platzierung klicken, um die Platzierungsstruktur zu erweitern.
  2. Auf den Zweig Position klicken, um die Felder für die X-, Y- und Z-Koordinaten zu erweitern.
  3. Auf die gewünschte Koordinate klicken, um das Symbol zum Bearbeiten des Ausdrucks anzuzeigen.
  4. Auf das Symbol zum Bearbeiten des Ausdrucks klicken, das so klein ist, dass es schwierig sein kann, es zu treffen.
    Alternativ kann auch die Taste = auf der Tastatur gedrückt werden. Dies kann sogar länger dauern als das Klicken auf das Symbol.

Man muss diese Klicks wiederholen, wenn man ein anderes Objekt auswählt. Immer und immer wieder...

Express-Platzierung (in Grün)

Das Makro Express Placement erstellt ein spezielles Fenster. Man kann dieses Fenster an einer beliebigen geeigneten Stelle andocken. Es zeigt drei Zeilen mit X-, Y- und Z-Koordinaten an. Diese Koordinaten enthalten Werte und Ausdrucksfelder. Sie können mit einem Doppelklick bearbeitet werden.

Installation

Addon-Manager

Suche Express-Platzirung im FreeCAD Addon-Manager und installiere es.

Direkter Start der Express-Platzierung

Das Addon Express Placement kann sofort heruntergeladen und in FreeCAD verwendet werden:

  1. Die Datei express-placement.FCMacro herunterladen und im Ordner User Macros innerhalb des FreeCAD-Installationsordners abablegen.
  2. Sie direkt über das FreeCAD-Hauptmenü Macro / Macros / User Macros ausführen.

Installieren der Express Placement-Symbolleisten-Schaltfläche

Um die Express-Positionierungstabelle schnell aufrufen zu können, kan man eine Schaltfläche platzieren, mit der man dieses Makro schnell ausführen und die Express-Positionierungstabelle aufrufen kann:

  1. Die Datei Express Placement.FCMacro herunterladen und sie im Ordner User Macros innerhalb des FreeCAD-Installationsordners ablegen.
  2. Das Makro Express Placement im Fenster User Macros auswählen, das über das FreeCAD-Hauptmenü MaKro / MaKros / Benutzermakros“ aufgerufen werden kann.
  3. Auf die Schaltfläche Werkzeugleiste drücken und den Anweisungen im Dialogfeld Walkthrough folgen, um die Schaltfläche Express Placement an der gewünschten Stelle in den FreeCAD-Symbolleisten zu platzieren.

Anwendung

Einfach das Makro Express Placement direkt oder über die Symbolleisten-Schaltfläche ausführen, und man sieht ein neues angedocktes Eigenschaftenfenster in der FreeCAD-Benutzeroberfläche. Man kann es an eine beliebige Stelle in der Benutzeroberfläche ziehen und jederzeit schließen, wenn man es nicht mehr benötigt. Wenn man es das nächste Mal wieder benötigt, führt man das Makro aus oder drückt erneut die Symbolleisten-Schaltfläche, um das Fenster Express Placement aufzurufen.

Wenn man die Position des ausgewählten Objekts ändern möchte, doppelklickt man einfach auf die gewünschte Zelle im Fenster Express Placement und gibt einen neuen Wert ein oder bearbeiten den vorhandenen Wert. Der neue Wert wird direkt in das Modell geschrieben.

Wenn man dieses Addon nützlich findet und der Meinung ist, dass es sich lohnt, mich für meine Arbeit mit ein paar Tassen Kaffee zu belohnen, kann man dies jederzeit über ☕ Buy me a coffee tun

Skript

Hier klicken, um den Addon-Quellcode anzuzeigen/auszublenden.

# -*- coding: utf-8 -*-
__Name__ = "Express Placement"
__Comment__ = "FreeCAD GUI addon that allow quick editing X,Y,Z coordinates of the selected object"
__Author__ = "screeneroner"
__Version__ = "1.0"
__Date__ = "2023-08-01"
__License__ = "GPL-3.0"
__Web__ = "https://wiki.freecad.org/Macro_Express_Placement"
__Wiki__ = "https://wiki.freecad.org/Macro_Express_Placement"
__Icon__ = "https://wiki.freecad.org/images/8/8f/Std_AxisCross_example.svg"
__Help__ = "Display and quickly edit selected object placement coordinates directly or via expressions"
__Status__ = "Working"
__Requires__ = "FreeCAD >= 0.19"
__Communication__ = "https://forum.freecad.org/memberlist.php?mode=viewprofile&u=60629"
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


''' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This macro is free software: you can redistribute it and/or modify it under the terms of the  
version 3 GNU General Public License as published by the Free Software Foundation. 
 
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 General Public License for more details (https://www.gnu.org/licenses/gpl-3.0.html) 
 
WARNING TO USERS AND MODIFIERS 
 
This script contains "Buy me a coffee" links to honor the author's hard work and dedication in creating 
all the features present in this code. Removing or altering these links not only violates the GPL license 
but also disregards the significant effort put into making this script valuable for the community. 
 
If you find value in this script and would like to show appreciation to the author, 
kindly consider visiting the site below and treating the author to a few cups of coffee: 
                           https://www.buymeacoffee.com/screeneroner 
Your honor and gratitude is greatly appreciated.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ''' 


import FreeCADGui as Gui
import FreeCAD as App
from PySide import QtGui, QtCore

# Define a function to create and display a table
def create_table():
    # Function to update the table with the selected object's data
    def update_table_with_selected_object():
        # Clear the table first
        clear_table()

        # Get the selected objects
        selection = Gui.Selection.getSelection()
        # If there's exactly one selected object
        if len(selection) == 1:
            selected_obj = selection[0]
            selected_object = selected_obj
            # Ensure the object isn't a spreadsheet
            if str(selected_obj.TypeId) != "Spreadsheet::Sheet":
                # Populate the table with the object's placement data
                populate_table_with_placement(selected_obj)
                # Store the selected object on the table widget
                table_widget.selected_object = selected_obj

    # Function to populate the table with an object's placement data
    def populate_table_with_placement(selected_obj):
        # Clear the table first
        clear_table()
    
        # Get the object's placement
        placement = selected_obj.Placement
        # Update each row of the table with the object's placement data
        for row in range(3):  # Limit to 3 instead of row_count
            value_widget = QtGui.QTableWidgetItem()
            value_widget.setText(str(getattr(placement.Base, ["x", "y", "z"][row])))
            table_widget.setItem(row, 0, value_widget)
    
        # Get the object's properties
        properties_list = selected_obj.ExpressionEngine
        # If the object has properties
        if properties_list is not None:
            # For each property that involves placement
            for prop in properties_list:
                if prop[0] in [".Placement.Base.x", ".Placement.Base.y", ".Placement.Base.z"]:
                    # Get the attribute's name
                    attribute = prop[0].split(".")[-1]
                    # Set the corresponding cell's value
                    expression_label = QtGui.QTableWidgetItem()
                    expression_label.setText(prop[1])
                    table_widget.setItem(["x", "y", "z"].index(attribute), 1, expression_label)
    
        # Add the new row with the support data
        support_label_widget = QtGui.QLabel(" ")
        support_link_widget = QtGui.QLabel( u'\u2615' + '  <a href="https://www.buymeacoffee.com/screeneroner">Buy me a coffee</a>  ')
        support_link_widget.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        support_link_widget.setTextFormat(QtCore.Qt.RichText)
        support_link_widget.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
        support_link_widget.setOpenExternalLinks(True)
                
        table_widget.setCellWidget(3, 0, support_label_widget)
        table_widget.setCellWidget(3, 1, support_link_widget)
    
        # Adjust the height of each row
        header = table_widget.horizontalHeader()
        header.setFixedHeight(24)  
        for row in range(row_count):
            table_widget.setRowHeight(row, 18)



    # Function to clear the table
    def clear_table():
        for row in range(row_count):
            for col in range(column_count):
                table_widget.takeItem(row, col)

    # Function to update the selected object's placement values based on edits to the table
    def update_values(row):
        item = table_widget.item(row, 0)
        if item is not None:
            # Get the edited text
            edited_text = item.text()
            # Get the label of the value that was edited
            value_label = ["x", "y", "z"][row]
            # Get the selected object
            selected_obj = table_widget.selected_object
            # Get the object's placement
            placement = selected_obj.Placement

            # If the edited text is not empty
            if edited_text != "":
                try:
                    # Try to convert the edited text to a float
                    edited_value = float(edited_text)
                    # Update the corresponding placement value
                    if value_label == "x":
                        placement.Base.x = edited_value
                    elif value_label == "y":
                        placement.Base.y = edited_value
                    elif value_label == "z":
                        placement.Base.z = edited_value
                except ValueError:
                    # If the text can't be converted to a float, print an error message
                    print("Invalid value entered. The value must be a valid number.")

                # Update the object's placement
                selected_obj.Placement = placement

                # Recompute the document to reflect the changes
                App.ActiveDocument.recompute()
                # print(f"Updated value: {edited_value} in row {row}, column 0")

                # Reselect the object to refresh the table data
                reselect_object(selected_obj)

    # Function to update the selected object's expression values based on edits to the table
    def update_expression(row):
        item = table_widget.item(row, 1)
        if item is not None:
            # Get the edited text
            edited_text = item.text()
            # Get the label of the expression that was edited
            expression_label = ["x", "y", "z"][row]
            # Get the selected object
            selected_obj = table_widget.selected_object
            # Get the attribute's name
            attribute = f".Placement.Base.{expression_label}"

            # Update the attribute's expression
            selected_obj.setExpression(attribute, edited_text if edited_text != "" else None)

            # Recompute the document to reflect the changes
            App.ActiveDocument.recompute()
            # print(f"Updated expression: {edited_text} in row {row}, column 1")

            # Reselect the object to refresh the table data
            reselect_object(selected_obj)

    # Function to reselect an object
    def reselect_object(selected_obj):
        # Clear the current selection
        Gui.Selection.clearSelection()
        # Add the selected object to the selection
        Gui.Selection.addSelection(selected_obj)

    # Define the table's dimensions
    row_count = 4
    column_count = 2

    # Create the table widget
    table_widget = QtGui.QTableWidget(row_count, column_count)
    table_widget.setHorizontalHeaderLabels(["Value", "Expression"])
    table_widget.setVerticalHeaderLabels(["x", "y", "z", " "])

    # Left align the headers
    header = table_widget.horizontalHeader()
    header.setDefaultAlignment(QtCore.Qt.AlignLeft)

    # Adjust columns to contents
    table_widget.setSizeAdjustPolicy(QtGui.QAbstractScrollArea.AdjustToContents)
    table_widget.resizeColumnsToContents()
    table_widget.resizeRowsToContents()

    table_widget.setShowGrid(False)

    # Assign a delegate to handle cell edits
    delegate = QtGui.QItemDelegate()
    table_widget.setItemDelegate(delegate)

    # Connect signals to handle cell edits
    delegate.commitData.connect(lambda: update_values(table_widget.currentRow()) if table_widget.currentColumn() == 0 else None)
    delegate.closeEditor.connect(
        lambda: update_expression(table_widget.currentRow()) if table_widget.currentColumn() == 1 else None
    )

    # Define a class to observe selection changes
    class SelectionObserver:
        # When an object is selected, update the table
        def addSelection(self, doc, obj, sub, pnt):
            update_table_with_selected_object()

        # When an object is deselected, update the table
        def removeSelection(self, doc, obj, sub):
            update_table_with_selected_object()

    # Create an instance of the observer class
    selection_observer = SelectionObserver()
    # Add the observer to the selection
    Gui.Selection.addObserver(selection_observer)

    # Update the table with the currently selected object's data
    update_table_with_selected_object()

    # Make the last column stretch to fill the remaining space
    table_widget.horizontalHeader().setStretchLastSection(True)

    # Get the main window
    mainWindow = Gui.getMainWindow()

    # Check if the dock widget already exists
    dock_widget = mainWindow.findChild(QtGui.QDockWidget, "ExpressPlacementWidget")

    # If the dock widget does not exist, create it
    if dock_widget is None:
        dock_widget = QtGui.QDockWidget("Express Placement")
        dock_widget.setObjectName("ExpressPlacementWidget")  # Assign an object name to the dock widget
        mainWindow.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock_widget)

    # Set the dock widget's widget to the table
    dock_widget.setWidget(table_widget)
    # Make sure the dock widget is visible
    dock_widget.setVisible(True)

# Create and display the table
create_table()