Qt日常

3 篇文章 0 订阅

1 使用键盘按键

.h

class MainWindow : public QMainWindow
{
protected:
    virtual void keyPressEvent(QKeyEvent *ev);
};

.cpp

void MainWindow::keyPressEvent(QKeyEvent *ev)
{
    switch (ev->key())
    {
    case Qt::Key_F1:
        std::cout << "111" << std::endl;
        break;
    }
    QWidget::keyPressEvent(ev);
}

但有的时候按键不好使用,比如有的按键不能响应,则需要在构造函数中添加这句:

this->grabKeyboard();

在实际情况中我们可能会长按一个键,长按过程中它会自动连续触发“按下”、“松开”的动作,如果不想被多次触发,可以加判断:bool QKeyEvent::isAutoRepeat()

void MainWindow::keyPressEvent(QKeyEvent *ev)
{
    if (ev->isAutoRepeat()) {
        std::cout << "Repeat" << std::endl;
    } else {
        std::cout << "Not Repeat" << std::endl;

        switch (ev->key())
        {
        case Qt::Key_A:
            std::cout << "111" << std::endl;
            break;
        case Qt::Key_D:
            std::cout << "222" << std::endl;
            break;
        }
    }
    QWidget::keyPressEvent(ev);
}

2 过滤事件

2.1 在label上画矩形

下面的例子是把事件过滤给label控件,在label上画矩形:
.h

class MainWindow : public QMainWindow
{
protected:
    bool eventFilter(QObject *watched, QEvent *event);
private:
    int x1=0, y1=0, x2=0, y2=0;
};

.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->label_2->installEventFilter(this); // 给控件安装事件过滤器
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->label_2) // 判断观测对象是哪个控件
    {
        if (event->type() == QEvent::Paint){ // 判断事件类型
            QPainter painter(ui->label_2);
            painter.setPen(QPen(Qt::red, 2));
            painter.drawRect(QRect(x1, y1, x2 - x1, y2 - y1));
        }
        else if(event->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            // if (mouseEvent->button() == Qt::LeftButton) 判断是否是鼠标左键
            // if (mouseEvent->buttons() & Qt::LeftButton) 判断是否包含鼠标左键
            x1 = mouseEvent->pos().x();
            y1 = mouseEvent->pos().y();
            QCursor cursor;
            cursor.setShape(Qt::ClosedHandCursor);
            QApplication::setOverrideCursor(cursor);
        }
        else if(event->type() == QEvent::MouseButtonRelease)
        {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            x2 = mouseEvent->pos().x(); //鼠标相对于所在控件的位置
            y2 = mouseEvent->pos().y();
            update(); // 触发绘制事件
            QApplication::restoreOverrideCursor();
        }
        else if(event->type() == QEvent::MouseMove)
        {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            x2 = mouseEvent->pos().x(); //鼠标相对于所在控件的位置
            y2 = mouseEvent->pos().y();
            update(); // 触发绘制事件
        }
    }
    return QWidget::eventFilter(watched, event);
}

2.2 在label上画封闭图形

下面的例子是把事件过滤给label控件,在label上画封闭图形:
.h

class MainWindow : public QMainWindow
{
private:
    QList<QPoint> point;
protected:
    bool eventFilter(QObject *watched, QEvent *event);
}

.cpp

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->label)
    {
        if (event->type() == QEvent::Paint) {
            QPainter painter(ui->label);
            painter.setRenderHint(QPainter::Antialiasing);
            //painter.translate(20, 20); // 偏移距离
            //painter.setBrush(Qt::red); // 填充色(纯色)
      //painter.setBrush(QColor(255, 0, 0, 100)); // 填充色(半透明)
            int p_num = point.size();
            QPoint points[p_num];
            for (int i = 0; i < p_num; i++) {
                points[i] = point[i];
            }

            painter.drawPolygon(points, p_num);
        }
        else if (event->type() == QEvent::MouseButtonPress) {
            point.clear();
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            point.append(mouseEvent->pos());
        }
        else if (event->type() == QEvent::MouseButtonRelease) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            point.append(mouseEvent->pos());
            update();
            QApplication::restoreOverrideCursor();
        }
        else if (event->type() == QEvent::MouseMove) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            point.append(mouseEvent->pos());
            update();
        }
    }
}

3 模拟按键点击事件

    QPoint pos(x1,y1);
    QMouseEvent event0(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QApplication::sendEvent(ui->label_2, &event0);
    QPoint pos2(x2,y2);
    QMouseEvent event1(QEvent::MouseButtonRelease, pos2, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QApplication::sendEvent(ui->label_2, &event1);

4 手动选择路径

QString DataPath;
// 选择文件夹
DataPath = QFileDialog::getExistingDirectory(this, tr("路径1:"), "/home/tianru/repeat-picture/");
// 选择文件
DataPath = QFileDialog::getOpenFileName(this,  tr("选择视频:"), "/home/tianru/",  tr("*.mp4"));

std::string path = DataPath.toStdString();

5 取出label里的图形

QPixmap pix;
pix = ui->label->grab(ui->label->rect());

QPixmap格式转换为Mat格式参考:opencv(c++)笔记.md

6 把Mat格式的图片显示在label上

    cv::Mat img = cv::imread(path, 1); // 获取Mat格式图片
    cv::cvtColor(img, img, CV_BGR2RGB);
    QImage image((const uchar*)img.data,img.cols,img.rows,img.cols*img.channels(), QImage::Format_RGB888);
    ui->label->setPixmap(QPixmap::fromImage(image));
    ui->label->setScaledContents(true);

7 Qstring 和 string 互换

类型方法
int -> QstringQString a = QString::number(123);
QString -> intint i = atoi(qstr.toStdString().c_str());
Qstring -> stringstring s = qstr.toStdString();
string -> QStringQString a = QString::fromStdString(s);

8 qmake 使用方法

  1. 区分平台
    qmake本身提供了在pro下判断平台的变量参数,如下:
macx {
message('this is macx.') # 打印信息
# 添加macx平台的内容
}
unix:!macx {
message('this is linux.') # 打印信息
# 添加linux平台的内容
}
win32 {
message('this is windows.') # 打印信息
# 添加windows平台的内容
}

执行qmake,编译输出里面会根据情况打印出上面的某条信息;

  1. 添加宏定义
DEFINES += TEST
# 判断宏定义是否存在
contains(DEFINES, TEST) {
    message('存在')
} else {
    message('不存在')
}
  1. 区分 debug 和 release 版本的库
CONFIG(debug, debug|release): {
# 添加内容
} else:CONFIG(release, debug|release): {
# 添加内容
}
  1. 路径中有空格加上双引号
LIBS += "-LD:\Program Files\opencv\opencv3.4.0\build\x64\vc14\lib"

9 读取硬件信息(windows)

在windows中读取cpu_id、disk_serial_number调用了wmic命令,读取mac地址用了qt中的QtNetwork相关函数,在使用QtNetwork头文件时一定要在pro文件中添加语句:QT += core gui network,别忘记了!
代码如下:
machine_info.h

#include <QProcess>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QHostInfo>
#include <QSysInfo>
#include <QDesktopWidget>
#include <QFileInfoList>
#include <QDir>
#include <QLibrary>
#include <QTime>
#include <QtCore>
#include <iostream>

QString get_WMIC(const QString &cmd);

bool get_cpu_id(std::string & cpu_id);

bool get_disk_serial_number(std::string & serial_no);

bool get_mac_address(std::string & mac_address);

machine_info.cpp

#include "get_machine_info_win.h"

QString get_WMIC(const QString &cmd)
{
    QProcess p;
    p.start(cmd);
    p.waitForFinished();
    QString result = QString::fromLocal8Bit(p.readAllStandardOutput());
    QStringList list = cmd.split(" ");
    result = result.remove(list.last(), Qt::CaseInsensitive);
    result = result.replace("\r", "");
    result = result.replace("\n", "");
    result = result.simplified();
    return result;
}

bool get_cpu_id(std::string &cpu_id)
{
    cpu_id = get_WMIC("wmic cpu get processorid").toStdString();
    return true;
}

bool get_disk_serial_number(std::string &serial_no)
{
    serial_no = get_WMIC("wmic diskdrive where index=0 get serialnumber").toStdString();
    return true;
}

bool get_mac_address(std::string &mac_address)
{
    QString strMac;
    QList<QNetworkInterface> netList = QNetworkInterface::allInterfaces();
    foreach(QNetworkInterface item, netList)
    {
        if((QNetworkInterface::IsUp & item.flags()) && (QNetworkInterface::IsRunning & item.flags()))
        {
            if(strMac.isEmpty() || strMac < item.hardwareAddress())
            {
                strMac = item.hardwareAddress();
            }
        }
    }
    mac_address = strMac.toStdString();
    return true;
}

10 读取/设置控件显示信息

10.1 QTextEdit

	// 读取数据
    QString data = ui->textEdit->toPlainText();

	// 写入数据
	QString data = "123";
	ui->textEdit->setPlainText(data);

10.2 QComboBox

	// 读取信息
	QString data = 	ui->comboBox->currentText()

	// 写入数据

11 定时器 QTimer

使用方法见代码:
.h

class MainWindow
{
public:
	MainWindow();
    QTimer * time_display;
public slots:
    void do_display();
}

.cpp

MainWindow::MainWindow() :
{
    time_display = new QTimer(this);
    connect(time_display, SIGNAL(timeout()), this, SLOT(do_display()));
    time_display->start(500);//开启定时器,周期500ms
    //time_display->stop();//关闭定时器
}
void MainWindow::do_display()
{
    std::cout << "1 " << std::endl;
}

12 string和Qstring转换中文乱码

为了避免中文乱码问题,可以采用下面的方法转换:

  • Qstring -> string

    std::string str;
    QString qstr;
    qstr = "你好"
    str = qstr.toLocal8Bit().data();
    
  • string -> Qstring

    std::string str;
    QString qstr;
    str = "你好"
    qstr = QString::fromLocal8Bit(str.c_str());
    

13 QgridLayout布局控件

  • 默认布局时会改变控件的尺寸和位置,如果不想改变,需要设置QgridLayout控件的相关属性,如:setSizeConstraint;
  • 填充控件
      QGridLayout * gridlayout = new QGradient();
    
      gridlayout->addWidget(new QCheckBox("hello"), 0, 1, 2, 3);//0表示纵向的索引,1表示横向的索引,2表示纵向占据2格,3表示横向占据3格
    
      QFrame * line = new QFrame();//创建线条
      line->setFrameShape(QFrame::HLine);//设置线条方向
      ui->gridLayout_attr->addWidget(line, 5, 0, 1, -1);//-1表示占据该行(或该列)所有格
    
  • 遍历布局控件的各个子控件
     QLayoutItem * item;
      for (int cc = ui->gridLayout->count()-1; cc >= 0; --cc)
      {
          QLayoutItem *it = ui->gridLayout->itemAt(cc);
          VideoList *orderHistory = qobject_cast<VideoList *>(it->widget()); // 这里的 VideoList 想要转换成的类型
          if (orderHistory != 0)
          {
              //doing something for orderHistory
              qDebug() << orderHistory->m_checkbox->text(); // 对该类型的控件做操作
          }
      }
    
  • 遍历并清除指定控件
      QLayoutItem * item;
      // 方法一
      while ((item = ui->gridLayout_attr->itemAt(0)) != 0) {
          std::string name = item->widget()->metaObject()->className();
          if (name == "QFrame") { // 按照什么条件筛选根据自己需求改
              item->widget()->deleteLater();
              item->widget()->setParent(NULL);
          }
          // 如果知道这个控件的类型,比如CCheckCombox,那么可以把item转换为该类型后再做操作
          CCheckCombox * b = qobject_cast<CCheckCombox *>(item->widget());
          if (b != 0)
              std::cout << b->count() << std::endl;
      }
    
      // 方法二
      for (int i = 0; i < gridLayout->count(); ++i) {
          item = gridLayout->itemAt(i);
          std::string name = item->widget()->metaObject()->className();
          if (name == "QFrame") { // 按照什么条件筛选根据自己需求改
              item->widget()->deleteLater();
              item->widget()->setParent(NULL);
              i--;
          }
      }
    

14 获取信号与槽中的信号发起者

在信号与槽的运用中,会出现多个信号指向一个槽函数,但是槽函数如何分辨是哪个控件发过来的信号呢,可以使用sender()函数获取当前信号的发起者,如:

    QPushButton * button = new QPushButton("X");
    button->setObjectName("aaaa");//设置对象名
    QPushButton * button2 = new QPushButton("X");
    button2->setObjectName("bbbb");//设置对象名
    connect(button, SIGNAL(clicked()), this, SLOT(close_one_property()));
    connect(button2, SIGNAL(clicked()), this, SLOT(close_one_property()));

槽函数:

// 需要先在头文件里声明槽函数
// ipublic slots:
//    void slot_function();

void MainWindow::slot_function()
{
    QObject * o = sender();
    std::string n = o->objectName().toLocal8Bit().data();//获取对象名
    std::cout << n << std::endl;
}

15 QCheckBox改变勾选框的图标

    ui->checkBox_13->setStyleSheet("QCheckBox::indicator{width:15px; height:15px;}\
                                   QCheckBox::indicator:unchecked{image:url(:/icon/uncheck.png);}\
                                   QCheckBox::indicator:checked{image:url(:/icon/check2.png);}");

16 QPushButton改变图标

    QIcon ico(":/icon/close.png");
    ui->pushButton_7->setIcon(ico); // 设置图案
    ui->pushButton_7->setIconSize(QSize(15,15));//设置尺寸
    ui->pushButton_7->setFlat(true);//去掉边缘

17 设置窗口标题

	MainWindow w;
	w.setWindowTitle(QString::fromStdString("xxx"));
	w.show();

18 Qt 获取目录

    //fun2();
    QString p = QCoreApplication::applicationDirPath();
    std::cout << "当前程序所在目录:" << p.toStdString() << std::endl;
    p = QDir::currentPath();
    std::cout << "当前工作目录:" << p.toStdString() << std::endl;
    p = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
    std::cout << "用户目录:" << p.toStdString() << std::endl;
    p = QDir::homePath();
    std::cout << "用户目录:" << p.toStdString() << std::endl;
    p = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    std::cout << "我的文档路径:" << p.toStdString() << std::endl;
    p = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    std::cout << "桌面路径:" << p.toStdString() << std::endl;
    p = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    std::cout << "程序数据存放路径:" << p.toStdString() << std::endl;
    p = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
    std::cout << "临时文件路径:" << p.toStdString() << std::endl;

19 信号与槽

  • 发送信号
// 定义信号函数
signals:
    void start_changed(); // 可以添加参数

// 发送信号
emit start_changed();
  • 连接信号与槽
// 定义
 QPushButton * m_button1;
private slots:
    void button_1_clicked();

// 实现
 m_button1 = new QPushButton(this);
 connect(m_button1, SIGNAL(pressed()), this, SLOT(button_1_clicked())); // 连接信号与槽

// 编写槽函数
void SlidingBar::button_1_clicked()
{
    // .............
}

20 给界面添加布局

在新创建的界面中,默认是没有布局的,布局一般用于窗体自适应大小,也就是说控件能根据窗体大小来改变自己的大小和位置。这里以添加垂直布局为例:

  • 向ui界面中任意拖动一个控件
  • 鼠标点击界面背景,再点击 工具 >> Form_Editor >> 打破布局
  • 点击 工具 >> Form_Editor >> 垂直布局

21 获取窗体改变事件、鼠标事件

#include <QMouseEvent>
// 声明
protected:
    virtual void resizeEvent(QResizeEvent *event) override;
    void mousePressEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);

// 实现
void SlidingBar::resizeEvent(QResizeEvent *event)
{
    //qDebug() << this->geometry().width();
}

void SlidingBar::mousePressEvent(QMouseEvent *event)
{
}
void SlidingBar::mouseReleaseEvent(QMouseEvent *event)
{
}
void SlidingBar::mouseMoveEvent(QMouseEvent *event)
{
    int pos = event->x();
    //qDebug() << pos;
}

22 把 Mat 图像等比例显示在 QLabel 上

保持 Mat 图像比例不变,根据 Qlabel 尺寸计算出合适的值,让 Mat 图像最大化显示。

// ui->frame 是背景框
// frame 是Mat图像
// m_q_label 是改变尺寸后的fame
//    m_q_label 需要做初始化,给他绑定一个父对象,和 ui->frame 一致,如:
//    m_qt_frame = new QLabel();
//    m_qt_frame->setParent(ui->centralWidget);
//    m_qt_frame->setStyleSheet("background-color: rgb(0, 0, 0);");
//    m_qt_frame->setGeometry(11, 11, 1, 1);
void MainWindow::resizeFrame(cv::Mat & frame)
{
    int w = frame.cols;
    int h = frame.rows;
    // 改变图片的尺寸
    int u_w = ui->frame->width();
    int u_h = ui->frame->height();
    int i_w = w;
    int i_h = h;
    if (i_w > u_w || i_h > u_h) {
        if (u_w * i_h - u_h * i_w > 0) {
            int i_h_temp = i_h;
            i_h = u_h;
            i_w = u_h * i_w / i_h_temp;
        } else {
            int i_w_temp = i_w;
            i_w = u_w;
            i_h = u_w * i_h / i_w_temp;
        }
    }
    w = i_w;
    h = i_h;
    int x = ui->frame->x();
    int y = ui->frame->y();
    x += (u_w - w)/2;
    y += (u_h - h)/2;
    m_qt_frame->setGeometry(x, y, w, h);

    cv::Mat img;
    cv::resize(frame, img, cv::Size(w, h));
    cv::cvtColor(img, img, CV_BGR2RGB);
    QImage image((const uchar*)img.data, img.cols,
                 img.rows, img.cols*img.channels(),
                 QImage::Format_RGB888);
    m_qt_frame->setPixmap(QPixmap::fromImage(image));
}

23 向 QTabWidget 添加 tab 和 button 等组件

    // 假如界面已经创建了 QTabWidget : ui->tabWidget
    QWidget * new_widget = new QWidget();
    QGridLayout * new_layout = new QGridLayout();
    QPushButton * button1 = new QPushButton(tr("1"));
    QPushButton * button2 = new QPushButton(tr("2"));
    QSpacerItem * spacer = new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); // 弹簧,第3个参数表示水平方向,第4个参数表示垂直方向
    new_layout->addWidget(button1, 0, 0); // 布局中插入按键1
    new_layout->addWidget(button2, 0, 1); // 布局中插入按键2
    new_layout->addItem(spacer,  1, 0);   // 布局中插入按键1
    new_widget->setLayout(new_layout);

    ui->tabWidget->insertTab(0, new_widget, "a");
    //ui->tabWidget->removeTab(0);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值