首页 > 其他分享 >实现Qtextedit控件大小改变时候希望不重新绘制

实现Qtextedit控件大小改变时候希望不重新绘制

时间:2024-10-24 19:46:31浏览次数:3  
标签:控件 NoRepaintTextEdit QTextEdit isResizing Qtextedit 绘制 event

实现Qtextedit控件大小改变时候希望不重新绘制


要在 QTextEdit 控件大小改变时防止其重新绘制,可以通过创建一个自定义的 QTextEdit 子类,并重载相关事件来控制绘制行为。以下是实现这一目标的详细步骤和示例代码:

  1. 创建自定义的 QTextEdit 子类
    首先,创建一个继承自 QTextEdit 的自定义类,例如 NoRepaintTextEdit。在这个类中,我们将重载 resizeEvent 和 paintEvent,以控制何时允许控件进行绘制。
NoRepaintTextEdit.h
#ifndef NOREPAINTTEXTEDIT_H
#define NOREPAINTTEXTEDIT_H

#include <QTextEdit>
#include <QResizeEvent>
#include <QPaintEvent>

class NoRepaintTextEdit : public QTextEdit {
    Q_OBJECT
public:
    explicit NoRepaintTextEdit(QWidget *parent = nullptr);

protected:
    void resizeEvent(QResizeEvent *event) override;
    void paintEvent(QPaintEvent *event) override;

private:
    bool m_isResizing; // 标记是否正在调整大小
};

#endif // NOREPAINTTEXTEDIT_H

NoRepaintTextEdit.cpp
#include "NoRepaintTextEdit.h"

NoRepaintTextEdit::NoRepaintTextEdit(QWidget *parent)
    : QTextEdit(parent), m_isResizing(false) {}

void NoRepaintTextEdit::resizeEvent(QResizeEvent *event) {
    // 标记开始调整大小
    m_isResizing = true;
    // 调用基类的 resizeEvent 以确保大小调整逻辑正常进行
    QTextEdit::resizeEvent(event);
    // 标记调整大小结束
    m_isResizing = false;
}

void NoRepaintTextEdit::paintEvent(QPaintEvent *event) {
    if (m_isResizing) {
        // 如果正在调整大小,则跳过绘制
        return;
    }
    // 否则,正常绘制
    QTextEdit::paintEvent(event);
}
  1. 使用自定义的 NoRepaintTextEdit 控件
    在你的应用程序中使用 NoRepaintTextEdit 代替标准的 QTextEdit 控件。例如:
main.cpp
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include "NoRepaintTextEdit.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    NoRepaintTextEdit *textEdit = new NoRepaintTextEdit();
    textEdit->setPlainText("请输入文本...");
    layout->addWidget(textEdit);

    window.setLayout(layout);
    window.resize(400, 300);
    window.show();

    return app.exec();
}
  1. 解释与注意事项
    工作原理
    resizeEvent:当 QTextEdit 发生大小改变时,resizeEvent 被触发。我们在此事件中将 m_isResizing 标记为 true,然后调用基类的 resizeEvent 以确保控件大小调整的逻辑正常进行。调整大小完成后,将 m_isResizing 标记为 false。

paintEvent:在绘制事件中,检查 m_isResizing 的状态。如果正在调整大小 (m_isResizing == true),则跳过绘制,防止控件在调整大小时重新绘制。

可能的问题
视觉问题:

不完整的绘制:跳过绘制可能导致控件在调整大小时显示不完整或异常,例如文本可能未正确重新布局或背景未正确更新。
闪烁与刷新:如果控件在调整大小后需要重新绘制来适应新大小,跳过绘制可能会在下一次正常绘制时导致闪烁或不一致。
性能影响:

有限的优化:QTextEdit 的绘制相对复杂,跳过部分绘制可能对性能的提升有限,且可能引入其他问题。
功能受限:

交互性问题:在跳过绘制时,用户可能看到不完整的界面更新,影响使用体验。

解决方案与优化
如果发现上述方法带来负面影响,可以考虑以下替代方案或优化方法:

  1. 使用 setUpdatesEnabled
    在调整大小时临时禁用更新,然后在调整完成后重新启用。这可以防止在调整大小期间进行任何绘制操作。
void NoRepaintTextEdit::resizeEvent(QResizeEvent *event) {
    setUpdatesEnabled(false); // 禁用更新
    QTextEdit::resizeEvent(event);
    setUpdatesEnabled(true);  // 重新启用更新
}

注意:这种方法会完全阻止在调整大小期间的任何绘制操作,可能导致控件显示不更新,需谨慎使用。

  1. 延迟绘制
    另一种方法是延迟控件的绘制,确保在调整大小完成后进行一次性绘制。这可以通过使用定时器来实现。
#include <QTimer>

// 在类定义中添加一个定时器
private:
    QTimer *m_paintTimer;

// 在构造函数中初始化定时器
NoRepaintTextEdit::NoRepaintTextEdit(QWidget *parent)
    : QTextEdit(parent), m_isResizing(false) {
    m_paintTimer = new QTimer(this);
    m_paintTimer->setSingleShot(true);
    connect(m_paintTimer, &QTimer::timeout, this, QOverload<>::of(&QTextEdit::update));
}

void NoRepaintTextEdit::resizeEvent(QResizeEvent *event) {
    m_isResizing = true;
    QTextEdit::resizeEvent(event);
    m_isResizing = false;

    // 延迟一定时间后重新绘制
    m_paintTimer->start(100); // 100 毫秒,根据需要调整
}

void NoRepaintTextEdit::paintEvent(QPaintEvent *event) {
    if (m_isResizing) {
        // 跳过绘制
        return;
    }
    QTextEdit::paintEvent(event);
}

解释:在调整大小完成后,启动定时器延迟一段时间再调用 update() 进行绘制,这样可以减少频繁的绘制操作并确保控件在调整大小后正确更新。

  1. 优化布局管理
    确保控件的布局管理合理,减少手动调整大小的需求,借助 Qt 的布局管理器(如 QVBoxLayout、QHBoxLayout 等)自动处理控件的大小和位置变化,从而减少或避免不必要的绘制。

4. 备选方案

如果上述方法不能满足需求,考虑以下备选方案:

  1. 使用双缓冲
    Qt 默认启用了双缓冲(Qt::WA_OpaquePaintEvent 和 Qt::WA_NoSystemBackground),这有助于减少闪烁和提高绘制效率。确保这些属性被正确设置。
NoRepaintTextEdit::NoRepaintTextEdit(QWidget *parent)
    : QTextEdit(parent), m_isResizing(false) {
    setAttribute(Qt::WA_OpaquePaintEvent, true);
    setAttribute(Qt::WA_NoSystemBackground, true);
}
  1. 限制重绘区域
    通过限制重绘事件只覆盖必要的区域,减少绘制开销。
void NoRepaintTextEdit::paintEvent(QPaintEvent *event) {
    if (m_isResizing) {
        return;
    }
    // 仅重绘事件涉及的区域
    QTextEdit::paintEvent(event);
}
  1. 自定义绘制策略
    根据具体需求自定义控件的绘制策略,可能需要更深入地控制文本布局、滚动条等元素的绘制方式。

5. 完整示例

以下是一个完整的示例,展示如何创建和使用 NoRepaintTextEdit 控件,并应用延迟绘制的优化方法。

NoRepaintTextEdit.h
#ifndef NOREPAINTTEXTEDIT_H
#define NOREPAINTTEXTEDIT_H

#include <QTextEdit>
#include <QResizeEvent>
#include <QPaintEvent>
#include <QTimer>

class NoRepaintTextEdit : public QTextEdit {
    Q_OBJECT
public:
    explicit NoRepaintTextEdit(QWidget *parent = nullptr);

protected:
    void resizeEvent(QResizeEvent *event) override;
    void paintEvent(QPaintEvent *event) override;

private:
    bool m_isResizing;
    QTimer *m_paintTimer;
};

#endif // NOREPAINTTEXTEDIT_H

NoRepaintTextEdit.cpp
#include "NoRepaintTextEdit.h"

NoRepaintTextEdit::NoRepaintTextEdit(QWidget *parent)
    : QTextEdit(parent), m_isResizing(false) {
    m_paintTimer = new QTimer(this);
    m_paintTimer->setSingleShot(true);
    m_paintTimer->setInterval(100); // 100 毫秒,可根据需要调整
    connect(m_paintTimer, &QTimer::timeout, this, QOverload<>::of(&QTextEdit::update));

    // 设置双缓冲属性
    setAttribute(Qt::WA_OpaquePaintEvent, true);
    setAttribute(Qt::WA_NoSystemBackground, true);
}

void NoRepaintTextEdit::resizeEvent(QResizeEvent *event) {
    m_isResizing = true;
    QTextEdit::resizeEvent(event);
    m_isResizing = false;

    // 启动定时器以延迟绘制
    m_paintTimer->start();
}

void NoRepaintTextEdit::paintEvent(QPaintEvent *event) {
    if (m_isResizing) {
        // 跳过绘制
        return;
    }
    QTextEdit::paintEvent(event);
}

main.cpp
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include "NoRepaintTextEdit.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    NoRepaintTextEdit *textEdit = new NoRepaintTextEdit();
    textEdit->setPlainText("请输入文本...");
    layout->addWidget(textEdit);

    window.setLayout(layout);
    window.resize(600, 400);
    window.show();

    return app.exec();
}

6. 总结

通过创建自定义的 QTextEdit 子类并重载 resizeEvent 和 paintEvent,可以在控件大小改变时控制其绘制行为。然而,这种方法需要仔细测试,以确保不会引入其他视觉或功能问题。根据实际需求,选择最适合的优化策略,以实现最佳的用户体验和性能。

重要提示:

测试与验证:在实际项目中应用这些修改时,请确保在不同平台和不同使用场景下充分测试,以验证其效果和稳定性。

权衡利弊:防止控件在调整大小时重绘可能带来性能上的优化,但也可能导致界面显示异常或用户体验下降。确保这种优化是必要且有效的。

考虑Qt自身的优化机制:Qt 已经对控件的绘制进行了大量优化,手动干预绘制行为应谨慎,以避免与Qt的优化机制发生冲突。

该博文为原创文章,未经博主同意不得转载。本文章博客地址:https://cplusplus.blog.csdn.net/article/details/143217882

标签:控件,NoRepaintTextEdit,QTextEdit,isResizing,Qtextedit,绘制,event
From: https://blog.csdn.net/it_xiangqiang/article/details/143217882

相关文章

  • WINCC V7.5报表制作联系续-表格控件中小数点前0的显示
    这一篇学习笔记在新浪博客记录过,这里再次记录一下。前面做了Wincc7.5SP2查询sqlserver后结果显示在microsofthierarchicalflexgridcontrol6.0(SP4)控件,这里会遇到一个问题,就是当小数点前面是0的时候,在表格控件不会显示出来。查询网络,都是二零零几年的一些答案,说是要修改区域......
  • 【HarmonyOS】根据文本内容动态测算文本控件宽高
    【HarmonyOS】根据文本内容动态测算文本控件宽高问题背景:一般情况下,在鸿蒙里文本控件Text或者Span的宽高,我们都会设置固定宽高,或者根据内容自适应,不设置固定宽高。但是在特殊场景下,例如,父组件的宽高需要根据子组件的内容动态设置宽高。或者是文本控件根据内容会有行数变化。都需......
  • 【2024】Adobe AI(Illustrator)绘制和编辑、排版工具软件下载安装
    目录一、AdobeAI(Illustrator)软件发展历史1.起源与早期发展2.中期扩展与突破3.近期创新与融合4.下载链接二、AdobeAI(Illustrator)软件功能介绍1.矢量绘图与设计2.排版与出版3.图像上色与特效三、AdobeAI(Illustrator)软件系统要求1.操作系统与处理器2.内存......
  • React实现画布——可绘制矩形和箭头
    目录思路代码效果本文将使用React、JSX、Rough.js实现一个简单的画布,可以绘制矩形和箭头。思路每一个图形包括:绘制的类型、起点的x坐标、起点的y坐标、宽、高。调用rough的generator()函数传入图形信息进行绘制,其中对于箭头需要进一步处理:根据宽高确定终点,并且定义角度等生......
  • el-table新增记录,通过id获行记录的控件焦点
    <el-table:data="formData.list"ref="tabRef"class="my-table"> <el-table-columnlabel="编码"align="center"min-width="150"class="custom-form-item">   <template#default......
  • DELPHI 隐藏程序窗口,以及TListView控件,点击标题进行排序
    设置视图: 运行效果:    unitHideWindown;interfaceusesWindows,Messages,SysUtils,Classes,Forms,StdCtrls,ActiveX,ComObj,ShellAPI,Tlhelp32,Vcl.Controls,Vcl.ComCtrls,psapi,Vcl.ExtCtrls;typeTForm1=class(TForm)GetWList......
  • matlab点击实时绘制bezier曲线
    贝塞尔曲线的原理贝塞尔曲线是通过一组控制点定义的参数曲线。曲线不会直接穿过这些点,但这些点会影响曲线的形状。控制点确定了曲线的弯曲程度和方向。贝塞尔曲线的数学公式基于伯恩斯坦多项式(BernsteinPolynomials)。对于一个n次的贝塞尔曲线,它由n+1个控制点​定义。曲线......
  • vue3 + echarts-wordcloud 绘制词云图表
    词云图,是一种文本数据的视觉展示,由词汇组成类似云的彩色图形。echarts-wordcloud是基于echarts的一个词云库,本篇主要介绍它的使用方法。安装npminstallechartsnpminstallecharts-wordcloud注意echarts-wordcloud@2isforecharts@5echarts-wordcloud@1isforec......
  • lazarus三方控件注意事项
    lazarus三方控件注意事项1)EHLIBTprintDbgrideh不能用,跟它源码,forfpc没有任何打印的代码。Tdbgrideh斑马线,设好后,无效。其它问题。。不知。可以明确:EHLIBforfpc不是全功能的,使用时要注意鉴别。2)FASTREPORT使用汉化,乱码,只能使用英文的。其它问题。。不知3)dataset-seri......
  • Winform控件基础与进阶----DataGridView
    Winform控件基础之封装一个通用的DataGridView操作类1、创建Winform项目2、创建公共控件操作文件夹3、主界面1、控件布局2、提取通用方法3、静态方法类实现4、其他工具类实现1、JsonHelper工具类实现2、TxtOperateHelper工具类实现5、数据模型实现1、创建表结构模型2......