QT实现的自定义按键精灵

一个QT实现的按键精灵(只写了鼠标部分,键盘用不到就懒得写了)。这里分享一下思路和一些碰到的问题。

功能思路

(1)重复鼠标点击过程:
		运行方式:
				连点:以固定的时间频率按顺序连续点击设置的点位,可以用来当连点器用。
				顺时:完全重复录制下来的鼠标点击过程,按设录制时的点击顺序和时间间隔循环。
		实现方式:
				录制:录制鼠标点击的轨迹(包括时间间隔)
				保存:以txt格式保存轨迹到制定文件夹下
				打开:打开已保存的鼠标轨迹
				运行:									
					移动:根据当前轨迹,按顺序移动到轨迹点位
					点击:在当前点位上,模拟鼠标的点击
(2)显示模式:
		考虑到某些游戏需要全屏,所以需要开发额外的显示模式:
				置顶:始终保持软件置于最顶层
				图标模式:将完整界面变为小图标,以免遮住游戏界面
					界面变换:保留图标,隐藏其他全部空间,背景变为透明
					图标移动:按住拖动图标
			 	隐藏模式: 隐藏整个界面,只显示游戏界面,通过键盘操作实现功能。
			 		键盘操作:绑定键盘键位,实现对软件的案件操作。
(3)附加功能:
		速度设置:设置连点模式下的点击速度
		时间显示:显示录制时间和运行时间
		点位显示:显示录制或打开的全部点位
		轨迹显示:用QChart同比显示运行轨迹(实时)

部分模块分享

主要是分享一些碰到的问题和一些QT以外的内容(Windwos.h),还有一些QChart的内容。其他东西,基本都是软件本身的架构、逻辑还有一些常用的东西,全放出来太多了,这里就不帖了。

鼠标拖动及图标化显示切换

因为是写在PC端给模拟器用的,所以直接用了C++的 Windows.h 这个类。
而使用Windows.h类的时候,可能会碰到库引用的问题,就是明明你可以在QT安装目录的对应文件夹里找到Windows.h,也可以正常#include它,但是,就是无法编译通过,这种情况下,所有基于Windows.h的变量和函数都会 报错。
解决方式也很简单,在调用该类的.cpp文件下,加入下面这行代码即可(加载#include之下,构造函数之上):

#pragma comment(lib, "user32.lib")

下面是一些虚函数的重载:
重载三个鼠标函数,实现界面拖动,变量的类型,都在后面注释了。

   void Wizard::mousePressEvent(QMouseEvent *event)
{
    //当鼠标左键点击时.
    if (event->button() == Qt::LeftButton)
    {
        m_move = true;  //bool
        //记录鼠标的世界坐标.
        m_startPoint = event->globalPos();  //QPoint
        //记录窗体的世界坐标.
        m_windowPoint = this->frameGeometry().topLeft();  //QPoint
    }
}

void Wizard::mouseMoveEvent(QMouseEvent *event)
{
    if (m_move == true)
    {
        //移动中的鼠标位置相对于初始位置的相对位置.
        QPoint relativePos = event->globalPos() - m_startPoint;
        //然后移动窗体即可.
        this->move(m_windowPoint + relativePos );
    }
}

void Wizard::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        //改变移动状态.
        m_move = false;
    }
}

图标化显示的时候,绘制透明遮罩,将widget的背景变为透明。

void Wizard::paintEvent(QPaintEvent *event)  
{
    QPainter painter(this);
    painter.fillRect(this->rect(), QColor(255, 255, 255, clarity));
}

本来用 button 来实现界面的点击变换是最方便的,但是拖动图标移动的功能始终无法在 button上实现,每次拖动,鼠标都会自动从按钮上锚定到widget的空白部分拖动,效果就很僵硬,qml里可以直接用mouseArea来实现,但widget我用得不多,所以最后只能用本身可以拖动的label代替button,然后给label加上事件过滤器实现界面变换的效果。

ui->moveIcon->installEventFilter(this);  //给选定的label添加事件过滤器,写在构造函数里

bool Wizard::eventFilter(QObject *watched, QEvent *event)  //label事件过滤器,最小(最大化)
{
    if(watched == ui->moveIcon)
    {
        //判断事件
        if(event->type() == QEvent::MouseButtonDblClick)  //双击图标,进行窗口变换
        {
            if (this->height()>120)  //如果为窗口模式
            {
                clarity = 0;  //通明度设为0
                ui->moveIcon->setPixmap(QPixmap(":/Res/image/最大化.png"));
                ui->exitbtn->hide();
                ui->runtime->hide();
                //…………
                //这边不全放出来了,隐藏所有控件
                this->setFixedSize(ui->moveIcon->width()+20,ui->moveIcon->height()+20);
            }
            else  //如果为图标藐视
            {
                clarity = 255;
                ui->moveIcon->setPixmap(QPixmap(":/Res/image/最小化.png"));
                ui->hideall->show();
                ui->runtime->show();
                //…………
                //显示所有控件
                this->setFixedSize(1040,802);
            }
            return true; //该事件已处理
        }
        else
            return false; //如果是其它事件,可以进行进一步的处理
    }
    else
        return QWidget::eventFilter(watched, event);
}
鼠标点击及键盘设置

模拟鼠标点击,mouse_event 为Windwos.h自带库函数。

//写在执行函数里
        SetCursorPos(pos_x,pos_y);//更改鼠标坐标,Window.h库函数,直接调即可,不用声明
        mouseaction(1,1, m_Pos);  //左键按下
        mouseaction(1,0, m_Pos);  //左键松开


void TimerRun::mouseaction(int key, int flag, const QPoint &point)
{
 //key: 1左键,0右键;  flag:1按下,0松开
    if (key == 1)
    {
        if (flag == 1)
            mouse_event(MOUSEEVENTF_LEFTDOWN, point.x(), point.y(), 0, 0);
        else
            mouse_event(MOUSEEVENTF_LEFTUP, point.x(), point.y(), 0, 0);
    }
    else
    {
        if (flag == 1)
            mouse_event(MOUSEEVENTF_RIGHTDOWN, point.x(), point.y(), 0, 0);
        else
            mouse_event(MOUSEEVENTF_RIGHTUP, point.x(), point.y(), 0, 0);
    }
}

键盘键位功能的设置。

void Wizard::keyPressEvent(QKeyEvent *event)
{
    int keyValue = event->key();

    if (keyValue == Qt::Key_F1)  //开始录制
        ui->beginrecord->click();
    if (keyValue == Qt::Key_F2)  //开始运行
        ui->startrun->click();
    if (keyValue == Qt::Key_F3)  //保存轨迹
        ui->savdfile->click();
    if (keyValue == Qt::Key_F4)  //打开文件
        ui->openfile->click();
    if (keyValue == Qt::Key_F5)  //隐藏界面
        ui->hideall->click();
    if (keyValue == Qt::Key_F9)  //退出软件
        ui->exitbtn->click();

//按住Ctrl,然后点击鼠标左键,实现点位录入
    if (keyValue == Qt::Key_Control && ui->beginrecord->text().compare("结束录制") == 0)  
    {
        //获取鼠标位置
        m_pos = QCursor::pos();//获取鼠标的绝对位置  QPoint
        int currenttime = rec_h*3600*1000+rec_min*60*1000+rec_s*1000;
        pos.insert(QString::number(poskey), tr("%1,%2,%3").arg(m_pos.x()).arg(m_pos.y()).arg(currenttime));  //QJsonObject
        QString str = tr("Point%1:(%2,%3)-%4").arg(poskey).arg(m_pos.x()).arg(m_pos.y()).arg(currenttime);
        ui->pointrecord->appendPlainText(str);  //打印显示点位
        poskey++;  //int,点位标志名
        chart->GenerateData_slot(m_pos.x(), 1080-m_pos.y());  //QChart图标实时更新
    }
}
QChart轨迹同步显示

这里直接把我自己设置的QChart全放出来吧,因为我也是第一次用这个,所以注释还是比较详细的
.h

#ifndef DYNAMICCHART_H
#define DYNAMICCHART_H

#include <QtCharts/QChart>
#include <QtCharts/QSplineSeries>
#include <QtCharts/QValueAxis>
#include <QTimer>

QT_CHARTS_USE_NAMESPACE

class DynamicChart : public QChart
{
    Q_OBJECT
public:
    DynamicChart(QChart *parent = nullptr);
    ~DynamicChart();

public slots:
    void GenerateData_slot(const int &x, const int &y);
    void ClearData_slot();

private:
    QLineSeries *m_series;//存放所有图表中点的坐标,如果想要显示2条或者以上的图表,则需要声明多个对象
    QValueAxis *m_axisX;
    QValueAxis *m_axisY;
};

#endif // DYNAMICCHART_H

.cpp

DynamicChart::DynamicChart(QChart *parent):
    QChart(parent),
    m_series(nullptr),
    m_axisX(new QValueAxis()),
    m_axisY(new QValueAxis())
{
    m_series = new QLineSeries(this);
    QPen DisplayStyle;
    DisplayStyle.setColor(QColor(11,80,240));//设置图表显示颜色
    DisplayStyle.setWidth(3);//设置图表显示宽度
    m_series->setPen(DisplayStyle);//将设置好的样式应用到series中,如果想要在一张图上显示多种样式
                                   //,那就要对多个series分别设置样式
    m_series->setPointsVisible(true);

    addSeries(m_series);
    addAxis(m_axisX,Qt::AlignBottom);//设置x轴以及对齐样式
    addAxis(m_axisY,Qt::AlignLeft);//设置y轴以及对齐样式

    m_axisX->setLabelFormat("%d");  //设置坐标轴数据格式
    m_axisX->setTickCount(10);//设置x轴之间的间隔
    m_axisX->setRange(0, 1920);//设置X轴的范围
    m_axisX->setGridLineColor(Qt::black);
    m_axisX->setMinorTickCount(1);
    m_axisX->setMinorGridLineColor(Qt::lightGray);

    m_axisY->setLabelFormat("%d");
    m_axisY->setTickCount(6);//设置Y轴之间的间隔
    m_axisY->setRange(0, 1080);//设置Y轴的范围
    m_axisY->setGridLineColor(Qt::black);
    m_axisY->setMinorTickCount(1);
    m_axisY->setMinorGridLineColor(Qt::lightGray);

    m_series->attachAxis(m_axisX);//将设置好的X轴放入series中
    m_series->attachAxis(m_axisY);//将设置好的Y轴放入series中
}

DynamicChart::~DynamicChart()
{
    delete m_axisY;
    delete m_axisX;
    delete m_series;
}

void DynamicChart::GenerateData_slot(const int &x, const int &y)
{
    m_series->append(x, y);//将数据放入series中,每加入一组数据,图表就会自动重画一次

}

void DynamicChart::ClearData_slot()
{
    m_series->clear();
}

效果演示

成品在下面,不保证没有bug,要用的自己下吧,发现bug了可以到下面留言,虽然我也大概率懒得改。
完整源码就不放了,像我这样的菜鸟写得代码,没什么借鉴意义,就不骗你们积分了。

在这里插入图片描述

链接:https://pan.baidu.com/s/1TtbntYaDi5P-hIR_euLFGw 
提取码:15m4
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值