主頁 > 後端開發 > 基于python實作ZigBee樹狀拓撲網路建構與動態地址分配及路由仿真

基于python實作ZigBee樹狀拓撲網路建構與動態地址分配及路由仿真

2021-01-08 11:16:15 後端開發

實作ZigBee樹狀拓撲網路建構與動態地址分配及路由仿真

輸出效果輸出效果1

輸出效果2

在這里插入圖片描述
源代碼以及分析

import tkinter as tk
import random
import math
import sys
# 設定最大遞回次數
sys.setrecursionlimit(2000)
# 設定一個常量代表傳感器固定半徑
SENOR_RADIUS = 6
class Window:
    def __init__(self, master):
        self.root = master
        self.createpage()
        self.run()
    '''創建界面'''
    def createpage(self):
        self.root.geometry('1210x710')
        # 設定視窗是否可以變化長/寬,False不可變,True可變,默認為True
        self.root.resizable(width=False, height=False)
        #設定模塊1 引數輸入 的各個部件在視窗的相對位置橫坐標
        flame1_text_x = 130
        #設定外圍框,讓界面更好看
        tk.LabelFrame(self.root, text='|引數|', fg='black', padx=10, pady=10,font='Verdana 10 bold').place(x=10, y=10, height=250, width=290)
        # ZigBee網路的nwkMaxChildren (Cm)
        tk.Label(self.root, text='最大子節點數(Cm):', fg='black').place(x = 15, y = 35)
        self.nwkMaxChildren_text = tk.StringVar(value="5")
        self.nwkMaxChildren = tk.Entry(self.root, textvariable=self.nwkMaxChildren_text)
        self.nwkMaxChildren.place(x = flame1_text_x , y = 35)
        # nwkMaxRouters (Rm)
        tk.Label(self.root, text='ZR節點數(Rm):', fg='black').place(x = 15, y = 65)
        self.nwkMaxRouters_text = tk.StringVar(value="3")
        self.nwkMaxRouters = tk.Entry(self.root, textvariable=self.nwkMaxRouters_text)
        self.nwkMaxRouters.place(x = flame1_text_x , y = 65)
        # newMaxDepth (Lm)
        tk.Label(self.root, text='網路最大深度(Lm):', fg='black').place(x=15, y=95)
        self.newMaxDepth_text = tk.StringVar(value="5")
        self.newMaxDepth = tk.Entry(self.root, textvariable=self.newMaxDepth_text)
        self.newMaxDepth.place(x = flame1_text_x , y = 95)
        # 協調器(coordinator)
        tk.Label(self.root, text='協調器(ZC):', fg='black').place(x=15, y=125)
        self.coordinator_text = tk.StringVar(value="1")#由于ZC的值固定為 1,所以我們也要設定ZC的值為 1
        self.coordinator = tk.Entry(self.root, textvariable=self.coordinator_text, state = 'readonly')
        # state Entry 組件可以設定的狀態:"normal","disabled" 或 "readonly"
        #(注意,它跟 "disabled" 相似,但它支持選中和拷貝,只是不能修改,而 "disabled" 是完全禁止)
        self.coordinator.place(x = flame1_text_x , y = 125)
        # 路由器(Router)
        tk.Label(self.root, text='路由器(ZR):', fg='black').place(x=15, y=155)
        self.router_text = tk.StringVar(value="15")
        self.router = tk.Entry(self.root, textvariable=self.router_text)
        self.router.place(x = flame1_text_x , y = 155)
        # 普通節點(Device)
        tk.Label(self.root, text='終端節點(ZED):', fg='black').place(x=15, y=185)
        self.device_text = tk.StringVar(value="15")
        self.device = tk.Entry(self.root, textvariable=self.device_text)
        self.device.place(x = flame1_text_x , y = 185)
        #傳感器通訊距離(distance_get)
        tk.Label(self.root, text='傳感器通訊距離:', fg='black').place(x=15, y=215)
        self.distance_get_text = tk.StringVar(value="300")
        self.distance_get = tk.Entry(self.root, textvariable=self.distance_get_text)
        self.distance_get.place(x = flame1_text_x , y = 215)
        # 創建按鈕
        tk.Button(self.root, text='ZigBee傳感器布置', command=self.Pictue_Create).place(x=50, y=280,height=50, width=200)
        #設定模塊2 路徑查找 的各個部件在視窗的相對位置縱坐標
        flame2_text_y = 400
        #創建外包框
        tk.LabelFrame(self.root, text='|路徑查找|', fg='black', padx=10, pady=10,font='Verdana 10 bold').place(x=10, y=flame2_text_y, height=120, width=290)
        #source_node_address 源節點地址
        tk.Label(self.root, text='源節點地址:', fg='black').place(x=15, y=flame2_text_y + 30)
        self.source_node_address_text = tk.StringVar()
        self.source_node_address = tk.Entry(self.root, textvariable=self.source_node_address_text)
        self.source_node_address.place(x = flame1_text_x , y = flame2_text_y + 30)
        #destination_node_address 目的節點地址
        tk.Label(self.root, text='目的節點地址:', fg='black').place(x=15, y=flame2_text_y + 70)
        self.destination_node_address_text = tk.StringVar()
        self.destination_node_address = tk.Entry(self.root, textvariable=self.destination_node_address_text)
        self.destination_node_address.place(x = flame1_text_x , y = flame2_text_y + 70)
        # 創建按鈕
        tk.Button(self.root, text='顯示路徑', command =  self.Path_Lookup_ready ).place(x=50, y=flame2_text_y + 140,height=50, width=200)      
        # 創建畫布
        self.cv = tk.Canvas(self.root, bg='white', width=900, height=700)
        self.cv.place(x=300)
        
    '''清空內容'''
    def Wipe_Data(self):
        # 清空文本框和畫圖框內的內容
        self.cv.delete(tk.ALL)
    '''創建ZC中心傳感器'''
    def Gathering_Point_Create(self):
        self.sensor_zc[0][0] = self.gathering_point_center_x
        self.sensor_zc[0][1] = self.gathering_point_center_y
        #設定標志數,表示這個傳感器是ZC
        self.sensor_zc[0][9] = 0
        self.cv.create_oval((self.gathering_point_center_x - SENOR_RADIUS, self.gathering_point_center_y - SENOR_RADIUS,
                                self.gathering_point_center_x + SENOR_RADIUS, self.gathering_point_center_y + SENOR_RADIUS),
                                outline='black',
                                fill='red'
                            )
        #設定ZC的初始地址和計算出C(skip)的值
        self.sensor_zc[0][7] = 6
        if(self.Rm == 1):
            Cskip = 1 + self.Cm * (self.Lm - self.sensor_zc[0][5] - 1)
        else:
            Cskip = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zc[0][5] - 1))) / (1 - self.Rm)
        self.sensor_zc[0][8] = int(Cskip)
        address = str(self.sensor_zc[0][7])
        C_skip = str(self.sensor_zc[0][8])
        text_string = address + " C:" + C_skip
        #創建字體
        self.cv.create_text(self.gathering_point_center_x, self.gathering_point_center_y + self.canvas_text_y, text = 'ZC-' + text_string)
    '''創建ZR中心傳感器'''
    def ZR_Sensor_Create(self):    
        for num_sensor_zr_temp in range(0, self.Zr):
            circle_center_x = random.randint(15, 885)
            circle_center_y = random.randint(15, 685)
            # 將每次隨機生成的傳感器的坐標 放入串列
            self.sensor_zr[num_sensor_zr_temp][0] = circle_center_x
            self.sensor_zr[num_sensor_zr_temp][1] = circle_center_y
            #設定標志數,表示這個傳感器是ZR
            self.sensor_zr[num_sensor_zr_temp][9] = 1
            self.cv.create_rectangle((circle_center_x - 5, circle_center_y - 5,
                                 circle_center_x + 10, circle_center_y + 5),
                                 outline='blue',
                                 fill='blue'
                                )

    '''創建ZED中心傳感器'''
    def ZED_Sensor_Create(self):   
        for num_sensor_zr_temp in range(0, self.Zed):
            circle_center_x = random.randint(15, 885)
            circle_center_y = random.randint(15, 685)
            # 將每次隨機生成的傳感器的坐標 放入串列
            self.sensor_zed[num_sensor_zr_temp][0] = circle_center_x
            self.sensor_zed[num_sensor_zr_temp][1] = circle_center_y
            #設定標志數,表示這個傳感器是ZED
            self.sensor_zed[num_sensor_zr_temp][7] = 2
            self.cv.create_oval((circle_center_x - SENOR_RADIUS, circle_center_y - SENOR_RADIUS,
                                 circle_center_x + SENOR_RADIUS, circle_center_y + SENOR_RADIUS),
                                 outline='purple',
                                 fill='purple'
                                )

    '''在canvas上畫圖'''
    def Pictue_Create(self):
        #將列印在畫布上的資訊格式化
        self.canvas_text_y = 12
        # 清空內容
        self.Wipe_Data()
        # 獲取輸入框中的內容
        self.Cm = self.nwkMaxChildren.get()
        self.Rm = self.nwkMaxRouters.get()
        self.Lm = self.newMaxDepth.get()
        self.Zc = self.coordinator.get()
        self.Zr = self.router.get()
        self.Zed = self.device.get()
        self.distance = self.distance_get.get()       
        # 列印獲取的內容
        #將獲取的數值轉成int
        self.Cm = int(self.Cm)
        self.Rm = int(self.Rm)
        self.Lm = int(self.Lm)
        self.Zc = int(self.Zc)
        self.Zr = int(self.Zr)
        self.Zed = int(self.Zed)
        self.distance = int(self.distance)
        # 創建存盤ZC(協調器)的二維串列
        self.sensor_zc = [[0 for i in range(10)]]
        # 創建存盤ZR(路由器)的二維串列
        self.sensor_zr = [[0 for i in range(10)]for j in range(self.Zr)]
        # 創建存盤ZED普通節點(Device)的二維串列
        self.sensor_zed = [[0 for i in range(8)]for j in range(self.Zed)]
        # 確定Zc的坐標&
        self.gathering_point_center_x = 450
        self.gathering_point_center_y = 350
        # 生成通訊中心(ZC)
        self.Gathering_Point_Create()
        # 創建臨時陣列儲存已經進行連接的ZR、ZED傳感器坐標等等資訊
        self.sensor_zr_temp = []
        self.sensor_zed_temp = []
        #創建ZR、ZED傳感器
        self.ZR_Sensor_Create()
        self.ZED_Sensor_Create()
        #列印生成的兩個陣列
        '''
        print('==========================================================')
        print("這是連接的ZR保存數值的串列:",self.sensor_zr)
        print("這是連接的ZED保存數值的串列:",self.sensor_zed)
        print('==========================================================')
        '''
        #判斷每個傳感器上的點的連接
        self.Tree_Topology_Establishment()
        #列印生成的兩個陣列
        '''
        print('----------------------------------------------------------')
        print("這是連接的ZC保存所有數值的串列:",self.sensor_zc)
        print("這是連接的ZR保存所有數值的串列:",self.sensor_zr_temp)
        print("這是連接的ZR保存沒有連接的串列:",self.sensor_zr)
        print("這是連接的ZED保存的串列:",self.sensor_zed_temp)
        print("這是連接的ZED保存沒有連接的串列:",self.sensor_zed)
        print('----------------------------------------------------------')
        '''
    '''計算ZC與旁邊傳感器ZC和ZED的關系,符合條件的進行連接'''
    def Cal_ZC_Connect(self):
        #把ZR旁邊的ZED結點連接起來R
        for num_sensor_zr in range(0, self.Zr):
            temp_x = self.gathering_point_center_x - self.sensor_zr[num_sensor_zr][0]
            temp_y = self.gathering_point_center_y - self.sensor_zr[num_sensor_zr][1]
            temp_x = temp_x * temp_x
            temp_y = temp_y * temp_y
            temp_distance = math.sqrt(temp_x + temp_y)
            #兩點的距離小于規定的傳感器通訊距離
            if(temp_distance <= self.distance):
                if(self.sensor_zc[0][3] < self.Cm):
                    if(self.sensor_zc[0][4] < self.Rm):
                        self.sensor_zc[0][4] = self.sensor_zc[0][4] + 1
                        self.sensor_zc[0][3] = self.sensor_zc[0][3] + 1
                        self.sensor_zr[num_sensor_zr][2] = 1
                        self.sensor_zr[num_sensor_zr][5] = self.sensor_zc[0][5] + 1
                        #顯示子結點在父節點中的編號
                        self.sensor_zr[num_sensor_zr][6] = self.sensor_zc[0][4]
                        #地址的分配
                        if(self.Rm == 1):
                            Cskip = 1 + self.Cm * (self.Lm - self.sensor_zc[0][5] - 1)
                        else:
                            Cskip = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zc[0][5] - 1))) / (1 - self.Rm)
                        #計算下一個子結點的地址
                        self.sensor_zr[num_sensor_zr][7] = self.sensor_zc[0][7] + 1 + self.sensor_zc[0][8] * (self.sensor_zc[0][4] - 1)
                        #計算下一個子結點的Cskip并存入陣列
                        Cskip_child = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zr[num_sensor_zr][5] - 1))) / (1 - self.Rm)
                        self.sensor_zr[num_sensor_zr][8] = int(Cskip_child)
                        #把地址和其他資料顯示在傳感器下面
                        address = str(self.sensor_zr[num_sensor_zr][7])
                        C_skip = str(self.sensor_zr[num_sensor_zr][8])
                        Num = str(self.sensor_zr[num_sensor_zr][6])
                        text_string = 'A:' + address# + ' C:' + C_skip + ' N:' + Num
                        self.cv.create_text(self.sensor_zr[num_sensor_zr][0], self.sensor_zr[num_sensor_zr][1] + self.canvas_text_y, text='ZR-' + text_string)
                        #對兩個傳感器進行連接
                        self.cv.create_line(self.gathering_point_center_x, self.gathering_point_center_y,
                                            self.sensor_zr[num_sensor_zr][0], self.sensor_zr[num_sensor_zr][1],
                                            fill='orange')
                        #創建臨時陣列存盤已經連接的傳感器的資料
                        temp_arr = self.sensor_zr[num_sensor_zr][::]
                        self.sensor_zr_temp.append(temp_arr)
        #把ZC旁邊的ZED結點連接起來
        for num_sensor_zed in range(0, self.Zed):
            temp_x = self.gathering_point_center_x - self.sensor_zed[num_sensor_zed][0]
            temp_y = self.gathering_point_center_y - self.sensor_zed[num_sensor_zed][1]
            temp_x = temp_x * temp_x
            temp_y = temp_y * temp_y
            temp_distance = math.sqrt(temp_x + temp_y)
            #兩點的距離小于規定的傳感器通訊距離
            if(temp_distance <= self.distance):
                if((self.Cm - self.sensor_zc[0][3]) > 0):
                    if(self.sensor_zed[num_sensor_zed][2] == 0):
                        self.sensor_zc[0][3] = self.sensor_zc[0][3] + 1
                        self.sensor_zed[num_sensor_zed][2] = 1
                        self.sensor_zed[num_sensor_zed][3] = self.sensor_zc[0][5] + 1
                        #顯示子結點在父節點中的編號
                        self.sensor_zed[num_sensor_zed][4] = self.sensor_zc[0][3] - self.sensor_zc[0][4]
                        #地址的分配
                        if(self.Rm == 1):
                            Cskip = 1 + self.Cm * (self.Lm - self.sensor_zc[0][5] - 1)
                        else:
                            Cskip = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zc[0][5] - 1))) / (1 - self.Rm)
                        #計算ZED的address
                        self.sensor_zed[num_sensor_zed][5] = self.sensor_zc[0][7] + self.sensor_zc[0][8] * self.Rm + self.sensor_zc[0][3] - self.sensor_zc[0][4]                        
                        #把地址顯示在傳感器下面
                        address = str(self.sensor_zed[num_sensor_zed][5])
                        Num = str(self.sensor_zed[num_sensor_zed][4])
                        text_string = 'A:' + address# + ' N:' + Num
                        self.cv.create_text(self.sensor_zed[num_sensor_zed][0], self.sensor_zed[num_sensor_zed][1] + self.canvas_text_y, text='ZED-' + text_string)
                        #對兩個傳感器之間連線
                        self.cv.create_line(self.gathering_point_center_x, self.gathering_point_center_y,
                                            self.sensor_zed[num_sensor_zed][0], self.sensor_zed[num_sensor_zed][1],
                                            fill='orange')
                        #創建臨時陣列存盤已經連接的傳感器的資料
                        temp_arr = self.sensor_zed[num_sensor_zed][::]
                        self.sensor_zed_temp.append(temp_arr)
    '''計算ZR與旁邊傳感器ZR的關系,符合條件的進行連接'''                
    def Cal_Con_ZRtoZR_Recursion(self):
        # 設定標志數
        self.i = 0
        # 對串列求差集
        difference_set = list(set([tuple(t) for t in self.sensor_zr]).difference(set([tuple(t) for t in self.sensor_zr_temp])))
        self.sensor_zr.clear()
        # 求差集以后 會變成串列包元組 需要轉化成串列包串列
        for num_sensor_zr_temp in range(0, (len(difference_set))):
            temp_arr_a = [  difference_set[num_sensor_zr_temp][0], 
                            difference_set[num_sensor_zr_temp][1], 
                            difference_set[num_sensor_zr_temp][2], 
                            difference_set[num_sensor_zr_temp][3], 
                            difference_set[num_sensor_zr_temp][4], 
                            difference_set[num_sensor_zr_temp][5],
                            difference_set[num_sensor_zr_temp][6],
                            difference_set[num_sensor_zr_temp][7],
                            difference_set[num_sensor_zr_temp][8],
                            difference_set[num_sensor_zr_temp][9]]
            self.sensor_zr.append(temp_arr_a)
        '''
        print('----------------------------------------------------------')
        print("這是sensor_zr串列:",self.sensor_zr,"它的長度為",len(self.sensor_zr))
        print("這是sensor_zr_temp串列:",self.sensor_zr_temp,"它的長度為",len(self.sensor_zr_temp))
        print('----------------------------------------------------------')
        '''
        # 對sensor_zr_temp 和 sensor_zr兩個串列遍歷
        '''
        外層回圈:對符合要求并已經進行連接的傳感器坐標串列遍歷
        '''
        for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
            #sensor_zr_temp: 儲存符合要求并已經進行連接的傳感器坐標
            '''
            內層回圈:對沒有遍歷或者不符合要求的傳感器坐標遍歷
            '''
            for num_sensor_zr in range(0, len(self.sensor_zr)):
                #sensor_zr: 儲存沒有遍歷或者不符合要求的傳感器坐標
                temp_x = self.sensor_zr[num_sensor_zr][0] - self.sensor_zr_temp[num_sensor_zr_temp][0]
                temp_y = self.sensor_zr[num_sensor_zr][1] - self.sensor_zr_temp[num_sensor_zr_temp][1]
                temp_x = temp_x * temp_x
                temp_y = temp_y * temp_y
                temp_distance = math.sqrt(temp_x + temp_y)
                #判斷每個點與剩余未連接點的連接情況
                if(temp_distance <= self.distance):
                    if(self.sensor_zr_temp[num_sensor_zr_temp][3] < self.Cm):
                        if(self.sensor_zr_temp[num_sensor_zr_temp][4] < self.Rm):
                            if(self.sensor_zr_temp[num_sensor_zr_temp][5] < self.Lm):
                                if(self.sensor_zr[num_sensor_zr][2] == 0):
                                    self.sensor_zr_temp[num_sensor_zr_temp][4] = self.sensor_zr_temp[num_sensor_zr_temp][4] + 1
                                    self.sensor_zr_temp[num_sensor_zr_temp][3] = self.sensor_zr_temp[num_sensor_zr_temp][3] + 1
                                    self.sensor_zr[num_sensor_zr][2] = 1
                                    self.sensor_zr[num_sensor_zr][5] = self.sensor_zr_temp[num_sensor_zr_temp][5] + 1
                                    #顯示子結點在父節點中的編號
                                    self.sensor_zr[num_sensor_zr][6] = self.sensor_zr_temp[num_sensor_zr_temp][4]
                                    #地址的分配
                                    if(self.Rm == 1):
                                        Cskip = 1 + self.Cm * (self.Lm - self.sensor_zr_temp[num_sensor_zr_temp][5] - 1)
                                    else:
                                        Cskip = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zr_temp[num_sensor_zr_temp][5] - 1))) / (1 - self.Rm)
                                    self.sensor_zr[num_sensor_zr][7] = self.sensor_zr_temp[num_sensor_zr_temp][7] + 1 + self.sensor_zr_temp[num_sensor_zr_temp][8] * (self.sensor_zr_temp[num_sensor_zr_temp][4] - 1) 
                                    Cskip_child = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zr[num_sensor_zr][5] - 1))) / (1 - self.Rm)
                                    self.sensor_zr[num_sensor_zr][8] = int(Cskip_child)
                                    #把地址顯示在傳感器下面
                                    address = str(self.sensor_zr[num_sensor_zr][7])
                                    C_skip = str(self.sensor_zr[num_sensor_zr][8])
                                    Num = str(self.sensor_zr[num_sensor_zr][6])
                                    text_string = 'A:' + address# + ' C:' + C_skip + ' N:' + Num
                                    self.cv.create_text(self.sensor_zr[num_sensor_zr][0], self.sensor_zr[num_sensor_zr][1] + self.canvas_text_y, text='ZR-' + text_string)
                                    
                                    #對兩個傳感器連線
                                    self.cv.create_line(self.sensor_zr[num_sensor_zr][0], self.sensor_zr[num_sensor_zr][1],
                                                        self.sensor_zr_temp[num_sensor_zr_temp][0], self.sensor_zr_temp[num_sensor_zr_temp][1],
                                                        fill='orange')
                                    #創建臨時陣列存盤已經連接的傳感器的資料
                                    temp_arr = self.sensor_zr[num_sensor_zr][::]
                                    self.sensor_zr_temp.append(temp_arr)
                                    # 當判定有點相連的 令標志數等于1
                                    self.i = 1

        '''這段代碼是取還沒有進行連接的傳感器坐標資料'''
        reList = list(set([tuple(t) for t in self.sensor_zr_temp]))
        self.sensor_zr_temp.clear()
        # 去重以后 會變成串列包元組 需要轉化成串列包串列
        for num_sensor_zr_temp in range(0, (len(reList))):
            temp_arr_a = [reList[num_sensor_zr_temp][0], 
                            reList[num_sensor_zr_temp][1], 
                            reList[num_sensor_zr_temp][2], 
                            reList[num_sensor_zr_temp][3], 
                            reList[num_sensor_zr_temp][4], 
                            reList[num_sensor_zr_temp][5],
                            reList[num_sensor_zr_temp][6],
                            reList[num_sensor_zr_temp][7],
                            reList[num_sensor_zr_temp][8],
                            reList[num_sensor_zr_temp][9]]
            self.sensor_zr_temp.append(temp_arr_a)

        if(self.i == 0):
            # 當沒有點可以遍歷的時候 退出遞回
            self.over()
        else:
            self.Cal_Con_ZRtoZR_Recursion()

    def Cal_Con_ZRtoZED_Recursion(self):
        #設定標志數
        self.i = 0
        # 對串列求差集
        difference_set = list(set([tuple(t) for t in self.sensor_zed]).difference(set([tuple(t) for t in self.sensor_zed_temp])))
        self.sensor_zed.clear()
        # 求差集以后 會變成串列包元組 需要轉化成串列包串列
        for num_sensor_zed_a in range(0, (len(difference_set))):
            temp_arr_a = [  difference_set[num_sensor_zed_a][0], 
                            difference_set[num_sensor_zed_a][1], 
                            difference_set[num_sensor_zed_a][2], 
                            difference_set[num_sensor_zed_a][3], 
                            difference_set[num_sensor_zed_a][4], 
                            difference_set[num_sensor_zed_a][5], 
                            difference_set[num_sensor_zed_a][6],
                            difference_set[num_sensor_zed_a][7]]
            self.sensor_zed.append(temp_arr_a)
        '''
        外層回圈:對符合要求并已經進行連接的傳感器坐標串列遍歷
        '''
        for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
            '''
            內層回圈:對沒有遍歷或者不符合要求的傳感器坐標遍歷
            '''
            for num_sensor_zed in range(0, len(self.sensor_zed)):
                #sensor_zr: 儲存沒有遍歷或者不符合要求的傳感器坐標
                #sensor_zr_temp: 儲存符合要求并已經進行連接的傳感器坐標
                temp_x = self.sensor_zed[num_sensor_zed][0] - self.sensor_zr_temp[num_sensor_zr_temp][0]
                temp_y = self.sensor_zed[num_sensor_zed][1] - self.sensor_zr_temp[num_sensor_zr_temp][1]
                temp_x = temp_x * temp_x
                temp_y = temp_y * temp_y
                temp_distance = math.sqrt(temp_x + temp_y)
                 #判斷每個點與剩余未連接點的連接情況
                if(temp_distance <= self.distance):
                    if((self.Cm - self.sensor_zr_temp[num_sensor_zr_temp][3]) > 0):
                        if(self.sensor_zed[num_sensor_zed][2] == 0):
                            if(self.sensor_zr_temp[num_sensor_zr_temp][5] < self.Lm):
                                self.sensor_zr_temp[num_sensor_zr_temp][3] = self.sensor_zr_temp[num_sensor_zr_temp][3] + 1
                                self.sensor_zed[num_sensor_zed][2] = 1
                                self.sensor_zed[num_sensor_zed][3] = self.sensor_zr_temp[num_sensor_zr_temp][5] + 1
                                self.sensor_zed[num_sensor_zed][4] = self.sensor_zr_temp[num_sensor_zr_temp][3] - self.sensor_zr_temp[num_sensor_zr_temp][4]
                                #地址的分配
                                if(self.Rm == 1):
                                    Cskip = 1 + self.Cm * (self.Lm - self.sensor_zr_temp[num_sensor_zr_temp][5] - 1)
                                else:
                                    Cskip = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - self.sensor_zr_temp[num_sensor_zr_temp][5] - 1))) / (1 - self.Rm)
                                #計算ZED的address
                                self.sensor_zed[num_sensor_zed][5] = self.sensor_zr_temp[num_sensor_zr_temp][7] + self.sensor_zr_temp[num_sensor_zr_temp][8] * self.Rm + self.sensor_zr_temp[num_sensor_zr_temp][3] - self.sensor_zr_temp[num_sensor_zr_temp][4]                        
                                #把地址顯示在傳感器下面
                                address = str(self.sensor_zed[num_sensor_zed][5])
                                Num = str(self.sensor_zed[num_sensor_zed][4])
                                text_string = 'A:' + address# + ' N:' + Num
                                self.cv.create_text(self.sensor_zed[num_sensor_zed][0], self.sensor_zed[num_sensor_zed][1] + self.canvas_text_y, text='ZED-' + text_string)                           
                                #對兩個傳感器進行連線
                                self.cv.create_line(self.sensor_zed[num_sensor_zed][0], self.sensor_zed[num_sensor_zed][1],
                                                    self.sensor_zr_temp[num_sensor_zr_temp][0], self.sensor_zr_temp[num_sensor_zr_temp][1],
                                                    fill='orange')
                                #創建臨時陣列存盤已經連接的傳感器的資料
                                temp_arr = self.sensor_zed[num_sensor_zed][::]
                                self.sensor_zed_temp.append(temp_arr)
                                # 當判定有點相連的 令標志數等于1
                                self.i = 1

        '''這段代碼是取還沒有進行連接的傳感器坐標資料'''
        reList = list(set([tuple(t) for t in self.sensor_zed_temp]))
        self.sensor_zed_temp.clear()
        # 去重以后 會變成串列包元組 需要轉化成串列包串列
        for num_sensor_zed_temp in range(0, (len(reList))):
            temp_arr_a = [  reList[num_sensor_zed_temp][0], 
                            reList[num_sensor_zed_temp][1], 
                            reList[num_sensor_zed_temp][2], 
                            reList[num_sensor_zed_temp][3],
                            reList[num_sensor_zed_temp][4], 
                            reList[num_sensor_zed_temp][5],
                            reList[num_sensor_zed_temp][6],
                            reList[num_sensor_zed_temp][7]]
            self.sensor_zed_temp.append(temp_arr_a)

        if(self.i == 0):
            # 當沒有點可以遍歷的時候 退出遞回
            self.over()
        else:
            self.Cal_Con_ZRtoZED_Recursion()

    '''構建ZigBee樹狀圖'''
    def Tree_Topology_Establishment(self):
        #判斷ZC和ZR、ZED是否可以進行連接,并對其分配地址
        self.Cal_ZC_Connect()
        #計算 ZR 和 ZR 的連接情況,并對其分配地址
        self.Cal_Con_ZRtoZR_Recursion()
        #計算 ZR 和 ZED 的連接情況,并對其分配地址
        self.Cal_Con_ZRtoZED_Recursion()
        
    '''路徑查找'''
    def Path_Lookup_ready(self):
        #讀取資料
        self.SNA = self.source_node_address.get()
        self.DNA = self.destination_node_address.get()
        self.SNA = int(self.SNA)
        self.DNA = int(self.DNA)
        # 創建存盤起始結點資訊的二維串列
        self.SNA_list = [0 for i in range(10)]
        # 創建存盤目的結點資訊的二維串列
        self.DNA_list = [0 for i in range(10)]
        #設定標志數,標志是否查找到結點地址
        Sign_SNA = 0
        Sign_DNA = 0
        #在ZC ZR ZED中找SNA
        while(1):
            if(self.sensor_zc[0][7] == self.SNA):
                #print('起始節點在ZC組中')
                Sign_SNA = 1
                self.SNA_list = self.sensor_zc[0][::]
                break

            for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
                if(self.sensor_zr_temp[num_sensor_zr_temp][7] == self.SNA):
                    #print('起始節點在ZR組中')
                    Sign_SNA =  1
                    self.SNA_list = self.sensor_zr_temp[num_sensor_zr_temp][::]
                    break
            if(Sign_SNA != 1): 
                for  num_sensor_zed_temp in range(0,len(self.sensor_zed_temp)):
                    if(self.sensor_zed_temp[num_sensor_zed_temp][5] == self.SNA):
                        #print('起始節點在ZED組中')
                        Sign_SNA =  1
                        self.SNA_list[0] = self.sensor_zed_temp[num_sensor_zed_temp][0]
                        self.SNA_list[1] = self.sensor_zed_temp[num_sensor_zed_temp][1]
                        self.SNA_list[2] = self.sensor_zed_temp[num_sensor_zed_temp][2]
                        self.SNA_list[5] = self.sensor_zed_temp[num_sensor_zed_temp][3]
                        self.SNA_list[6] = self.sensor_zed_temp[num_sensor_zed_temp][4]
                        self.SNA_list[7] = self.sensor_zed_temp[num_sensor_zed_temp][5]
                        self.SNA_list[8] = self.sensor_zed_temp[num_sensor_zed_temp][6]
                        self.SNA_list[9] = self.sensor_zed_temp[num_sensor_zed_temp][7]
                        break
            break
        # 輸出SNA_list)
        # print(self.SNA_list)
        # 在ZC ZR ZED中找DNA
        while(1):
            if(self.sensor_zc[0][7] == self.DNA):
                #print('目的節點在ZC組中')
                Sign_DNA = 1
                self.DNA_list = self.sensor_zc[0][::]
                break

            for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
                if(self.sensor_zr_temp[num_sensor_zr_temp][7] == self.DNA):
                    #print('目的節點在ZR組中')
                    Sign_DNA =  1
                    self.DNA_list = self.sensor_zr_temp[num_sensor_zr_temp][::]
                    break
            if(Sign_DNA != 1):               
                for  num_sensor_zed_temp in range(0,len(self.sensor_zed_temp)):
                    if(self.sensor_zed_temp[num_sensor_zed_temp][5] == self.DNA):
                        #print('目的節點在ZED組中')
                        Sign_DNA =  1
                        self.DNA_list[0] = self.sensor_zed_temp[num_sensor_zed_temp][0]
                        self.DNA_list[1] = self.sensor_zed_temp[num_sensor_zed_temp][1]
                        self.DNA_list[2] = self.sensor_zed_temp[num_sensor_zed_temp][2]
                        self.DNA_list[5] = self.sensor_zed_temp[num_sensor_zed_temp][3]
                        self.DNA_list[6] = self.sensor_zed_temp[num_sensor_zed_temp][4]
                        self.DNA_list[7] = self.sensor_zed_temp[num_sensor_zed_temp][5]
                        self.DNA_list[8] = self.sensor_zed_temp[num_sensor_zed_temp][6]
                        self.DNA_list[9] = self.sensor_zed_temp[num_sensor_zed_temp][7]
                        break
            break   
        # 輸出DNA_list
        # print(self.DNA_list)
        if(Sign_DNA == 0) or (Sign_SNA == 0):
            self.over()
        else:
            #查找&進入遞回
            self.Path_Lookup()

    def Path_Lookup(self):
        #判斷兩個點的地址是否相同
        if(self.SNA_list[7] == self.DNA_list[7]):
            return 0
        #對兩個傳感器進行判斷
        else:
            #計算當前SNA的父節點的Cskip
            if (self.SNA_list[9] == 0):
                deep_SNA = 0
            else:
                deep_SNA = self.SNA_list[5] - 1
            if(self.Rm == 1):
                Cskip_SNA = 1 + self.Cm * (self.Lm - self.sensor_zc[0][5] - 1)
            else:
                Cskip_SNA = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - deep_SNA - 1))) / (1 - self.Rm)
            Cskip_SNA = int(Cskip_SNA)
            #計算計算當前DNA的父節點的CskipD
            if (self.DNA_list[9] == 0):
                deep_DNA = 0
            else:
                deep_DNA = self.DNA_list[5] - 1
            if(self.Rm == 1):
                Cskip_DNA = 1 + self.Cm * (self.Lm - self.sensor_zc[0][5] - 1)
            else:
                Cskip_DNA = (1 + self.Cm - self.Rm - self.Cm * math.pow(self.Rm,(self.Lm - deep_DNA - 1))) / (1 - self.Rm)
            Cskip_DNA = int(Cskip_DNA)
            #判斷DNA是不是在SNA的子樹中
            if (self.SNA_list[9] == 0) or ((self.SNA_list[9] == 1) and (self.SNA_list[7] < self.DNA_list[7]) and ( self.DNA_list[7] < (self.SNA_list[7] + Cskip_SNA))):
                #DNA在SNA的子樹中,DNA向父節點回寫,并以父節點覆寫DNA中的資料
                #print('DNA在SNA的子樹中')
                #通過公式反推子結點對應父節點的地址
                if(self.DNA_list[9] == 1):
                    DNA_Parent_Address = self.DNA_list[7] - 1 - Cskip_DNA * (self.DNA_list[6] - 1)
                else:
                    DNA_Parent_Address = self.DNA_list[7] - Cskip_DNA * self.Rm - self.DNA_list[6]
                #print(DNA_Parent_Address)
                #用父節點的地址向ZC的地址比對,判斷當前子結點的父節點是不是ZC
                if(self.sensor_zc[0][7] == DNA_Parent_Address):
                    #對兩個傳感器進行連接
                    self.cv.create_line(self.gathering_point_center_x, self.gathering_point_center_y,
                                        self.DNA_list[0], self.DNA_list[1],
                                        fill='blue'
                                        )
                    self.DNA_list = self.sensor_zc[0][::]
                #用父節點的地址向ZR的地址比對,判斷當前子結點的父節點對應的ZR
                for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
                    if(self.sensor_zr_temp[num_sensor_zr_temp][7] == DNA_Parent_Address):
                        self.cv.create_line(self.sensor_zr_temp[num_sensor_zr_temp][0], self.sensor_zr_temp[num_sensor_zr_temp][1],
                                        self.DNA_list[0], self.DNA_list[1],
                                        fill='blue'                                    
                                        )
                        self.DNA_list = self.sensor_zr_temp[num_sensor_zr_temp][::]
                        break

            else:
                #DNA不在SNA的子樹中
                #print('DNA不在SNA的子樹中')
                #SNA向父節點回寫,并以父節點覆寫SNA中的資料
                #通過公式反推子結點對應父節點的地址
                if(self.SNA_list[9] == 1):
                    SNA_Parent_Address = self.SNA_list[7] - 1 - Cskip_SNA * (self.SNA_list[6] - 1)
                else:
                    SNA_Parent_Address = self.SNA_list[7] - Cskip_SNA * self.Rm - self.SNA_list[6]
                #print(SNA_Parent_Address)
                #用父節點的地址向ZC的地址比對,判斷當前子結點的父節點是不是ZC
                if(self.sensor_zc[0][7] == SNA_Parent_Address):
                    #對兩個傳感器進行連接
                    self.cv.create_line(self.gathering_point_center_x, self.gathering_point_center_y,
                                        self.SNA_list[0], self.SNA_list[1],
                                        fill='blue')
                    self.SNA_list = self.sensor_zc[0][::]
                #用父節點的地址向ZR的地址比對,判斷當前子結點的父節點對應的ZR
                for num_sensor_zr_temp in range(0, len(self.sensor_zr_temp)):
                    if(self.sensor_zr_temp[num_sensor_zr_temp][7] == SNA_Parent_Address):
                        self.cv.create_line(self.sensor_zr_temp[num_sensor_zr_temp][0], self.sensor_zr_temp[num_sensor_zr_temp][1],
                                        self.SNA_list[0], self.SNA_list[1],
                                        fill='blue')
                        self.SNA_list = self.sensor_zr_temp[num_sensor_zr_temp][::]
                        break
        '''
        print('遞回完成后的SNA:',self.SNA_list)      
        print('遞回完成后的DNA:',self.DNA_list)               
        print('-------------------------------------------------')
        '''
        #遞回
        self.Path_Lookup()
                
    def over(self):
        return 0
        #print("遞回完成")

    def run(self):
        try:
            self.root.mainloop()
        except Exception as e:
            print("*** exception:\n".format(e))

def main():
    window = tk.Tk()
    window.title('SensorProject Design By HJK and ZN')
    Window(window).run()

if __name__ == '__main__':
    main()

打包好的檔案,下載后解壓點擊其中的 sensorprojectfinal.exe 就可以運行了

鏈接:https://pan.baidu.com/s/1rPiKkslLS8cV7UR8wJs-Tg
提取碼:1111

演算法思想:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/246176.html

標籤:python

上一篇:Python爬取小姐姐圖片

下一篇:2021年1月6日運行Python腳本的一些說明與教程【淘寶-天貓超市飛天茅臺1499搶購】

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more