摘要:使用 wxFormBuilder 搭建軟體架構,Python 3.6 程式設計實作了Linux及Windows系統時間同步軟體設計,可用于系統内上位機、闆卡及計算機的系統時間同步。
1 引言
時間同步是計算機應用系統一個最基本的要求,集中式系統時間無二義性,而分布式系統本身沒有标準的時間統一,是以必須建立分布式系統的時間統一系統。時間同步分為系統級時間同步和裝置級時間同步,裝置級時間同步較為簡單,隻要把原子鐘産生的同步脈沖信号1PPS輸入到相應的裝置即可,系統級時間同步主要是針對系統内的上位機及計算機系統時間的同步。
2 軟體設計原理

圖1 系統級時間同步設計原理
系統級時間同步設計原理如圖1所示。基于NTP/SNTP協定的網絡時間伺服器,可以從GPS衛星上擷取标準時鐘信号,并将這些資訊在網絡中傳輸。NTP/SNTP協定除了可以估算資料包在網絡上的往返延遲外,還可獨立地估算本地計算機時鐘偏差,進而實作在網絡上的高精度計算機時間校時。NTP/SNTP協定是一種TCP/IP協定,其本身的傳輸基于UDP,保留端口号123。同步精度在ms量級。
設計原理如下,首先建立網絡時間用戶端,用戶端調用socket建立UDP套接字,用于連接配接網絡時間伺服器。然後,用戶端向網絡時間伺服器發送請求,伺服器傳回包含時間資訊的資料包,用戶端對收到的資料包進行解析處理,計算得到資料包在網絡上的往返傳播延時和本地時鐘補償延時等參數,進而得到精确的本地時間,最後調用相關指令對計算機系統(Windows和Linux)的日期和時間進行修改,以實作時間同步。對于Linux系統的時間同步,需要通過SSH連接配接登陸到系統,然後執行同步指令。
系統時間同步軟體采用Python 3.6語言設計完成,使用wxPython GUI圖形庫搭建軟體架構, socket庫完成UDP通信,paramiko庫完成SSH連接配接Linux系統。運作框圖如圖2所示。
圖2 軟體運作界面
軟體操作使用說明如下:
1) 首先輸入網絡時間伺服器位址、協定及端口号;
2) Windows系統時間同步,點選開始同步按鈕,可完成計算機與網絡時間伺服器的單次時間同步。若需要計算機按一定時間間隔同步網絡時間伺服器,可勾標明時同步功能,在定時文本框中輸入時間間隔,注意是毫秒,然後點選開始定時同步按鈕可進行定時同步,點選暫停同步按鈕可以暫停定時同步。
3) Linux系統時間同步,輸入Linux系統的IP位址、使用者名、密碼。點選開始同步按鈕,自動登入Linux系統并完成Linux系統與網絡時間伺服器的單次時間同步。若需要定時同步功能,操作步驟與步驟2一樣。
4) 單次同步和定時同步的同步狀态資訊在下方同步結果顯示文本框中可以檢視,同步狀态資訊包括資料包在網絡上的往返傳播延時、本地時鐘補償延時、目前精确的系統時間以及是否成功修改本地計算機系統時間。
3 Python編碼
使用 wxFormBuilder生成wxPython GUI圖形界面。下圖是wxFormBuilder軟體運作界面。
生成的圖形界面代碼如下:
檔案:system_time_sync_frame.py
# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilder (version Jun 17 2015)
## http://www.wxformbuilder.org/
##
## PLEASE DO "NOT" EDIT THIS FILE!
###########################################################################
import wx
import wx.xrc
###########################################################################
## Class system_time_sync_frame
###########################################################################
class system_time_sync_frame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent = None, id = wx.ID_ANY, title = u"系統時間同步軟體v1.0", pos = wx.DefaultPosition, size = wx.Size( 594,477 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
# # 設定視窗标題的圖示
# self.icon = wx.Icon('time.ico', wx.BITMAP_TYPE_ICO)
# self.SetIcon(self.icon)
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
self.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString ) )
self.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_INACTIVECAPTIONTEXT ) )
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_MENU ) )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
sbSizer1 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"【網絡時間伺服器配置】" ), wx.HORIZONTAL )
sbSizer1.SetMinSize( wx.Size( 100,10 ) )
bSizer15 = wx.BoxSizer( wx.HORIZONTAL )
bSizer5 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText3 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"時間伺服器IP位址:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText3.Wrap( -1 )
self.m_staticText3.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer5.Add( self.m_staticText3, 0, wx.ALL, 5 )
self.m_textCtrl_timeserver = wx.TextCtrl( sbSizer1.GetStaticBox(), wx.ID_ANY, u"182.92.12.11", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer5.Add( self.m_textCtrl_timeserver, 0, wx.ALL, 5 )
bSizer15.Add( bSizer5, 1, 0, 5 )
bSizer6 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText4 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"端口号:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText4.Wrap( -1 )
self.m_staticText4.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer6.Add( self.m_staticText4, 0, wx.ALL, 5 )
self.m_textCtrl_port = wx.TextCtrl( sbSizer1.GetStaticBox(), wx.ID_ANY, u"123", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer6.Add( self.m_textCtrl_port, 0, wx.ALL, 5 )
bSizer15.Add( bSizer6, 1, 0, 5 )
bSizer7 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText5 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"協定:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText5.Wrap( -1 )
self.m_staticText5.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer7.Add( self.m_staticText5, 0, wx.ALL, 5 )
self.m_textCtrl_protocol = wx.TextCtrl( sbSizer1.GetStaticBox(), wx.ID_ANY, u"SNTP", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer7.Add( self.m_textCtrl_protocol, 0, wx.ALL, 5 )
bSizer15.Add( bSizer7, 1, 0, 5 )
sbSizer1.Add( bSizer15, 0, wx.EXPAND, 5 )
bSizer1.Add( sbSizer1, 1, wx.EXPAND|wx.TOP|wx.RIGHT|wx.LEFT, 5 )
sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"【Windows系統時間同步】" ), wx.HORIZONTAL )
bSizer10 = wx.BoxSizer( wx.VERTICAL )
bSizer51 = wx.BoxSizer( wx.HORIZONTAL )
self.m_checkBox_win = wx.CheckBox( sbSizer2.GetStaticBox(), wx.ID_ANY, u"定時同步(ms):", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer51.Add( self.m_checkBox_win, 0, wx.ALL, 5 )
self.m_textCtrl_timer_1 = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, u"1000", wx.DefaultPosition, wx.Size( -1,-1 ), 0 )
bSizer51.Add( self.m_textCtrl_timer_1, 0, wx.ALL, 5 )
bSizer10.Add( bSizer51, 0, 0, 5 )
sbSizer2.Add( bSizer10, 1, wx.EXPAND|wx.ALIGN_RIGHT, 5 )
bSizer12 = wx.BoxSizer( wx.HORIZONTAL )
self.m_button_win_sync_start = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"開始同步(B)", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
self.m_button_win_sync_start.SetFont( wx.Font( 11, 72, 90, 92, False, "Times New Roman" ) )
bSizer12.Add( self.m_button_win_sync_start, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 )
self.m_button_win_sync_stop = wx.Button( sbSizer2.GetStaticBox(), wx.ID_ANY, u"暫停同步(B)", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
self.m_button_win_sync_stop.SetFont( wx.Font( 11, 72, 90, 92, False, "Times New Roman" ) )
bSizer12.Add( self.m_button_win_sync_stop, 0, wx.ALL, 5 )
sbSizer2.Add( bSizer12, 1, wx.ALIGN_CENTER|wx.RIGHT|wx.LEFT|wx.EXPAND, 5 )
bSizer1.Add( sbSizer2, 1, wx.EXPAND|wx.BOTTOM, 5 )
sbSizer3 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"【Linux系統時間同步】" ), wx.VERTICAL )
bSizer151 = wx.BoxSizer( wx.HORIZONTAL )
bSizer52 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText31 = wx.StaticText( sbSizer3.GetStaticBox(), wx.ID_ANY, u"IP位址:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText31.Wrap( -1 )
self.m_staticText31.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer52.Add( self.m_staticText31, 0, wx.ALL, 5 )
self.m_textCtrl_linuxserver = wx.TextCtrl( sbSizer3.GetStaticBox(), wx.ID_ANY, u"192.168.1.205", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer52.Add( self.m_textCtrl_linuxserver, 0, wx.ALL, 5 )
bSizer151.Add( bSizer52, 1, wx.EXPAND, 5 )
bSizer61 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText41 = wx.StaticText( sbSizer3.GetStaticBox(), wx.ID_ANY, u"使用者名:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText41.Wrap( -1 )
self.m_staticText41.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer61.Add( self.m_staticText41, 0, wx.ALL, 5 )
self.m_textCtrl_username = wx.TextCtrl( sbSizer3.GetStaticBox(), wx.ID_ANY, u"root", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer61.Add( self.m_textCtrl_username, 0, wx.ALL, 5 )
bSizer151.Add( bSizer61, 1, wx.EXPAND, 5 )
bSizer71 = wx.BoxSizer( wx.HORIZONTAL )
self.m_staticText51 = wx.StaticText( sbSizer3.GetStaticBox(), wx.ID_ANY, u"密碼:", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_staticText51.Wrap( -1 )
self.m_staticText51.SetFont( wx.Font( wx.NORMAL_FONT.GetPointSize(), 70, 90, 90, False, wx.EmptyString ) )
bSizer71.Add( self.m_staticText51, 0, wx.ALL, 5 )
self.m_textCtrl_passwd = wx.TextCtrl( sbSizer3.GetStaticBox(), wx.ID_ANY, u"fatri123", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer71.Add( self.m_textCtrl_passwd, 0, wx.ALL, 5 )
bSizer151.Add( bSizer71, 1, wx.EXPAND, 5 )
sbSizer3.Add( bSizer151, 1, 0, 5 )
bSizer14 = wx.BoxSizer( wx.HORIZONTAL )
bSizer511 = wx.BoxSizer( wx.HORIZONTAL )
self.m_checkBox_linux = wx.CheckBox( sbSizer3.GetStaticBox(), wx.ID_ANY, u"定時同步(ms):", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer511.Add( self.m_checkBox_linux, 0, wx.ALL, 5 )
self.m_textCtrl_timer_2 = wx.TextCtrl( sbSizer3.GetStaticBox(), wx.ID_ANY, u"1000", wx.DefaultPosition, wx.Size( -1,-1 ), 0 )
bSizer511.Add( self.m_textCtrl_timer_2, 0, wx.ALL, 5 )
bSizer14.Add( bSizer511, 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL|wx.TOP|wx.BOTTOM, 5 )
bSizer121 = wx.BoxSizer( wx.HORIZONTAL )
self.m_button_linux_sync = wx.Button( sbSizer3.GetStaticBox(), wx.ID_ANY, u"開始同步(B)", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
self.m_button_linux_sync.SetFont( wx.Font( 11, 72, 90, 92, False, "Times New Roman" ) )
self.m_button_linux_sync.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_3DLIGHT ) )
bSizer121.Add( self.m_button_linux_sync, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 )
self.m_button_linux_sync_stop = wx.Button( sbSizer3.GetStaticBox(), wx.ID_ANY, u"暫停同步(B)", wx.Point( -1,-1 ), wx.DefaultSize, 0 )
self.m_button_linux_sync_stop.SetFont( wx.Font( 11, 72, 90, 92, False, "Times New Roman" ) )
bSizer121.Add( self.m_button_linux_sync_stop, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5 )
bSizer14.Add( bSizer121, 1, wx.EXPAND, 5 )
sbSizer3.Add( bSizer14, 1, wx.EXPAND, 5 )
bSizer1.Add( sbSizer3, 2, wx.EXPAND|wx.BOTTOM, 5 )
sbSizer4 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"同步結果顯示:" ), wx.HORIZONTAL )
self.m_textCtrl_sync_result = wx.TextCtrl( sbSizer4.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.Size( 500,200 ), wx.HSCROLL|wx.TE_MULTILINE )
sbSizer4.Add( self.m_textCtrl_sync_result, 0, wx.ALL, 5 )
bSizer1.Add( sbSizer4, 4, wx.EXPAND, 5 )
self.SetSizer( bSizer1 )
self.Layout()
self.Centre( wx.BOTH )
# Connect Events
self.m_checkBox_win.Bind( wx.EVT_CHECKBOX, self.m_checkBox_win_OnCheck )
self.m_button_win_sync_start.Bind( wx.EVT_BUTTON, self.m_button_win_sync_OnButtonClick )
self.m_button_win_sync_stop.Bind( wx.EVT_BUTTON, self.m_button_win_sync_stop_OnButtonClick )
self.m_checkBox_linux.Bind( wx.EVT_CHECKBOX, self.m_checkBox_linux_OnCheck )
self.m_button_linux_sync.Bind( wx.EVT_BUTTON, self.m_button_linux_sync_OnButtonClick )
self.m_button_linux_sync_stop.Bind( wx.EVT_BUTTON, self.m_button_linux_sync_stop_OnButtonClick )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def m_checkBox_win_OnCheck( self, event ):
event.Skip()
def m_button_win_sync_OnButtonClick( self, event ):
event.Skip()
def m_button_win_sync_stop_OnButtonClick( self, event ):
event.Skip()
def m_checkBox_linux_OnCheck( self, event ):
event.Skip()
def m_button_linux_sync_OnButtonClick( self, event ):
event.Skip()
def m_button_linux_sync_stop_OnButtonClick( self, event ):
event.Skip()
主程式:time_sync_main.py
# -*- coding: utf-8 -*-
"""
Date: Wed Dec 12 13:28:23 2018
Author: heat.huang
"""
import paramiko
import system_time_sync_frame
import wx
import time
import socket
import struct
import win32api
########### MainWindow ###################
class MainWindow(system_time_sync_frame.system_time_sync_frame):
def __init__(self, parent):
super().__init__(self)
# 設定視窗标題的圖示
self.icon = wx.Icon('time.ico', wx.BITMAP_TYPE_ICO)
self.SetIcon(self.icon)
#初始化複選框的定時間隔,用于判斷複選框的勾選
self.timer_val_win = 0
self.timer_val_linux = 0
# 建立 win_sync 定時器
self.timer_win = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.win_time_sync, self.timer_win)
# 建立 linux_sync 定時器
self.timer_linux = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.linux_time_sync, self.timer_linux)
######### 從網絡時間伺服器擷取時間 ###############
def get_time_from_ntpserver(self):
# 網絡時間伺服器位址 和端口号
ntp_server = self.m_textCtrl_timeserver.GetValue()
ntp_port = int(self.m_textCtrl_port.GetValue())
# 使用socket建立一個IPv4的UDP連接配接
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 1900年1月1日00:00:00~1970年1月1日00:00:00的總秒數,2208988800s
# 0x83aa7e80 是1900 到 1970年的總秒數,以十六進制表示
time1990_1970 = 0x83aa7e80
# 起始源時間戳--請求資訊離開用戶端的時間
# time.time()傳回目前時間的時間戳(1970紀元後經過的浮點秒數)
t1 = time.time()
# 使用struct.pack()打包資料,B表示8bit,即一個位元組寬度,
# I表示32bit,Q表示64bit
# <<是左移,它後面跟的數字表示移動的位數
# | 表示按位或運算符:隻要對應的兩個二進位有一個為1時,結果位就為1
ntppack = struct.pack("!BBBBIIIQQQQ",3<<6 | 3<<3 | 3,1,10,1,0,0,0,0,0,0,0)
# 用戶端向網絡時間伺服器發送請求
sock.sendto(ntppack, (ntp_server,ntp_port))
# 用戶端接收到時間伺服器傳回的包
resp, addr = sock.recvfrom(1024)
# 目的地時間戳--資訊包到達用戶端的時間
t4 = time.time()
# 用戶端使用struct.unpack()解包;
# 這裡LI VN Mode Stratum Poll Precision放到一個64bit裡面
# struct.unpack(fmt,string)傳回一個由解包資料(string)得到的一個元組(tuple)
# ‘!’表示network(=big-endian 大端)
(vi, root, refeTime, oriTime, receTime, tranTime) = struct.unpack("!QQQQQQ", resp)
# print(struct.unpack("!QQQQQQ",resp))
# Mode=4 表示伺服器傳回标志,判斷是否是時間伺服器傳回
# 十進制4用二進制表示 0100,在64bit中,0100左移56位,
# 随後與64bit的vi進行或運算,以此判斷...
# ...Mode的值是否為4
if vi == vi | 4<<56:
# 對解包得到的64bit總秒數取高32位,即獲得整秒數,
# 并減去1900-1970年之間的秒數
# 接收時間戳--伺服器收到查詢請求時間
receTime = (receTime/(2**32) - time1990_1970)
# 傳輸時間戳--伺服器回複時間資訊包時間
tranTime = (tranTime/(2**32) - time1990_1970)
# 計算本地時鐘補償compensation time
comTime = ((receTime - t1) + (tranTime - t4)) /2
# 計算往返傳播延遲 propagation delay
propaTime = (t4 - t1) + (tranTime - receTime)
# 将往返傳播延時(ms)和本地時鐘補償(ms)資訊添加到文本框
self.m_textCtrl_sync_result.AppendText('\n\n=====同步結果=====\n往返傳播延時(ms):{0:3f} \n本地時鐘補償(ms):{1:3f}'.format(propaTime*1000,comTime*1000))
# 目的地時間戳加本地時鐘補償得到準确的本地時間precise local time
preTime = t4 + comTime
# time.strftime():
# Convert a time tuple to a string according to a format specification
# 将精确的本地時間資訊添加到文本框
self.m_textCtrl_sync_result.AppendText('\n' + '' + time.strftime("Local Time: %Y-%m-%d %H:%M:%S", time.localtime(preTime)))
sock.close()
return preTime
######### Windows 系統時間同步 ###############
def win_time_sync(self, event):
preTime = self.get_time_from_ntpserver()
# 修改系統時間
# gmtime([seconds]):
# Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.GMT)
(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst)= time.gmtime(preTime)
# 調用win32api.SetSystemTime()修改系統時間
win32api.SetSystemTime(tm_year, tm_mon, tm_wday, tm_mday, tm_hour, tm_min, tm_sec, 0)
# 将成功修改系統時間資訊添加到文本框
self.m_textCtrl_sync_result.AppendText('\n' + 5*'*' + ' \nWindows系統時間修改成功 ' + '\n')
######### Linux 系統時間同步 ###############
def linux_time_sync(self, event):
try:
######## 建立SSH對象
ssh = paramiko.SSHClient()
######## 允許連接配接不在know_hosts檔案中的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
host_name = self.m_textCtrl_linuxserver.GetValue()
user_name = self.m_textCtrl_username.GetValue()
pass_word = self.m_textCtrl_passwd.GetValue()
# print("host_name: ", host_name)
# print("user_name: ", user_name)
# print("pass_word: ", pass_word)
####### 連接配接主要闆
ssh.connect(host_name, 22, user_name, pass_word)
######## 執行指令
# 得到精确的本地時間
preTime = self.get_time_from_ntpserver()
preDate = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(preTime))
cmd = "date -s " + "\"" + preDate + "\""
#print("cmd: ", cmd)
stdin, stdout, stderr = ssh.exec_command(cmd)
result = stdout.read()
result = str(result, encoding = "utf-8")
result = '\n' + 5*'*' + '\nLinux系統時間修改為:' + result + '\n'
self.m_textCtrl_sync_result.AppendText(result)
# print(result)
####### 關閉連接配接
ssh.close()
except:
Show_Message_Box("Linux系統時間同步失敗!")
############### 定時同步設定 ###################
### 定義函數--開始定時同步
def OnStart_Win(self, event):
# 時間間隔為毫秒量級,啟動定時器
self.timer_win.Start(int(self.m_textCtrl_timer_1.GetValue()))
def OnStart_Linux(self, event):
# 時間間隔為毫秒量級,啟動定時器
self.timer_linux.Start(int(self.m_textCtrl_timer_2.GetValue()))
#### 定義函數--暫停定時同步
def OnStop_Win(self, event):
self.timer_win.Stop()
self.timer_val_win = 0
def OnStop_Linux(self, event):
self.timer_linux.Stop()
self.timer_val_linux = 0
############# 按鍵對應的響應函數 ####################
###### win ######
def m_checkBox_win_OnCheck( self, event ): #複選框1
self.timer_val_win = int(self.m_textCtrl_timer_1.GetValue())
def m_button_win_sync_OnButtonClick( self, event ): # win-button-start
#如果複選框被選中,調用定時啟動函數,實作定時同步
if self.timer_val_win > 0:
self.OnStart_Win(event)
else:
self.win_time_sync(event)
def m_button_win_sync_stop_OnButtonClick( self, event ):# win-button-stop
if self.timer_val_win > 0:
self.OnStop_Win(event)
else:
pass
###### linux ######
def m_checkBox_linux_OnCheck( self, event ): #複選框2
self.timer_val_linux = int(self.m_textCtrl_timer_2.GetValue())
def m_button_linux_sync_OnButtonClick( self, event ):# linux-button-start
#如果複選框被選中,調用定時啟動函數,實作定時同步
if self.timer_val_linux > 0:
self.OnStart_Linux(event)
else:
self.linux_time_sync(event)
def m_button_linux_sync_stop_OnButtonClick( self, event ): # linux-button-stop
if self.timer_val_linux > 0:
self.OnStop_Linux(event)
else:
pass
## show message
def Show_Message_Box(message):
dlg = wx.MessageDialog(None, message, "提示資訊", wx.CLOSE | wx.ICON_QUESTION)
if dlg.ShowModal() == wx.ID_CLOSE:
dlg.Close(True)
dlg.Destroy
######### 執行主函數 ###############
if __name__ == '__main__':
app = wx.App()
main_win = MainWindow(None)
main_win.Show()
app.MainLoop()
注意:exe可執行檔案的打包使用 pyinstaller 工具,具體的打包方法參見論壇的文章:https://blog.csdn.net/zt_xcyk/article/details/73786659
下面是我打包生成的exe檔案。