python root.mainloop_tkinter root.mainloop与While True循环

我正在使用tkinter显示一些基于我正在读取的电压的标签。但是,它在一次读取后停止执行。我发现这是由于root.mainloop()引起的。但我没办法修好。我已经包括了我的代码。root.mainloop()位于while True的末尾。from Tkinter import *

import spidev

import time

import os

import RPi.GPIO as GPIO

import numpy

GPIO.cleanup()

GPIO.setmode(GPIO.BOARD)

GPIO.setup(7, GPIO.OUT)

GPIO.setup(11, GPIO.OUT)

GPIO.setup(13, GPIO.OUT)

GPIO.setup(15, GPIO.OUT)

GPIO.setup(12, GPIO.OUT)

adcvolt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

batvolt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

root = Tk() #Makes the window

w,h = root.winfo_screenwidth(), root.winfo_screenheight()

root.overrideredirect(1)

root.geometry("%dx%d+0+0"%(w,h))

labelFont = ("times",15 ,"bold", "italic")

labelText1 = StringVar()

labelText2 = StringVar()

labelText3 = StringVar()

labelText4 = StringVar()

labelText5 = StringVar()

labelText6 = StringVar()

labelText1.set("Battery Management System")

label1 = Label(root, textvariable=labelText1, height=3, anchor="center")

label1.config(font=labelFont)

label1.pack()

labelText2.set("Wait")

label2 = Label(root, textvariable=labelText2, height=3, anchor="center")

label2.config(font=labelFont)

label2.pack()

labelText3.set("Wait")

label3 = Label(root, textvariable=labelText3, height=3, anchor="center")

label3.config(font=labelFont)

label3.pack()

labelText4.set("Wait")

label4 = Label(root, textvariable=labelText4, height=3, anchor="center")

label4.config(font=labelFont)

label4.pack()

labelText5.set("Wait")

label5 = Label(root, textvariable=labelText5, height=3, anchor="center")

label5.config(font=labelFont)

label5.pack()

labelText6.set("Wait")

label6 = Label(root, textvariable=labelText6, height=3, anchor="center")

label6.config(font=labelFont)

label6.pack()

#root.wm_title("Window Title") #Makes the title that will appear in the top left

#root.config(background = "#FFFFFF") #sets background color to white

# Open SPI bus

spi = spidev.SpiDev()

spi.open(0,0)

# Function to read SPI data from MCP3008 chip

# Channel must be an integer 0-7

def ReadChannel(channel):

adc = spi.xfer2([1,(8+channel)<<4,0])

data = ((adc[1]&3) << 8) + adc[2]

return data

#Function to select multiplexer channel on 74HCT4067 chip

#Channel must be an integer 0-15

def MuxSelect(muxchannel):

if muxchannel == 0:

GPIO.output(7,0)

GPIO.output(11,0)

GPIO.output(13,0)

GPIO.output(15,0)

elif muxchannel == 1:

GPIO.output(7,0)

GPIO.output(11,0)

GPIO.output(13,0)

GPIO.output(15,1)

elif muxchannel == 2:

GPIO.output(7,0)

GPIO.output(11,0)

GPIO.output(13,1)

GPIO.output(15,0)

elif muxchannel == 3:

GPIO.output(7,0)

GPIO.output(11,0)

GPIO.output(13,1)

GPIO.output(15,1)

elif muxchannel == 4:

GPIO.output(7,0)

GPIO.output(11,1)

GPIO.output(13,0)

GPIO.output(15,0)

elif muxchannel == 5:

GPIO.output(7,0)

GPIO.output(11,1)

GPIO.output(13,0)

GPIO.output(15,1)

elif muxchannel == 6:

GPIO.output(7,0)

GPIO.output(11,1)

GPIO.output(13,1)

GPIO.output(15,0)

elif muxchannel == 7:

GPIO.output(7,0)

GPIO.output(11,1)

GPIO.output(13,1)

GPIO.output(15,1)

elif muxchannel == 8:

GPIO.output(7,1)

GPIO.output(11,0)

GPIO.output(13,0)

GPIO.output(15,0)

elif muxchannel == 9:

GPIO.output(7,1)

GPIO.output(11,0)

GPIO.output(13,0)

GPIO.output(15,1)

elif muxchannel == 10:

GPIO.output(7,1)

GPIO.output(11,0)

GPIO.output(13,1)

GPIO.output(15,0)

elif muxchannel == 11:

GPIO.output(7,1)

GPIO.output(11,0)

GPIO.output(13,1)

GPIO.output(15,1)

elif muxchannel == 12:

GPIO.output(7,1)

GPIO.output(11,1)

GPIO.output(13,0)

GPIO.output(15,0)

elif muxchannel == 13:

GPIO.output(7,1)

GPIO.output(11,1)

GPIO.output(13,0)

GPIO.output(15,1)

elif muxchannel == 14:

GPIO.output(7,1)

GPIO.output(11,1)

GPIO.output(13,1)

GPIO.output(15,0)

elif muxchannel == 15:

GPIO.output(7,1)

GPIO.output(11,1)

GPIO.output(13,1)

GPIO.output(15,1)

# Function to convert data to voltage level,

# rounded to specified number of decimal places.

def ConvertVolts(data,places):

volts = (data * 3.3) / 1023

volts = round(volts,places)

return volts

# Define sensor channels

voltage_channel = 0

# Define delay between readings

delay = 2

while True:

count = 0

while count<15:

MuxSelect(count)

# Read the voltage sensor data

voltage_level = ReadChannel(voltage_channel)

voltage_volts = ConvertVolts(voltage_level,2)

adcvolt[count] = voltage_volts

batvolt[count] = adcvolt[count] * 2.842

#print adcvolt[count]

#print batvolt[count]

#print count

count = count + 1

#time.sleep(delay)

labelText2.set('Cell1= '+str(batvolt[0])+'V Cell2= ' +str(batvolt[1])+'V Cell3= '+str(batvolt[2]))

#root.update()

labelText3.set('Cell4= '+str(batvolt[3])+'V Cell5= ' +str(batvolt[4])+'V Cell6= '+str(batvolt[5]))

# root.update()

labelText4.set('Cell7= '+str(batvolt[6])+'V Cell8= ' +str(batvolt[7])+'V Cell9= '+str(batvolt[8]))

# root.update()

labelText5.set('Cell10= '+str(batvolt[9])+'V Cell11= ' +str(batvolt[10])+'V Cell12= '+str(batvolt[11]))

# root.update()

labelText6.set('Cell13= '+str(batvolt[12])+'V Cell14= ' +str(batvolt[13])+'V Cell15= '+str(batvolt[14]))

root.update()

print "shit"

medianvolt = numpy.median(batvolt)

maxvolt = max(batvolt)

minvolt = min(batvolt)

diff1 = maxvolt-medianvolt

diff2 = medianvolt-minvolt

if diff1>0.02 or diff2>0.02:

GPIO.output (12,1)

time.sleep(120)

GPIO.output (12,0)

# Wait before repeating loop

time.sleep(delay)

root.update()

root.mainloop() #start monitoring and updating the GUI. Nothing below here runs.

import tkinter as tk from tkinter import messagebox, simpledialog import time import threading import os import pandas as pd from datetime import datetime import os import subprocess class FloatTimer: def __init__(self): self.root = tk.Tk() self.root.title("悬浮计时器") self.root.overrideredirect(True) self.root.attributes('-topmost', True) self.root.attributes('-alpha', 0.9) # 计时变量 self.elapsed_time = 0 self.running = False self.start_time = 0 self.last_save_time = 0 self.session_records = [] # 存储计时记录 self.current_segment_start = None # 当前计时段的开始时间 self.current_segment_end = None # 当前计时段的结束时间 # 创建UI self.time_label = tk.Label(self.root, text="00:00:00", font=("Arial", 20), bg='black', fg='white') self.time_label.pack(fill=tk.BOTH) btn_frame = tk.Frame(self.root, bg='black') btn_frame.pack(fill=tk.BOTH) self.start_btn = tk.Button(btn_frame, text="开始", command=self.toggle_start, width=5) self.start_btn.pack(side=tk.LEFT, padx=5, pady=5) reset_btn = tk.Button(btn_frame, text="重置", command=self.reset_timer) reset_btn.pack(side=tk.LEFT, padx=5, pady=5) save_btn = tk.Button(btn_frame, text="保存", command=self.save_current_session) save_btn.pack(side=tk.LEFT, padx=5, pady=5) close_btn = tk.Button(btn_frame, text="关闭", command=self.on_close) close_btn.pack(side=tk.RIGHT, padx=5, pady=5) # 绑定事件 self.time_label.bind("<ButtonPress-1>", self.start_drag) self.time_label.bind("<B1-Motion>", self.on_drag) # 设置位置 self.set_position_top_right() # 初始化保存目录 self.save_directory = os.path.join(os.path.expanduser("~"), "TimerRecords") os.makedirs(self.save_directory, exist_ok=True) # 启动自动保存线程 self.auto_save = True threading.Thread(target=self.auto_save_records, daemon=True).start() def set_position_top_right(self): """将窗口置于屏幕右上角""" self.root.update_idletasks() screen_width = self.root.winfo_screenwidth() window_width = self.root.winfo_reqwidth() x_pos = screen_width - window_width - 20 y_pos = 20 self.root.geometry(f"+{x_pos}+{y_pos}") def start_drag(self, event): self.x_start = event.x self.y_start = event.y def on_drag(self, event): x = self.root.winfo_x() + (event.x - self.x_start) y = self.root.winfo_y() + (event.y - self.y_start) self.root.geometry(f"+{x}+{y}") def toggle_start(self): if not self.running: # 开始计时 self.running = True self.start_btn.config(text="结束") self.start_time = time.time() - self.elapsed_time self.current_segment_start = datetime.now() # 启动计时线程 threading.Thread(target=self.update_timer, daemon=True).start() else: # 结束计时 self.running = False self.start_btn.config(text="开始") self.current_segment_end = datetime.now() # 记录结束时间并获取类型 self.record_session() # 重置当前计时段 self.current_segment_start = None self.current_segment_end = None def reset_timer(self): if self.running: # 如果正在运行,先结束当前计时 self.running = False self.start_btn.config(text="开始") self.current_segment_end = datetime.now() self.record_session() # 记录当前计时段 # 重置所有计时变量 self.elapsed_time = 0 self.time_label.config(text="00:00:00") self.start_btn.config(text="开始") self.current_segment_start = None self.current_segment_end = None def record_session(self): """记录计时会话并获取类型""" if not self.current_segment_start or not self.current_segment_end: return # 计算持续时间 duration = (self.current_segment_end - self.current_segment_start).total_seconds() # 格式化时间 hours, remainder = divmod(duration, 3600) minutes, seconds = divmod(remainder, 60) formatted_duration = f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}" # 弹出对话框获取类型 category = simpledialog.askstring("计时类型", "请输入计时类型(如工作/学习/休息):", parent=self.root) if not category: category = "未分类" # 添加记录 self.session_records.append({ "日期": self.current_segment_start.strftime("%Y-%m-%d"), "开始时间": self.current_segment_start.strftime("%H:%M:%S"), "结束时间": self.current_segment_end.strftime("%H:%M:%S"), "持续时间": formatted_duration, "类型": category }) def save_current_session(self): """手动保存当前会话记录""" if self.session_records: self.save_to_excel() self.session_records = [] # 清空记录 messagebox.showinfo("保存成功", "计时记录已保存到Excel文件") else: messagebox.showinfo("无记录", "没有计时记录需要保存") def auto_save_records(self): """自动保存记录到Excel""" while True: if self.auto_save and self.session_records: current_time = time.time() # 每5分钟自动保存一次且记录不为空 if current_time - self.last_save_time > 300: # 300秒=5分钟 self.save_to_excel() self.last_save_time = current_time time.sleep(60) # 每分钟检查一次 def save_to_excel(self): """保存记录到Excel文件,按日期分类""" if not self.session_records: return # 获取当前日期作为文件名 current_date = datetime.now().strftime("%Y-%m-%d") file_path = os.path.join(self.save_directory, f"{current_date}.xlsx") print(f"计时记录保存位置: {self.save_directory}") # 创建DataFrame df = pd.DataFrame(self.session_records) # 重新排序列 column_order = ["日期", "开始时间", "结束时间", "持续时间", "类型"] df = df[column_order] # 如果文件已存在,追加数据;否则创建新文件 if os.path.exists(file_path): try: existing_df = pd.read_excel(file_path) combined_df = pd.concat([existing_df, df], ignore_index=True) combined_df.to_excel(file_path, index=False) except Exception as e: # 文件可能被其他程序占用,尝试创建新文件 error_file = os.path.join(self.save_directory, f"error_{int(time.time())}.xlsx") df.to_excel(error_file, index=False) messagebox.showerror("保存错误", f"文件被占用,已创建新文件: {error_file}") else: df.to_excel(file_path, index=False) def update_timer(self): """更新计时器显示""" while self.running: self.elapsed_time = time.time() - self.start_time hours, remainder = divmod(self.elapsed_time, 3600) minutes, seconds = divmod(remainder, 60) self.time_label.config(text=f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}") time.sleep(0.1) def on_close(self): """关闭窗口前的处理""" # 如果正在计时,先结束并记录 if self.running: self.running = False self.current_segment_end = datetime.now() self.record_session() # 保存所有记录 if self.session_records: self.save_to_excel() self.root.destroy() def run(self): self.root.mainloop() if __name__ == "__main__": timer = FloatTimer() timer.run() print(f"{'计时器已退出':-^50}") 将这段代码的文件保存路径改为‘E:\研究生\日常’,并对文件重新命名为‘时间记录’
最新发布
11-10
import tkinter as tk from tkinter import messagebox # 添加此行以解决错误 import time import threading import os import pandas as pd from datetime import datetime class FloatTimer: def __init__(self): self.root = tk.Tk() self.root.overrideredirect(True) self.root.attributes('-topmost', True) self.root.attributes('-alpha', 0.9) # 计时变量 self.elapsed_time = 0 self.running = False self.start_time = 0 self.last_save_time = 0 self.session_records = [] # 存储计时记录 # 创建UI self.time_label = tk.Label(self.root, text="00:00:00", font=("Arial", 20), bg='black', fg='white') self.time_label.pack(fill=tk.BOTH) btn_frame = tk.Frame(self.root, bg='black') btn_frame.pack(fill=tk.BOTH) self.start_btn = tk.Button(btn_frame, text="开始", command=self.toggle_start, width=5) self.start_btn.pack(side=tk.LEFT, padx=5, pady=5) reset_btn = tk.Button(btn_frame, text="重置", command=self.reset_timer) reset_btn.pack(side=tk.LEFT, padx=5, pady=5) save_btn = tk.Button(btn_frame, text="保存", command=self.save_current_session) save_btn.pack(side=tk.LEFT, padx=5, pady=5) close_btn = tk.Button(btn_frame, text="关闭", command=self.on_close) close_btn.pack(side=tk.RIGHT, padx=5, pady=5) # 绑定事件 self.time_label.bind("<ButtonPress-1>", self.start_drag) self.time_label.bind("<B1-Motion>", self.on_drag) # 设置位置 self.set_position_top_right() # 初始化保存目录 self.save_directory = os.path.join(os.path.expanduser("~"), "TimerRecords") os.makedirs(self.save_directory, exist_ok=True) # 启动自动保存线程 self.auto_save = True threading.Thread(target=self.auto_save_records, daemon=True).start() def set_position_top_right(self): """将窗口置于屏幕右上角""" self.root.update_idletasks() screen_width = self.root.winfo_screenwidth() window_width = self.root.winfo_reqwidth() x_pos = screen_width - window_width - 20 y_pos = 20 self.root.geometry(f"+{x_pos}+{y_pos}") def start_drag(self, event): self.x_start = event.x self.y_start = event.y def on_drag(self, event): x = self.root.winfo_x() + (event.x - self.x_start) y = self.root.winfo_y() + (event.y - self.y_start) self.root.geometry(f"+{x}+{y}") def toggle_start(self): self.running = not self.running if self.running: self.start_btn.config(text="暂停") self.start_time = time.time() - self.elapsed_time threading.Thread(target=self.update_timer, daemon=True).start() else: self.start_btn.config(text="继续") # 记录暂停时的计时信息 current_time = time.time() duration = current_time - (self.start_time + self.elapsed_time - current_time) self.record_session("暂停", duration) def reset_timer(self): if self.running: self.running = False self.start_btn.config(text="开始") # 记录重置时的计时信息 current_time = time.time() duration = current_time - (self.start_time + self.elapsed_time - current_time) self.record_session("重置", duration) self.elapsed_time = 0 self.time_label.config(text="00:00:00") self.start_btn.config(text="开始") def record_session(self, action, duration): """记录计时会话""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") hours, remainder = divmod(duration, 3600) minutes, seconds = divmod(remainder, 60) formatted_duration = f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}" self.session_records.append({ "日期": datetime.now().strftime("%Y-%m-%d"), "时间": timestamp, "动作": action, "持续时间": formatted_duration, "持续秒数": duration }) def save_current_session(self): """手动保存当前会话记录""" if self.session_records: self.save_to_excel() self.session_records = [] # 清空记录 messagebox.showinfo("保存成功", "计时记录已保存到Excel文件") # 修复此处 else: messagebox.showinfo("无记录", "没有计时记录需要保存") # 修复此处 def auto_save_records(self): """自动保存记录到Excel""" while True: if self.auto_save and self.session_records: current_time = time.time() # 每5分钟自动保存一次且记录不为空 if current_time - self.last_save_time > 300: # 300秒=5分钟 self.save_to_excel() self.last_save_time = current_time time.sleep(60) # 每分钟检查一次 def save_to_excel(self): """保存记录到Excel文件,按日期分类""" if not self.session_records: return # 获取当前日期作为文件名 current_date = datetime.now().strftime("%Y-%m-%d") file_path = os.path.join(self.save_directory, f"{current_date}.xlsx") print(f"计时记录保存位置: {self.save_directory}") # 创建DataFrame df = pd.DataFrame(self.session_records) # 如果文件已存在,追加数据;否则创建新文件 if os.path.exists(file_path): try: existing_df = pd.read_excel(file_path) combined_df = pd.concat([existing_df, df], ignore_index=True) combined_df.to_excel(file_path, index=False) except Exception as e: # 文件可能被其他程序占用,尝试创建新文件 error_file = os.path.join(self.save_directory, f"error_{int(time.time())}.xlsx") df.to_excel(error_file, index=False) else: df.to_excel(file_path, index=False) def update_timer(self): """更新计时器显示""" while self.running: self.elapsed_time = time.time() - self.start_time hours, remainder = divmod(self.elapsed_time, 3600) minutes, seconds = divmod(remainder, 60) self.time_label.config(text=f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}") time.sleep(0.1) def on_close(self): """关闭窗口前的处理""" if self.session_records: self.save_to_excel() self.root.destroy() def run(self): self.root.mainloop() if __name__ == "__main__": timer = FloatTimer() timer.run() print('计时器以退出!!!!!') 修改一下这个excel保存的内容,需要保存记录的时间,以及计时qisi
11-10
import tkinter as tk from tkinter import ttk, scrolledtext import threading import queue import pyaudio from vosk import Model, KaldiRecognizer class VoiceRecognitionApp: def __init__(self, root): self.root = root self.root.title("实时语音识别系统 v1.0") # 初始化语音识别模型 self.model = Model(lang="en-us") # 下载对应语言模型:https://alphacephei.com/vosk/models self.recognizer = KaldiRecognizer(self.model, 16000) # 创建GUI组件 self.create_widgets() # 音频配置 self.audio = pyaudio.PyAudio() self.stream = None self.is_recording = False # 线程安全队列 self.text_queue = queue.Queue() # 启动界面更新线程 self.update_ui() def create_widgets(self): # 控制面板 control_frame = ttk.Frame(self.root) control_frame.pack(pady=10) self.btn_start = ttk.Button(control_frame, text="开始录音", command=self.toggle_recording) self.btn_start.pack(side=tk.LEFT, padx=5) # 结果显示区域 self.text_area = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, width=60, height=15) self.text_area.pack(padx=10, pady=5, fill=tk.BOTH, expand=True) # 状态栏 self.status_var = tk.StringVar() status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN) status_bar.pack(side=tk.BOTTOM, fill=tk.X) def toggle_recording(self): if not self.is_recording: self.start_recording() else: self.stop_recording() def start_recording(self): self.is_recording = True self.btn_start.config(text="停止录音") self.status_var.set("录音中...") # 打开音频流 self.stream = self.audio.open( format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000, stream_callback=self.audio_callback ) self.stream.start_stream() def stop_recording(self): self.is_recording = False self.btn_start.config(text="开始录音") self.status_var.set("就绪") if self.stream: self.stream.stop_stream() self.stream.close() def audio_callback(self, in_data, frame_count, time_info, status): if self.recognizer.AcceptWaveform(in_data): result = self.recognizer.Result() self.text_queue.put(result[14:-3]) # 提取识别文本 return (None, pyaudio.paContinue) def update_ui(self): try: while True: text = self.text_queue.get_nowait() self.text_area.insert(tk.END, text + "\n") self.text_area.see(tk.END) except queue.Empty: pass self.root.after(100, self.update_ui) if __name__ == "__main__": root = tk.Tk() app = VoiceRecognitionApp(root) root.mainloop()详细解释代码的每一部分
05-31
import tkinter as tk from tkinter import messagebox import threading class PopupGenerator: def __init__(self): self.root = tk.Tk() self.root.geometry("200x120") self.root.title("无限弹窗") self.root.protocol("WM_DELETE_WINDOW", lambda: None) # 用户不可关闭弹窗一 self.common_style = {"font": ("华文新魏", 14)} self.label = tk.Label(self.root, text="恭喜你打开了这个程序", **self.common_style, fg="red") self.label.pack(pady=20) self.close_program_button = tk.Button(self.root, text="关闭程序", command=self.try_detox, **self.common_style, bg="green", fg="white") self.close_program_button.pack(pady=10) self.popup_count = 0 self.detox_attempts = 0 self.popup_positions = [] # 存储已存在弹窗的位置信息 self.generate_popup() def generate_popup(self): if self.popup_count < 20: popup = tk.Toplevel(self.root) popup.title("无限弹窗") popup.geometry("200x120") # 检查已存在弹窗的位置,设置新弹窗的位置 x, y = self.calculate_popup_position(popup.winfo_reqwidth(), popup.winfo_reqheight()) popup.geometry(f"+{x}+{y}") popup_label = tk.Label(popup, text="多试一下", fg="blue", **self.common_style) popup_label.pack(pady=20) popup.protocol("WM_DELETE_WINDOW", self.on_popup_close) self.popup_count += 1 threading.Timer(1, self.generate_popup).start() def calculate_popup_position(self, width, height): # 计算新弹窗的位置,避免重叠 x_offset, y_offset = 25, 25 x = self.root.winfo_x() + x_offset + len(self.popup_positions) * x_offset y = self.root.winfo_y() + y_offset + len(self.popup_positions) * y_offset # 存储新弹窗的位置信息 self.popup_positions.append((x, y)) return x, y def on_popup_close(self): self.generate_additional_popup() def generate_additional_popup(self): additional_popup = tk.Toplevel(self.root) additional_popup.title("无限弹窗") additional_popup.geometry("200x120") # 检查已存在弹窗的位置,设置新弹窗的位置 x, y = self.calculate_popup_position(additional_popup.winfo_reqwidth(), additional_popup.winfo_reqheight()) additional_popup.geometry(f"+{x}+{y}") additional_popup_label = tk.Label(additional_popup, text="并没有用", fg="purple", **self.common_style) additional_popup_label.pack(pady=20) def try_detox(self): self.detox_attempts += 1 if self.detox_attempts <= 10: messagebox.showinfo("温馨提示", f"你不会觉得点了 {self.detox_attempts} 次就有用吧") else: messagebox.showinfo("没想到啊", f"你居然坚持点了 {self.detox_attempts}次") self.root.destroy() if __name__ == "__main__": popup_generator = PopupGenerator() popup_generator.root.mainloop()
11-08
import tkinter as tk from tkinter import scrolledtext, ttk, filedialog, messagebox import subprocess import threading import os import datetime class ADBBackupTool: def __init__(self, root): self.root = root root.title("晶晨/海思ADB备份工具") def center_window(width, height, y_offset=0): screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() x = (screen_width - width) // 2 y = (screen_height - height) // 2 + y_offset return f"{width}x{height}+{x}+{y}" root.geometry(center_window(1200, 700, -50)) self.context_menu = tk.Menu(root, tearoff=0) self.context_menu.add_command(label="复制", command=lambda: self.copy_text()) self.context_menu.add_command(label="粘贴", command=lambda: self.paste_text()) self.context_menu.add_separator() self.context_menu.add_command(label="全选", command=lambda: self.select_all()) self.main_frame = tk.Frame(root) self.main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) self.main_frame.columnconfigure(0, weight=1) self.main_frame.rowconfigure(0, weight=1) RIGHT_PANE_WIDTH = 300 self.cmd_frame = tk.Frame(self.main_frame) self.cmd_frame.grid(row=0, column=0, sticky="nsew") self.cmd_label = tk.Label(self.cmd_frame, text="命令窗口", font=('Arial', 10, 'bold')) self.cmd_label.pack(anchor='w') self.cmd_text = scrolledtext.ScrolledText( self.cmd_frame, wrap=tk.WORD, font=('Consolas', 10), bg='black', fg='white', insertbackground='white' ) self.cmd_text.pack(fill=tk.BOTH, expand=True) self.cmd_text.bind("<Button-3>", self.show_context_menu) self.function_frame = tk.Frame(self.main_frame, width=RIGHT_PANE_WIDTH) self.function_frame.grid(row=0, column=1, sticky="nsew", padx=(5, 0)) self.function_frame.pack_propagate(False) self.conn_frame = tk.LabelFrame(self.function_frame, text="连接设置", padx=5, pady=5) self.conn_frame.pack(fill=tk.X, pady=(0, 5)) ip_port_frame = tk.Frame(self.conn_frame) ip_port_frame.pack(fill=tk.X, pady=2) tk.Label(ip_port_frame, text="IP地址:").pack(side=tk.LEFT, padx=(0, 5)) self.ip_entry = tk.Entry(ip_port_frame, width=15) self.ip_entry.pack(side=tk.LEFT, padx=(0, 10)) self.ip_entry.insert(0, "192.168.31.200") self.ip_entry.bind("<Button-3>", self.show_context_menu) tk.Label(ip_port_frame, text="端口号:").pack(side=tk.LEFT, padx=(0, 5)) self.port_entry = tk.Entry(ip_port_frame, width=9) self.port_entry.pack(side=tk.LEFT) self.port_entry.insert(0, "5555") self.port_entry.bind("<Button-3>", self.show_context_menu) self.connect_btn = tk.Button( self.conn_frame, text="连接设备", command=self.connect_device, bg="#4CAF50", fg="white" ) self.connect_btn.pack(fill=tk.X, pady=(5, 0)) self.query_frame = tk.LabelFrame(self.function_frame, text="快速查询", padx=5, pady=5) self.query_frame.pack(fill=tk.X, pady=(0, 5)) self.cmd_var = tk.StringVar() self.cmd_combobox = ttk.Combobox( self.query_frame, textvariable=self.cmd_var, values=["请选择命令", "晶晨分区获取", "晶晨dtb备份到桌面", "海思分区获取","海思分区获取2", "保存海思分区表", "U盘路径查询"], state="readonly", height=5, width=25 ) self.cmd_combobox.pack(fill=tk.X, pady=2) self.cmd_combobox.current(0) # 默认选中"请选择命令" self.cmd_combobox.bind("<<ComboboxSelected>>", self.update_cmd_entry) self.cmd_mapping = { "晶晨分区获取": "adb shell ls /dev/block", "晶晨dtb备份到桌面": 'adb pull "/dev/dtb" "C:\\Users\\Administrator\\Desktop\\dtb"', "海思分区获取": 'adb shell "cd /dev/block/platform/soc/by-name && ls -l"', "海思分区获取2": "adb shell cat /proc/partitions ", "保存海思分区表": "save_hisilicon_partitions", "U盘路径查询": "adb shell df" } self.cmd_entry = tk.Entry(self.query_frame) self.cmd_entry.pack(fill=tk.X, pady=2) self.cmd_entry.insert(0, "可手动输入") self.cmd_entry.bind("<Button-3>", self.show_context_menu) self.cmd_entry.bind("<FocusIn>", self.on_entry_focus_in) self.cmd_entry.bind("<Key>", self.on_entry_key_press) self.run_cmd_btn = tk.Button( self.query_frame, text="执行命令", command=self.execute_custom_cmd, bg="#2196F3", fg="white" ) self.run_cmd_btn.pack(fill=tk.X, pady=(0, 5)) self.partition_select_frame = tk.LabelFrame(self.function_frame, text="选择要备份的分区", padx=5, pady=5) self.partition_select_frame.pack(fill=tk.BOTH, expand=True) self.partition_container = tk.Frame(self.partition_select_frame) self.partition_container.pack(fill=tk.BOTH, expand=True) self.partition_scrollbar = ttk.Scrollbar(self.partition_container) self.partition_scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.partition_canvas = tk.Canvas( self.partition_container, yscrollcommand=self.partition_scrollbar.set, bg='#f0f0f0', highlightthickness=0 ) self.partition_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.partition_scrollbar.config(command=self.partition_canvas.yview) self.partition_list_frame = tk.Frame(self.partition_canvas, bg='#f0f0f0') self.partition_canvas.create_window((0, 0), window=self.partition_list_frame, anchor="nw") self.partition_list_frame.bind( "<Configure>", lambda e: self.partition_canvas.configure( scrollregion=self.partition_canvas.bbox("all") ) ) self.partition_vars = {} self.chip_type = None self.select_all_var = tk.BooleanVar() self.select_all_check = tk.Checkbutton( self.partition_list_frame, text="全选", variable=self.select_all_var, command=self.toggle_select_all, bg='#f0f0f0', anchor='w', font=('Arial', 10) ) self.select_all_check.pack(fill=tk.X, pady=2, padx=5) self.backup_btn = tk.Button( self.function_frame, text="备份选中分区", command=self.start_backup, bg="#9C27B0", fg="white" ) self.backup_btn.pack(fill=tk.X, pady=(5, 0)) self.status_bar = tk.Label(root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W) self.status_bar.pack(side=tk.BOTTOM, fill=tk.X) self.check_adb() def save_hisilicon_partitions(self): """保存海思分区表到桌面""" if not hasattr(self, 'chip_type') or self.chip_type != "海思": messagebox.showerror("错误", "请先获取海思分区表") return desktop_path = "C:\\Users\\Administrator\\Desktop" save_path = os.path.join(desktop_path, "海思分区表.txt") try: content = self.cmd_text.get("1.0", tk.END) lines = content.split('\n') partition_lines = [line for line in lines if "->" in line] if not partition_lines: messagebox.showerror("错误", "未找到分区信息") return with open(save_path, 'w', encoding='utf-8') as f: f.write("海思设备分区表\n") f.write(f"生成时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") f.write("="*50 + "\n") for line in partition_lines: f.write(line + "\n") self.append_cmd_output(f"分区表已保存到桌面: 海思分区表.txt") messagebox.showinfo("成功", "分区表已保存到桌面:\n海思分区表.txt") except Exception as e: self.append_cmd_output(f"保存分区表出错: {str(e)}") messagebox.showerror("错误", f"保存分区表出错:\n{str(e)}") def on_entry_focus_in(self, event): if self.cmd_entry.get() == "请选择命令或手动输入": self.cmd_entry.delete(0, tk.END) def on_entry_key_press(self, event): if self.cmd_entry.get() == "请选择命令或手动输入": self.cmd_entry.delete(0, tk.END) def update_cmd_entry(self, event): selected = self.cmd_combobox.get() self.cmd_entry.delete(0, tk.END) self.cmd_entry.insert(0, self.cmd_mapping.get(selected, "")) def show_context_menu(self, event): self.current_widget = event.widget try: self.current_widget.focus_set() self.context_menu.post(event.x_root, event.y_root) except Exception as e: print(f"显示右键菜单出错: {e}") return "break" def copy_text(self): try: if isinstance(self.current_widget, (tk.Entry, scrolledtext.ScrolledText)): self.current_widget.event_generate("<<Copy>>") except Exception as e: print(f"复制出错: {e}") def paste_text(self): try: if isinstance(self.current_widget, (tk.Entry, scrolledtext.ScrolledText)): self.current_widget.event_generate("<<Paste>>") except Exception as e: print(f"粘贴出错: {e}") def select_all(self): try: if isinstance(self.current_widget, tk.Entry): self.current_widget.select_range(0, tk.END) self.current_widget.icursor(tk.END) elif isinstance(self.current_widget, scrolledtext.ScrolledText): self.current_widget.tag_add(tk.SEL, "1.0", tk.END) self.current_widget.mark_set(tk.INSERT, "1.0") self.current_widget.see(tk.INSERT) except Exception as e: print(f"全选出错: {e}") def check_adb(self): try: result = subprocess.run("adb version", shell=True, capture_output=True, text=True) if "Android Debug Bridge" in result.stdout: self.append_cmd_output("ADB已就绪\n" + result.stdout.split('\n')[0]) else: self.append_cmd_output("错误: ADB未正确安装") messagebox.showerror("错误", "ADB未正确安装,请先安装ADB工具") except Exception as e: self.append_cmd_output(f"检查ADB出错: {str(e)}") messagebox.showerror("错误", f"检查ADB出错: {str(e)}") def execute_custom_cmd(self): cmd = self.cmd_entry.get() if not cmd: self.append_cmd_output("错误: 请输入要执行的命令") return if cmd == "save_hisilicon_partitions": self.save_hisilicon_partitions() return self.append_cmd_output(f"执行命令: {cmd}") threading.Thread(target=self._execute_cmd, args=(cmd,), daemon=True).start() def _execute_cmd(self, cmd): try: process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, universal_newlines=True ) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: self.root.after(0, self.append_cmd_output, output.strip()) stderr = process.stderr.read() if stderr: self.root.after(0, self.append_cmd_output, f"错误:\n{stderr.strip()}") self.root.after(0, self.append_cmd_output, f"命令执行完成,返回值: {process.returncode}") if "ls /dev/block" in cmd or "by-name" in cmd: self._parse_partitions(cmd) except Exception as e: self.root.after(0, self.append_cmd_output, f"执行命令出错: {str(e)}") def _parse_partitions(self, cmd): for widget in self.partition_list_frame.winfo_children()[1:]: widget.destroy() self.partition_vars.clear() partitions = [] if "by-name" in cmd: self.chip_type = "海思" self.append_cmd_output("检测到海思设备分区表") result = subprocess.run(cmd, shell=True, capture_output=True, text=True) for line in result.stdout.split('\n'): if "->" in line: part_name = line.split("->")[-1].split("/")[-1].strip() if part_name: partitions.append(part_name) else: self.chip_type = "晶晨" self.append_cmd_output("检测到晶晨设备分区表") result = subprocess.run(cmd, shell=True, capture_output=True, text=True) for line in result.stdout.split('\n'): if line and not line.startswith("total") and not line.startswith("ls:"): part_name = line.split()[-1] if part_name and part_name not in ["", "by-name", "platform"]: partitions.append(part_name) if partitions: self._display_partitions(partitions) self.append_cmd_output("分区列表已更新,请在右侧选择要备份的分区") else: self.append_cmd_output("未找到分区信息") def connect_device(self): ip = self.ip_entry.get() port = self.port_entry.get() if not ip or not port: self.append_cmd_output("错误: 请输入IP地址和端口号") return self.append_cmd_output(f"尝试连接设备: {ip}:{port}") self.connect_btn.config(state=tk.DISABLED, text="连接中...") threading.Thread(target=self._adb_connect, args=(ip, port), daemon=True).start() def _adb_connect(self, ip, port): try: cmd = f"adb connect {ip}:{port}" self.append_cmd_output(f"执行: {cmd}") process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, universal_newlines=True ) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: self.root.after(0, self.append_cmd_output, output.strip()) stderr = process.stderr.read() if stderr: self.root.after(0, self.append_cmd_output, f"错误:\n{stderr.strip()}") if process.returncode == 0: self.root.after(0, self.status_bar.config, {"text": f"已连接: {ip}:{port}"}) else: self.root.after(0, self.append_cmd_output, "连接失败!") except Exception as e: self.root.after(0, self.append_cmd_output, f"连接出错: {str(e)}") finally: self.root.after(0, self.connect_btn.config, {"state": tk.NORMAL, "text": "连接设备"}) def _display_partitions(self, partitions): for part in partitions: self.partition_vars[part] = tk.BooleanVar() cb = tk.Checkbutton( self.partition_list_frame, text=part, variable=self.partition_vars[part], anchor='w', bg='#f0f0f0', font=('Arial', 10) ) cb.pack(fill=tk.X, pady=2, padx=5) self.partition_list_frame.update_idletasks() self.partition_canvas.config(scrollregion=self.partition_canvas.bbox("all")) self.partition_canvas.bind_all("<MouseWheel>", lambda event: self.partition_canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")) def toggle_select_all(self): select_all = self.select_all_var.get() for var in self.partition_vars.values(): var.set(select_all) def start_backup(self): selected_partitions = [part for part, var in self.partition_vars.items() if var.get()] if not selected_partitions: messagebox.showwarning("警告", "请至少选择一个分区进行备份") return backup_dir = filedialog.askdirectory(title="选择备份保存目录") if not backup_dir: self.append_cmd_output("备份已取消") return self.append_cmd_output(f"将备份保存到: {backup_dir}") self.backup_btn.config(state=tk.DISABLED, text="备份中,请稍等...") threading.Thread( target=self._perform_backup, args=(selected_partitions, backup_dir), daemon=True ).start() def _perform_backup(self, partitions, backup_dir): try: self.append_cmd_output("准备备份环境...") self._execute_adb_command("adb shell \"rm -rf /sdcard/backup\"") self._execute_adb_command("adb shell \"mkdir -p /sdcard/backup\"") for i, partition in enumerate(partitions): progress = (i + 1) / len(partitions) * 100 self.append_cmd_output(f"正在备份 {partition} ({i + 1}/{len(partitions)}) - {progress:.1f}%") backup_cmd = f"adb shell \"dd if=/dev/block/{partition} | gzip -c > /sdcard/backup/{partition}.img.gz\"" self._execute_adb_command(backup_cmd) self.append_cmd_output("正在从设备下载备份文件...") pull_cmd = f"adb pull /sdcard/backup \"{backup_dir}\"" self._execute_adb_command(pull_cmd) self._execute_adb_command("adb shell \"rm -rf /sdcard/backup\"") self.append_cmd_output(f"备份完成! 文件已保存到: {backup_dir}") messagebox.showinfo("完成", f"备份已完成,文件保存在:\n{backup_dir}") except Exception as e: self.append_cmd_output(f"备份出错: {str(e)}") messagebox.showerror("错误", f"备份过程中出错:\n{str(e)}") finally: self.root.after(0, self.backup_btn.config, {"state": tk.NORMAL, "text": "备份选中分区"}) def _execute_adb_command(self, cmd): self.append_cmd_output(f"执行: {cmd}") process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, universal_newlines=True ) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: self.root.after(0, self.append_cmd_output, output.strip()) stderr = process.stderr.read() if stderr: self.root.after(0, self.append_cmd_output, f"错误:\n{stderr.strip()}") if process.returncode != 0: raise Exception(f"命令执行失败: {cmd}") def append_cmd_output(self, text): self.cmd_text.insert(tk.END, text + "\n") self.cmd_text.see(tk.END) if __name__ == "__main__": root = tk.Tk() app = ADBBackupTool(root) root.mainloop() 在这个基础上曾加http下载 sparsege格式 这个先取消
07-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值