比如这样的需求需要焦点通过上下左右在按钮和widget或者其他窗口类中切换。
核心实现方法就是通过一个信号单例接收全局的键盘事件并发出信号每个要切换的焦点类都连接上接收到信号的窗口类或者button将自己的指针传入单例类延时50ms后(一般50毫秒后所有连接信号的槽函数都执行完了)再在这个单例类中获取当前焦点的对象的全局坐标和所有的对象比对全局坐标通过方向计算找到最近的一个对象设置焦点。
代码文件就一个
#ifndef FOCUSMANAGEMENT_H
#define FOCUSMANAGEMENT_H
#include <QObject>
#include <QTimer>
#include <QWidget>
#include <QMap>
#include <QApplication>
class FocusManagement : public QObject
{
Q_OBJECT
public:
static FocusManagement* getinstance();
void startJudge(QWidget * w,Qt::Key);
private:
explicit FocusManagement(QObject *parent = 0);
void clearInfo();
signals:
void sigFocusChange(Qt::Key key);
public slots:
void onTimeOut();
private:
QTimer m_timer;
Qt::Key m_currentKey;
QList<QWidget*>m_eventWidgetList;
QMap<int,QWidget*>m_eventMap;
};
#endif // FOCUSMANAGEMENT_H
#include "focusmanagement.h"
#include <QLine>
#include <QDebug>
FocusManagement *FocusManagement::getinstance()
{
static FocusManagement *instance = NULL;
if(instance == NULL)
{
instance = new FocusManagement();
}
return instance;
}
void FocusManagement::startJudge(QWidget *w, Qt::Key key)
{
if(!w){
return;
}
m_eventWidgetList.push_back(w);
if(m_timer.isActive())
return;
m_timer.start(50);
m_currentKey = key;
}
void FocusManagement::clearInfo()
{
m_eventWidgetList.clear();
m_eventMap.clear();
}
FocusManagement::FocusManagement(QObject *parent) : QObject(parent)
{
connect(&m_timer,SIGNAL(timeout()),this,SLOT(onTimeOut()));
}
void FocusManagement::onTimeOut()
{
m_timer.stop();
QWidget * cfw = qApp->focusWidget();
if(cfw == nullptr){
clearInfo();
return;
}
QPoint cfp;
switch (m_currentKey) {
case Qt::Key_Up:
cfp = cfw->mapToGlobal(QPoint(cfw->width()/2,0));
break;
case Qt::Key_Down:
cfp = cfw->mapToGlobal(QPoint(cfw->width()/2,cfw->height()));
break;
case Qt::Key_Left:
cfp = cfw->mapToGlobal(QPoint(0,cfw->height()/2));
break;
case Qt::Key_Right:
cfp = cfw->mapToGlobal(QPoint(cfw->width(),cfw->height()/2));
break;
default:
break;
}
for(int i = 0 ; i<m_eventWidgetList.size();i++)
{
QWidget *evw = m_eventWidgetList.at(i);
if(evw == cfw)
continue;
QPoint evp;
switch (m_currentKey) {
case Qt::Key_Up:
evp = evw->mapToGlobal(QPoint(evw->width()/2,evw->height()));
if(evp.y()<= cfp.y()){
m_eventMap[QLineF(evp,cfp).length()] = evw;
}
break;
case Qt::Key_Down:
evp = evw->mapToGlobal(QPoint(evw->width()/2,0));
if(evp.y()>= cfp.y()){
m_eventMap[QLineF(evp,cfp).length()] = evw;
}
break;
case Qt::Key_Left:
evp = evw->mapToGlobal(QPoint(evw->width(),evw->height()/2));
if(evp.x()- cfp.x()<=0){
m_eventMap[QLineF(evp,cfp).length()] = evw;
}
break;
case Qt::Key_Right:
evp = evw->mapToGlobal(QPoint(0,evw->height()/2));
if(evp.x()- cfp.x()>=0){
m_eventMap[QLineF(evp,cfp).length()] = evw;
}
break;
default:
break;
}
}
if(!m_eventMap.isEmpty()){
m_eventMap.first()->setFocus();
}
clearInfo();
}
需要切换焦点的类的槽函数
#include "testwidget.h"
#include "ui_testwidget.h"
TestWidget::TestWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::TestWidget)
{
ui->setupUi(this);
m_eventWidgetList.push_back(ui->pushButton);
m_eventWidgetList.push_back(ui->pushButton_2);
m_eventWidgetList.push_back(ui->pushButton_3);
connect(FocusManagement::getinstance(),SIGNAL(sigFocusChange(Qt::Key)),this,SLOT(onFocusChange(Qt::Key)));
}
TestWidget::~TestWidget()
{
delete ui;
}
void TestWidget::onFocusChange(Qt::Key key)
{
for(int i = 0; i<m_eventWidgetList.size();i++)
{
FocusManagement::getinstance()->startJudge(static_cast<QWidget*>(m_eventWidgetList.at(i)),key);
}
}