PDA

Ver la Versión Completa : [Duda] Hacer referencia a un "Name" con una variable


Josber
15 de enero de 2023, 20:27
Estoy intentando a través de una variable, hacer referencia al Nombre (propiedad 'Name') de un CONTROL, por ejemplo, suponiendo que tengo dos controles en un form, que uno se llama NOMBRE y el otro se llama APELLIDOS, la codificación sería


WORKING-STORAGE SECTION.
01 CONTROL_NAME PIC X(32) VALUE SPACES.
01 FLAG PIC 9.
.
.
.
PROCEDURE DIVISION.
INICIO-000.
.
.
.
IF FLAG = 0
MOVE "Name" OF NOMBRE TO CONTROL_NAME
ELSE
MOVE "Name" OF APELLIDOS TO CONTROL_NAME
END-IF.
.
.
.
MOVE SPACES TO "Text" OF CONTROL_NAME.


Pero al compilar me da el error
F_PRUEBA PRUEBA(182) : JMN2505I-S 'TO' must be specified in the MOVE statement. 'TO' is assumed.

Por lo que presupongo que, el error es que no tiene ni idea de qué control estoy usando, ya que la sintaxis, está bien

¿Hay alguna manera de hacerlo?

Mil gracias y un salu2.-

Kuk
16 de enero de 2023, 09:36
@Josber,


MOVE SPACES TO "Text" OF CONTROL_NAME. *> ERROR!!!!
MOVE SPACES TO CONTROL_NAME.


Se te están mezclando ya los controles del Power y las variables Cobol :D

O sea que tu problema está ne la línea 20 ;)

Josber
16 de enero de 2023, 10:42
@Kuk, no, no está mal, yo no quiero vaciar la variable CONTROL_NAME, quiero vaciar el control cuyo nombre es el que hay en la variable CONTROL_NAME, (pongo vaciar, pero podría ser, usar el 'hwnd', tipo de letra, colores, etc, cualquier propiedad del control), o sea, unas veces querré vaciar el control Nombre y otras veces el control Apellidos, dependiendo del valor que tenga CONTROL_NAME.

Un salu2.-

Kuk
16 de enero de 2023, 11:15
@Josber, amigo, ya lo pillo. Pues esto no lo puedes hacer como tu quieres... pero sí de esta manera:


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COBJECT OBJECT REFERENCE POW-COBJECT.
01 OBJETO OBJECT REFERENCE COM.

01 contenido pic x(50).

PROCEDURE DIVISION.

move spaces to contenido

move CmText1 to COBJECT

CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO

invoke OBJETO "SET-Text" using contenido

Josber
16 de enero de 2023, 11:50
Gracias @Kuk, que mal, no me sirve porque, lo que he puesto es un ejemplo 'al vuelo', realmente lo necesito con otras propiedades, como sería usar el hwnd, color, foco, etc. Imagínate que son varios controles ListView, y que dependiendo de unos parámetros externos, necesite poner un checkbox en ciertos ListView, para ello, necesito saber el hwnd de ese control en concreto

Éste, sería el código que funciona perfectamente


MOVE "hWnd" OF VIEW2 TO WS-HANDLE.
CALL "SendMessageA" WITH STDCALL USING BY VALUE WS-HANDLE
BY VALUE LVM-SETEXTENDEDLISTVIEWSTYLE
BY VALUE LVS-EX-CHECKBOXES
.
.
.


y éste el que quiero usar, pero que no funciona


EVALUATE OPC
WHEN 1
MOVE "View1" TO CONTROL_NAME
WHEN 2
MOVE "View2" TO CONTROL_NAME
.
.
.
END-EVALUATE.


MOVE "hWnd" OF CONTROL_NAME TO WS-HANDLE.
CALL "SendMessageA" WITH STDCALL USING BY VALUE WS-HANDLE
BY VALUE LVM-SETEXTENDEDLISTVIEWSTYLE
BY VALUE LVS-EX-CHECKBOXES
.
.
.


El tema está en que son muchos controles y esto ahorraría escribir mucho, ya no para el ListView, sino para otros controles que he de usar que no tienen nada que ver con un ListView.

Muchas gracias.-

Kuk
16 de enero de 2023, 13:30
@Josber, cómo que no? Sí que funciona! :)


01 contenido pic x(50).
01 hwnd pic s9(9) comp-5.
01 WM_SETTEXT pic s9(9) comp-5 value H"000C".
PROCEDURE DIVISION.

move "Hola Josber" to contenido

move CmText1 to COBJECT

CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO

invoke OBJETO "GET-hwnd" returning hwnd

call "SendMessageA" with stdcall using by value hwnd
by value WM_SETTEXT
by value 0
by reference contenido

Kuk
16 de enero de 2023, 13:38
@Josber, también tienes la siguiente opción que se me acaba de ocurrir y me parece que es lo que estabas buscando exactamente:


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 miTextBox OBJECT REFERENCE AMixed-DCmTextbox-Main-with-DCfGroupItem-Main.
PROCEDURE DIVISION.

move CmText1 to miTextBox

move "Hola Josber" to "Text" OF miTextBox



Para ver qué clase debes indicar en OBJECT REFERENCE, tienes que mirar en la carpeta DEBUG el fichero MainForm.prc y dentro buscar el nombre del control, por ejemplo CmText1 y luego copiar y usar la clase en tu código. Quiere decir que todos los CmText tendrán esta clase en referencia. Podrías hasta hacer un OCCURS tipo:


01 campoDeTexto.
05 misTextBox OCCURS 100 OBJECT REFERENCE AMixed-DCmTextbox-Main-with-DCfGroupItem-Main.

Josber
16 de enero de 2023, 19:49
@Kuk, si uso la primera opción, (porque la segunda no me gusta, además que es un poco problemática porque los controles están en un Array de controles), y la defino como me has puesto


01 COBJECT OBJECT REFERENCE POW-COBJECT.
01 OBJETO OBJECT REFERENCE COM.


Así, tal y como está, en 01 OBJETO, al compilar me da el error:

JMN5100I-S The class-name specified in the USAGE OBJECT REFERENCE clause is invalid. The class-name is ignored.

ya sé que no sería el caso pero, si defino en REPOSITORY


CLASS COM AS "*COM".


entonces me da el error:

error LNK2001: unresolved external symbol _XXXXXXXXXXX

donde _XXXXXXXXXXX, es el nombre de la subrutina de la PROCEDURE donde están definidas esas variables.

¿Dónde puede estar el problema?

Kuk
16 de enero de 2023, 20:41
@Josber, la segunda opción no tiene por qué ser un array. Puedes usar una sola variable por tipo de componente visual. Así que bueno, en realidad es lo que querías en principio. Y mientras que no uses componentes distintos una sola variable te vale.

En cuanto al problema de compilación de la primera opción. Es el error de que te falta la librería correspondiente. En caso de mi ejemplo, SendMessageA es la librería User32.lib.

A mi el ejemplo del código me compila y funciona correctamente.

Y es verdad que tienes que añadir lo de


CLASS COM AS "*COM".

Josber
17 de enero de 2023, 12:12
@Josber,

En cuanto al problema de compilación de la primera opción. Es el error de que te falta la librería correspondiente. En caso de mi ejemplo, SendMessageA es la librería User32.lib.


La verdad es que tengo otros programas que sí utilizan SendMessageA, (para el tema de poner y quitar líneas, checkbox, etc. en un listview, se hace todo a través de esa llamada), y no tienen incluida la librería User32.lib, pero, de todas maneras, éste sí que la tiene incorporada, porque si no, con el tema del tooltip "casero", no funcionaría y me daría error al compilar, para ser exactos, están incluidas esa librería y advapi32.lib

876

Kuk
17 de enero de 2023, 13:27
error LNK2001: unresolved external symbol _XXXXXXXXXXX

donde _XXXXXXXXXXX, es el nombre de la subrutina de la PROCEDURE donde están definidas esas variables.

¿Dónde puede estar el problema?

¿Estás respetando las minúsculas/mayúsculas? Alguna chorrada que se nos escapa por algún lado.

Josber
17 de enero de 2023, 19:44
¿Estás respetando las minúsculas/mayúsculas?

Bueno eso ya está solucionado, increíblemente, he borrado la librería, he hecho un re-build completo, la he vuelto a añadir, compilado otra vez y ... ¡¡ta-channnn!!, ya no ha dado el error. El problema que tengo ahora es que si hago ésto


PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
MOVE "Name" OF CAMPO (I) TO NOMBRE_CONTROL
END-PERFORM.

move NOMBRE_CONTROL to COBJECT.
CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO.


al ejecutar, me salta el error

JMP0221I-U CALL ERROR OCCURRED IN 'GET-hwnd' OF THE METHOD INVOCATION. 'NULL'

porque COBJECT, tiene valor 0, (NULL)

Sin embargo, si hago


PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
MOVE CAMPO (I) TO COBJECT
END-PERFORM.

CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO.


Funciona perfectamente, (aquí COBJECT, si que tiene un valor positivo), por lo visto, no se puede pasar el nombre a través de una variable, que es lo que necesito realmente, así que, de momento lo voy a dejar, porque no puedo pasar más tiempo con esto, lo haré manualmente de momento y más adelante, si puedo, lo retomaré.

muchas gracias.-

Kuk
17 de enero de 2023, 20:21
@Josber, sí es verdad, cuando añades algo de vez en cuando el cache no se refresa y el Build no lo toma en cuenta. Hay que hacer Rebuild.

El "Name" es una propiedad, como un campo del control (objeto), no tiene Handle (hwnd).

Si pasas por COM/OLE, para obtener Propiedades o ponerlas, es todo pasando por INVOKE OBJETO "[ación]-[nombre_propiedad]", donde ación es SET o GET y nombre_propiedad es cualquiera que tiene el componente, como hwnd, Name, Width etc.

Ejemplos:


...
MOVE CAMPO (I) TO COBJECT
...
CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO.

INVOKE OBJETO "GET-Name" RETURNING WS-NOMBRE
INVOKE OBJETO "GET-Text" RETURNING WS-CONTENIDO

MOVE "Hola Josber" TO WS-CONTENIDO

INVOKE OBJETO "SET-Text" USING WS-CONTENIDO

invoke OBJETO "SetFocus"
invoke OBJETO "Refresh"

Fito
17 de enero de 2023, 22:18
Hola Amigos: Estoy tratando de seguir el hilo de esta conversación y hay conceptos que no manejo. Están programando a un nivel que no domino.

Pero tratando de entender los que quieres @Josber es con la misma rutina poder manejar las propiedades de distintos controles pasando como parámetro el nombre del control.

El "Name" de un control es un string, no es un objeto, por eso no podés hacer esto

PERFORM VARYING I FROM 1 BY 1 UNTIL I > 6
MOVE "Name" OF CAMPO (I) TO NOMBRE_CONTROL
END-PERFORM.

move NOMBRE_CONTROL to COBJECT.
CALL "POWERCONVTOCOM" USING COBJECT RETURNING OBJETO.


COBJECT espera que le muevas un objeto no un string.

Ahora hacer


MOVE CAMPO (I) TO COBJECT


en lugar de


MOVE "Name" OF CAMPO (I) TO NOMBRE_CONTROL


Debería servirte lo mismo, porque en el "campo" COBJECT tendrías el objeto en cuestión. O seguramente algo se me está escapando.

Perdón por la ignorancia, pero es medio complicado para mi cabeza.

Saludos

Fito...

Kuk
18 de enero de 2023, 09:00
@Fito, no se te escapa nada, llevas razón, es eso ;)

Josber
18 de enero de 2023, 10:32
@Fito, Sí es correcto lo que dices pero, no he puesto que CAMPO (I), es el nombre de un control que está en array, por lo que "su 'Name'", es CAMPO(n), ése nombre es el que necesito mover a una variable porque, no sólo es el control CAMPO (I), hay más controles, como INFO (I), SUM (I), VIEW (I), etc.
Entonces, yo lo que quiero es ahorrar programación, imagina que quiero vaciar esos campos, (que no es el caso, porque es más complicado), tendría que hacer un MOVE SPACES a cada uno de esos controles, sin embargo, si puedo mover la propiedad Name a una variable y luego "referenciar" esa variable en el INVOKE, ahorraría líneas de código.

Si hago:

MOVE CAMPO (I) TO COBJECT.

funciona perfectamente, pero si hago, (que es lo que necesito):

MOVE "Name" OF CAMPO (I) TO NOMBRE_CONTROL.
MOVE NOMBRE_CONTROL TO COBJECT.

ya no funciona, a pesar de que NOMBRE_CONTROL, contiene el valor correcto, en el primer caso COBJECT, tiene un valor positivo, pero en el segundo caso, COBJECT, tiene un valor 0, (nulo).

Espero que se entienda

Un salu2.-

Kuk
18 de enero de 2023, 12:46
@Josber, te estás liando yo creo :D ;)

Posibilidad Nº1 utilizando OBJECT-REFERENCE nombre_de_la_clase:


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 misTextBox.
05 miTextBox occurs 3 times OBJECT REFERENCE AMixed-DCmTextbox-Main-with-DCfGroupItem-Main.

01 nombreTextBox pic x(20).
01 contenTextBox pic x(30).
01 idx pic 9(4) comp-5.
PROCEDURE DIVISION.

move "Hola Josber" to "Text" OF CmText1
move "Esta es la" to "Text" OF CmText2
move "posibilidad 1" to "Text" OF CmText3

move CmText1 to miTextBox(1)
move CmText2 to miTextBox(2)
move CmText3 to miTextBox(3)

move 1 to idx

perform until idx > 3
move "Name" OF miTextBox(idx) to nombreTextBox
move "Text" OF miTextBox(idx) to contenTextBox

display "Nombre: " nombreTextBox " contenido: " contenTextBox

add 1 to idx
end-perform



Posibilidad Nº2, pasando por COM/OLE:


ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COBJECT OBJECT REFERENCE POW-COBJECT.

01 misTextBox.
05 miTextBox occurs 3 times OBJECT REFERENCE COM.

01 nombreTextBox pic x(20).
01 contenTextBox pic x(30).
01 idx pic 9(4) comp-5.
PROCEDURE DIVISION.

move "Hola Josber" to "Text" OF CmText1
move "Esta es la" to "Text" OF CmText2
move "posibilidad 2" to "Text" OF CmText3

move CmText1 to COBJECT
CALL "POWERCONVTOCOM" USING COBJECT RETURNING miTextBox(1)

move CmText2 to COBJECT
CALL "POWERCONVTOCOM" USING COBJECT RETURNING miTextBox(2)

move CmText3 to COBJECT
CALL "POWERCONVTOCOM" USING COBJECT RETURNING miTextBox(3)

move 1 to idx

perform until idx > 3
invoke miTextBox(idx) "GET-Name" returning nombreTextBox
invoke miTextBox(idx) "GET-Text" returning contenTextBox

display "Nombre: " nombreTextBox " contenido: " contenTextBox

add 1 to idx
end-perform

Fito
18 de enero de 2023, 15:23
Holaaa:

Exacto @Kuk, hay que hacer un array de objetos, no un array de los name de los objetos.

Está muy buena tu idea @Josber, yo tengo en un método del formulario todos los move y se hace larga la programación

Saludos

Fito...