从一位大佬的文章中了解到键盘事件在按下第二个键位时,keyPressEvent触发,第一个键位数据会被第二个键位数据顶替(ev->key()),这样就使得我们无法直接按下多键运行。但是当我们松开第一个键位时,此时会触发一次keyReleaseEvent,这时的键值又被更替为第一个键位值。
根据以上情况,我们在keyPressEvent,keyReleaseEvent中做点操作,定义一个长度为2的数组,当keyPressEvent触发时存储键值,再用一个函数来根据数组中的值触发目的操作。用一个定时器来不断调用这个函数,但这个定时器的时间值要小,以此达到瞬间反应的效果。当我们松开键盘时,在keyReleaseEvent中用当前键值ev->key()与数组中的值匹配,如果有就把这个数组值修改成一个无用值,让函数对此信息做不出操作。
注意,存储键值是添加上,不是顶替,因此也要在存储时做个判断,遍历数组,如果出现无用值,就把它顶替掉,然后立即停止循环。这样做其实有点问题,文末再提出。(菜,求轻点喷)
定义数组,无用值随便取,不要取到键值就行,这里我取-1初始化。
int keys[2] = { -1,-1 };
keyPressEvent与keyReleaseEvent两兄弟
void mainWindow::keyPressEvent(QKeyEvent* ev)
{
for (int i = 0; i < 2; i++)
{
if (keys[i] == -1)
{
keys[i] = ev->key();
break;
}
}
QWidget::keyPressEvent(ev);
}
void mainWindow::keyReleaseEvent(QKeyEvent* ev)
{
for (int i = 0; i < 2; i++)
{
if (ev->key() == keys[i])
{
keys[i] = -1;
break;
}
}
QWidget::keyReleaseEvent(ev);
}
操作函数,第一个if语句里的就是操作了,判断wasd。(这里用switch更好,当时我想着操作很少就用了if语句)
void mainWindow::move()
{
for (int i = 0; i < 2; i++)
{
if (keys[i] == Qt::Key_W)
{
if (gamer.Pointy- UpSpeed >= 0)
{
gamer.Pointy -= UpSpeed;
gamer_Label.move(gamer.Pointx, gamer.Pointy);
}
}
if (keys[i] == Qt::Key_S)
{
if(gamer.Pointy+157+ DownSpeed <= WindowY)
{
gamer.Pointy += DownSpeed;
gamer_Label.move(gamer.Pointx, gamer.Pointy);
}
}
if (keys[i] == Qt::Key_A)
{
if (gamer.Pointx - LeftSpeed > 0)
{
gamer.Pointx -= LeftSpeed;
gamer_Label.move(gamer.Pointx, gamer.Pointy);
}
}
if (keys[i] == Qt::Key_D)
{
if (gamer.Pointx +251+ RightSpeed < WindowX)
{
gamer.Pointx += RightSpeed;
gamer_Label.move(gamer.Pointx, gamer.Pointy);
}
}
}
}
定时器KeysTimer和它的connect函数
keysTimer.setInterval(4);
keysTimer.start();
connect(&keysTimer, &QTimer::timeout, this, [=]()
{
move();
});
这里说下我之前提到的问题,就是我如果同时按下三个键,再松开一个键,程序有点延迟地反馈给我剩下两个键的操作。原因是,说是同时,其实也有先后,前两个键值已经把数组的无用值顶替,第三个键无法录入但还是按着,但是也会间断性的触发第三个键位的keyPressEvent,当第一个键松开时,就会在间断触发时立即录入,然后执行操作。
这个问题也好解决,就是扩充数组到3位或n位,但与此同时3位以上或n位以上同时按下松开一个键或多个时也会延迟操作。希望有大佬改进或提出一个新办法来解决。
文章开头提到的那位大佬文章qt中想判断两个键被按下时_qt如何判断两个键同时按下_yc_Blog的博客-CSDN博客