Insert a list of attributes into a component. (With Ruby console)

Dear people, I’ve been designing in sketchup with dynamic components for years, I already have a programming pattern between “Parent” and “Child” items, but I always have to manually insert, I’ve never studied Ruby.

My question is: can I select a component and within the ruby ​​console insert a command with all my default attributes so that once for this selected item the variables are created with predetermined or null values?

#--------------#
(Pt-BR)
Pessoas queridas, a anos que projeto em sketchup com componentes dinâmicos, já tenho um padrão de programação entre itens “Pai” e itens “filhos”, porem sempre tenho que inserir manualmente, nunca estudei Ruby, minha pergunta é: posso selecionar um componente e dentro do console ruby inserir um comando com todos os meus atributos padrão para que uma vez para este item selecionado seja criado as variáveis já com os valores pré determinados ou nulos?

Hi try this.

1 Like

Hello, that would not be it, I think I expressed myself badly.

What I get is through the Ruby console to insert attributes into a component:

if selection.first.is_a?(Sketchup::ComponentInstance)
component_instance = selection.first
component_definition = component_instance.definition
attribute_dict = component_definition.attribute_dictionary(“Custom_Attributes”, true)
attribute_dict[“alex1”] = 10.5
attribute_dict[“alex2”] = 20.5
end

Now the Alex1 and Alex2 attributes are correct and with working values, but apart from seeing this inside the component’s Attributes window, I don’t see them. I can edit only through the console.
(google translate)

to the🥰

Try this…

def aplyZone()
  entities = Sketchup.active_model.selection
  lst_comps = entities.grep(Sketchup::Face)

  prompts = ["Zone?"]
  defaults = [""]
  input = UI.inputbox(prompts, defaults, "Data entry")

  for i in lst_comps do
    i.set_attribute "SomeName", "zone", "A"
    iscDict = i.definition.attribute_dictionary("SomeName")
    iscZone = iscDict.attribute_dictionary("zone", true)
    iscZone.set_attribute "Label", "value", "#{input[0]}"
    iscZone.set_attribute "Label", "is_hidden", false
    iscZone.set_attribute "Label", "attribute_type", String
  end
end

aplyZone()

It could be what you are looking for…(I have not tested, is part of code I wrote for other plugin)

1 Like

Acho que sua publicação tem muito a ver o que preciso, necessito de um script que me retorne em uma mensagem o valor de um atributo personalizado no componente. Pode me ajudar como posso acessar esse valor e mostrar na tema em uma mensagem como essa abaixo?

Mais ao invés de pegar o “definition.name” do componente preciso do valor do atributo personalizado “int_cat”.

Já possuo uma biblioteca muito grande de componentes desenvolvidos esse recurso me ajudaria muito durante meus projetos.

Here you go:

def get_att(dc,att) # Returns the current value of the attribute.
  # Always check instance first:
  val = dc.get_attribute( 'dynamic_attributes', att)
  if val.nil? # Does not differ from definition:
    val = dc.definition.get_attribute( 'dynamic_attributes', att)
  end
  return val
end

model = Sketchup.active_model
sel = model.selection.grep(Sketchup::ComponentInstance)
dc = sel [0]
my_attr_val = get_att(dc,'cust_attr')

result = UI.messagebox('cust_attr = ' + my_attr_val.to_s, MB_OK)

Test Componenmt.skp (15.9 KB)

1 Like

Verdadeiramente fiquei muito feliz pela sua ajuda e ainda mais por ter solucionado algo já havia tentado de várias formas. Estou tentando ajustar agora para interagir essa parte que vc ajudou com o que ja tenho, existe um problema!
Meus blocos existem centenas de componentes aninhados e preciso acessar as variáveis que criei de todos os componentes aninhados.

Segue o código no qual estou tentando acertar!!

reporter_csv.rb (2.3 KB)

Esse é o resultado atual abaixo:

Então os valores de “int_cat” e “intprocess” se repetem e não vem o valor real de cada componente.

Hey glad it worked for you happy to help. OK try this:


def filter_instances(selset)  # Grabs Groups and Component instances into an array.
  selset.grep(Sketchup::Group).concat(selset.grep(Sketchup::ComponentInstance))
end

def select_children(instance, cumulative) # Grab all nested Groups and Components in a selection.
  children = filter_instances(instance.definition.entities) # Grab Groups and Components that are children - 2nd level.
  cumulative.concat(children) # Add them to cumulative array.
  children.each { |child| select_children(child, cumulative) } # Repeat with 2nd level to get 3rd level, etc... 
end

def get_att(dc,att) # Returns the current value of the attribute.
  # Always check instance first:
  val = dc.get_attribute( 'dynamic_attributes', att)
  if val.nil? # Does not differ from definition:
    val = dc.definition.get_attribute( 'dynamic_attributes', att)
  end
  return val
end

model       = Sketchup.active_model
selset      = model.selection.to_a
parents     = filter_instances(selset)
cumulative  = [] # container for all Groups and Components in selection
cumulative.concat(parents)
parents.each { |inst| select_children(inst, cumulative) }

puts cumulative

has_attribute = [] # container for components with your attribute
cumulative.each do |dc|
 if get_att(dc,cust_att)
   has_attribute << dc
 end
end
  
puts has_attribute

EDIT: missed an = sign

2 Likes

Vou tentar utilizar esse código, no caso ele me retornara um array com todos os atributos personalizados? No caso eu tenho já tenho o formato que utilizo pelo exportador de relatórios nativo do Sketchup.

Esse é o modelo do template:

TEMPLATE INTPROCESS .txt (757 Bytes)

Só precisa renomear para .grt, formato não suportado para Up.

1 Like

It should return an array of the Components which have the attribute. Not sure I am following you, what exactly is the end goal of your script? Once you have the components in an array you can assign whatever attributes you want to them with the .set_attribute method.

Try this code with the test file, it should clarify things for us I hope.

Test Componenmt.skp (17.0 KB)


def filter_instances(selset)  # Grabs Groups and Component instances into an array.
  selset.grep(Sketchup::Group).concat(selset.grep(Sketchup::ComponentInstance))
end

def select_children(instance, cumulative) # Grab all nested Groups and Components in a selection.
  children = filter_instances(instance.definition.entities) # Grab Groups and Components that are children - 2nd level.
  cumulative.concat(children) # Add them to cumulative array.
  children.each { |child| select_children(child, cumulative) } # Repeat with 2nd level to get 3rd level, etc... 
end

def get_att(dc,att) # Returns the current value of the attribute.
  # Always check instance first:
  val = dc.get_attribute( 'dynamic_attributes', att)
  if val.nil? # Does not differ from definition:
    val = dc.definition.get_attribute( 'dynamic_attributes', att)
  end
  return val
end

def is_dynamic?(dc) # Looks for 'dynamic_attributes' ditionary.
  dc.attribute_dictionary('dynamic_attributes') || dc.definition.attribute_dictionary('dynamic_attributes')
end

def get_name(dc) # Returns Component or Group name.
  name = dc.name
  if name.empty?
    if is_dynamic?(dc)
      name = get_att( dc, 'name')
      name = get_att( dc, '_name') unless name
      name = dc.definition.name unless name
    else # Not a Dynamic Component.
      name = dc.definition.name
    end
  end
  return name
end

model       = Sketchup.active_model
selset      = model.selection.to_a
parents     = filter_instances(selset)
cumulative  = [] # container for all Groups and Components in selection
cumulative.concat(parents)
parents.each { |inst| select_children(inst, cumulative) }

puts 'cumulative contents: '
cumulative.each do |dc|
  puts get_name(dc)
end

puts

has_attribute = [] # container for components with your attribute
cumulative.each do |dc|
 if get_att(dc,'cust_attr')
  unless has_attribute.include? dc
    has_attribute << dc
  end
 end
end
  
puts 'has_attribute contents: '
has_attribute.each do |dc|
  puts get_name(dc)
end

In your last example I did not see cust_attr = 3 (in a message box or puts in the Ruby Console) using SU '23. Did I miss something?

This example is simply to grab all of the components in a selection, including all nested levels, and separate those with the desired attributes. After that @DouglasAnjos can do whatever he wants with the attribute holding components…

Hey @DouglasAnjos, I went over your code and got it to generate a .csv file I think as you wanted. Here is the adjusted code:


require 'csv' # What is CSV?

def exportar_nome_e_material_para_csv(componente, csv)
  model = Sketchup.active_model
  sel = model.selection.grep(Sketchup::ComponentInstance)
  dc = sel [0]
  int1 = get_att(dc,'int_cat')
  int2 = get_att(dc,'intprocess')

  if componente.is_a?(Sketchup::ComponentInstance)
    nome_componente = componente.definition.name
    if componente.material 
      material_componente = componente.material.display_name
    else
      material_componente = 'Nenhum material'
    end

    def get_att(dc,att) # Returns the current value of the attribute.
      # Always check instance first:
      val = dc.get_attribute( 'dynamic_attributes', att)
      if val.nil? # Does not differ from definition:
        val = dc.definition.get_attribute( 'dynamic_attributes', att)
      end
      return val
    end

    csv << [nome_componente, material_componente, int1, int2]

    # Itera sobre as instâncias aninhadas
    componente.definition.entities.each do |entidade_aninhada|
      # Recursivamente chama a função para os componentes aninhados
      exportar_nome_e_material_para_csv(entidade_aninhada, csv)
    end
  end
end

# Método principal para exportar nome e material de todos os componentes para CSV
def exportar_nome_e_material_de_todos_os_componentes
  # Obtém a seleção atual no modelo do SketchUp
  selecao = Sketchup.active_model.selection

  # Verifica se há algo selecionado
  if selecao.empty?
    UI.messagebox('Nenhum componente selecionado para exportar.')
    return
  end

  # Escolha do arquivo de destino
  arquivo_csv = UI.savepanel('Exportar Nome e Material de Todos os Componentes', '', 'exportar_nome_e_material_todos_componentes.csv')

  return unless arquivo_csv

  # Abre o arquivo CSV para gravação
  CSV.open(arquivo_csv, 'w') do |csv|
    # Cabeçalho do CSV
    csv << ['Nome do Componente', 'Material']

    # Itera sobre a seleção
    selecao.each do |entidade|
      # Recursivamente chama a função para os componentes aninhados
      exportar_nome_e_material_para_csv(entidade, csv)
    end
  end

  UI.messagebox('Exportação concluída com sucesso!')
end

# Chama o método principal para exportar nome e material de todos os componentes para CSV
exportar_nome_e_material_de_todos_os_componentes

1 Like

Em resposta venho informar que foi solucionado e consegui gerar meu relatório dos componentes da minha biblioteca de móveis que já tenho desenvolvida, o meu objetivo e criar uma listagem para meu componentes já desenvolvidos, único problema que tenho por final é que eu tenho um atributo com letras maiúsculas e meu script não consegue interpreta-lo, vou postar o código como ficou e também a saída do atributo “IntProcess”.

Haveria uma forma de conseguir extrair o valor desse atributo mesmo com letras maiúsculas sem ter que editar em todas meus componentes. vou postar o arquivo abaixo.

IntProcessReporter.txt (3.1 KB)

Imagem abaixo mostra que o atributo “IntProcess” em valor “0” ou “1” e na saida ele vai vazio, renomeando ele para minúsculo deu certo.

Agradeço a todos pelo apoio e orientação, jamais teria conseguido sem auxilio de vocês.

1 Like

Try ‘intprocess’ instead of ‘IntProcess’. In a DC the attribute label is case sensitive, however the attribute itself is all lower case.

If you do not have it Attribute Inspector is very helpful with DCs.

Olá!!!
Você quis dizer para alterar no rótulo dos DC ou alterar no Script?
Fiz alteração das duas formas e só obtive resultado alterando realmente o rótulo, mais para isso eu teria que entrar em absolutamente todos meus componentes já desenvolvidos que são milhares e alterar.
Caso não tenha outra saída vou ter que fazer isso manualmente.

Se puder me explicar mais afundo por gentileza.

Eu tenho o plugin sim instalado mais como pode perceber sou novo por aqui e ainda estou travado até mesmo para interpretar todo contexto mais estou diariamente focado em aprender e aprofundar na linguagem e desenvolvimento na linguagem Ruby.

1 Like

Hey! I meant to change the script not the label. Could you upload an example component with the script as it is now? It would be easier for me to try to help.

Claro… aqui está!!
int_process_reporter.txt (2.8 KB)
Gaveteiro.skp (13.1 MB)

Note que na posição de saida “Intprocess” não recebe o valor!

1 Like