尝试动态创建UI /图像元素并不断更新它们

时间:2018-07-05 14:20:31

标签: json list dictionary unity3d

我正在尝试为Unity3D中的Microsoft HoloLens构建应用程序。该应用程序将以JSON形式从python应用程序接收数据。 python发送的JSON如下:

{
    "PC_Station": [{
        "PLC_1": {
            "DB1": {
                "test123": 0
            },
            "STOP": false,
            "START": false,
            "Start_1": false,
            "Stop_1": false,
            "Led1": false,
            "Led2": false,
            "Led3": false,
            "Counter": 0,
            "Sliderval": 0
        }
    }]
}

应用程序的源代码在这里:

using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Linq;
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine.UI;
using Newtonsoft.Json;
using System.Collections;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;
#if !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;

#endif

public class UDPCommunication : Singleton<UDPCommunication>
{
    // Connection variables
    private string port = "8000";
    private string externalIP = "172.16.24.251";
    private string externalPort = "8001";
    public static int size = 0;
    public static List<Dictionary<string, string>> abc = new List<Dictionary<string, string>>();
    public static List<string> varz;
    public GameObject canvas;
    public GameObject Panel;
    public GameObject image;
    public GameObject imagetext;
    public GameObject numbertext;
    public Image testimg;
    private GameObject getImageTags;
    private GameObject getNumberTags;
    private GameObject[] canvases;
    private GameObject[] panels;
    private GameObject[] tiles;
    private GameObject[] texts;
    private float scaler = 0.0125f;
    // UI/Text elements
    const string TurnOn = "on";
    private uint sliderVal;
    // Sets up a Queue
    private string receivedmsg;
    public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
    private void Awake()
    {

    }

    IEnumerator updateTags()
    {
        while (true)
        {
            Debug.Log("List count" + abc.Count);
            for (int i = 0; i < abc.Count; i++)
            {
                foreach (KeyValuePair<string, string> item in abc[i])
                {
                    testimg = GameObject.Find(item.Key).GetComponent<Image>();
                    if(item.Value == "True")
                    {
                        testimg.color = Color.green;
                    }
                    if(item.Value == "False")
                    {
                        testimg.color = Color.red;
                    }
                }       
            }
            yield return new WaitForSeconds(0.25f);
        }
    }
#if !UNITY_EDITOR
    // Socket initialization
    DatagramSocket socket;
#endif
#if !UNITY_EDITOR


    IEnumerator initGUI()
    {
        while(true){
            if(receivedmsg == null){
                Debug.Log("None");
            }
            else{
                Debug.Log(receivedmsg);
                break;
            }
        }
        yield return new WaitForSeconds(1.0f);
        yield return StartCoroutine(createUserInterface(receivedmsg));
        //yield return StartCoroutine(updateTags());
        Debug.Log("left initgui");
    }
    // use this for initialization
    async void Start()
    {
        /*StartCoroutine(SendSliderValue());
        Button btn_on = led1_button_on.GetComponent<Button>();
        Button btn_off = led1_button_off.GetComponent<Button>();
        Button btn1_on = led3_button_on.GetComponent<Button>();
        Button btn1_off = led3_button_off.GetComponent<Button>();

        btn_on.onClick.AddListener(delegate {TaskWithParameters("Led1 on"); });
        btn_off.onClick.AddListener(delegate {TaskWithParameters("Led1 off"); });
        btn1_on.onClick.AddListener(delegate {TaskWithParameters("Led3 on"); });
        btn1_off.onClick.AddListener(delegate {TaskWithParameters("Led3 off"); });*/
        //string json = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false,\"Frap\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 55}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";

        Debug.Log("Waiting for a connection...");
        socket = new DatagramSocket();
        socket.MessageReceived += Socket_MessageReceived;

        //createUserInterface(receivedmsg);
        HostName IP = null;
        try
        {
            var icp = NetworkInformation.GetInternetConnectionProfile();

            IP = Windows.Networking.Connectivity.NetworkInformation.GetHostNames()
            .SingleOrDefault(
                hn =>
                    hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
                    == icp.NetworkAdapter.NetworkAdapterId);

            await socket.BindEndpointAsync(IP, port);
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
            Debug.Log(SocketError.GetStatus(e.HResult).ToString());
            return;
        }
        SendMessage("test");
        StartCoroutine(updateTags());
        StartCoroutine(initGUI());


    }


    void TaskWithParameters(string message)
    {
        Debug.Log("sending Message");
        SendMessage(message);
    }

    private async System.Threading.Tasks.Task SendMessage(string message)
    {
        using (var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(externalIP), externalPort))
        {
            using (var writer = new Windows.Storage.Streams.DataWriter(stream))
            {
                var data = Encoding.UTF8.GetBytes(message);
                writer.WriteBytes(data);
                await writer.StoreAsync();
                Debug.Log("Sent: " + message);
            }
        }
    }
#else


    // Use this for initialization.
    void Start()
    {

    }
#endif
    // Update is called once per frame.
    void Update()
    {
        // Dequeues items until there are no more items on the queue.
        while (ExecuteOnMainThread.Count > 0)
        {
            ExecuteOnMainThread.Dequeue().Invoke();
        }
    }

    IEnumerator SendSliderValue()
    {
        Debug.Log("entered slider class");
        GameObject theplayer = GameObject.Find("Hololens-Slider");
        TubeSliderManager test = theplayer.GetComponent<TubeSliderManager>();
        while (true)
        {
            sliderVal = test.CurrentValue;
            string s = "Slidervalue" + sliderVal.ToString();
            SendMessage(s);
            yield return new WaitForSeconds(0.5f);
        }
    }


#if !UNITY_EDITOR

    //this method gets called when a message is received
    private async void Socket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
    {
        // Read the received message.
        Stream streamIn = args.GetDataStream().AsStreamForRead();
        StreamReader reader = new StreamReader(streamIn);
        receivedmsg = await reader.ReadLineAsync();
        //Debug.Log("MESSAGE: " + message);
        // if the count is zero, the message will be relayed to the setStuff method, which processes the string continuously.
        // The message contains a JSON string which is received from the server.
        if (ExecuteOnMainThread.Count == 0)
        {
            ExecuteOnMainThread.Enqueue(() =>
            {
                //Debug.Log(receivedmsg);
                //pass msg to function here
            });
        }
    }
#endif

    IEnumerator createUserInterface(string jsonstring)
    {
        Debug.Log("entered create UI");
        var root = JToken.Parse(jsonstring);
        StartCoroutine(IterateJtoken(root));
        canvases = new GameObject[abc.Count];
        panels = new GameObject[abc.Count];
        for (int i = 0; i < abc.Count; i++)
        {
            canvases[i] = Instantiate(canvas, transform.position, transform.rotation);
            canvases[i].name = "Canvas" + i;
            canvases[i].transform.position += new Vector3(i * 14, 0, 30);
            panels[i] = Instantiate(Panel, transform.position, transform.rotation);
            panels[i].name = "Panel";
            panels[i].transform.SetParent(canvases[i].transform, false);
            for (int z = 0; z < abc[i].Count; z++)
            {
                tiles = new GameObject[abc[i].Count];
                texts = new GameObject[abc[i].Count];
                tiles[z] = Instantiate(image, transform.position, transform.rotation);
                tiles[z].name = abc[i].ElementAt(z).Key;
                tiles[z].transform.SetParent(panels[i].transform, false);
                texts[z] = Instantiate(imagetext, transform.position, transform.rotation);
                texts[z].name = abc[i].ElementAt(z).Key + "text";
                texts[z].transform.SetParent(tiles[z].transform, false);
                texts[z].GetComponent<Text>().text = abc[i].ElementAt(z).Key;
                texts[z].transform.position += new Vector3(44 * scaler, -4 * scaler, 0);
                if (Regex.IsMatch(abc[i].ElementAt(z).Value, @"^\d+$"))
                {
                    numbertext = Instantiate(imagetext, transform.position, transform.rotation);
                    numbertext.name = abc[i].ElementAt(z).Key + "value";
                    numbertext.transform.SetParent(tiles[z].transform, false);
                    texts[z].transform.position += new Vector3(0, 19.5f * scaler, 0);
                    numbertext.transform.position += new Vector3(77 * scaler, -18.5f * scaler, 0);
                }
            }
        }
        yield return null;
    }



    IEnumerator IterateJtoken(JToken jtoken)
    {
        abc.Clear();
        foreach (var value in jtoken)
        {
            foreach (JArray test in value)
            {
                for (int i = 0; i < test.Count; i++)
                {
                    foreach (var item in test[i])
                    {
                        var itemproperties = item.Parent;
                        foreach (JToken token in itemproperties)
                        {
                            if (token is JProperty)
                            {
                                var prop = token as JProperty;
                                //Console.WriteLine(prop.Name);           //PLC name
                                var plc = (JObject)prop.Value;
                                Dictionary<string, string> variables = new Dictionary<string, string>();
                                foreach (KeyValuePair<string, JToken> val in plc)
                                {
                                    if (val.Value is JObject)
                                    {
                                        JObject nestedobj = (JObject)val.Value;
                                        foreach (JProperty nestedvariables in nestedobj.Properties())
                                        {
                                            size++;
                                            var nestedVariableName = nestedvariables.Name;
                                            var nestedVariableValue = nestedvariables.Value;
                                            variables.Add(nestedVariableName, nestedVariableValue.ToString());
                                            //Console.WriteLine(nestedVariableName+" "+nestedVariableValue);
                                        }

                                    }
                                    else
                                    {
                                        size++;
                                        var variableName = val.Key;
                                        var variableValue = val.Value;
                                        variables.Add(variableName, variableValue.ToString());
                                        //Console.WriteLine(variableName+" "+variableValue);
                                    }

                                }
                                abc.Add(new Dictionary<string, string>(variables));
                            }
                        }
                    }
                }
            }
        }
        yield return new WaitForSeconds(0.5f);
    }
}

使用函数Socket_MessageReceived接收消息。如您所见,我正在使用UDP套接字进行接收和发送(SendMessage函数)。 在异步void Start()函数中,我启动了一个协程,该协程使用名为initGUI()的函数来设置所有运动对象。 Socket_MessageReceived函数接收我上面提到的JSON字符串。接收到的消息将不断保存并更新为名为接收到的私人字符串。

当我初始化函数initGUI()时,该函数将等待直到字符串不为空,在收到消息后,另一个协程将启动。这个协程为HoloLens构建了用户界面,该函数称为createUserInterface。

在此函数中,接收到的字符串将转换为JToken,然后将启动另一个名为IterateJtoken的函数,该函数会将内容添加到词典列表中。填写词典列表后,createUserInterface函数将正确构建接口。

虽然我能够正确地构建用户界面,但是我希望能够在JSON字符串中的值更改时更新用户界面。例如,在我的JSON字符串中,我有一个名为“ Start”的变量,其值为false。在用户界面中,我有一个根据变量值更改的Unity UI /图像。所以true表示图片为绿色,false表示图片为红色。

我该如何使其动态更新?

每次尝试调用Iterate JToken时,我都尝试清空字典列表,但这不起作用。

1 个答案:

答案 0 :(得分:1)

在问到您的问题

之前,我已经发现了一些问题:
  1. 您的协程等待消息损坏:

    IEnumerator initGUI()
    {
        while(true){
            if(receivedmsg == null){
                Debug.Log("None");
            }
            else{
                Debug.Log(receivedmsg);
                break;
            }
        }
    

如果receivedmsg为空/空并且也没有yield指令,则此循环永远不会终止。您要等第二个 之后,循环才会终止,这没有任何意义。请改用WaitUntil(() => receivedmsg != null)

您可能还想添加isEmpty()支票。

  1. createUserInterface不必是协程。您内部只有一个yield指令,之后没有任何代码。

  2. IterateJtoken同样适用,只是这次收益是持续一段时间而不是null(为什么?)。我怀疑这可能打算放在一个或多个for循环中。

现在,您的问题。您希望能够更新GUI,而不仅仅是构建它。我的建议是使用字典在字符串(JSON键)和在initGui中创建的Unity GameObject之间映射。然后,当您对新的数据包数据进行更新时,可以查询字典而不是创建对象。