# Python - How to Add a Text Field to the UI? [duplicate]

I'm trying to create a text field in the UI that will allow users to enter a directory path, then press a button to export an fbx file to that path.

The Button creation into the UI works great. But I can't find information on setting up the text field for users to enter information. I took a try at it, but my setup isn't working for the String text input, only the button works. What am I doing wrong? (Page has been update to reflect comments below changes)

    import bpy

class WorthGroupToolsSettings(bpy.types.PropertyGroup):
file_path: bpy.types.StringProperty(name="File path",
description="Test",
default="",
maxlen=1024,
subtype="FILE_PATH")

class WorthGroup_Panel(bpy.types.Panel):
bl_idname = "WorthGroupTools_PT_Panel"
bl_label = "WorthGroup Tools Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"

def draw(self, context):
layout = self.layout
row = layout.row()

worth_group_tools = context.scene.worth_group_tools
row.prop(worth_group_tools, "file_path")

# This creates the button.  Works great!
row.operator('view3d.export_fbx', text="Export Selected")


I modified my page, it should work but I get the following error message from this code:

class WorthGroupToolsSettings(bpy.types.PropertyGroup):
file_path: bpy.types.StringProperty(name="File path",
description="Test",
default="",
maxlen=1024,
subtype="FILE_PATH")


The error message is:

File "C:\Users\WG\AppData\Roaming\Blender Foundation\Blender\2.80\scripts\addons\Blender\WorthGroupTools_panel.py", line 4, in <module>
class WorthGroupToolsSettings(bpy.types.PropertyGroup):
File "C:\Users\WG\AppData\Roaming\Blender Foundation\Blender\2.80\scripts\addons\Blender\WorthGroupTools_panel.py", line 9, in WorthGroupToolsSettings
subtype="FILE_PATH")
TypeError: bpy_struct.__new__(type): expected a single argument


I also want to note I also have a __init__.py page and a operator page. This is what the __init__.py page appears as:

    import bpy

from . WorthGroupTools_op import WorthGroupTools_Operator
from . WorthGroupTools_panel import WorthGroup_PT_Panel
from . WorthGroupTools_panel import WorthGroupToolsSettings

bl_info = {
"name": "WorthGroup Tools",
"author": "",
"description": "",
"blender": (2, 80, 0),
"version": (0, 0, 1),
"location": "View3D",
"warning": "",
"category": "Generic"
}

classes = (WorthGroupTools_Operator, WorthGroupToolsSettings, WorthGroup_Panel)

# register, unregister = bpy.utils.register_classes_factory(classes)

def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.worth_group_tools = bpy.props.PointerProperty(type=WorthGroupToolsSettings)

def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.worth_group_tools

if __name__ == "__main__":
register()

• rjg, Unfortunately I'm still confused after reading the link you consider is a duplicate to my question. The user in the link you sent uses a variable, "update_oha_quicklink_root_folder", is this a boolean? His root_folder = "StringProperty", I get "not defined", should I stick with the method I tried, "bpy.props.StringProperty"? Does this even work if my class is "bpy.types.Panel"? Or do I need to create an entirely new class called "bpy.types.PropertyGroup"? If I need a new class, how would I link it to my Panel's row layout? – Teriander Aug 14 '19 at 19:44
• Right, sorry. It's better to put the properties in an extra class that is registered as well. I'll post an answer later this night that shows how to add the property in case nobody else does, I'm a bit busy atm. – Robert Gützkow Aug 14 '19 at 19:47

With a PropertyGroup and a PointerProperty you can register all your properties in the scene. They are then accessible by panels or operators under the name you've chosen.

The StringProperty allows you to set the subtype to FILE_PATH which creates a text field with a file selector. Once clicked this triggers Blender's file browser and the user can select a file. The path to the file is then stored in the property.

import bpy

class WorthGroupToolsSettings(bpy.types.PropertyGroup):
file_path: bpy.props.StringProperty(name="File path",
description="Some elaborate description",
default="",
maxlen=1024,
subtype="FILE_PATH")

class WORTHGROUPTOOLS_PT_panel(bpy.types.Panel):
bl_label = "WorthGroup Tools Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"

def draw(self, context):
layout = self.layout
row = layout.row()

worth_group_tools = context.scene.worth_group_tools
row.prop(worth_group_tools, "file_path")

classes = (WorthGroupToolsSettings,
WORTHGROUPTOOLS_PT_panel)

def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.worth_group_tools = bpy.props.PointerProperty(type=WorthGroupToolsSettings)

def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.worth_group_tools

if __name__ == "__main__":
register()


• Thank you so much for a detailed answer, I will test now! – Teriander Aug 15 '19 at 1:22
• Thanks again rjg. I've made changes that I believe should mirror your suggestion, but I get an error. I've posted details above about the error and updated the script. Any idea what's causing this? I'm using VSCode + Blender Development to launch blender. Also, if you need the FULL detail of the error results please let me know . I narrowed it down in the post. – Teriander Aug 15 '19 at 2:35
• It should be bpy.props.StringProperty not bpy.types.StringProperty in the Settings class. – Robert Gützkow Aug 15 '19 at 5:57
• That's it! Thanks buddy! – Teriander Aug 15 '19 at 15:01