屏蔽输入法并保留光标

很多时候我们有自己键盘的时候不需要系统默认输入法,比如一些手机银行密码输入,淘宝密码输入等。

我们在API10之前使用的接口:

editText.setInputType(InputType.TYPE_NULL);

在API10之后使用就会出现没有光标的问题,虽然系统默认输入法仍然能够被屏蔽。

下面看一个方法,反射系统的隐藏API。

private void setShowSoftInputOnFocus(EditText editText) {
	if (android.os.Build.VERSION.SDK_INT <= 10) {
		editText.setInputType(InputType.TYPE_NULL);
	} else {
		getWindow().setSoftInputMode(
				WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
		try {
			Class<EditText> cls = EditText.class;
			Method setShowSoftInputOnFocus;
			setShowSoftInputOnFocus = cls.getMethod(
					"setShowSoftInputOnFocus", boolean.class);
			setShowSoftInputOnFocus.setAccessible(true);
			setShowSoftInputOnFocus.invoke(editText, false);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

或者使用论坛上 http://bbs.youkuaiyun.com/topics/390258609 的方法:

public void hideSoftInputMethod(EditText ed){
	getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); 
	
	int currentVersion = android.os.Build.VERSION.SDK_INT;
	String methodName = null;
	if(currentVersion >= 16){
		// 4.2
		methodName = "setShowSoftInputOnFocus";
	}
	else if(currentVersion >= 14){
		// 4.0
		methodName = "setSoftInputShownOnFocus";
	}
	
	if(methodName == null){
		ed.setInputType(InputType.TYPE_NULL);  
	}
	else{
    Class<EditText> cls = EditText.class;  
    Method setShowSoftInputOnFocus;  
    try {
			setShowSoftInputOnFocus = cls.getMethod(methodName, boolean.class);
			setShowSoftInputOnFocus.setAccessible(true);  
	    setShowSoftInputOnFocus.invoke(ed, false); 
		} catch (NoSuchMethodException e) {
			ed.setInputType(InputType.TYPE_NULL);
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
	}  
}

上面的方法都是来自于其他博客或者论坛,记录并进行整合;




class BankCardLineEdit(QLineEdit): def __init__(self, parent=None): super().__init__(parent) # 连接文本改变信号 self.textChanged.connect(self.format_text) def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace: # 记录当前光标位置 cursor_pos = self.cursorPosition() text = self.text() # 如果光标位置为0,不做处理 if cursor_pos == 0: return # 判断光标前一个字符是否是空格 if text[cursor_pos-1] == ' ': # 删除空格及其前面的一个非空格字符 new_text = text[:cursor_pos-2] + text[cursor_pos:] new_cursor_pos = cursor_pos - 2 else: # 删除一个字符 new_text = text[:cursor_pos-1] + text[cursor_pos:] new_cursor_pos = cursor_pos - 1 # 设置新文本,这将触发textChanged信号,进而调用format_text self.setText(new_text) # 设置光标位置 self.setCursorPosition(new_cursor_pos) # 注意:这里设置文本后,format_text会被调用,所以我们需要在format_text中调整光标位置 # 但是,format_text中会根据规则重新计算光标位置,所以我们这里设置的光标位置可能会被覆盖 # 因此,我们需要在format_text中知道这次文本改变是由于我们设置文本造成的,且我们已经有new_cursor_pos,那么format_text中应该使用这个位置作为参考 # 然而,format_text中我们只能获取到当前的文本和当前的光标位置(在设置new_text后,光标位置是new_cursor_pos,但在format_text中,我们可能会改变文本,所以需要重新计算) # 所以,我们这里不设置光标位置,而是在format_text中统一设置 # 因此,注释:self.setCursorPosition(new_cursor_pos) # 改为:在format_text中计算新的光标位置 # 但是,我们如何将new_cursor_pos传递给format_text?因为format_text是在textChanged信号中调用的,它没有参数。 # 解决方案:我们可以设置一个实例变量,记录下一次格式化应该使用的参考光标位置(即文本改变前的光标位置,也就是new_cursor_pos) self.next_cursor_pos = new_cursor_pos else: # 对于非退格键,记录当前光标位置(在父类处理前) self.next_cursor_pos = self.cursorPosition() super().keyPressEvent(event) def format_text(self, text): # 格式化文本:每4位插入一个空格 # 先移除所有空格 clean_text = text.replace(' ', '') # 重新插入空格 formatted_text = '' for i in range(0, len(clean_text), 4): if i > 0: formatted_text += ' ' formatted_text += clean_text[i:i+4] # 计算新的光标位置 # 如果没有设置next_cursor_pos,我们使用当前的光标位置(由光标选中获取) if hasattr(self, 'next_cursor_pos'): old_cursor_pos = self.next_cursor_pos # 清除这个属性,避免影响下一次 del self.next_cursor_pos else: old_cursor_pos = self.cursorPosition() # 计算格式化后的光标位置 # 原理:计算在格式化前,光标位置之前的非空格字符数(count_before) count_before = 0 for i in range(old_cursor_pos): if i < len(text) and text[i] != ' ': count_before += 1 # 在格式化文本中,count_before个字符(非空格)现在分布在:count_before + (count_before // 4) [因为每4个非空格字符会有一个空格] 的位置上 # 但是,注意:如果count_before=0,那么前面没有字符,光标位置为0 if count_before == 0: new_cursor_pos = 0 else: # 空格插入的位置:在第4、8、12...个字符后插入,所以 count_before 个字符前面有多少个空格?答案是 (count_before - 1) // 4 new_cursor_pos = count_before + (count_before - 1) // 4 # 但是,如果 (count_before) % 4 == 0,那么最后一个字符后面没有空格,所以不需要减1?我们上面的公式 (count_before-1)//4 在count_before=4时是 (3//4)=0,不对。 # 修正: count_before 个非空格字符,会分成 (count_before+3) // 4 组,每组4个,那么组数减1就是空格数(因为n组有n-1个空格?)但是,当 count_before<=4 时,有一个组,没有空格;5-8时,有两个组,中间一个空格。 # 空格数 = (count_before - 1) // 4 ? let's test: # count_before=1 -> 0 # count_before=4 -> (3//4)=0 -> 4+0=4 -> 但是格式化文本是4个字符,光标可以在0-4,如果光标在4(即末尾),那么位置4是合理的。 # count_before=5 -> (4//4)=1 -> 5+1=6 -> 格式化文本:前4个字符+空格+1个字符 -> 位置6(在空格后面)?但是光标应该在第五个字符后面,即位置6(正确)。 # 所以公式 new_cursor_pos = count_before + (count_before - 1) // 4 似乎正确。 # 但是,我们 formatted_text 的长度可能大于 new_cursor_pos,所以 new_cursor_pos 必须在0到len(formatted_text)之间 # 设置格式化后的文本 if text != formatted_text: # 阻塞信号,避免递归 self.blockSignals(True) self.setText(formatted_text) self.blockSignals(False) # 设置新的光标位置 self.setCursorPosition(min(new_cursor_pos, len(formatted_text))) 当设置每2位插入一个空格时光标应该怎么改
最新发布
08-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值