Qt源码解析11-QLineEdit与QValidator关系源码解析

news2025/7/12 11:20:48

Qt源码解析 索引

Qt源码解析11-QLineEdit与QValidator关系源码解析

测试

本想了解QRegExpValidator的正则表达式如何生效的,发现分析起来比想象的复杂。

测试实例:

// regexp: optional '-' followed by between 1 and 3 digits
    QRegExp rx("-?\\d{1,3}");
    QValidator *validator = new QRegExpValidator(rx, this);
​
    ui.lineEdit->setValidator(validator);

测试界面:

键盘操作输入 - 号,数字,输入其他字母和字符是输入不了的。

 

问题:QRegExpValidator是如何生效的。

问题2:每次输入后,字符输入不了的原因。这个是在分析过程中产生的。分析前认为每次都会调用QRegExpValidator表达式去判断输入的正确性。

分析

步骤0:

查看设置setValidator函数,分析control变量对QValidator的处理。在输入字符串后并没有调用获取QValidator的函数(实际上搜索出错,没有把所有函数所有全面)。产生了上面的问题2。

void QLineEdit::setValidator(const QValidator *v)
{
    Q_D(QLineEdit);
    d->control->setValidator(v);
}

共有三个函数应用了QValidator变量。对窗口路径不感兴趣的同学可以直接直接挑战步骤4

bool QWidgetLineControl::fixup() 
​
bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool edited)
​
bool QWidgetLineControl::hasAcceptableInput(const QString &str) const

步骤1:

分析问题2需要跟踪窗口处理流程,参见windows窗口处理函数

跟踪后发现,Qt把所有的windows事件放在WM_QT_SENDPOSTEDEVENTS事件中处理

    WM_QT_SOCKETNOTIFIER = WM_USER,
    WM_QT_SENDPOSTEDEVENTS = WM_USER + 1,
    WM_QT_ACTIVATENOTIFIERS = WM_USER + 2,

步骤2:

进一步跟踪,要想知道输入后的操作,跟踪到函数中,找到处理输入的操作。

bool QWidget::event(QEvent *event)
{
    //Step 1.ignore mouse and key events when disabled.忽略失能的widget事件处理
    ...
    //Step 2
    case QEvent::KeyPress:
        QKeyEvent *k = (QKeyEvent *)event;
        bool res = false;
        if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
            if (k->key() == Qt::Key_Backtab
                || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
                res = focusNextPrevChild(false);
            else if (k->key() == Qt::Key_Tab)
                res = focusNextPrevChild(true);
            if (res)
                break;
        }
        keyPressEvent(k);//进入QLineEdit的重载函数
        break;
}

总结:

QLineEdit有个很重要的QWidgetLineControl类型成员变量,setValidator这个函数最终也是通过此成员变量实现。所以两个问题有合并为一个问题----QWidgetLineControl对输入的处理。

步骤3:

真实处理插入字符的函数

/*!
    \internal
​
    Inserts the given \a newText at the current cursor position.
    If there is any selected text it is removed prior to insertion of
    the new text.
*/
void QWidgetLineControl::insert(const QString &newText)
{
    int priorState = m_undoState;
    removeSelectedText();
    internalInsert(newText);
    finishChange(priorState);//此函数产生效果需要参考QLineEdit信号textChanged和textEdited区别
}

步骤4:

finishChange函数中处理字符有效性问题

m_validator->validate(textCopy, cursorCopy)

最终调用的还是:

bool QRegExp::exactMatch(const QString &str) const
/*QRegExp类中,结构 QRegExpPrivate 包含除自动机之外的正则表达式的私有数据。它使许多 QRegExp 对象可以将相同的 QRegExpEngine 对象与不同的 QRegExpPrivate 对象一起使用。*/
private:
    QRegExpPrivate *priv;

到此步骤才是真正想分析的。标题都改了,QValidator源码分析单独出一期。

QLineEdit控件信号textChanged和textEdited区别

[signal] void QLineEdit::textChanged(const QString &text)
    
This signal is emitted whenever the text changes. The text argument is the new text.
Unlike textEdited(), this signal is also emitted when the text is changed programmatically, for example, by calling setText().
Note: Notifier signal for property text. 
/*每当文本更改时,都会发出此信号。文本参数是新文本。
与 textEdited() 不同,当以编程方式更改文本时,也会发出此信号,例如,通过调用 setText()。
注意:属性文本的通知程序信号。*/
    
[signal] void QLineEdit::textEdited(const QString &text)
    
This signal is emitted whenever the text is edited. The text argument is the new text.
Unlike textChanged(), this signal is not emitted when the text is changed programmatically, for example, by calling setText().
    /*每当编辑文本时,都会发出此信号。文本参数是新文本。
与 textChanged() 不同,当以编程方式更改文本(例如,通过调用 setText())时,不会发出此信号。*/
    

windows窗口处理函数

一、注册

    WNDCLASS wc;
    wc.style = 0;
    wc.lpfnWndProc = qt_internal_proc;
    ...
    atom = RegisterClass(&wc);

lpfnWndProc的声明原型:

LRESULT (CALLBACK* WNDPROC) (HWND, UINT, WPARAM, LPARAM);

Qt通过qt_internal_proc函数处理事件消息。

参考:callWindowProcA 函数(winuser.h)

将消息信息传递给指定的窗口过程。

语法

C++复制

LRESULT CallWindowProcA(
  [in] WNDPROC lpPrevWndFunc,
  [in] HWND    hWnd,
  [in] UINT    Msg,
  [in] WPARAM  wParam,
  [in] LPARAM  lParam
);

参数

[in] lpPrevWndFunc

类型: WNDPROC

上一个窗口过程。 如果通过调用设置为GWL_WNDPROCDWL_DLGPROCnIndex 参数的 GetWindowLong 函数来获取此值,则它实际上是窗口或对话框过程的地址,或者仅对 CallWindowProc 有意义的特殊内部值。

[in] hWnd

类型:HWND

用于接收消息的窗口过程的句柄。

[in] Msg

类型: UINT

消息。

[in] wParam

类型: WPARAM

其他的消息特定信息。 此参数的内容取决于 Msg 参数的值。

[in] lParam

类型: LPARAM

其他的消息特定信息。 此参数的内容取决于 Msg 参数的值。

返回值

类型: LRESULT

返回值指定消息处理的结果,具体取决于发送的消息。

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

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

相关文章

JUC学习笔记——共享模型之管程

在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的管程部分 我们会分为以下几部分进行介绍: 共享问题共享问题解决方案线程安全分析Monitorsynchronized锁Wait/notify模式之保护性暂停模式之生产者消费者park线程状态转换详解多锁操作活跃…

学生护眼灯怎么选择?推荐学生护眼台灯十大名牌排行榜

护眼台灯是学生们常用的照明产品,也是最受喜爱的护眼产品之一,选购一款护眼台灯要看什么指标呢?除了外观、价格上,更重要的是五个硬性标准,照度、显色、频闪、色温、蓝光。 为了大家更快速选择出合适的台灯&#xff0…

基于51单片机的出租车计价器proteus仿真原理图PCB

功能: 0.本系统采用STC89C52作为单片机 1.LCD1602液晶显示有四个状态 a) 时间显示 b) 时间设置 c) 计价器显示 d) 计价器设置 2.按键切换四个不同显示状态 3.默认为时间显示状态,长按’切换‘键切换至计价器模式 4.在时间显示状态下按‘设置’键可设置时…

C++类的运算符重载.md

11.8 类的运算符重载 运算符重载是一种形式的C多态 运算符重载将充值该的概念扩展到运算符上,允许赋予C运算符多种含义。 C允许将运算符重载扩展到用户定义类型,例如,允许使用将两个对象相加。 11.8.1 操作符重载定义 要重载运算符&#xff0…

FutureTask-详解(二)-ThreadPollExecutor-并发编程(Java)

文章目录1 FutureTask1.1 简介1.2 成员变量1.3 构造方法1.4 主要执行流程分析1.4.1 run任务执行1.4.1.1 run方法1.4.1.2 set(result)方法1.4.1.3 setException(ex)方法1.4.1.4 finishCompletion()方法1.4.2 get() 执行流程1.4.2.1 get()方法1.4.2.2 awaitDone()方法1.4.2.3 rem…

C++获取计算机硬件信息(Linux)

C获取计算机硬件信息(Windows) https://blog.csdn.net/hhy321/article/details/121258036 C获取计算机硬件信息(Linux) https://blog.csdn.net/hhy321/article/details/127930470 “春赏百花秋望月,夏有凉风冬观雪。若…

InnoDB之Undo log写入和恢复

1. 前言 为了实现事务的回滚和MVCC,InnoDB设计了Undo log模块,简单来说就是在修改记录前先记下日志,以便之后能将记录恢复成修改前的样子。针对insert、delete、update这三种不同的操作,InnoDB设计了不同类型的undo log&#xff…

Redis 常见问题

一、 什么是Redis? Redis 是一个使用 C 语言写成的,开源的高性能key-value非关系缓存数据库;Redis的数据都基于缓存的,所以很快,每秒可以处理超过 10万次读写操作;Redis也可以实现数据写入磁盘中&#xff…

Spring源码里开天辟地的五个Bean,再介绍一个学习方法

准备工作 首先咱们还是来写一个最简单的例子: 用的还是 https://github.com/xiexiaojing/yuna 里的代码,只是标签和引用都换成了Spring原生的。 配置类就是配置了扫描路径: 在可以被扫描的包路径下定义了一个Bean对象。用了Component注解这…

Java#16(包装类和集合练习)

目录 基本数据类型对应的包装类: 一.添加学生对象并遍历 二.添加用户对象并判断是否存在 三.添加手机对象并返回要求的数据 基本数据类型对应的包装类: byte------>Byte short------->Short char------->Character int------->Integer long------->Long flo…

MRT(MODIS Reprojection Tool) 下载及安装教程

大家下载MODIS数据的时候,大多是hdf的格式数据。HDF数据包括11个波段的数据(如下图),假如想要其中一个波段数据,我们需要批量提取,这时就要用到NASA提供的MODIS Reprojection Tool,此工具虽不能…

c++ 指针,new运算符

1、指针相关基础知识: 1.1、指针一般指向变量的地址,等同于变量名前加&,如下: int a 3; int* p; p &a; 1.2、 * 符号被称为间接值运算符或解除引用运算符,将其运用于指针,可以获取指针指向的值…

【Java八股文总结】之IO流

文章目录Java IO流一、IO基础知识1、字节流2、字符流3、字节缓冲流4、打印流5、随机访问流6、字节流和字符流的区别?二、IO设计模式1、装饰器模式2、适配器模式Q:适配器模式和装饰器模式的区别?3、工厂模式4、观察者模式三、IO模型详解&#…

柯桥留学日语培训机构有吗日本人平时都喝什么酒?

日本葡萄酒侍酒大师高野丰先生,带来一瓶在北海道发现的陈年白兰地。 那是2014年的事,高野先生去北海道十胜地区的一家葡萄酒厂考察,在一个多年未开启的葡萄酒储存库的角落里,发现了一只陈旧的酒桶,他很好奇地问酒厂的…

Javaweb filter过滤器 跟 listener监听器

Filter 权限控制:登录才能进数据库等 统一编码:统一各种编码 Filter快速入门 放行前,我们对request里的数据进行处理 处理完,然后放行,携带到对应的资源里去 放行后,对response的数据进行处理 //将re…

C/C++问题:一个指针的大小是多少?怎么理解指针变量的存在

目录 举例 一、 int a; int (*(*v)[])(); 二、 int func(); int (*func)(); 三、 const; int const a; const int a; int const*r; int *const r; 四、一个指针的大小是多少?(补充) 举例 一、 int a; 可以看到上面声明了一个变…

【MySQL基础】SQL语言的概述、组成及特点

目录 一、SQL的概述 二、SQL语言的组成 三、SQL语言的特点 语法特点: 💟 创作不易,不妨点赞💚评论❤️收藏💙一下 一、SQL的概述 SQL全称: Structured Query Language,是结构化查询语言&am…

数据结构先序序列创建二叉树

2022.11.19连发两回。 先序序列创建二叉树任务描述相关知识编程要求测试说明C/C代码任务描述 本关任务:利用先序遍历创建二叉树,并给出相应二叉树的中序遍历结果。 相关知识 为了完成本关任务,你需要掌握:1.二叉树的前序遍历&a…

win11系统下,迅雷启动后闪退的问题

win11系统,迅雷最新版本。 之前用迅雷一直好好的,某天要下东西突然发现点击就闪退,进程管理器里一点痕迹都没有。 启动就闪退,没有一点点痕迹。 因为之前是win10系统,一直用的好好的,考虑是不是win11系统…

创建自己数据集全套流程

目录 1、准备自己具有的数据集 2、标注数据----json格式 3、标注数据转为分割图----voc格式 4、增广数据集 5、分训练集以及验证集 1、准备自己具有的数据集 注意:数据集必须是统一的后缀格式,jpg或者png 2、标注数据----json格式 采用labelme标注…