根据输入框输入内容长度改变按钮状态-全局异常捕获

本文详细介绍了一个Android应用中UI更新的实现方式,通过监听EditText的文字变化来动态更新Button的状态和背景色。同时,深入探讨了如何使用自定义的UnCatchHandler全局捕获异常类来处理应用程序中的未捕获异常,确保应用的稳定运行。

MainActivity.java

public class MainActivity extends AppCompatActivity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        init();



    }

    private void init() {
        final Button button_change_bg_demo = findViewById(R.id.button_change_bg_demo);
        EditText edit_change_bg_demo = findViewById(R.id.edit_change_bg_demo);

        //給edit添加文字改变监听
        //注意:这里不是set,而是add开头
        edit_change_bg_demo.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                //改变之前
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                //按钮可以点击,并且改变颜色
                button_change_bg_demo.setEnabled((s.length() >= 6));
            }

            @Override
            public void afterTextChanged(Editable s) {
                //文字改变过后
            }
        });
    }


//    private void doError(){
//        Object o  = null;
//        o.toString();
//    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/edit_change_bg_demo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button_change_bg_demo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/selector_button_enable"
        android:enabled="false"
        />

</LinearLayout>

selector_button_ennable.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--state_enabled  是否可用的状态-->
    <item android:state_enabled="true" android:drawable="@color/colorPrimary"/>
    <item android:state_enabled="false" android:drawable="@color/colorAccent"/>
</selector>

UnCatchHandler.java

/**
 * 全局捕获异常类,实现Thread.UncaughtExceptionHandler
 * @author hasee
 */
public class UnCatchHandler implements Thread.UncaughtExceptionHandler {
    private static UnCatchHandler mUnCatchHandler;
    private Context mContext;

    /**
     * 一定要写个单例
     * @return
     */
    public static UnCatchHandler getInstance(Context context) {
        if(mUnCatchHandler == null){
            synchronized (UnCatchHandler.class) {
                mUnCatchHandler = new UnCatchHandler(context);
            }
        }
        return mUnCatchHandler;
    }

    private UnCatchHandler(Context context) {
        init(context);
    }

    public void init(Context context) {
        //获取默认的系统异常捕获器
        //把当前的crash捕获器设置成默认的crash捕获器
        Thread.setDefaultUncaughtExceptionHandler(this);
        mContext = context.getApplicationContext();
    }

    /**
     * 保存我们抛出的异常至SD卡
     * @param t
     * @param e
     */
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        try {
            //如果不需要写到SD卡,则不需要打开以下注释
//            saveSD(e);

            //打印异常信息
            Log.i("1607C", e.getLocalizedMessage());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

//    /**
//     * 存储sd卡
//     */
//    private void saveSD(Throwable throwable) throws Exception {
//        //判断SD卡状态
//        //MEDIA_MOUNTED 存储媒体已经挂载,并且挂载点可读/写
//        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//            //彻底退出
//            android.os.Process.killProcess(android.os.Process.myPid());
//            System.exit(0);
//            return;
//        }
//
//        //获取手机的一些信息
//        PackageManager pm = mContext.getPackageManager();
//        PackageInfo inFo = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);
//
//        //获取版本信息
//        String versionName = inFo.versionName;
//        int versionCode = inFo.versionCode;
//
//        int version_code = Build.VERSION.SDK_INT;
//
//        //Android版本号
//        String release = Build.VERSION.RELEASE;
//        //手机型号
//        String mobile = Build.MODEL;
//
//        //手机制造商
//        String mobileName = Build.MANUFACTURER;
//
//        //存储至sdCard下
//        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
//
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
//        String time = simpleDateFormat.format(new Date());
//
//        //找到文件夹路径,创建exception文件夹
//        File f = new File(path, "exception");
//        f.mkdirs();
//
//        //找到文件夹路径,查找exception + time的txt文件夹
//        File file = new File(f.getAbsolutePath(), "exception" + time + ".txt");
//
//        //如果文件没有,则创建
//        if (!file.exists()) {
//            file.createNewFile();
//        }
//
//        String data = "\nMobile型号:" + mobile + "\nMobileName:" + mobileName + "\nSDK版本:" + version_code +
//                "\n版本名称:" + versionName + "\n版本号:" + versionCode + "\n异常信息:" + throwable.toString();
//
//        Log.i("dj", data);
//
//        //以下是写入文件
//        byte[] buffer = data.trim().getBytes();
//        FileOutputStream fileOutputStream = new FileOutputStream(file);
//        // 开始写入数据到这个文件。
//        fileOutputStream.write(buffer, 0, buffer.length);
//        fileOutputStream.flush();
//        fileOutputStream.close();
//
//        android.os.Process.killProcess(android.os.Process.myPid());
//        System.exit(0);
//    }
}

MyApplication.java

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        UnCatchHandler.getInstance(getApplicationContext()).init(getApplicationContext());
//        CrashReport.initCrashReport(getApplicationContext(), "f9f67393ee", true);
    }
}

 

import PySimpleGUI as Py import time import threading import os import queue image_path1 = "D:/software/demo/pythonProject/images/image1.png" image_path2 = "D:/software/demo/pythonProject/images/image2.png" # 检查图片是否存在 if not os.path.exists(image_path1): print(f"[!] 图片1不存在: {image_path1}") image_path1 = None if not os.path.exists(image_path2): print(f"[!] 图片2不存在: {image_path2}") image_path2 = None a = 'jyrz' g = 'zbjszj' layout1 = [ [Py.Text('jdsj--')], [Py.Button('tips'), Py.Button('wykd')] ] window_position = (210, 0) # 定义主窗口的布局,这里设置了窗口在屏幕上的起始位置为(横坐标50, 纵坐标50) window1 = Py.Window('jdsq', layout1, size=(1500, 68), no_titlebar=True, location=window_position, finalize=True) window1.keep_on_top_set() Py.theme('DarkBlue3') # PySimpleGUI 设置主题颜色 def run_periodic_reminder(): """周期性提醒输入:调用即自动弹出输入框,无需点击“开始提醒”""" layout7 = [ [Py.Text("📌 周期性提醒已激活:每次取消后10秒自动重试")], [Py.Multiline("", size=(60, 15), key='-OUTPUT-', disabled=True, autoscroll=True)], [Py.Button('退出', key='EXIT')] # 删除了 'START' 按钮 ] window7 = Py.Window('周期性提醒控制器', layout7, finalize=True) next_popup_time = time.time() + 1 # 🟢 立即设定1秒后触发 reminder_active = True # 🟢 自动激活 popup_active = False input_popup = None def show_input_popup(): layout_popup = [ [Py.Text('请输入一个数字:')], [Py.Input(key='-INPUT-', size=(30, 1), focus=True)], [Py.Button('OK', bind_return_key=True), Py.Button('Cancel')] ] return Py.Window('请输入数字', layout_popup, keep_on_top=True, finalize=True) try: while True: # --- 主窗口事件 --- if window7 is None: break event7, values7 = window7.read(timeout=100) if window7 is None: break # 处理退出 if event7 in ('EXIT', Py.WINDOW_CLOSED): break # 🟢 自动检查是否该弹出输入框(无需点击“开始”) if reminder_active and next_popup_time and time.time() >= next_popup_time and not popup_active: popup_active = True input_popup = show_input_popup() # 处理输入弹窗 if input_popup is not None: try: event_p, values_p = input_popup.read(timeout=100) except: event_p, values_p = None, None if event_p == 'OK' and '-INPUT-' in values_p: user_input = values_p['-INPUT-'].strip() try: num = float(user_input) formatted_num = int(num) if num.is_integer() else num window7['-OUTPUT-'].update(f"✔️ 录入成功:{formatted_num} —— 提醒停止\n", append=True) reminder_active = False next_popup_time = None except Exception: window7['-OUTPUT-'].update(f"❌ 输入无效:'{user_input}',10秒后重试...\n", append=True) next_popup_time = time.time() + 10 finally: try: input_popup.close() except: pass input_popup = None popup_active = False elif event_p in (None, 'Cancel'): try: input_popup.close() except: pass input_popup = None popup_active = False window7['-OUTPUT-'].update("⛔ 用户取消,10秒后将再次提醒...\n", append=True) next_popup_time = time.time() + 10 # 10秒后重试 finally: if 'window7' in locals() or window7 is not None: try: window7.close() except: pass if input_popup is not None: try: input_popup.close() except: pass def run_single_flow(): """运行一次完整的 window3 流程""" Py.theme('LightBlue') input_history = [] # 存储已确认的数字 last_input_time = None INPUT_TIMEOUT = 5.0 current_text = '' # 使用一个固定宽度的 Text 框实现横向排列 + 自动换行 layout3 = [ [Py.Image(key='img1', filename=image_path1) if image_path1 else Py.Text("加载失败")], [Py.Text("请在5秒内输入一个数字,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(20, 1), focus=True)], [Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Text("已记录的数字(横向排列,自动换行):")], # 设置 size=(None, 10) 表示不限宽度列,高度最多10行;text_color 和 background_color 提升可读性 [Py.Frame('', [[ Py.Text("", size=(600, 10), # 长度约600字符,超出则自动换行,最多10行 key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 10)) ]], size=(600, 50), pad=10)], # 控制整体显示区域大小以便触发换行 [Py.Button('cxxldb')], [Py.Button('txlxk')], [Py.Button('lxbfh')], [Py.Button('--jchdj--')], ] window3 = Py.Window('自动换行横向记录器', layout3, resizable=True) while True: event3, values3 = window3.read(timeout=100) if event3 == Py.WINDOW_CLOSED: break new_text = values3['-INPUT-'].strip() input_changed = new_text != current_text current_text = new_text # 验证是否为有效数字 valid_number = False try: if current_text: float(current_text) valid_number = True except ValueError: pass # 输入变化且合法 → 重置计时器 if input_changed and valid_number: last_input_time = time.time() window3['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 5秒无操作将自动提交") # 超时自动提交 if last_input_time is not None: elapsed = time.time() - last_input_time if elapsed >= INPUT_TIMEOUT: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) # 更新历史显示:空格分隔,让系统自动换行 history_str = ' '.join(map(str, input_history)) window3['-HISTORY-'].update(history_str) window3['-STATUS-'].update("🎉 已自动记录!") window3['-INPUT-'].update('') current_text = '' last_input_time = None except Exception as e: window3['-STATUS-'].update("❌ 提交失败") last_input_time = None # 状态栏提示 elif last_input_time is None and current_text and not valid_number: window3['-STATUS-'].update("❌ 请输入有效的数字") elif last_input_time and valid_number: remaining = max(0, int(INPUT_TIMEOUT - (time.time() - last_input_time) + 0.9)) if remaining > 0: window3['-STATUS-'].update(f"⏳ 还剩 {remaining} 秒自动提交...") if event3 in (Py.WIN_CLOSED, 'lxbfh'): window3.close() elif event3 == 'cxxldb': window1.hide() elif event3 == 'txlxk': window3.close() layout4 = [ [Py.Image(key='img1', filename=image_path1) if image_path1 else Py.Text("加载失败")], [Py.Text("请在5秒内输入一个数字,之后5秒无操作将自动记录:")], [Py.Input(key='-INPUT-', size=(20, 1), focus=True)], [Py.Text("", size=(60, 1), key='-STATUS-')], [Py.Text("已记录的数字(横向排列,自动换行):")], # 设置 size=(None, 10) 表示不限宽度列,高度最多10行;text_color 和 background_color 提升可读性 [Py.Frame('', [[ Py.Text("", size=(600, 10), # 长度约600字符,超出则自动换行,最多10行 key='-HISTORY-', relief='sunken', background_color='white', text_color='black', font=('Courier', 10)) ]], size=(600, 50), pad=10)], # 控制整体显示区域大小以便触发换行 [Py.Button('jrrsby')], [Py.Button('jrqsby')], ] window4 = Py.Window('自动换行横向记录器', layout4, resizable=True) while True: event4, values4 = window4.read(timeout=100) if event4 == Py.WINDOW_CLOSED: break new_text = values4['-INPUT-'].strip() input_changed = new_text != current_text current_text = new_text # 验证是否为有效数字 valid_number = False try: if current_text: float(current_text) valid_number = True except ValueError: pass # 输入变化且合法 → 重置计时器 if input_changed and valid_number: last_input_time = time.time() window4['-STATUS-'].update(f"✅ 输入中 '{current_text}' ... 5秒无操作将自动提交") # 超时自动提交 if last_input_time is not None: elapsed = time.time() - last_input_time if elapsed >= INPUT_TIMEOUT: try: num = float(current_text) formatted_num = int(num) if num.is_integer() else num input_history.append(formatted_num) # 更新历史显示:空格分隔,让系统自动换行 history_str = ' '.join(map(str, input_history)) window4['-HISTORY-'].update(history_str) window4['-STATUS-'].update("🎉 已自动记录!") window4['-INPUT-'].update('') current_text = '' last_input_time = None except Exception as e: window4['-STATUS-'].update("❌ 提交失败") last_input_time = None # 状态栏提示 elif last_input_time is None and current_text and not valid_number: window4['-STATUS-'].update("❌ 请输入有效的数字") elif last_input_time and valid_number: remaining = max(0, int(INPUT_TIMEOUT - (time.time() - last_input_time) + 0.9)) if remaining > 0: window4['-STATUS-'].update(f"⏳ 还剩 {remaining} 秒自动提交...") elif event4 == 'jrrsby': window4.close() Py.theme('LightBlue') # 历史记录列表 recorded_numbers = [] # 定义布局 layout5 = [ [Py.Text("请输入一个数字:")], [Py.Input(key='-INPUT-', size=(30, 1), do_not_clear=False)], # do_not_clear=False 表示默认清空 [Py.Button('blkyjc', bind_return_key=True), Py.Button('删除')], [Py.HorizontalSeparator()], [Py.Text("已保留的数字(横向排列,自动换行):")], [Py.Text("", size=(50, 10), key='-HISTORY-', relief='sunken', background_color='white', text_color='black')] ] # 创建窗口 window5 = Py.Window('数字记录器 - 保留或删除', layout5) while True: event5, values5 = window5.read() if event5 == Py.WINDOW_CLOSED: break input_value = values5['-INPUT-'].strip() if event5 == 'blkyjc': window5.close() run_periodic_reminder() if input_value == '': window4['-HISTORY-'].update("⚠️ 输入为空,无法保留") else: try: num = float(input_value) formatted_num = int(num) if num.is_integer() else num recorded_numbers.append(formatted_num) # 更新历史显示(横向空格分隔,自动换行) history_text = ' '.join(map(str, recorded_numbers)) window5['-HISTORY-'].update(history_text) # 清空输入框(do_not_clear=False 已自动处理,但仍显式更新以防万一) window5['-INPUT-'].update('') except ValueError: window5['-STATUS-'].update("❌ 不是有效数字!") elif event5 == '删除': # 直接清空输入框 window5['-INPUT-'].update('') elif event4 == 'jrqsby': window4.close() Py.theme('LightBlue') # 历史记录列表 recorded_numbers = [] # 定义布局 layout6 = [ [Py.Text("请输入一个数字:")], [Py.Input(key='-INPUT-', size=(30, 1), do_not_clear=False)], # do_not_clear=False 表示默认清空 [Py.Button('blkyjc', bind_return_key=True), Py.Button('删除')], [Py.HorizontalSeparator()], [Py.Text("已保留的数字(横向排列,自动换行):")], [Py.Text("", size=(50, 10), key='-HISTORY-', relief='sunken', background_color='white', text_color='black')] ] # 创建窗口 window6 = Py.Window('数字记录器 - 保留或删除', layout6) while True: event6, values6 = window6.read() if event6 == Py.WINDOW_CLOSED: break input_value = values6['-INPUT-'].strip() if event6 == 'blkyjc': window6.close() run_periodic_reminder() if input_value == '': window6['-HISTORY-'].update("⚠️ 输入为空,无法保留") else: try: num = float(input_value) formatted_num = int(num) if num.is_integer() else num recorded_numbers.append(formatted_num) # 更新历史显示(横向空格分隔,自动换行) history_text = ' '.join(map(str, recorded_numbers)) window6['-HISTORY-'].update(history_text) # 清空输入框(do_not_clear=False 已自动处理,但仍显式更新以防万一) window6['-INPUT-'].update('') except ValueError: window6['-STATUS-'].update("❌ 不是有效数字!") elif event6 == '删除': # 直接清空输入框 window6['-INPUT-'].update('') elif event3 == '--jchdj--': window3.close() window1.un_hide() # 弹出礼物窗口 run_periodic_reminder() # 主事件循环 while True: event1, values1 = window1.read() if event1 == Py.WIN_CLOSED: break if event1 == 'tips': layout2 = [[Py.Text(g, size=(170, 2), auto_size_text=True)]] window2 = Py.Window('ktrx', layout2, size=(940, 210), finalize=True, keep_on_top=True) window2.read(timeout=5000, close=True) if event1 == 'wykd': run_single_flow() 在窗口3中先点击cxxldb,再点击--jchdj--,然后弹出窗口7,再窗口7输入数字后OK,在窗口7中点击退出按钮有时会闪退
最新发布
11-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值