Qt君


  • 首页

  • 关于

  • 归档

  • 搜索

QThread类

发表于 2019-04-08

QThread类提供一种独立于平台的线程管理方式。

头文件 #include <QThread>
qmake QT += core
继承于 QObject

1.公有类型

enum Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, …, InheritPriority}

2.公有函数

QThread(QObject *parent = nullptr)
virtual ~QThread()
QAbstractEventDispatcher * eventDispatcher() const
void exit(int returnCode = 0)
bool isFinished() const
bool isInterruptionRequested() const
bool isRunning() const
int loopLevel() const
QThread::Priority priority() const
void requestInterruption()
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
void setPriority(QThread::Priority priority)
void setStackSize(uint stackSize)
uint stackSize() const
bool wait(unsigned long time = ULONG_MAX)

3.公有重载函数

virtual bool event(QEvent *event) override

4.公有槽函数

void quit()
void start(QThread::Priority priority = InheritPriority)
void terminate()

5.信号

void finished()
void started()

6.静态公有成员

QThread * create(Function &&f, Args &&… args)
QThread * create(Function &&f)
QThread * currentThread()
Qt::HANDLE currentThreadId()
int idealThreadCount()
void msleep(unsigned long msecs)
void sleep(unsigned long secs)
const QMetaObject staticMetaObject
void usleep(unsigned long usecs)
void yieldCurrentThread()

7.受保护函数

int exec()
virtual void run()

8.静态受保护成员

void setTerminationEnabled(bool enabled = true)

9.详细描述

  QThread类提供一种独立于平台的线程管理方式。
  一个QThread实例管理程序中的一个线程。QThread的执行开始于run()。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。

9.1使用QThread方法

方法1(工作对象方法)

  你可以使用QObject::moveToThread()将工作对象移动到线程中使用。

  • 示例:
    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
    class Worker : public QObject
    {
    Q_OBJECT
    public slots:
    void doWork(const QString &parameter) {
    QString result;
    /* ... here is the expensive or blocking operation ... */
    emit resultReady(result);
    }

    signals:
    void resultReady(const QString &result);
    };

    class Controller : public QObject
    {
    Q_OBJECT
    QThread workerThread;
    public:
    Controller() {
    Worker *worker = new Worker;
    worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    connect(this, &Controller::operate, worker, &Worker::doWork);
    connect(worker, &Worker::resultReady, this, &Controller::handleResults);
    workerThread.start();
    }

    ~Controller() {
    workerThread.quit();
    workerThread.wait();
    }

    public slots:
    void handleResults(const QString &);

    signals:
    void operate(const QString &);
    };

  将线程移动到工作线程内执行。因为在线程中有队列的信号槽连接机制,所以在不同线程中使用信号槽是安全的。

方法2(继承QThread方法)

  另一种单独在线程中执行的方式是继承QThread后重新实现run()函数(run函数内用户的执行操作)。

  • 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class WorkerThread : public QThread
    {
    Q_OBJECT
    void run() override {
    QString result;
    /* ... here is the expensive or blocking operation ... */
    emit resultReady(result);
    }
    signals:
    void resultReady(const QString &s);
    };

    void MyObject::startWorkInAThread()
    {
    WorkerThread *workerThread = new WorkerThread(this);
    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    workerThread->start();
    }

  在上面示例中,线程将在运行函数返回后退出。除非调用exec(),否则线程中不会运行任何事件循环。

  重要的是要记住,QThread实例位于实例化它的旧线程中,而不是位于调用run()的新线程中。这意味着QThread的所有队列槽和调用的方法都将在旧线程中执行。因此,希望调用新线程中的槽的开发人员必须使用工作对象方法;新的槽不应直接实现到子类QThread中。

  与队列槽或调用的方法不同,直接在QThread对象上调用的方法将在调用该方法的线程中执行。当子类化QThread时,请记住构造函数在旧线程中执行,而run()在新线程中执行。如果从两个函数访问一个成员变量,则从两个不同的线程访问该变量。需要检查这样做是否安全。

  注意:在跨不同线程与对象交互时必须小心。有关详细信息,请参见同步线程。

9.2管理线程

  QThread会通过信号started()和finished通知你,或者您可以使用isFinished()和isRunning()查询线程的状态。

  你可以调用exit()和quit()来停止线程。在极端的情况下,你希望强制使用terminate()来终止线程。但是,这样做是又危险又令人气馁。详细请读terminate()和setTerminateEnabled()相关文档。

  从Qt4.8起,通过将finished()信号连接到QObject::deleteLater(),可以释放位于刚刚结束的线程中的对象。

  使用wait()来阻塞调用线程,直到另外一个线程执行完成或直到经过指定时间。

  QThread还提供了与平台无关的静态睡眠函数:sleep()、msleep()和usleep()分别为秒、毫秒和微秒。这些函数在Qt 5.0中是公有函数(Qt 4.0版本为保护函数)。

  注意:wait()和sleep()函数通常是不必要的,因为Qt是一个事件驱动框架。与其使用wait(),还不如考虑监听finished()信号,或使用QTimer代替sleep()函数。

  静态函数currentThreadID()和currentThread()返回当前执行线程的标识符。前者返回线程的平台特定ID;后者返回QThread指针。

  要选择线程的名称(例如,在Linux上的命令ps -L标识),可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),则给线程的名称将是线程对象运行时类型的类名(例如,对于Mandelbrot示例中的”RenderThread”,因为它是QThread子类的名称)。请注意,目前在Windows的发布版本中不可用。

  另外请参阅,Qt在线程中的支持, QThreadStorage, 同步线程, Mandelbrot示例, 信号量示例, 等待条件示例.

10.成员类型文档

  枚举 QThread::Priority(优先权)
  此枚举类型指示操作系统应如何调度新创建的线程。

常量 值 描述
QThread::IdlePriority 0 仅在没有其他线程运行时调度。
QThread::LowestPriority 1 调度的次数比LowPriority少。
QThread::LowPriority 2 调度的次数比NormalPriority少。
QThread::NormalPriority 3 操作系统的默认优先级。
QThread::HighPriority 4 调度的次数比NormalPriority多。
QThread::HighestPriority 5 调度的次数比HighPriority多。
QThread::TimeCriticalPriority 6 经可能多地调度。
QThread::InheritPriority 7 使用与创建线程相同的优先级。(这是默认值)

11.成员函数文档

1
QThread::QThread(QObject *parent = nullptr)

  构造一个新QThread来管理一个新线程。父线程拥有QThread的所有权。直到调用start(),线程才开始执行。
  另外请参阅start()。


1
[virtual] QThread::~QThread()

  销毁QThread。
  注意,删除QThread对象不会停止它管理的线程的执行。删除正在运行的QThread(即isFinished()返回false)将导致程序崩溃。在删除QThread之前,等待finished()信号。


1
[static] QThread *QThread::create(Function &&f, Args &&... args)

  创建一个新的QThread对象,该对象将使用参数args和执行函数f。
  新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
  返回新创建的QThread实例。

  注意:调用者获得返回的QThread实例的所有权。
  注意:此函数仅在使用c++ 17时可用。
  警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。

  该函数从Qt 5.10中引入。
  另外请参阅start()。


1
static] QThread *QThread::create(Function &&f)

  创建一个新的QThread对象,该对象将执行函数f。
  新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
  返回新创建的QThread实例。

  注意:调用者获得返回的QThread实例的所有权。
  注意:此函数仅在使用c++ 17时可用。
  警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。

  该函数从Qt 5.10中引入。
  另外请参阅start()。


1
[static] QThread *QThread::currentThread()

  返回一个指向管理当前执行线程的QThread的指针。


1
[static] Qt::HANDLE QThread::currentThreadId()

  返回当前执行线程的线程句柄。
  注意:在Windows上,这个函数返回由Win32函数GetCurrentThreadId()返回的DWORD(Windows线程ID),而不是由Win32函数GetCurrentThread()返回的伪句柄(Windows线程句柄)。
  警告:此函数返回的句柄用于内部目的,不应在任何应用程序代码中使用。


1
[override virtual] bool QThread::event(QEvent *event)

  重新实现QObject::event()。


1
QAbstractEventDispatcher *QThread::eventDispatcher() const

  返回指向线程的事件调度程序对象的指针。如果线程不存在事件调度程序,则此函数返回0。
  该函数从Qt 5.0中引入。
  另外请参阅setEventDispatcher()。


1
[protected] int QThread::exec()

  进入事件循环,并等待直到调用exit(),返回传递给exit()的值。如果通过quit()调用exit(),返回的值为0。
  这个函数应该在run()中调用。需要调用这个函数(run())来启动事件处理。
  另外请参阅quit()和exit()。


1
void QThread::exit(int returnCode = 0)

  告诉线程的事件循环使用退出代码退出。
  调用此函数后,线程离开事件循环,并从对QEventLoop::exec()的调用返回。QEventLoop::exec()函数返回退出代码。
  按照惯例,退出代码为0表示成功,任何非零值表示错误。

  请注意,与同名的C库函数不同,此函数会返回到调用者和停止的事件处理。
  调用exit函数后在此线程中不再启动QEventLoop,直到再次调用QThread::exec()。 如果QThread::exec()中的事件循环没有运行,那么下一次调用QThread::exec()也会立即返回。
  另外请参阅quit与QEventLoop。


1
[signal] void QThread::finished()

  该信号在完成执行之前从关联线程中发出。
  发出此信号时,事件循环已停止运行。 除延迟删除事件外,线程中不再处理任何事件。 此信号可以连接到QObject::deleteLater(),以释放该线程中的对象。

  注意:如果使用terminate()终止关联的线程,则不确定从哪个线程发出此信号。
  注意:这是一个私有信号。它可以用于信号连接,但不能由用户发出。
  另外请参阅started()。


1
[static] int QThread::idealThreadCount()

  返回可在系统上运行的理想线程数。这样就可以查询系统中的实际和逻辑处理器内核的数量。如果无法检测到处理器核心数,则此函数返回1。


1
bool QThread::isFinished() const

  如果线程结束则返回true,否则返回false。
  另外请参阅isRunning。


1
bool QThread::isInterruptionRequested() const

  如果可以停止在此线程上运行的任务,则返回true。requestInterruption()函数可以进行请求中断操作。

  此函数可用于长时间运行的任务中判断中断状态。 从不检查或操作此函数的返回值是安全的,但建议在长时间运行的函数中定期执行此操作。
  注意:不要经常调用它,以保持低开销。

1
2
3
4
5
6
7
void long_task() {
forever {
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
}

译者注:

1
2
3
4
5
6
7
>virtual void run() Q_DECL_OVERRIDE {
> while (!isInterruptionRequested()) // 判断是否请求终止
> {
> /* 用户耗时操作 */
> }
>}
>

  该函数从Qt 5.2中引入。
  另外请参阅currentThread()和requestInterruption()。


1
bool QThread::isRunning() const

  如果线程正在运行则返回true,否则返回false。
  另外请参阅isFinished()。


1
int QThread::loopLevel() const

  返回线程的当前事件循环级别。
  注意:这只能在线程本身内调用,即当它是当前线程时。
  该函数从Qt 5.5引入。


1
[static] void QThread::msleep(unsigned long msecs)

  强制当前线程休眠msecs毫秒。

  如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

  注意:此功能不保证准确性。 在重负载条件下,应用程序可能比msecs睡眠时间更长。 某些操作系统可能会将msecs舍入到10 ms或15 ms。
  另外请参阅sleep()和usleep。


1
QThread::Priority QThread::priority() const

  返回正在运行的线程的优先级。 如果线程未运行,则此函数返回InheritPriority。
  该函数从Qt 4.1中引入。
  另外请参阅Priority,setPriority()和start()。


1
[slot] void QThread::quit()

  告诉线程的事件循环退出并返回代码0(成功)。相当于调用QThread::exit(0)。
  如果线程没有事件循环,则此函数不执行任何操作。
  另外请参阅exit()和QEventLoop。


1
void QThread::requestInterruption()

  请求中断线程。 该请求是建议性的,由线程上运行的代码来决定它是否以及如何根据此类请求执行操作。此函数不会停止在线程上运行的任何事件循环,也不会以任何方式终止它。

译者注:
示例:

  • 当用户执行killAndWait()函数后则会导致run()函数内循环体结束,从而结束线程执行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    >class WorkerThread : public QThread
    >{
    > Q_OBJECT
    >public:
    > void killAndWait()
    > {
    > requestInterruption(); /* 请求终止 */
    > quit();
    > wait();
    > }
    >
    >protected:
    > virtual void run() Q_DECL_OVERRIDE
    > {
    > while (!isInterruptionRequested()) /* 判断是否终止 */
    > {
    > /* 用户耗时操作 */
    > }
    > }
    >};
    >

  该函数从Qt 5.2中引入。
  另外请参阅isInterruptionRequested()。


1
[virtual protected] void QThread::run()

  线程的起点。在调用start()之后,新创建的线程自动调用此函数。默认实现只是调用exec()。
  您可以重新实现此功能以便于高级线程管理。 从此方法返回将结束线程的执行。

  另外请参阅start()和wait()。


1
void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)

  将线程的事件调度器设置为eventDispatcher。 只有当没有为该线程安装事件调度器时,才可以执行此操作。 也就是说,在使用start()启动线程之前,或者在主线程的情况下,在实例化QCoreApplication之前。 此方法获取对象的所有权。

  该函数从Qt 5.0中引入。
  另外请参阅eventDispatcher()。


1
void QThread::setPriority(QThread::Priority priority)

  此函数设置正在运行的线程的优先级。 如果线程没有运行,则此函数不执行任何操作并立即返回。使用start()启动具有特定优先级的线程。
  优先级参数可以是QThread::Priority枚举中的任何值,但InheritPriorty除外。
  优先级参数的影响取决于操作系统的调度策略。 特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅http://linux.die.net/man/2/sched_setscheduler以获取更多详细信息)。

  该函数从Qt 4.1中引入。
  另外请参阅Priority,priority()和start()。


1
void QThread::setStackSize(uint stackSize)

  将线程的最大堆栈大小设置为stackSize。如果stackSize大于0,则最大堆栈大小设置为stackSize字节,否则最大堆栈大小由操作系统自动确定。

  警告:大多数操作系统对线程堆栈大小设置了最小和最大限制。如果堆栈大小超出这些限制,则线程将无法启动。
  另外请参阅stackSize();


1
[static protected] void QThread::setTerminationEnabled(bool enabled = true)

  根据enabled参数启用或禁用当前线程的终止。该线程必须由QThread启动。

  如果enabled为false,则禁用终止。对QThread::terminate()的未来调用将立即返回而不起作用。相反,终止延迟直到启用终止。

  如果enabled为true,则启用终止。对QThread::terminate()的未来调用将正常终止该线程。 如果终止已被延迟(即在终止禁用的情况下调用QThread::terminate()),则此函数将立即终止调用线程。 请注意,在这种情况下,此函数不会返回。

  另外请参阅terminate()。


1
[static] void QThread::sleep(unsigned long secs)

  强制当前线程休眠secs秒。

  如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

  注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。
  另外请参阅msleep()和usleep()。


1
uint QThread::stackSize() const

  返回线程的最大堆栈大小(如果使用setStackSize()设置),否则返回0。
  另外请参阅setStackSize()。


1
[slot] void QThread::start(QThread::Priority priority = InheritPriority)

  通过调用run()开始执行该线程。操作系统将根据优先级参数调度线程。如果线程已在运行,则此函数不执行任何操作。

  优先级参数的影响取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅sched_setscheduler文档以获取更多详细信息)。

  另外请参阅run()和terminate()。


1
[signal] void QThread::started()

  在调用run()函数之前,该信号在开始执行时从关联的线程发出。

  注意:这是一个私有信号。 它可以用于信号连接,但不能由用户发出。
  另外请参阅finished()。


1
[slot] void QThread::terminate()

  终止线程的执行。根据操作系统的调度策略,线程可能会立即终止也可能不会立即终止。 请确保terminate()之后使用QThread :: wait()来等待结束。

  当线程终止时,所有等待线程都将被唤醒。

  警告:此功能很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。修改数据时可以终止线程。会导致线程无法自行清理,解锁任何保持的互斥锁等。简而言之,只有在绝对必要的情况下才使用此功能。

  可以通过调用QThread::setTerminationEnabled()显式启用或禁用terminate()的生效。在终止被禁用时调用此函数会导致终止延迟,直到重新启用终止。有关更多信息,请参阅QThread::setTerminationEnabled()的文档。
  另外请参阅setTerminationEnabled()。


1
[static] void QThread::usleep(unsigned long usecs)

  强制当前线程休眠usecs秒。

  如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event())。

  注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。一些操作系统可能将usecs调到10 ms或15 ms;另外在Windows上,它将调到1ms的倍数。
  另外请参阅sleep()和usleep()。


1
bool QThread::wait(unsigned long time = ULONG_MAX)

  阻塞线程,直到满足以下任一条件:

  • 条件1:与此QThread对象关联的线程已完成执行(即从run()返回时)。如果线程已完成,此函数将返回true。 如果线程尚未启动,它也会返回true。
  • 条件2:等待的时间已过。 如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(线程必须从run()返回)。 如果等待超时,此函数将返回false。

  这提供了与POSIX pthread_join()函数类似的功能。
  另外请参阅sleep()和terminate()。


1
[static] void QThread::yieldCurrentThread()

  如果有的话,将当前线程的执行产生到另一个可运行的线程。请注意,操作系统决定切换到那个线程。

译者注: 放弃当前时间片切换到其他线程,而切换到那一个线程由系统决定。


  • 原文来源:

    1
    https://doc.qt.io/qt-5/qthread.html
  • 译者:Qt君

使用qmake生成vs项目文件

发表于 2019-04-07

使用qmake生成生成Visual Studio 2010项目文件.

1
qmake -spec win32-msvc2010 -tp vc project.pro

C/C++黑魔法-编译期断言

发表于 2019-04-06

今天查看Linux内核源码,出现一个很奇怪的用法。可以在静态编译期的断言。

1. 内核源码kernel.h

  • BUILD_BUG_ON_ZERO判断表达式非零值编译器报错;
  • BUILD_BUG_ON_NULL判断表达式指针地址非空报错。
    1
    2
    3
    4
    5
    6
    /* Force a compilation error if condition is true, but also produce a
    result (of value 0 and type size_t), so the expression can be used
    e.g. in a structure initializer (or where-ever else comma expressions
    aren't permitted). */
    #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
    #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))

2. 源码解析

  • (e):计算表达式e;
  • !!(e):逻辑否定两次;
  • -!!(e):0如果是0; 否则-1;
  • struct{int: -!!(0);} --> struct{int: 0;}:如果它为零,那么我们声明一个结构,其中包含一个宽度为零的匿名整数位域。这样会编译正常;
  • struct{int: -!!(1);} --> struct{int: -1;}:如果它不是零,那么它将是一些负数。声明任何具有负宽度的位域是编译错误。
  • 利用位域的宽度做编译判断,因为任何负数的位域都是错误的。

3. 为什么不使用断言?

  • 静态断言宏实现了编译时测试,断言宏assert是一个运行时测试;
  • 可以在编译器找出错误。无论在何种程度上,在编译时都可以检测到问题,就更好了。特别是在操作系统的关键部分。

软件的熵

发表于 2019-04-05

出现问题就要入手修正,不然无序熵就会慢慢扩大,导致项目走向衰败。

    尽管软件开发几乎不受任何物理定律的约束,熵对我们的影响很大。熵时一个来自物理学的概念,指的是某个系统中的”无序”的总量。遗憾的是,热力学定律保证了宇宙中的熵倾向于最大化。当软件中的无序增长时,程序员们称之为”软件腐烂”。
    有很多因素可以促生软件腐烂。其中最重要的一个似乎时开发项目时的心理(或文化)。即使你的团队只有你一个人,你开发项目时的心理也可能是非常微妙的事情。尽管制定了最好的计划,拥有最好的开发者,项目在其生命期中仍可能遭遇毁灭和衰败。而另外有一些项目,尽管遇到巨大的困难和接连而来的挫折,却成功地击败自然的无序倾向,设法取得相当好的结果。
    ——引用自《程序员修炼之道》

Linux调度时机

发表于 2019-04-04

介绍linux进程/线程的调度时机,linux使用时间片方式进行调度。

  • 进程状态转换的时刻,如进程中止、进程睡眠等;
  • 进程主动释放时间片;
  • 可运行队列中新增加一个进程;
  • 进程时间片用完;
  • 进程从系统调用返回用户态;
  • 内核处理完中断后,进程返回用户态。

QQmlContext设置上下文

发表于 2019-04-03

使用QQmlContext类设置qml界面的上下文。

例子

  • setContextProperty为设置myModel属性名字到qml中使用,modelData为上下文数据;
  • QQmlComponent为创建qml组件。
    1
    2
    3
    4
    5
    6
    7
    8
    QQmlEngine engine;
    QStringListModel modelData;
    QQmlContext *context = new QQmlContext(engine.rootContext());
    context->setContextProperty("myModel", &modelData);

    QQmlComponent component(&engine);
    component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
    QObject *window = component.create(context);

向上/向下取整与四舍五入

发表于 2019-04-02

向上取整为存在大于0的小数位该数+1;
向下取整为存在大于0的小数位该数-1;
四舍五入为小数大于5的+1.

向上取整

1
2
3
#include <math.h>
ceil(0.1); // 输出:1
ceil(-0.1); // 输出:0
1
2
3
#include <QtMath>
qCeil(0.1); // 输出:1
qCeil(-0.1); // 输出:0

向下取整

1
2
3
#include <math.h>
floor(0.1); // 输出:0
floor(-0.1); // 输出:-1
1
2
3
#include <QtMath>
qFloor(0.1); // 输出:0
qFloor(-0.1); // 输出:-1

四舍五入

1
2
#include <math.h>
round(0.5); // 输出:0

查找Github最高星标的项目(附996.ICU目前排行)

发表于 2019-04-01

查找Github最高星标项目和克隆项目。

  • 查找最高星标项目stars:>0
    most_star.png

  • 查找最高克隆项目stars:>1
    most_fork.png

  • 查找最活跃项目
    most_trending.png

C/C++黑魔法-三字母彩蛋

发表于 2019-03-31

三字母(trigraphs)使用三个特殊的符号解析为对应符号的例如??(映射为]

编译通过的示例

  • 编译加入三字符选项trigraphs参数;
  • 如: gcc -trigraphs trigr.c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>

    int main(int argc, char *argv??(??))
    ??<
    printf("%s\n", "??!"); // |
    printf("%s\n", "??("); // [
    printf("%s\n", "??)"); // ]
    printf("%s\n", "??<"); // {
    printf("%s\n", "??>"); // }
    printf("%s\n", "??'"); // ^
    printf("%s\n", "??="); // #
    printf("%s\n", "??-"); // ~
    return 0;
    ??>

起源

  • 在最初的Unix和C的时代使用ASR-33电传打字机时候,由于这个设备很慢,且支持的ASCII字符集视图以0x5f结束,导致了某些字符不能打印出来,以至于定义三字母来解决特定的ASR-33上的ASCII子集以及缺少高ASCII值的其他环境;
  • 引入标准ISO/IEC646及其前身ASCII(ANSI X3.4),
    详细请查看https://en.wikipedia.org/wiki/ISO/IEC_646#History
  • 最后建议不要使用三字母,编写人们可以理解的代码。

部分对照表参考

三字母 含义
??( [
??) ]
??< {
??> }
??’ ^
??= #
??! \
??- ~
??(??) [][]
??<??> {}

Qt软键盘-发送按键事件

发表于 2019-03-30

发送按键事件到当前聚焦的窗体。

1.获取当前聚焦的QWidget

1
2
QWidget *receiver = QApplication::focusWidget();
qDebug()<<"Send key event to focus widget "<<receiver->objectName();

2.装载press与release事件

  • key为按键键值(整型);
  • value为按键实际值(QString).
    1
    2
    QKeyEvent keyPress(QEvent::KeyPress,     key, Qt::NoModifier, value);
    QKeyEvent keyRelease(QEvent::KeyRelease, key, Qt::NoModifier, value);

3.发送按键事件

1
2
QApplication::sendEvent(receiver, &keyPress);
QApplication::sendEvent(receiver, &keyRelease);
1…232425…32
Qt君

Qt君

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