当前位置: 首页 > news >正文

qt实现一个安卓测试小工具

qt实现一个安卓测试小工具

  • 最终效果:
  • 目录结构
  • 源码
    • gui.py 主要是按钮,文本控制代码
    • main.py 主要是逻辑代码
    • gui.spec 是打包使用的
    • adb.ui
  • 打包为exe

最终效果:

在这里插入图片描述
在这里插入图片描述

目录结构

上面2个是打包的生成的不用管
在这里插入图片描述

源码

gui.py 主要是按钮,文本控制代码

from PySide2.QtCore import QTimer, QTime, QDateTime
from PySide2.QtWidgets import QApplication, QMessageBox
from PySide2.QtUiTools import QUiLoader
from main import PackNameOperate, Log, wifi_adb_connect, Devices, input_text,LogcatManager,capture_screenshot
import os, sys
import subprocessdev = Devices()
log=LogcatManager('D:/jb/logcat')def processPath(path):''':param path: 相对于根目录的路径:return: 拼接好的路径'''if getattr(sys, 'frozen', False):  # 判断是否存在属性frozen,以此判断是打包的程序还是源代码。false为默认值,即没有frozen属性时返回falsebase_path = sys._MEIPASS  # 该属性也是打包程序才会有,源代码尝试获取该属性会报错else:base_path = os.path.abspath(".")  # 当源代码运行时使用该路径return os.path.join(base_path, path)txt=r'''1、日志保存路径'D:\jb\logcat',截图保存路径'D:\jb\tu',路径不存在会自动创建
2、应用切换功能是输入2个包名,点一下按钮可以切换到其中一个,在点一下就是切到另一个,如此循环
3、开启wifi adb是新开一个tcpip端口进行wifiadb连接,开启成功后马上拔掉adb线,不然这个wifiadb会被干掉,当然也可以在点一次
4、如果按钮啥的不起作用,可以看看是不是设备离线了,把adb线拔了在插上就可以了,按钮被禁用是检查到没有设备连接而不是设备离线。 ゚゚・。・゚゚。       ゚。        。゚    ゚・。・゚    ︵                 ︵(        ╲        /       /╲          ╲/       /╲          ╲  /╭ ͡   ╲          ╲╭ ͡   ╲        ╲         ノ
╭ ͡   ╲        ╲         ╱╲
'''
class Stats:def __init__(self):self.kill_list = ['获取当前运行的包名','杀掉当前启动的app','清除当前app缓存信息', '清楚缓存并且杀掉app', '清楚缓存并且杀掉app并且重新启动']self.ui = QUiLoader().load(processPath('adb.ui'))# 下拉框添加内容self.ui.kill_apps.addItems(self.kill_list)# 按钮点击事件self.ui.qd_app.clicked.connect(self.qd)self.ui.zx.clicked.connect(self.kill)self.ui.get_log.clicked.connect(self.log)self.ui.disable.clicked.connect(self.wifi_disable)self.ui.enable.clicked.connect(self.wifi_enable)self.ui.bk.clicked.connect(self.bluetooth_enable)self.ui.bg.clicked.connect(self.bluetooth_disable)self.ui.huqie.clicked.connect(self.hq)self.ui.wifi_adb.clicked.connect(self.wifi_adb_)self.ui.write_in.clicked.connect(self.text_write_in)self.ui.get_device.clicked.connect(self.devices)self.ui.suoyou.clicked.connect(self.suoyou_log)self.ui.dell.clicked.connect(self.del_log)self.ui.time.clicked.connect(self.yl)self.ui.jt.clicked.connect(self.jietu)self.timer1 = QTimer()self.timer1.setInterval(5000)  # 设置定时器1的触发间隔为3秒self.timer1.timeout.connect(self.devices)self.timer1.start()self.devices()self.timer2 = QTimer()self.timer2.setInterval(1000)  # 设置定时器2的触发间隔为1秒self.timer2.timeout.connect(self.update_button_text)self.timer2.start()self.update_button_text()  # 初始self.ui.ttt.setPlainText(txt)def update_button_text(self):current_datetime = QDateTime.currentDateTime()time_text = current_datetime.toString('yyyy-MM-dd dddd hh:mm:ss')self.ui.time.setText(time_text)def check_adb_connection(self, d):'''控制按钮是否都可用'''buttons = [self.ui.qd_app,self.ui.zx,self.ui.get_log,self.ui.disable,self.ui.enable,self.ui.bk,self.ui.bg,self.ui.huqie,self.ui.wifi_adb,self.ui.write_in,self.ui.get_device,self.ui.suoyou,self.ui.dell,self.ui.time,self.ui.jt]for button in buttons:button.setEnabled(d)def qd(self):'''app根据包名启动'''pack_name = self.ui.pack_name.text()if PackNameOperate.pack_name_start(pack_name) == 1:QMessageBox.critical(self.ui, '包名错误', '请检查包名是否输入正确!')else:QMessageBox.information(self.ui, '操作成功', f'{pack_name}启动完成')# QMessageBox.close()def kill(self):'''app杀后台,清除缓存,启动等组合操作'''xz = self.ui.kill_apps.currentText()index = self.kill_list.index(xz)if PackNameOperate.kill_app(index) == 0:QMessageBox.information(self.ui, '操作成功', f'"{xz}"执行完成')elif '包名' in PackNameOperate.kill_app(index):QMessageBox.information(self.ui, '操作成功', PackNameOperate.kill_app(index))else:QMessageBox.critical(self.ui, '错误', '设备未连接或者未启动adb模式')def log(self):'''抓日志'''Log.test()def wifi_enable(self):subprocess.getoutput('adb shell svc wifi enable')QMessageBox.information(self.ui, '操作成功', f'wifi已打开')def wifi_disable(self):subprocess.getoutput('adb shell svc wifi disable')QMessageBox.information(self.ui, '操作成功', f'wifi已关闭')def bluetooth_enable(self):subprocess.getoutput('adb shell svc bluetooth enable')QMessageBox.information(self.ui, '操作成功', f'帅哥蓝牙已打开')def bluetooth_disable(self):subprocess.getoutput('adb shell svc bluetooth disable')QMessageBox.information(self.ui, '操作成功', f'蓝牙已关闭')def wifi_adb_(self):ml = wifi_adb_connect()if ml[0]==0:QMessageBox.information(self.ui, '操作成功', f'已经连接wifiadb成功,命令为:{ml[1]},请3s内拔掉adb线')else:QMessageBox.information(self.ui, '操作失败', f'开启失败,命令为:{ml[1]},未获取到ip信息,检查是否处于同一个wifi')def text_write_in(self):text = self.ui.text.text()input_text(text)# subprocess.run(['adb', 'shell', 'input', 'text', text])QMessageBox.information(self.ui, '操作成功', '写入完成')def jietu(self):capture_screenshot()QMessageBox.information(self.ui, '操作成功', '截图成功')def devices(self):d = dev.dev_id()'''获取当前连接的设备id'''if d[0] == 0:devices_info = d[1]self.check_adb_connection(True)elif d[0] == 00:devices_info = d[1]self.check_adb_connection(True)else:devices_info = d[1]self.check_adb_connection(False)self.ui.device.setText(str(devices_info))def suoyou_log(self):log.save_logcat()QMessageBox.information(self.ui, '操作成功', '日志导出完成')def del_log(self):log.clear_logcat()QMessageBox.information(self.ui, '操作成功', '日志清除完成')def yl(self):QMessageBox.information(self.ui, '嘿嘿', '要天天开心呀')def hq(self):'''2个应用互切'''pack_1 = self.ui.pack1.text()pack_2 = self.ui.pack2.text()print(pack_1, pack_2)if pack_1 == '':QMessageBox.information(self.ui, '操作失败', '包名1填下,谢谢')elif pack_2 == '':QMessageBox.information(self.ui, '操作失败', '包名2填下,谢谢')elif PackNameOperate.huqie(pack_1, pack_2) == 11:QMessageBox.information(self.ui, '操作失败', f'找不到{pack_1}这个包')elif PackNameOperate.huqie(pack_1, pack_2) == 12:QMessageBox.information(self.ui, '操作失败', f'找不到{pack_2}这个包')elif PackNameOperate.huqie(pack_1, pack_2) == 1:QMessageBox.information(self.ui, '操作失败', '当前运行的应用不是输入自定义的2个互切应用')elif pack_1 == pack_2:QMessageBox.information(self.ui, '操作成功', '一个包写2遍没太大必要啊')else:QMessageBox.information(self.ui, '操作成功', '切换完成')app = QApplication([])
stats = Stats()
stats.ui.show()
app.exec_()

main.py 主要是逻辑代码

import os
import re
import shutil
import subprocess
import time
from time import sleep
import datetimeclass PackNameOperate():@classmethoddef pack_name_start(cls, pack_name):'''根据包名启动app'''output = subprocess.getoutput(f'adb shell monkey -p {pack_name} --throttle 1 -s 2 -v -v -v 1')if 'No activities found to run, monkey aborted' in output:print('车机不存在该包名,请检查包名是否输入正确')return 1else:return 0@classmethoddef kill_app(cls, l):''':param l: 0不输入是获取当前运行的包名,1是杀掉当前启动的app,2是清除当前app缓存信息,3是清楚缓存并且杀掉app,4是根据上一个前三个操作的包名启动app:return:'''output = subprocess.getoutput('adb shell dumpsys window | findstr mCurrentFocus')if not output == '':try:pack_name = 'com.' + re.findall(r'com.(.*?)/com', output)[0]except:pack_name = 'com.' + re.findall(r'com.(.*?)/io', output)[0]if l == 0:print(f'当前运行的包名是{pack_name}')return f'当前运行的包名是{pack_name}'if l == 1:subprocess.getoutput(f'adb shell am force-stop {pack_name}')print(f'包名为{pack_name}的app已经杀掉')elif l == 2:subprocess.getoutput(f'adb shell pm clear {pack_name}')print(f'包名为{pack_name}的app缓存清楚成功')elif l == 3:subprocess.getoutput(f'adb shell pm clear {pack_name}')subprocess.getoutput(f'adb shell am force-stop {pack_name}')print(f'包名为{pack_name}的app清楚缓存并且杀掉成功')elif l == 4:subprocess.getoutput(f'adb shell pm clear {pack_name}')subprocess.getoutput(f'adb shell am force-stop {pack_name}')cls.pack_name_start(pack_name)print(f'包名为{pack_name}的app清楚缓存并且杀掉成功')print(f'{pack_name}重新启动完成')return 0print('设备未连接或者未启动adb模式')return 1@classmethoddef get_pack_name(cls):output = subprocess.getoutput('adb shell dumpsys window | findstr mCurrentFocus')try:pack_name = 'com.' + re.findall(r'com.(.*?)/com', output)[0]except:pack_name = 'com.' + re.findall(r'com.(.*?)/io', output)[0]# print(f'当前运行的包名是{pack_name}')return pack_name@classmethoddef huqie(cls, pack1, pack2):a = cls.get_pack_name()print(f'当前在运行的包名{a}')if a == pack1:if cls.pack_name_start(pack2) == 1:# 说明包名不对return 12elif a == pack2:if cls.pack_name_start(pack1) == 1:return 11else:print('当前运行的应用不输入自定义的2个互切应用')return 1class Log():@classmethoddef test(cls):for i in range(4):sleep(0.3)print(f'控制台打印{i}')# @classmethod# def move_file(cls, besave_dir=ys__log_path, fm='zip'):#     """#     将文件夹压缩成指定格式的压缩包#     :param besave_dir: 压缩文件夹的目录 如 ---r"D:\log_dir"#     :param format: 压缩的格式:"zip", "tar", "gztar","bztar", "xztar"#     :return:#     """#     if os.path.exists(besave_dir):#         zip_name = shutil.make_archive(besave_dir, f'{fm}', besave_dir)#         print(zip_name)  # 返回文件的最终路径## @classmethod# def del_dir(cls, dir_path=pc_log_path):#     '''删除目录下所有文件'''#     for filename in os.listdir(dir_path):#         file_path = os.path.join(dir_path, filename)#         if os.path.isfile(file_path) or os.path.islink(file_path):#             os.unlink(file_path)#         elif os.path.isdir(file_path):#             shutil.rmtree(file_path)## @classmethod# def log(cls):#     cls.del_dir()#     subprocess.getoutput(f'adb pull {cj_log_path} {pc_log_path}')#     cls.move_file()# Log.test()def wifi_adb_connect():def get_car_wifi_ip():process = subprocess.run(['adb', 'shell', 'ifconfig', 'wlan0'], capture_output=True, text=True)output = process.stdout.strip()ip_line = [line for line in output.split('\n') if 'inet addr' in line]if len(ip_line) > 0:ip = ip_line[0].split()[1].split(':')[1]subprocess.run(['adb', 'tcpip', '6666'])print(f'端口号6666')return ipelse:return None# 使用示例:获取车机的WiFi IPcar_wifi_ip = get_car_wifi_ip()print(car_wifi_ip)# ip = car_wifi_ipsubprocess.run(['adb', 'disconnect'])subprocess.run(['adb', 'connect', f'{car_wifi_ip}:6666'])# 获取连接状态输出result = subprocess.run(['adb', 'devices'], capture_output=True, text=True)output = result.stdout.strip().encode('utf-8').decode('gbk')print(output)if '不知道这样的主机' in output:return 1,outputelse:return 0, f'adb connect {car_wifi_ip}:6666'class Devices:def check_adb_connection(self):try:# 检查连接状态command = 'adb devices'output = subprocess.check_output(command.split()).decode().strip()# 检查输出结果中是否包含设备列表if 'List of devices attached' in output:# 提取设备列表devices = output.split('\n')[1:]# 检查设备列表是否为空if len(devices) > 0:# 提取所有设备的设备IDdevice_ids = [device.split('\t')[0] for device in devices]return device_idselse:return Noneelse:return Noneexcept subprocess.CalledProcessError:return Nonedef dev_id(self):device_ids = self.check_adb_connection()# if 'offline' in subprocess.getoutput(f'adb shell'):#     subprocess.run(['adb', 'kill-server'])#     time.sleep(1)#     subprocess.run(['adb', 'start-server'])#     print('检测到设备离线,重启adb服务解决中')if device_ids is not None:if len(device_ids) == 1:# print(f"设备ID: {device_ids[0]}")return 0, f"设备ID: {device_ids[0]}"elif len(device_ids) > 1 :# 清除所有连接subprocess.run(['adb', 'disconnect'])# print(f'干掉了{device_ids[1:]}等设备')return 00, f"设备ID: {device_ids[0]},干掉了{device_ids[1:]}等设备"else:return 1else:# print("ADB未成功连接到任何设备")return 1, "ADB未成功连接到任何设备,按钮全部禁用"def input_text(text):# 转义特殊字符text = text.replace('\\', '\\\\').replace('"', '\\"')# 执行 adb shell input text 命令subprocess.run(['adb', 'shell', 'input', 'text', f'"{text}"'])class LogcatManager:def __init__(self, save_directory):self.save_directory = save_directorydef _get_device_info(self):# 获取设备的Android版本android_version_cmd = ['adb', 'shell', 'getprop', 'ro.build.version.release']android_version_process = subprocess.Popen(android_version_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)android_version_output, _ = android_version_process.communicate()android_version = android_version_output.strip()# 获取屏幕分辨率screen_resolution_cmd = ['adb', 'shell', 'wm', 'size']screen_resolution_process = subprocess.Popen(screen_resolution_cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, universal_newlines=True)screen_resolution_output, _ = screen_resolution_process.communicate()screen_resolution = screen_resolution_output.strip().split()[2]# 获取系统版本信息system_info_cmd = ['adb', 'shell', 'getprop', 'ro.build.description']system_info_process = subprocess.Popen(system_info_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)system_info_output, _ = system_info_process.communicate()system_info = system_info_output.strip()return android_version, screen_resolution, system_infodef _create_directory(self, directory):if not os.path.exists(directory):os.makedirs(directory)def _get_current_time(self):return datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S')def _build_file_name(self, android_version, screen_resolution, system_info):current_time = self._get_current_time()file_name = f'{current_time}.Android{android_version}.{screen_resolution}.{system_info}.logcat.txt'return file_namedef _build_file_path(self, file_name):file_path = os.path.join(self.save_directory, file_name)return file_pathdef _export_logcat(self, file_path):# 执行 adb logcat -d 命令,导出日志到文件cmd = ['adb', 'logcat', '-d']process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)# 检查目录是否存在,如果不存在则创建目录self._create_directory(self.save_directory)try:with open(file_path, 'wb') as file:for line in process.stdout:file.write(line)print(f'Logcat已成功导出到文件:{file_path}')except Exception as e:print(f'保存Logcat文件时发生错误:{e}')def save_logcat(self):# 获取设备信息android_version, screen_resolution, system_info = self._get_device_info()# 构建文件名file_name = self._build_file_name(android_version, screen_resolution, system_info)# 构建完整的文件路径file_path = self._build_file_path(file_name)# 导出Logcat并保存到文件self._export_logcat(file_path)# return 'Logcat已成功导出成功'## def save_realtime_logcat(self):#     # 获取设备信息#     android_version, screen_resolution, system_info = self._get_device_info()##     # 构建文件名#     file_name = self._build_file_name(android_version, screen_resolution, system_info)##     # 构建完整的文件路径#     file_path = self._build_file_path(file_name)#     # 执行 adb logcat 命令,实时保存日志到文件#     cmd = ['adb', 'logcat']#     print(f'实时保存的Logcat已成功保存到文件:{file_path}')#     with open(file_path, 'w') as file:#         process = subprocess.Popen(cmd, stdout=file, stderr=subprocess.PIPE, universal_newlines=True)#         try:#             process.wait()#         except KeyboardInterrupt:#             process.terminate()def clear_logcat(self):# 执行 adb shell logcat -c 命令,清除Logcat日志cmd = ['adb', 'shell', 'logcat', '-c']subprocess.run(cmd)print('Logcat日志已清除')# return 'Logcat日志已清除'
def capture_screenshot():from datetime import datetime# 获取当前时间并格式化为字符串current_time = datetime.now().strftime("%Y-%m-%d-%H_%M_%S")# 创建目录directory = "D:/jb/tu/"os.makedirs(directory, exist_ok=True)# 执行ADB命令进行截图subprocess.run(["adb", "shell", "screencap", "-p", "/sdcard/screenshot.png"])# 将截图文件复制到本地目录local_path = os.path.join(directory, f"{current_time}.png")subprocess.run(["adb", "pull", "/sdcard/screenshot.png", local_path])return 0

gui.spec 是打包使用的

# -*- mode: python ; coding: utf-8 -*-block_cipher = Nonea = Analysis(['gui.py'],pathex=[],binaries=[],datas=[('adb.ui','.')],hiddenimports=[],hookspath=[],hooksconfig={},runtime_hooks=[],excludes=[],win_no_prefer_redirects=False,win_private_assemblies=False,cipher=block_cipher,noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)exe = EXE(pyz,a.scripts,a.binaries,a.zipfiles,a.datas,[],name='shy',debug=False,bootloader_ignore_signals=False,strip=False,upx=True,upx_exclude=[],runtime_tmpdir=None,console=True,disable_windowed_traceback=False,argv_emulation=False,target_arch=None,codesign_identity=None,entitlements_file=None,icon=['i.ico'],
)

adb.ui

是qt设计师生成的ui界面,设置属性配合代码操作

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>adb_shell</class><widget class="QWidget" name="adb_shell"><property name="geometry"><rect><x>0</x><y>0</y><width>768</width><height>564</height></rect></property><property name="windowTitle"><string>安卓测试操作</string></property><layout class="QVBoxLayout" name="verticalLayout_4"><item><widget class="QPushButton" name="time"><property name="text"><string>时间</string></property></widget></item><item><widget class="QTabWidget" name="tabWidget"><property name="currentIndex"><number>0</number></property><widget class="QWidget" name="widget"><property name="minimumSize"><size><width>0</width><height>18</height></size></property><attribute name="title"><string>常用操作</string></attribute><layout class="QVBoxLayout" name="verticalLayout_2"><item><widget class="QGroupBox" name="groupBox"><property name="title"><string>根据包名操作</string></property><layout class="QVBoxLayout" name="verticalLayout"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><widget class="QLineEdit" name="pack_name"><property name="placeholderText"><string>请输入app包名</string></property></widget></item><item><widget class="QPushButton" name="qd_app"><property name="text"><string>启动app</string></property></widget></item></layout></item><item><layout class="QHBoxLayout" name="horizontalLayout_2"><item><widget class="QComboBox" name="kill_apps"/></item><item><widget class="QPushButton" name="zx"><property name="text"><string>执行</string></property></widget></item></layout></item><item><layout class="QHBoxLayout" name="horizontalLayout_3"><item><widget class="QLineEdit" name="pack1"><property name="placeholderText"><string>包名1</string></property></widget></item><item><widget class="QLineEdit" name="pack2"><property name="placeholderText"><string>包名2</string></property></widget></item><item><widget class="QPushButton" name="huqie"><property name="text"><string>应用切换</string></property></widget></item></layout></item><item><widget class="QGroupBox" name="groupBox_3"><property name="title"><string>系统控制</string></property><layout class="QVBoxLayout" name="verticalLayout_3"><item><layout class="QHBoxLayout" name="horizontalLayout_4"><item><widget class="QPushButton" name="wifi_adb"><property name="text"><string>开启wifiadb</string></property></widget></item><item><widget class="QPushButton" name="enable"><property name="text"><string>wifi打开</string></property></widget></item><item><widget class="QPushButton" name="disable"><property name="text"><string>wifi关闭</string></property></widget></item><item><widget class="QPushButton" name="bk"><property name="text"><string>蓝牙打开</string></property></widget></item><item><widget class="QPushButton" name="bg"><property name="text"><string>蓝牙关闭</string></property></widget></item></layout></item></layout></widget></item><item><widget class="QLineEdit" name="text"/></item><item><widget class="QPushButton" name="write_in"><property name="text"><string>开始写入文本(不支持中文)</string></property></widget></item><item><widget class="QLineEdit" name="device"><property name="text"><string/></property></widget></item><item><widget class="QPushButton" name="get_device"><property name="text"><string>查询当前连接的设备(5s自动查询一次)</string></property></widget></item></layout></widget></item></layout></widget><widget class="QWidget" name="tab_6"><attribute name="title"><string>日志操作和使用说明</string></attribute><layout class="QVBoxLayout" name="verticalLayout_6"><item><layout class="QVBoxLayout" name="verticalLayout_5"><item><layout class="QHBoxLayout" name="horizontalLayout_5"><item><widget class="QPushButton" name="jt"><property name="text"><string>截图</string></property></widget></item><item><widget class="QPushButton" name="dell"><property name="text"><string>清除logcat</string></property></widget></item><item><widget class="QPushButton" name="suoyou"><property name="text"><string>抓取从现在到之前的所有logcat</string></property></widget></item><item><widget class="QPushButton" name="get_log"><property name="text"><string>控制台打印测试</string></property><property name="iconSize"><size><width>10</width><height>10</height></size></property></widget></item></layout></item><item><widget class="QPlainTextEdit" name="ttt"><property name="readOnly"><bool>true</bool></property></widget></item></layout></item></layout></widget></widget></item></layout></widget><resources/><connections/>
</ui>

打包为exe

https://blog.csdn.net/aaaaaaaaanjjj/article/details/134157127

相关文章:

qt实现一个安卓测试小工具

qt实现一个安卓测试小工具 最终效果&#xff1a;目录结构源码gui.py 主要是按钮&#xff0c;文本控制代码main.py 主要是逻辑代码gui.spec 是打包使用的adb.ui 打包为exe 最终效果&#xff1a; 目录结构 上面2个是打包的生成的不用管 源码 gui.py 主要是按钮&#xff0c;文…...

驾驭未来,智能化管理——汽车ERP系统

在汽车行业竞争日益激烈的今天&#xff0c;如何提高生产效率、优化供应链管理&#xff0c;确保产品质量和客户满意度成为汽车制造企业亟需解决的难题。为解决这一问题&#xff0c;汽车企业资源计划&#xff08;ERP&#xff09;系统应运而生。本文将为您介绍汽车ERP系统&#xf…...

flutter开发实战-当前界面无操作60s返回主页实现

flutter开发实战-当前界面无操作60s返回主页实现 当前界面无操作60s返回主页实现&#xff0c;主要是通过Timer来控制&#xff0c;当监听界面是否有pointerDown时候&#xff0c;如果超过60s仍没有操作&#xff0c;则返回主页。 一、Listener Listener是用来用于调用回调以响应…...

绩效考核的基础及基本内容

人力资源是企业的第一资源&#xff0c;员工绩效水平决定着人力资源价值的实现程度&#xff0c;绩效是企业永远的重点&#xff0c;没有绩效&#xff0c;一切无从谈起。很多企业在实施考核时扩大了绩效考核的积极作用&#xff0c;并没有考虑企业对绩效考核负面效应的承载能力&…...

阿坤老师的彩带插花(蓝桥杯)

阿坤老师的彩带插花 问题描述 阿坤老师是个充满创意的手工艺教师&#xff0c;他最近在教学生们制作彩带插花。每束彩带插花由多段彩带组成&#xff0c;每段彩带有左端和右端&#xff0c;左端到右端的长度不一。阿坤老师发现&#xff0c;有些彩带被完全插在了其他彩带之内&…...

系列二十四、Spring设计模式之策略模式

一、前言 对于我们Java开发人员来说&#xff0c;Spring框架的重要性不言而喻&#xff0c;可以说Java领域之所以发展这么壮大&#xff0c;生态这么丰富&#xff0c;功能这么强大&#xff0c;是离不开Spring以及由其衍生出来的各种子模块的&#xff0c;正是由它们共同奠定了JavaE…...

Linux常用命令——basename命令

在线Linux命令查询工具 basename 打印目录或者文件的基本名称 补充说明 basename命令用于打印目录或者文件的基本名称。basename和dirname命令通常用于shell脚本中的命令替换来指定和指定的输入文件名称有所差异的输出文件名称。 语法 basename(选项)(参数)选项 --help&…...

LeetCode17.电话号码的字母组合

写这题的时候没有啥DFS思路&#xff0c;感觉还是DFS没刷明白&#xff0c;还需要多提高 参考链接&#xff1a; 【还得用回溯算法&#xff01;| LeetCode&#xff1a;17.电话号码的字母组合-哔哩哔哩】 https://b23.tv/oTuy71C class Solution {public List<String> lette…...

为Oracle链接服务器使用分布式事务

1 现象 在SQL Server中创建指向Oracle的链接服务器&#xff0c;SQL语句在事务中向链接服务器插入数据。返回链接服务器无法启动分布式事务的报错。 2 解决 在Windows平台下&#xff0c;SQL Server依赖分布式事务协调器&#xff08;MSDTC&#xff09;来使用分布式事务&#xff0…...

代洋集团,引领绿色能源新潮流

代洋集团&#xff0c;引领绿色能源新潮流&#xff0c;成功安装了先进的太阳能电池阵列。这一环保举措&#xff0c;不仅彰显了我们对可持续发展的执着追求&#xff0c;更为整个园区带来了绿色能源的革新。 这个高效的太阳能电池阵列&#xff0c;利用纯净的阳光转化为清洁电力&a…...

LuatOS-SOC接口文档(air780E)--rtos - RTOS底层操作库

rtos.receive(timeout) 接受并处理底层消息队列. 参数 传入值类型 解释 int 超时时长,通常是-1,永久等待 返回值 返回值类型 解释 msgid 如果是定时器消息,会返回定时器消息id及附加信息, 其他消息由底层决定,不向lua层进行任何保证. 例子 无 rtos.timer_start(id…...

一名技术Leader应该是创作者

今天看了一本书叫做《黑客与画家》。它里面提到一个很重要的概念就是黑客&#xff08;优秀的程序员&#xff09;是一名建筑师&#xff0c;而不是一名工程师。 传统的主管和互联网的Leader 这两者有什么区别呢&#xff1f;关键点在于建筑师是思考做什么&#xff0c;而工程师是…...

Java多线程总结

一、概念&#xff1a; 1、什么是多任务 多任务就是在同一时间做多件事情&#xff0c;如边吃饭边玩手机等。看起来是多个任务都在做&#xff0c;本质上我们的大脑在同一时间依旧只做了一件件事情 2、什么是程序 程序是指令和数据的有序集合&#xff0c;其本身没有…...

docker devicemapper: Error running DeleteDevice dm_task_run failed

docker 删除容器&#xff0c;遇到&#xff1a; devicemapper: Error running DeleteDevice dm_task_run failed 异常 [hadoophadoop02 ~]$ sudo docker rm 5ede1280f0bf Error response from daemon: container 5ede1280f0bf791e91d40038b15decd42e8923546ae578abd96e08114c76…...

第二十章总结

一.线程简介 二.创建线程 1.继承Thread类 Thread类中常用的两个构造方法如下&#xff1a; public Thread():创建一个新的线程对象。 public Thread(String threadName):创建一个名称为threadName的线程对象。 继承Thread类创建一个新的线程的语法如下&#xff1a; public …...

Linux环境安装Java,Tomcat,Mysql,

1、Java的安装 载 jdk1.8 注&#xff1a;此处 CentOS7 是64位&#xff0c;所以下载的是&#xff1a;Linux x64&#xff0c; 文件类型为 tar.gz 的文件 JDK 官网地址&#xff1a;https://www.oracle.com/java/ cd /usr/local/ mkdir jdk cd jdk/tar -xvf jdk-8u202-linux-x64.…...

前后端分离开发出现的跨域问题

先说说什么是跨域。 请求的URL地址中的协议、域名、端口号中的任意一个与当前URL不同就是跨域。 比如&#xff1a; 当前页面的URL请求的URL是否跨域原因htttp://localhost:8080htttps://localhost:8080是协议不同htttp://localhostll:8080htttp://localhost:8080是域名不同htt…...

水淼采集器-免费水淼采集器下载

在当今数字时代&#xff0c;随着信息的迅猛增长&#xff0c;许多网站管理员面临一个共同而具有挑战性的问题——如何在短时间内获取大量优质内容&#xff0c;以满足用户对信息的不断需求&#xff1f;水淼采集器&#xff0c;作为一个备受瞩目的解决方案&#xff0c;正成为许多人…...

[DASCTF 2023 0X401七月暑期挑战赛] web刷题记录

文章目录 EzFlask方法一 python原型链污染方法二 flask框架静态文件方法三 pin码计算 MyPicDisk方法一 字符串拼接执行命令方法二 phar反序列化 ez_cms EzFlask 考点&#xff1a;python原型链污染、flask框架理解、pin码计算 源码如下 import uuidfrom flask import Flask, re…...

Python超级详细的变量命名规则

Python 需要使用标识符给变量命名&#xff0c;其实标识符就是用于给程序中变量、类、方法命名的符号&#xff08;简单来说&#xff0c;标识符就是合法的名字&#xff09;。 Python 语言的标识符必须以字母、下画线&#xff08;_&#xff09;开头&#xff0c;后面可以跟任意数目…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架

1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...

从0开始学习R语言--Day17--Cox回归

Cox回归 在用医疗数据作分析时&#xff0c;最常见的是去预测某类病的患者的死亡率或预测他们的结局。但是我们得到的病人数据&#xff0c;往往会有很多的协变量&#xff0c;即使我们通过计算来减少指标对结果的影响&#xff0c;我们的数据中依然会有很多的协变量&#xff0c;且…...

Yolo11改进策略:Block改进|FCM,特征互补映射模块|AAAI 2025|即插即用

1 论文信息 FBRT-YOLO&#xff08;Faster and Better for Real-Time Aerial Image Detection&#xff09;是由北京理工大学团队提出的专用于航拍图像实时目标检测的创新框架&#xff0c;发表于AAAI 2025。论文针对航拍场景中小目标检测的核心难题展开研究&#xff0c;重点解决…...