返回顶部

QT相关

Qt 优秀视频资源

1,
链接:https://pan.baidu.com/s/1SNkIkEFAOCjZYbq4YqxM3w
提取码:qzk1
它里面使用Python作为开发语言,使用PyQt5来大体的介绍了QWidget相关的各个类的使用,比较适合入门


2,
https://www.bilibili.com/video/BV1AX4y1w7Nt
这套视频是b站的免费视频,它里面使用C++作为开发语言。它使用QCreator作为开发工具,
使用QDesigner和代码混合的方式进行编程,
也讲解了更多的主题(传统控件,代理,文件操作,QSql,QPainter,QGraphics,QCharts,3d图表,自定义插件等)。
它的一个缺点是没有使用VS作为开发工具,建议学习这套视频的时候可以使用VS!

 

基础知识

输出函数

可以使用  qlogging.h 中的qInfo ,也可以使用 QDebug 中的qDebug。

例子:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "qlogging.h"
#include "QDebug"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qInfo()<<"hello QT 1";
    qDebug()<<"hello QT 2";

}

MainWindow::~MainWindow()
{
    delete ui;
}
mainwindow.cpp

定时器

使用QTimer, 

三步骤: 1,创建QTimer 2, connect 信号槽, 3 timer.start(dura)

例子:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QDebug"
#include "QTimer"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    timer = new QTimer();
    connect(timer,&QTimer::timeout,this,&MainWindow::print);
    timer->start(1000);

    connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::print);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::print()
{
    qDebug()<< "size "<<size();
}
mainwindow.cpp

 

其他方法:

使用QObject中带的 startTimer  和 timerEvent

class AnalogClockWindow :public RasterWindow
{
public:
    AnalogClockWindow();

protected:
    void timerEvent(QTimerEvent *event) override;

private:
    int mn_timerId;
};

AnalogClockWindow::AnalogClockWindow()
{
    mn_timerId = startTimer(1000);
}

void AnalogClockWindow::timerEvent(QTimerEvent *event)
{
    if (event->timerId() == mn_timerId)
    {
        qDebug() << "-----------1s----------- ";
    }
}
View Code

 

 

 

 

Qt使用 MSVC编译器 中文乱码问题

一,使用Qt creator 

在Qt Creator中使用msvc的编译器

两个问题:1,编译失败  2 运行时乱码

1,编译时失败的原因是因为creator 创建文件是utf8 不带bom,但是 msvc是微软的,使用utf8要带bom,所以编译失败。

2,运行时乱码的解决方法是 在当前的文件头加上  #pragma execution_character_set("utf-8")

https://blog.csdn.net/u013001137/article/details/103934813

 

二,使用VS

VS默认创建的文件是utf8无bom,写中文会导致文件编码改变,和第一种情况一样,保证文件编码为utf8-bom,然后使用#pragma execution_character_set("utf-8")

可以下载VS插件:force utf8(with bom)

 

 

总结就是 使用msvc编译器要保证 文件编码为utf8-bom,然后在文件头加上 #pragma execution_character_set("utf-8")

 

QT改变QComboBox Item的间距

    class PopupItemDelegate : public QStyledItemDelegate
    {
    public:
        using QStyledItemDelegate::QStyledItemDelegate;
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 
        {
            QSize s = QStyledItemDelegate::sizeHint(option, index);
            s.setHeight(20);
            return s;
        }
    };

        // 方法一    
    //QListView *fontSizeView = new QListView(ui.comboBox);
    //ui.comboBox->setView(fontSizeView);

    // 方法二
    ui.comboBox->view()->setItemDelegate(new PopupItemDelegate(ui.comboBox));
    ui.comboBox->addItems({ "一号","二号","三号","四号","五号","六号","七号" });

 

QT 多UI 和 自定义QDesigner插件

1,多UI:我们新建QT Widget Class 生成 .h .cpp .ui ,可以在ui中快速布局,在.h 和 .cpp 中进行事件的重写等一些DIY操作。使用的时候,拖入适当的控件,将其提升为前面自定义的类即可。

2,自定义QDesigner插件:我们也可以通过将常用的控件打包成.h .lib .dll 将其放入到QDesigner的插件目录中,这样后面就可以像自带的控件一样进行拖拽。

  具体方法是 QtCreator新建项目 -> 其他项目 -> Qt 设计师自定义控件。 需要注意的是:最后编译输出的时候,要加入头文件<QtUiPlugin/QDesignerExportWidget>,然后使用QDESIGNER_WIDGET_EXPORT声明所要输出的类,不然编译出的lib dll 中将没有该类,最后使用的时候也会报错。

 

以上情形都是因为QT自带的控件不满足我们的使用需求,例如没有好看的样式,没有相应的事件(例如QLineEdit中就没有鼠标点击信号发出来)。

一般使用第一种方法,因为第二种比较简便,而且如果有新的需求可以随时更改,而第一种则需要重新生成dll。

QLabel 显示图片(图片大小跟随label的改变而改变)

QLabel lblImage;
lblImage->setPixmap( QPixmap( "big_image.jpg" ) );
lblImage->setScaledContents( true );
lblImage->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
View Code
setScaledContents(true) 和 setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );

QPainter 绘图,平移和旋转时候遇到的问题

由于QPainter默认是以左上角来的,所以会和我们期望中的中心点平移和旋转有差异,所以在平移和旋转之前我们需要进行一定的操作,才能达到我们想要的效果。

 

void Demo::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setRenderHint(QPainter::TextAntialiasing);

    //生成五角星的5个顶点的
    qreal R = 100;
    QPolygonF starPolygon;
    starPolygon << QPointF(2*R, R);
    for (int i = 1; i < 5; ++i)
        starPolygon << QPointF(R + R * std::cos(1.2 * i * 3.14),
            R + R * std::sin(1.2 * i * 3.14));

    // 在中心( 100 100) 画一个 R = 100 的五角星  
    painter.save();
    QPointF center(100, 100);
    QPointF rVec(100, 100);
    painter.translate(center - rVec);
    painter.drawPolygon(starPolygon);
    painter.restore();

    // 在中心( 300 100) 画一个 R = 50 的五角星  
    painter.save();
    center = QPointF(300, 100);
    rVec = QPointF(50, 50);
    painter.translate(center - rVec);
    painter.scale(0.5, 0.5);
    painter.drawPolygon(starPolygon);
    painter.restore();

    // 在中心( 450 100) 画一个 R = 100 的五角星  
    // 旋转的话 需要注意 系统默认是以左上角旋转的,比较麻烦一些 
    painter.save();
    float w = 2*R;
    float h = 2*R;
    float alpha = atan2(h,w);          // 均为弧度 
    float theta = 90*3.1415926/180.0;
    float r = std::sqrt(1.0 / 4.0*(h*h + w * w)); 
    float xc = (450 - R)+ 1 / 2.*w;
    float yc = (100 - R) + 1 / 2.*h;
    float xDes = -r * std::cos(theta)*std::cos(alpha) + r * std::sin(theta)*std::sin(alpha) + xc;
    float yDes = -r * std::cos(theta)*std::sin(alpha) - r * std::sin(theta)*std::cos(alpha) + yc;
    painter.translate(xDes, yDes);
    painter.rotate(theta * 180 / 3.1415926);
    painter.drawPolygon(starPolygon);
    painter.restore();

}

 

qInstallMessageHandler问题

在release 模式下,是无法获取到 日志的文件名,行号,函数名的,需要额外的配置

//Qt Creator下,在pro文件中添加下面这一行
DEFINES += QT_MESSAGELOGCONTEXT
//Visual Studio中,在项目解决方案属性-》 C/C++  -》  预处理器  -》 预处理器定义。
//添加下列信息
QT_MESSAGELOGCONTEXT

Qt 嵌入ocx插件(windows上)

使用步骤

1,注册插件进入系统中

  1.1 把*.ocx拷贝到C:\Windows\SysWOW64

  1.2 以管理员身份运行cmd,切换到上述目录,执行regsvr32 *.ocx即可注册成功

2,获取插件的uuid 

  2.1 利用oleviewer.exe打开ocx文件查看。可利用everything搜索oleviewer.exe来查找它的位置。

3,生成对应的.h 和.cpp文件

  3.1 利用QT提供的dumpcpp.exe(一般在QT安装目录)来将*.ocx生成相应的文件,例如dumpcpp.exe {00000000-0000-0000-0000-000000000000}。此时就会生成h和cpp 文件。

 

QTVS中使用ocx控件示例

https://github.com/zzzcb/qt/tree/main/qt_vs_project/qt_ocx

 

Qt creator 中配置CDB

参考文档:https://blog.csdn.net/libaineu2004/article/details/89445792

安装CDB

CDB(command line debugger)是MSVC版本QT调试用的。正如GDB是mingw版的QT一样。

安装Visual Studio是没有cdb的。需要手动安装。运行winsdksetup.exe,从中选择cdb。

 

安装完成后可以在如下目录中找到cdb.exe 

Qt 中的坐标系

https://programmer.ink/think/hello-qt-qt-coordinate-system.html

1. Physical Coordinate System
The physical coordinate system is the device coordinate system, where the origin is in the upper left corner, in pixels, the X coordinate grows to the right, and the Y coordinate grows down.

2. Logical Coordinate System
An Abstract coordinate system whose units are determined by a specific problem and whose direction of growth is determined by a specific problem.

QPainter draws graphics using a logical coordinate system, in which the size and location of graphics are converted to a physical coordinate system and then drawn on the device. By default, the logical coordinate system is the same as the physical coordinate system.

3. Viewport
A view port is any specified rectangular area in a physical coordinate system.

4. Windows
A window is a rectangular area corresponding to a physical coordinate system in a logical coordinate system.

Viewport and window are the same rectangle in different coordinate systems. There is a mapping relationship between the viewport and the coordinate points in the window. Viewport and window can convert each other by coordinate transformation.
#ifndef SINEWAVE_H
#define SINEWAVE_H


#include <QWidget>
#include <QPainter>

class SineWave : public QWidget
{
    Q_OBJECT
private:
    void drawBackGround(QPainter* painter);
    void drawCave(QPainter* painter);
    void paintEvent(QPaintEvent *event);
public:
    SineWave(QWidget *parent = 0);
    ~SineWave();
};

#endif // SINEWAVE_H
sinewave.h
#include "sinewave.h"
#include <QPen>
#include <QPointF>
#include <qmath.h>
#include <QDebug>

SineWave::SineWave(QWidget *parent):QWidget(parent)
{

}

SineWave::~SineWave()
{

}

void SineWave::drawBackGround(QPainter* painter)
{
    QPen pen;
    pen.setStyle(Qt::SolidLine);
    painter->setViewport(50, 50, width()-100, height()-100);
    painter->setWindow(-10, 2, 20, -4); // (-10, 2)    (10, -2)
    painter->fillRect(-10, 2, 20, -4, Qt::black);

    pen.setColor(Qt::white);
    pen.setWidth(0);
    painter->setPen(pen);

    painter->drawLine(QPointF(-10, 1.5), QPointF(10, 1.5));
    painter->drawLine(QPointF(-10, 1), QPointF(10, 1));
    painter->drawLine(QPointF(-10, 0.5), QPointF(10, 0.5));
    painter->drawLine(QPointF(-10, -0.5), QPointF(10, -0.5));
    painter->drawLine(QPointF(-10, -1), QPointF(10, -1));
    painter->drawLine(QPointF(-10, -1.5), QPointF(10, -1.5));

    painter->drawLine(QPointF(-8, 2), QPointF(-8, -2));
    painter->drawLine(QPointF(-6, 2), QPointF(-6, -2));
    painter->drawLine(QPointF(-4, 2), QPointF(-4, -2));
    painter->drawLine(QPointF(-2, 2), QPointF(-2, -2));
    painter->drawLine(QPointF(2, 2), QPointF(2, -2));
    painter->drawLine(QPointF(4, 2), QPointF(4, -2));
    painter->drawLine(QPointF(6, 2), QPointF(6, -2));
    painter->drawLine(QPointF(8, 2), QPointF(8, -2));


    pen.setWidthF(3.0);
    pen.setCosmetic(true);
    painter->setPen(pen);
    painter->drawLine(QPointF(-10, 0), QPointF(10, 0));   // x
    painter->drawLine(QPointF(0, 2), QPointF(0, -2));     // y
}


void SineWave::SineWave::drawCave(QPainter* painter)
{
    QPen pen;
    pen.setColor(Qt::green);
    pen.setWidth(0);

    painter->setPen(pen);
    for(double x=-10; x<10; x+=0.01)
    {
          double y = qSin(x);
          painter->drawPoint(QPointF(x, y));
    }
}

void SineWave::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    drawBackGround(&painter);
    drawCave(&painter);
}
sinewave.cpp

 

Qt 中类型转换

如果知道父类一定会转换为某个子类,则用static_cast,它没有做动态类型检测,所以速度更快。它的返回值无法判断是否转换成功。

如果父类可能会转换为多个子类,则用qobject_cast,它只支持继承于QObject的类,可以通过返回值判断是否转换成功。

如果父类可能会转换为多个子类,且该类未继承QObject,则用dynamic_cast, 可以通过返回值判断是否转换成功。

如果是在QGraphicsView框架中,可以使用qgraphicsitem_cast,可以通过其返回值来判断是否转换成功。前提是要重写type()函数。

如果是在QStyleOption中,qstyleoption_cast,进行转换

 

Qt 中信号槽

DirectConnection
	slot立即执行,slot在 signalling线程 执行 
QueuedConnection
	当 receiver's thread 回到事件循环时执行slot,slot在 receiver's thread 执行
BlockingQueuedConnection
	与 QueuedConnection 相同,不过 signalling线程 阻塞直到slot结束
	如果receiver存活于signalling thread 将会导致死锁 
想让slot在哪个线程执行? 
	signalling thread: -> DirectConnection
	receiver's thread:
		是否阻塞 signalling thread?:
			不阻塞 -> QueuedConnection
			阻塞   -> BlockingQueuedConnection

 

posted @ 2021-11-29 09:44  Zcb0812  阅读(128)  评论(0编辑  收藏  举报