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

news2024/12/23 1:23:29

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序开发——开发账号注册与配置

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 概述 本文的重点在于介绍注册微信小程序开发账号的步骤及其流程。 账号注册 请点击官方网站右上角的 https://mp.weixin.qq.com/ 立即注册&#xff0c;图示如下&#xf…

Python 和 Node.js 之间通信 JSON 数据

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在实际应用中&#xff0c;不同编程语言之间的通信是常见的需求。Python和Node.js是两个流行且功能强大的编程语言&#xff0c;它们之间使用JSON格式进行数据交换是一种高效和灵活的方式。本文将详细介绍如何在Py…

unity3d NPC自动寻路不移动

烘焙的路面不能有间隔&#xff0c;调整地面重新烘焙

基于mvc电影院售票预订选座系统php+vue+elementui

本影院售票系统主要包括二大功能模块&#xff0c;管理员功能模块和用户功能模块。 &#xff08;1&#xff09;管理员模块&#xff1a;系统中的核心用户管理员登录后&#xff0c;通过管理员功能来管理后台系统。主要功能有&#xff1a;首页、个人中心、电影类型管理、场次时间管…

还在担心发抖音没素材跟文案?[腾讯云HAI] AIGC带你蹭热度“今年你失去了什么?”

目录 &#x1f433;前言&#xff1a; &#x1f680;了解高性能应用服务 HAI &#x1f47b;即插即用 轻松上手 &#x1f47b;横向对比 青出于蓝 &#x1f424;应用场景-AI作画 &#x1f424;应用场景-AI对话 &#x1f424;应用场景-算法研发 &#x1f680;使用HAI进行…

人工智能技术发展漫谈

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 人工智能发展历程 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;的发展历史可以追溯到20世纪中叶。以下是一些关键时刻和阶段&#xff1a; 起…

基于Spring原生框架构建原生Spring的第一个程序!

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

Linux shell编程学习笔记31:alias 和 unalias 操作 命令别名

目录 0 前言1 定义别名2 查看别名 2.1 查看所有别名2.2 查看某个别名 2.2.1 alias 别名2.2.2 alias | grep 别名字符串2.2.3 使用 CtrlAltE 组合键3 unalias&#xff1a;删除别名4 如何执行命令本身而非别名 4.1 方法1&#xff1a;使用 CtrlAltE 组合键 && unalias4…

Appium自动化测试:sdk版本和手机版本不兼容你就这样做,分分钟解决问题

使用pythonappium执行自动化测试脚本提示报错 环境&#xff1a;python3.7以上&#xff0c;appium1.21.0&#xff1b;设备&#xff1a;华为max8真机 报错信息&#xff1a; android.intent.category.LAUNCHER -f 0x10200000 exited with code 4294967295; Stderr: Security ex…

【Python】python天气数据抓取与数据分析(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

MySQL企业版之Firewall(SQL防火墙)

​​​1. 关于Firewall插件 2. Firewall插件的工作方式 3. Firewall插件测试 4. 总结延伸阅读 1. 关于Firewall插件 Friewall是MySQL企业版非常不错的功能插件之一,启用Firewall功能后,SQL的执行流程见下图示意: 2. Firewall插件的工作方式 Firewall插件的工作机制大概是…

算法基础二

回文数 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 示例 1&#xff1a; 输入&#xff1…

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

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

智慧化工~工厂设备检修和保全信息化智能化机制流程

化工厂每年需要现场检修很多机器&#xff0c;比如泵、压缩机、管道、塔等等&#xff0c;现场检查人员都是使用照相机&#xff0c;现场拍完很多机器后&#xff0c;回办公室整理乱糟糟的照片&#xff0c;但是经常照了之后无法分辨是哪台设备&#xff0c;而且现场经常漏拍&#xf…

ROC及曲线面积汇总学习

目录 ROC基础 生成模拟数据 率的计算 R语言计算测试 ROCR&#xff1a; pROC ROC绘制 单个ROC 两个ROC Logistic回归的ROC曲线 timeROC ROC基础 ROC曲线的横坐标是假阳性率&#xff0c;纵坐标是真阳性率&#xff0c;需要的结果是这个率表示疾病阳性的率&#xff08;…

第六节HarmonyOS UIAbility内页面的跳转和数据传递

一、页面跳转 在一个应用包含一个UIAbility的场景下&#xff0c;可以通过新建多个页面来实现和丰富应用的内容。这会涉及到UIAbility内页面的新建以及UIAbility内页面的跳转和数据传递。 打开DevEco Studio&#xff0c;选择一个Empty Ability工程模板&#xff0c;创建一个工程&…

基于Python+OpenCV+dlib+Tensorflow深度学习的人脸表情识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 人脸表情识别是一种重要的计算机视觉任务&#xff0c;它涉及到对人脸图像中的表情进行分类和理解。在这个系统中&am…

力扣23. 合并 K 个升序链表(java,最小堆解法)

Problem: 23. 合并 K 个升序链表 文章目录 题目描述思路解题方法复杂度Code 题目描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 思路 1.对于合并k个有序链表&#xff0c;我们较为容易想…

使用Tensorboard可视化 遇到无法访问此网站

问题&#xff1a; 使用Tensorboard可视化 遇到无法访问此网站 解决方法&#xff1a;后面加上服务器ip[参考] tensorboard --logdir目标目录 --hostxxx.xxx.xxx.xx

简要介绍Spring原生框架与Spring是轻量级框架的原因

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…