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

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

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

最终效果:

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

目录结构

上面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 subprocess

dev = Devices()
log=LogcatManager('D:/jb/logcat')

def processPath(path):
    '''
    :param path: 相对于根目录的路径
    :return: 拼接好的路径
    '''
    if getattr(sys, 'frozen', False):  # 判断是否存在属性frozen,以此判断是打包的程序还是源代码。false为默认值,即没有frozen属性时返回false
        base_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 datetime

class PackNameOperate():
    @classmethod
    def 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 1
        else:
            return 0

    @classmethod
    def 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 0
        print('设备未连接或者未启动adb模式')
        return 1

    @classmethod
    def 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

    @classmethod
    def huqie(cls, pack1, pack2):
        a = cls.get_pack_name()
        print(f'当前在运行的包名{a}')
        if a == pack1:
            if cls.pack_name_start(pack2) == 1:
                # 说明包名不对
                return 12
        elif a == pack2:
            if cls.pack_name_start(pack1) == 1:
                return 11
        else:
            print('当前运行的应用不输入自定义的2个互切应用')
            return 1


class Log():
    @classmethod
    def 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 ip
        else:
            return None

    # 使用示例:获取车机的WiFi IP
    car_wifi_ip = get_car_wifi_ip()
    print(car_wifi_ip)
    # ip = car_wifi_ip
    subprocess.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,output
    else:
        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:
                    # 提取所有设备的设备ID
                    device_ids = [device.split('\t')[0] for device in devices]
                    return device_ids
                else:
                    return None
            else:
                return None
        except subprocess.CalledProcessError:
            return None


    def 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 1
        else:
            # 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_directory



    def _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_info

    def _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_name

    def _build_file_path(self, file_name):
        file_path = os.path.join(self.save_directory, file_name)
        return file_path

    def _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 = None


a = 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/197103.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3怎么提升效率的?为什么vue3比vue2快?效率提升主要在哪些方面?

官方文档中说vue3在 客户端渲染效率比vue2提升了1.3~2倍&#xff0c; SSR渲染效率比vue2提升了2~3倍&#xff0c;那么究竟是怎么提升的呢&#xff1f; 一、静态提升 在 vue3项目中的package.json文件中&#xff0c;可以看到这个 vue/compiler-sfc&#xff0c;它是用来解析(.v…

数据在内存中的存储练习题

数据在内存中的存储练习题 文章目录 数据在内存中的存储练习题1. 练习一2.练习二3. 练习三4. 练习四5. 练习五6. 练习六7. 总结 1. 练习一 #include <stdio.h>int main() {char a -1;signed b -1;unsigned char c -1;printf("a %d b %d c %d", a, b, c)…

PHP+vue+elementui高校学生社团信息管理系统o7q4a

社团是由高校用户依据兴趣爱好自愿组成&#xff0c;按照章程自主开展活动的用户组织。高校社团是实施素质教育的重要途径和有效方式&#xff0c;在加强校园文化建设、提高用户综合素质、引导用户适应社会、促进用户交流等方面发挥着重要作用&#xff0c;是新形势下有效凝聚用户…

Echarts legend图例配置项 设置位置 显示隐藏

Echarts 官网完整配置项 https://echarts.apache.org/zh/option.html#legend 配置项 legend: { }设置图例为圆形 icon: circle,//设置图例为圆形设置图例位置 top: 20%//距离顶部百分之20//y:bottom 在底部显示设置图例 宽度 高度 itemWidth: 10,//设置图例宽度 itemHeight: …

PCL 计算点云图中任意两点的欧式距离

目录 一、算法原理二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 使用PCL实现在可视化界面上用鼠标点选两个点,输出两点的坐标和两点之间的欧式距离。 二、代码…

HttpRunner原来还能这么用,大开眼界!!!

hook机制 Httprunner 框架中的 hook 机制相当于unittest框架中的 setup , teardown 函数&#xff0c;用来进行测试用例执行之前的环境初始化以及测试用例执行完毕之后的环境清理操作。 httprunner 中的 hooks 机制可以用在测试用例层级也可以用在测试步骤层级&#xff0c;其关键…

OSG编程指南<十三>:OSG渲染状态

1、前言 在 OSG 中存在两棵树&#xff0c;即场景树和渲染树。渲染树是一棵以 StateSet 和 RenderLeaf 为节点的树&#xff0c;它可以做到 StateSet 相同的 RenderLeaf 同时渲染而不用切换 OpenGL状态&#xff0c;并且做到尽量少但在多个不同 State 间切换。渲染树在 CullVisito…

01 项目架构

关于我 曾经就职于蚂蚁金服&#xff0c;多年的后端开发经验&#xff0c;对微服务、架构这块研究颇深&#xff0c;同时也是一名热衷于技术分享、拥抱开源技术的博主。 个人技术公众号&#xff1a;码猿技术专栏个人博客&#xff1a;www.java-family.cn 前期一直在更新《Spring…

sqli-labs关卡21(基于cookie被base64编码的报错盲注)通关思路

文章目录 前言一、回顾上一关知识点二、靶场需要了解的前置知识1、什么是base64编码&#xff1f; 三、靶场第二十一关通关思路1、判断注入点2、爆数据库名3、爆数据库表4、爆数据库列5、爆数据库关键信息 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于…

Funbox9_GaoKao通过NC获取反向shell

一. 发现主机 arp-scan -l -I eth0 找打GaoKao主机IP地址 173.30.1.128 二. Nmap扫描主机 nmap -A -T5 172.30.1.128 -A &#xff1a;系统探测&#xff0c;版本检测&#xff0c;脚本扫描&#xff0c;路由跟踪 -T(0-5)&#xff1a;数字越大速度越快(准确度低)&#xff0c;数字越…

vue+echarts实现依赖关系无向网络拓扑结图节点折叠展开策略

目录 引言 一、设计 1. 树状图&#xff08;不方便呈现节点之间的关系&#xff0c;次要考虑&#xff09; 2. 力引导依赖关系图 二、力引导关系图 三、如何实现节点的Open Or Fold 1. 设计逻辑 节点展开细节 节点收缩细节 代码实现 四、结果呈现 五、完整代码 引言 我…

离散数学-集合论基础

3.1集合的基本概念 1&#xff09;集合及元素 2&#xff09;集合的表示 3&#xff09;集合的关系 4&#xff09;特殊集合 3.2集合的运算 并、交、差、对称差 3.3集合的划分与覆盖 3.4排斥包含管理 3.1集合的基本概念 1&#xff09;集合及元素 将某种具有同种属性的个体…

扩散模型实战(十三):ControlNet结构以及训练过程

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xff…

振南技术干货集:znFAT 硬刚日本的 FATFS 历险记(9)

注解目录 1、znFAT 的起源 1.1 源于论坛 &#xff08;那是一个论坛文化兴盛的年代。网友 DIY SDMP3 播放器激起了我的兴趣。&#xff09; 1.2 硬盘 MP3 推了我一把 &#xff08;“坤哥”的硬盘 MP3 播放器&#xff0c;让我深陷 FAT 文件系统不能自拔。&#xff09; 1.3 我…

智能优化算法应用:基于缎蓝园丁鸟算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于缎蓝园丁鸟算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于缎蓝园丁鸟算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.缎蓝园丁鸟算法4.实验参数设定5.算法结果…

WIN10 x86环境部署ARM虚拟机(银河麒麟)

我们经常使用的是x86架构的cpu&#xff0c;而对于不同cpu架构的arm架构的操作系统&#xff0c;我们可以通过QEMU模拟器来进行模拟一个arm环境 1、部署前的准备 arm的镜像&#xff1a; 以此镜像为例&#xff1a;Kylin-Server-10-SP2-aarch64-Release-Build09-20210524.iso QE…

每日一练【移动零】

一、题目描述 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 二、题目解析 可以…

docker限制容器内存的方法

在服务器中使用 docker 时&#xff0c;如果不对 docker 的可调用内存进行限制&#xff0c;当 docker 内的程序出现不可预测的问题时&#xff0c;就很有可能因为内存爆炸导致服务器主机的瘫痪。而对 docker 进行限制后&#xff0c;可以将瘫痪范围控制在 docker 内。 因此&#…

1、nmap常用命令

文章目录 1. 主机存活探测2. 常见端口扫描、服务版本探测、服务器版本识别3. 全端口&#xff08;TCP/UDP&#xff09;扫描4. 最详细的端口扫描5. 三种TCP扫描方式&#xff08;1&#xff09;TCP connect 扫描&#xff08;2&#xff09;TCP SYN扫描&#xff08;3&#xff09;TCP …

两部手机数据传输后备忘录不见了怎么回事

想必很多人都遇到过&#xff0c;当两部手机进行备忘录数据传输后&#xff0c;突然发现备忘录不见了&#xff0c;这让人不禁着急上火&#xff0c;我也曾经遇到过这种事情导致很多重要的内容都丢失了。 一般出现这种情况可能是因为&#xff0c;两部手机使用的是不同的云服务&…