Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

QtCreator画UML

发表于 2019-07-24

Qt君是如何用QtCreator画UML图的。

  Qt君和往日一样,被分配了一个任务,就是设计一个网络模块。Qt君看到任务一到就来劲了,立马撸起袖子干了。

  Qt君一直在挠着自己的头,看来是遇到些难题了。看到Qt君不停挠自己的头,小张也看不过去了,在这样挠下去就会变成我这样的头了。

  小张:看到你代码遇坑了吧,主要是没有事先设计好代码?

  平时一向头铁的Qt君实在没办法了挠了挠自己的头问:我应该怎么做?

  工欲善其事必先利其器,写代码就像盖房子一样,需要对它进行设计,而设计图(蓝图)是你设计的体现。小张建议Qt君使用QtCreator软件的画UML图(统一建模)。

  Qt君经过好一阵子摸索,Qt君总结了以下的使用方法。

新建UML图步骤:

  1. 文件->新建文件或项目;
    插图
  2. Modeling->Scratch Model或Model也可以。
    插图

    简单使用方法:

  • 左侧栏为工具栏,可以画类图,包图,组件图,部署图,用例图,活动图,序列图。
  • 左侧工具栏使用拖动的方式拖到中间空白处。
    插图
  • 右上栏为文件元素栏,每拖放一个元素会在该元素目录相应添加。
  • 右下栏为属性栏,可以修改元素的属性(图中选中的是类图属性)。
    插图

  Qt君摸了摸自己的头说:又可以愉快地玩耍了。

有关更多信息可参考:

1
https://doc.qt.io/qtcreator/creator-modeling.html

轻量级Qt键盘-原理篇

发表于 2019-07-23

以类图,顺序图为切入点分析键盘使用原理。

1.类图分析

1.1 AbstractKeyboard与Keyboard
  类图中AbstractKeyboard继承于QWidget,而Keyboard则继承于AbstractKeyboard。

  或许有人会问,为什么Keyboard直接继承于QWidget这样更简单直接?
这里看情况,在单个键盘的情况下这种做法是简单直接。如何是存在多个键盘(数字键盘,字母键盘等),我们需要切换起来就会变得很麻烦。

  AbstractKeyboard提供name与setName接口是为了标识多个键盘的情况。
类图
1.2 Keyboard与KeyButton

  • Keyboard存在多个KeyButton;
  • Keyboard类通过构造多个按键并使用(h1(),h2(),h3(),h4())进行布局。
  • 当用户按下切换大小写按钮触发事先构造绑定在Keyboard类的switchCapsLock槽函数。

1.3 KeyButton与KeyMode

  • 由于KeyButton的KeyMode为了表达按键的多种显示,比如小写q,当按下大写切换就会变为大写Q,当按下字符切换就会切换到数字1。
  • KeyMode的Mode包含按键的key值,按键的value,按键在界面的显示值,还有按键的类型​。

    2.用户使用键盘顺序图

    顺序图

3. 用户切换大小写键盘为例

顺序图

附录

  • 对应plantUML类图源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    @startuml
    skinparam classAttributeIconSize -1
    QWidget <|-- AbstractKeyboard
    AbstractKeyboard <|-- Keyboard
    Keyboard o-right- "1..*" KeyButton
    KeyButton o-up- "1" KeyMode
    QPushButton <|-down- KeyButton
    package KeyMode {
    Mode o-- Type
    }

    class QWidget {
    ..internal..
    }

    class QPushButton {
    ..internal..
    }

    class AbstractKeyboard {
    + name(): QString
    + setName(QString)
    + onKeyPressed(int, QString)
    + [signal] keyPressed(int, QString)
    }

    class Keyboard {
    - switchCapsLock()
    - switchSpecialChar()
    - switchEnOrCh()
    - h1():QHBoxLayout
    - h2():QHBoxLayout
    - h3():QHBoxLayout
    - h4():QHBoxLayout
    }

    class KeyButton {
    + KeyButton(const QList<Mode>, QWidget *)
    + mode():Mode
    + switchCapsLock()
    + switchSpecialChar()
    + switching()
    + [signals] pressed(int,QString)
    }

    enum Type {
    Auto
    LowerCase
    UpperCase
    SpecialChar
    }

    class Mode<<(S,#ff7700)>> {
    + key:int
    + value:QString
    + display:QString
    + type:Type
    }

    hide QWidget fields
    hide AbstractKeyboard fields
    hide Keyboard fields
    hide KeyButton fields
    hide Type method
    hide Mode method
    @enduml
  • 对应plantUML顺序图源码:

    1
    2
    3
    4
    5
    6
    7
    @startuml
    actor 使用者
    使用者 -> KeyButton: 按下键盘按钮
    KeyButton -> Keyboard: 发送pressed信号
    Keyboard -> AbstractKeyboard: 触发onKeyPressed槽函数
    AbstractKeyboard -> QApplication:向QApplication发送按键事件
    @enduml
1
2
3
4
5
6
7
8
@startuml
actor 使用者
使用者 -> KeyButton: 按下切换大小写按钮
KeyButton -> Keyboard: 发送pressed信号
Keyboard -> Keyboard: 触发switchCapsLock槽函数
Keyboard -> KeyButton: 遍历调用switchCapsLock函数
KeyButton -> KeyButton: 根据Mode的模式显示对应字符
@enduml

看看Qt里那些使用了匿名函数

发表于 2019-07-22

匿名函数也可以被叫做Lambda表达式,自C++11中引入该特性。本文主要介绍Qt里使用到的匿名函数。

插图

1. connect中使用

  • connect中可以使用匿名函数代替槽函数进行一些简单操作。
  • 原型:

    1
    2
    3
    4
    5
    6
    7
    //connect to a functor
    template <typename Func1, typename Func2>
    static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
    connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
    {
    return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
    }
  • 示例:

    1
    2
    3
    4
    QPushButton *button = new QPushButton;
    connect(button, &QPushButton::clicked, [this]() {
    ...
    });

2. 排序使用

  • 原型:

    1
    2
    3
    4
    5
    6
    template <typename RandomAccessIterator, typename LessThan>
    QT_DEPRECATED_X("Use std::sort") inline void qSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan)
    {
    if (start != end)
    QAlgorithmsPrivate::qSortHelper(start, end, *start, lessThan);
    }
  • 使用:

    1
    2
    3
    4
    5
    6
    7
    QList<int> list{3, 1, 2};
    qSort(list.begin(),
    list.end(),
    [](int left, int right)->bool {
    return left < right;
    }
    );

3. 高级线程中使用

  • QtConcurrent命名空间中的run接口支持匿名函数,用起来简直爽得不要不要的。
  • 原型:

    1
    2
    3
    4
    5
    template <typename T>
    QFuture<T> run(T (*functionPointer)())
    {
    return (new StoredFunctorCall0<T, T (*)()>(functionPointer))->start();
    }
  • 使用:

    1
    2
    3
    QtConcurrent::run([=](){
    ...
    });

4. 定时器中使用

  • QTimer的singleShot也支持匿名函数,用起来直观明了。
  • 原型:

    1
    void singleShot(int msec, Functor functor)
  • 使用:

    1
    2
    3
    QTimer::singleShot(1000, [](){
    qDebug()<<"Finished!!!";
    });

5. 与QVariant结合使用

  • 这个功能基本不会用到,楞是要找出一个用法可以看下Qt君往期推送的Qt网络开源库系列篇中有用到。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Q_DECLARE_METATYPE(std::function<void ()>)

    int main(int argc, char *argv[])
    {
    std::function<void ()> f = [](){ qDebug()<<"22"; };
    QVariant var = QVariant::fromValue(f);
    if (var.canConvert<std::function<void ()> >()) {
    std::function<void ()> func = var.value<std::function<void ()>>();
    func();
    }
    }

6. std::for_each

  • 原型:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<class InputIterator, class Function>
    Function for_each(InputIterator first, InputIterator last, Function fn)
    {
    while (first!=last) {
    fn (*first);
    ++first;
    }
    return fn; // or, since C++11: return move(fn);
    }
  • 示例:

    1
    2
    3
    4
    5
    6
    QList<int> list{1, 2, 3};
    std::for_each(list.begin(),
    list.end(),
    [](int i) {
    ...
    });

关于Qt中更多的匿名函数(Lambda表达式)写法也可以在留言区一起讨论。

轻量级Qt键盘-介绍篇

发表于 2019-07-21

本文介绍Qt君最近编写的一个Qt键盘,该键盘主要功能有大小写切换,中英文切换(后续实现)数字输入,符号输入等基本功能,未来还会支持换肤,手写功能。

键盘演示

实现初衷

  • 供大家交流学习;
  • 希望以轻量级(嵌入式设备)键盘为特点不断发展该键盘项目(源码地址在文末)。
    键盘界面

项目预览

  • 文件目录
    文件目录

  • 基类键盘AbstractKeyboard

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class AbstractKeyboard : public QWidget
    {
    Q_OBJECT
    public:
    AbstractKeyboard(QWidget *parent = 0);
    ~AbstractKeyboard();

    const QString name();
    void setName(const QString &name);

    public slots:
    virtual void update(const QString &text);
    void onKeyPressed(int key, QString value);

    signals:
    void keyPressed(int key, QString value);
    };
  • 实现类键盘Keyboard

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Keyboard : public AbstractKeyboard
    {
    Q_OBJECT
    public:
    Keyboard(QWidget *parent = NULL);

    protected:
    void resizeEvent(QResizeEvent *e);

    private slots:
    void switchCapsLock();
    void switchSpecialChar();
    void switchEnOrCh();
    };
  • 键盘按钮KeyButton

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class KeyButton : public QPushButton
    {
    Q_OBJECT
    public:
    enum Type { Auto = 0, LowerCase, UpperCase, SpecialChar };

    struct Mode {
    int key; /* Qt::Key */
    QString value; /* text */
    QString display; /* display text */
    Type type; /* default: Auto */
    };

    KeyButton(const QList<Mode> modes = QList<Mode>(), QWidget *parent = NULL);
    Mode mode();

    void onReponse(const QObject* receiverObj, const QString &receiver);

    void switchCapsLock();
    void switchSpecialChar();
    void switching(); /* Cycle switch. */

    signals:
    void pressed(int key, QString value);
    };

后续更新

  • 轻量级Qt键盘-介绍篇
  • 轻量级Qt键盘-原理篇
  • 轻量级Qt键盘-实现篇
  • 后续会不定期更新关于主要新增功能介绍文章。
    键盘界面

关于更多

  • 源码地址:

    1
    https://github.com/aeagean/QtKeyboard
  • 本文首发公众号:Qt君

Qt快捷屏幕截图

发表于 2019-07-19

介绍两种Qt屏幕截图的方法。

方法1

  • 接口:

    1
    2
    3
    4
    5
    QPixmap QScreen::grabWindow(WId window, 
    int x = 0,
    int y = 0,
    int width = -1,
    int height = -1)
  • 示例:

    1
    2
    QScreen *screen = QGuiApplication::primaryScreen();
    screen->grabWindow(0).save("screen_shot.jpg", "jpg"); // 0值为整个电脑屏幕WId
  • 可以通过设置x,y坐标位置和width,height的大小来截图。

方法2

  • 接口:

    1
    2
    QPixmap QWidget::grab(const QRect &rectangle = QRect(QPoint(0, 0), 
    QSize(-1, -1)))
  • 示例:

    1
    2
    QWidget widget;
    widget.grab().save("screen_shot.jpg", "jpg");
  • 和QScreen的grabWindow一样可以通过设置坐标位置和窗口的大小来截图。

头铁小君使用死循环

发表于 2019-07-18

头铁小君和小张争论用for(;;)好还是while(true)好。

  小张昨晚敲代码到凌晨两点,早上回来也是精神满满的。哼着小曲路过头铁小君的座位,看到头铁小君桌面写着:

1
2
3
for (;;) {
...
}

  小张看了看说:这不是死循环吗?干嘛用这个呢?看起来也不直观,用while(1)尤其是while(true)更有可读性。我也经常用不会错的,拍了拍头铁小君的肩膀以示肯定。

  一早就被人数落的头铁小君,心有不甘地说:我用for(;;)比你的while(true)快呀。

  小张摸了摸自己的光头,看来是要放大招了。你说的这种情况是旧的非优化编译器时代才是,现代编译器for(;;)和while(true)生成的汇编都一样了,它们运行速度都一样。不信你可以写个C代码生成汇编对比下。

  头铁小君不信,立马写了个测试程序:

1
2
for (;;);
while(true);

  使用命令gcc -S test.c生成汇编文件test.s

1
2
.L2:
jmp .L2

  看到汇编内容居然一样的,心还是不服。头铁小君也不是浪得虚名的!!!我头铁小君我就是要用for (;;),可是我还要给点理由反驳一下,不然看小张得意洋洋的样子岂不是要飞了。

  思前想后,有了!就用大神Kernighan & Ritchie说的话来反驳

1
2
3
Kernighan & Ritchie long ago recommended for (;;) , which has the additional benefit
of insuring against the visually-confusing defect of a while (l); referencing a variable ‘l’.
Kernighan & Ritchie很久以前就推荐使用for(;;),它有一个额外的好处,可以防止1与字母I的视觉混乱缺陷。

  头铁小君在某些印刷体或字体库中阿拉伯数字1与字母I很像,小张你看我用for(;;)是对的吧。

  小张不屑地说道,你说1和I很像,这个我认,但是我还可以用while(true)啊,这个可读性更好。

  头铁小君顿时觉得很有道理,都想伸个大拇指点赞了。可是头铁小君的性格头铁出了名,不会改的。看来是要逼出他大招了。

  小张你看while(1)字符长度为8,while(true)字符长度为11,而for(;;)字符长度为7。单纯用字符长度比较字符短的占用的存储空间少,这间接证明运行速度快。

  小张看到头铁小君这么头铁,连忙说:好吧,你赢了。

  某天小张无意看到头铁小君的死循环写法:

1
2
3
4
5
6
#define Q_FOREVER for(;;)
#define forever Q_FOREVER

forever {
....
}

  摸了摸自己的光头说:哎哟,这个不错。

匹配版本号

发表于 2019-07-17

小张伸了伸懒腰,软件终于上线了,准备下班。看到发布包很多软件版本实在太乱了,心想不能让它这么乱,小张打算整理一下。

插图

小张简单地列出版本列表:

1
2
3
4
5
6
7
v1.0.1
v1.0.2
v1.0.2a
v1.0.3
1.0.3.beta
V1.0.4
1.0.5

这么多版本号那就先匹配vx.x.x格式吧。

1
^v\d+(\.\d+){2}$

看了看感觉只匹配了

1
2
3
v1.0.1
v1.0.2
v1.0.3

并没有匹配到V1.0.4,小张又写了起来。

1
^[vV]\d+(\.\d+){2}$

这次可以了吧,摸了摸自己没有头发的头,突然摸到了一根头发,小张想了想,把那根头发拔下来的同时想到了1.0.5也要匹配上,甭管它有没有v和V前缀,我都要匹配。

1
^(\d+(\.\d+){2})|([vV]\d+(\.\d+){2})$

看了看还是有些不简洁,又重新写了

1
^[vV]{0,1}\d+(\.\d+){2}$

这时候小张又摸了摸自己的头,不错不错,顺便也记下笔记好下班。

  • ^匹配输入字符串开始的位置。
  • $匹配输入字符串结尾的位置。
  • \d匹配一个数字字符。
  • {0,1}循环语句,最多循环一次。
  • {2}循环语句,循环两次。
  • +循环语句循环一次或多次。
  • |逻辑或语句,用于多条匹配语句组合。
  • [vV]{0,1}表示v或V可任意出现一个或可不出现。
  • \d+表示数字至少出现一次,比如1,10,100,1000。
  • (\.\d+){2}表示循环匹配两次括号内的语句,如.1.10,.11.11。

Qml开发中的性能Tips(翻译文)

发表于 2019-07-16

1.关于图像性能Tips

1.1 位图格式对比矢量图格式

  Qt支持任何标准图像格式,包括PNG和JPEG等位图格式,以及SVG等矢量图形格式。与位图图像相比,渲染SVG图像很慢。

1.2 异步加载大图像

  如果同步加载图像,则会阻塞UI界面。在许多情况下,图像不需要立即可见,因此它们可以是延迟加载的。

  • 如果不需要立即显示图像,则应在单独的线程中异步加载图像。这可以通过将QML的Image异步(asynchronous)设置为true来完成。这样,用户界面就可以保持响应。
  • 请注意,此属性仅对从本地文件系统读取的图像有效。通过网络资源(例如HTTP)加载的图像始终是异步加载的。

1.3 避免调整和缩放

  • 调整大小/缩放是QML中非常繁重的操作。使用原始大小的图像,而不是调整大小图像的大小/缩放大小。

1.4 大图像使用sourceSize属性

  图像通常是QML用户界面中使用占用最大的内存。

  • sourceSize应与大图像一起使用,因为属性设置为加载的图像则存储着实际像素数。
  • 如果你有一个很大的图像32642448,但你设置了sourceSize为204153,那么它会缩小并将被存储为204*153的内存。
  • 如果图像的实际大小大于sourceSize,则缩小图像。 这样,大图像不会占用超过必要的内存;
  • 这对于从外部源加载或由用户提供的内容尤为重要。
  • 请注意,动态更改此属性会导致重新加载图像源,甚至可能来自网络,如果它不在内存缓存中。
  • 图像在内部进行缓存和共享,因此如果多个图像元素使用相同的源,则只加载图像的一个内存。

1.5 仅在必要时启用Image的smooth属性

  启用smooth属性对性能不利。使用自然大小的图像或禁用动画中的平滑(smooth)处理。

  • Image的smooth属性可在缩放或转换时平滑处理图像。
  • 平滑处理提供更好的视觉质量,但速度较慢。
  • 如果图像以其自然大小显示,则Image的smooth没有视觉效果或性能影响。
  • 如果您确实需要启用Image的smooth属性,请在动画开始时禁用平滑处理,并在动画结束时重新启用它(仅当图像在屏幕上静止时,缩放瑕疵才可见)。

1.6 避免由多个元素组成图像

  由单个图像组成的图像比由多个元素组成图像效率更高。

  • 例如,可以使用放置在提供阴影的图像上的矩形来创建具有阴影的图像。
  • 提供包括框架和阴影的图像效率更高。

2.关于列表性能Tips

2.1 确保您的数据模型尽可能快

  在许多情况下,慢速模型(slow model)实际上是列表滚动性能的瓶颈。请确保数据模型尽可能快。

  • 视图被轻弹(拖动)时,必须快速创建代理;
  • 例如,在单击委托时仅需要的任何其他功能应由Loader在需要时创建;
  • 在委托中将QML的数量保持在最低水平。委托中的元素越少,视图的滚动速度就越快;
  • 在列表委托中,仅将QML用于用户界面,并使用C++实现其余部分(例如:数据生成,数据处理)。不要使用JavaScript。

2.2 在ListView/GridView中使用CacheBuffer

  在某些情况下,cacheBuffer在改善ListView/GridView性能方面很有用。默认的cacheBuffer为零。

  • cacheBuffer属性确定是否在视图的可见区域之外实例化委托(delegate)。
  • 请注意,cacheBuffer以像素为单位定义,例如: 如果委托高20像素,则cacheBuffer设置为40(最多2个委托实例),可见区域下方的2个委托实例可以保留在内存中。
  • 设置此值可以提高滚动行为的流畅性,但要牺牲额外的内存使用量。数据本身不缓存,但缓存的是实例化委托。
  • 对于较短的列表,那么其中每个项都可以缓存。
  • 对于较长的列表,cacheBuffer没有带来好处,因为创建条目的速度与快速滚动时没有缓存的速度相同。cacheBuffer只是推迟了问题的发生,也就是说,它只是将委托创建的位置推到列表/网格可见部分的上方/下方。
  • 更多关于cacheBuffer信息请查看:
    1
    http://doc.qt.io/qt-5/qml-qtquick-listview.html#cacheBuffer-prop

2.3 避免无用的绘画

  你应该防止在同一个区域重复绘画。例如,如果您提供了应用程序的背景,则可以防止QDeclarativeView绘制其窗口背景:

1
2
3
4
5
QDeclarativeView window;
window.setAttribute(Qt::WA_OpaquePaintEvent);
window.setAttribute(Qt::WA_NoSystemBackground);
window.viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
window.viewport()->setAttribute(Qt::WA_NoSystemBackground);

  此外,考虑使用Item作为根元素而不是Rectangle,以避免多次绘制背景:

  • 如果你的根元素是一个Rectangle,就会绘制每个像素,甚至可能是几次。
  • 系统QDeclarativeView首先绘制背景,然后绘制所有QML元素。
  • 您可能有一个Rectangle作为根元素,并且内部有很多元素,没有不透明度覆盖大部分Rectangle。在这种情况下,系统正在进行无用的绘画。
  • 您可以改为使用Item作为根元素,因为它没有视觉外观。
  • 如果您需要绘制背景,但是具有覆盖屏幕一部分的静态UI元素,您仍然可以使用Item作为根元素并在这些静态项之间锚定一个Rectangle。这样你就不会做无用的绘画。
      更多信息请查看:
    1
    http://doc.qt.io/qt-5/qtquick-performance.html#rendering

3.使用动态加载优化性能

  如果需要解析大量QML,则QML应用程序会缓慢启动。如果整个应用程序在一个代码量巨大的QML文件中实现,就会发生这种情况。明智地将应用程序划分为逻辑实体,在开始时加载最小QML,然后再使用加载器Loader根据需要加载更多QML。

  • Loader控件可用于动态加载和卸载在QML文件中定义的可视QML组件或在QML文件中定义的项/组件。这种动态行为允许开发人员控制应用程序的内存使用和启动速度。
  • 将应用程序划分为几个QML文件,以便每个文件包含一个逻辑UI实体。这种装卸方式更容易控制。每个应用程序不应该写一个巨大代码量的QML文件。
  • 在应用程序启动时加载绝对最少量的QML,以使您的应用程序尽快启动。在应用程序UI可见后,您可以连接到网络并显示微调器等。
  • 如果您的第一个视图非常复杂并且需要加载大量QML,请显示一个启动画面,让用户感觉某些事情正在发生(过渡效果)。
  • 您应该只根据需要加载UI片段,例如当用户导航到另一个视图时,但是另一方面,在视图之间导航(切换)可能需要更多的时间。
  • 更多Loader控件信息请查看:
    1
    http://doc.qt.io/qt-5/qml-qtquick-loader.html

4.其他QML的一些性能Tips

  如果您有一个固定长度的简单列表,您可以尝试使用Flickable+Column+Repeater来优化性能,而不是使用QML的ListView。虽然创建列表会慢一些,但是列表滚动会更流畅。

4.1 在过渡动画中尽可能为屏幕的小区域设置动画

  如果您需要在一秒钟内移动3个元素,请尝试每次移动300毫秒。该系统可以计算需要重新绘制的项的边界,并在这些边界内绘制所有内容。

4.2 避免复杂的裁剪

  您应该只在真正需要的时候启用裁剪clip功能。默认clip值为false。

  • 如果启用了裁剪,则Item将把自己的绘制以及其子项的绘制裁剪到其边界矩形。

4.3 如果从QML文件中去掉注释或空白,是否有助于提高性能?

  不是真的。这些文件在启动时被重新处理为二进制内存表示,因此到运行时应该不会有性能差异。您可能很幸运,获得了0.5%的改进,然后只在启动时(QML解析就是在这里完成的),其他地方都没有。

4.4 避免不必要的转换

  如果属性的给定值与属性指定的类型不匹配,QML将执行类型转换。这种转换会消耗额外的内存。

  • 例如,Image和BorderImage需要一个图像源,类型为url。如果图像源的属性定义为string,则需要转换,实际上它应该是url属性。
  • 错误方法:

    1
    property string messageAvatar: ""
  • 正确方法:

    1
    property url messageAvatar: ""

4.5 小心字符串操作

  • 操作符的多次使用通常意味着多次内存分配。
  • 使用StringBuilder获得更高效的字符串。QStringBuilder使用表达式模板并重新实现运算符,这样当您使用的多个子字符串连接将被推迟,直到最终结果将被分配给QString。 此时,已知最终结果所需的存储量。然后调用内存分配器一次以获得所需的空间,并将子串逐个复制到其中。
  • 定义QT_USE_FAST_CONCATENATION,QT_USE_FAST_OPERATOR_PLUS宏来优化字符串内存操作。

最后

  • 有关更多QML性能优化相关信息可查看:

    1
    http://doc.qt.io/qt-5/qtquick-performance.html
  • 本文翻译自Qt官网,发布于微信公众号:Qt君

    1
    2
    3
    4
    https://wiki.qt.io/Performance_tip_Images
    https://wiki.qt.io/Performance_tip_Lists
    https://wiki.qt.io/Performance_tip_Use_Loaders
    https://wiki.qt.io/Performance_tip_QML_other

存在i+1小于i

发表于 2019-07-15

i为整数,在数学代数中i+1比i大,但是在编程上却不尽是,来看看什么原因吧。

成立条件

  当i的值为INT_MAX时i + 1 < i成立。

原因

  INT_MAX值为2147483647,而INT_MAX + 1则会整数溢出变为-2147483648,就会导致i + 1 < i。

现实意义

  • 作数值运算时需要考虑到溢出问题,在上述情况中应该增加对i + 1范围的判断避免数值的溢出。
  • 划重点笔试经常考。

QClipboard使用

发表于 2019-07-14

QClipboard类提供对系统剪贴板的读写。

普通使用

  • 获取剪切板的文本内容。

    1
    2
    QClipboard *clipboard = QApplication::clipboard();
    QString text = clipboard->text();
  • 设置剪切板本文内容。

    1
    2
    QClipboard *clipboard = QApplication::clipboard();
    clipboard->setText(newText);

进阶使用

  • 通过QClipboard的mimeData对象来判断剪切板的内容属性。
  • 相对于QClipboard剪切板mimeData可以识别的类型有图像数据,html数据,纯文本数据。
  • 例子:
      (1)获取系统剪切板内容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const QClipboard *clipboard = QApplication::clipboard();
    const QMimeData *mimeData = clipboard->mimeData();

    if (mimeData->hasImage()) {
    /* 获取剪切板图像数据。 */
    QPixmap pixmap = qvariant_cast<QPixmap>(mimeData->imageData());
    ...
    }
    else if (mimeData->hasHtml()) {
    /* 获取剪切板html数据。 */
    QString html = mimeData->html();
    ...
    }
    else if (mimeData->hasText()) {
    /* 获取剪切板纯文本数据。 */
    QString text = mimeData->text();
    ...
    }
    else {
    setText("Cannot display data");
    }

  (2)设置系统剪切板内容:

1
2
3
4
5
6
QClipboard *clipboard = QApplication::clipboard();
QMimeData mimeData;
mimeData.setImageData(QPixmap("hello.png")); // 图像数据
// mimeData.setHtml("<h1>Heool world.</h1>"); // Html数据
// mimeData.setText("Hello world."); // 纯文本数据
clipboard->setMimeData(&mimeData);

1…121314…32
Qt君

Qt君

313 日志
41 标签
© 2019 Qt君
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4
粤ICP备 - 16070052号