开篇先放成果(桌面精灵用的图片皆为网上的图片,后准备自己做一下)
可以实现获取在桌面的位置,产生相应的变化,比如用鼠标将他拖到电脑屏幕边缘,会吸附到电脑边缘(其实就是换了一张图片,对窗口进行一些操作,比如动画、透明度调整),单击右键会出现菜单,点击菜单可以做一些事情。
环境为vs2019+qt5.13 release 64bit
首先要有一个主题思路,比如,窗口怎么设计成透明的,去掉菜单栏,图像随着鼠标的移动怎么变化。下面会在讲解函数的同时说明。
首先,将窗口设计成透明的,我们需要一个widget 在他里面加入一个label来显示图片,widget的大小与label的大小一样最好。
注:代码中是用resize定的大小,可以用adjustSize()来使其适应内部图片的大小。
//构造函数
evle::evle(QWidget *parent)
: QWidget(parent)
{
label = new QLabel(this);
this->setAttribute(Qt::WA_TranslucentBackground, true);
this->setWindowFlags(Qt::FramelessWindowHint); //只是使窗口的标题栏隐藏
//设置图片
QPixmap pixw = QPixmap("Resources/1.png");
label->setPixmap(pixw);
label->resize(128,128);
//label->adjustSize();
lastPos = this->pos();
}
其中lastPos这个句会在下面讲解。
窗口设置好了,下一步我们该来设定鼠标事件了,我们希望在鼠标拖动他的时候可以改变图标,在鼠标将他拖到桌面边缘的时候,它可以附着在桌面边缘等功能。
这个时候就需要鼠标事件来实现。
void mousePressEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
根据英语很容易判断其用法。在介绍函数之前,我们需要先了解一下全局坐标和局部坐标,globalPos(),pos();
globalPos()可以获得位于桌面的全局坐标,以左上角为原点,左到右,为x轴,上到下,为y轴。
pos()获得的是局部坐标,即在窗口中的坐标,以窗口的左上角为原点。
用event->button()来获得按下的是哪个键。
我们这里定左键拖动,右键出现下拉菜单,中键说话。
文本转语音调用的是QTextToSpeech这个qt自带的文本语音转换类。
void evle::speak()
{
QTextToSpeech* tts = new QTextToSpeech(this);
tts->setLocale(QLocale::English);//设置语言环境
tts->setRate(0.0);//设置语速-1.0到1.0
tts->setPitch(1.0);//设置音高-1.0到1.0
tts->setVolume(1.0);//设置音量0.0-1.0
if (tts->state() == QTextToSpeech::Ready)
{
tts->say("hi steve");//开始合成文本
}
}
右键出现菜单。如果直接显示中文会出现乱码,需要下面的两行代码来将中文设置成UTF8的编码方式,然后即可显示中文了。
//输出中文
QTextCodec* codec = QTextCodec::codecForName("System");
codec->setCodecForLocale(QTextCodec::codecForName("UTF8"));
首相声明一个菜单实列,在添加菜单项的时候用的是QAction,用addAction()函数可以将该项加入到菜单中,通过信号与槽,将他们触发的信号绑定到你想调用的函数,便可以通过点击对应的菜单项,实现你想要的功能。
其中左键计算的relativePos,是在后边moustMoveEvent需要用到的。
void evle::mousePressEvent(QMouseEvent* event)
{
//pos()为局部坐标 globalPos()为全局坐标
if (event->button() == Qt::LeftButton)
{//左键拖动窗体
relativePos = this->pos() - event->globalPos();//计算相对坐标
}
if (event->button() == Qt::MidButton) //中键
{
//调用函数,实现语音
speak();
}
if (event->button() == Qt::RightButton) //右键
{
//输出中文
QTextCodec* codec = QTextCodec::codecForName("System");
codec->setCodecForLocale(QTextCodec::codecForName("UTF8"));
QAction* act_about = new QAction(codec->toUnicode("关于"), this);
QAction* act_mainwindow = new QAction(codec->toUnicode("打开主窗口"), this);
QAction* act_exit = new QAction(codec->toUnicode("退出"), this);
QObject::connect(act_about, SIGNAL(triggered()), this, SLOT(about_window()));
QObject::connect(act_exit, SIGNAL(triggered()), this, SLOT(close()));
QMenu *menu = new QMenu(this);
menu->addAction(act_about); //添加菜单项1
menu->addAction(act_mainwindow);
menu->addAction(act_exit); //添加菜单项2
menu->exec(QCursor::pos());
}
}
下一个函数是由鼠标移动来触发的,这里我们便需要一个全局变量或者类中的一个变量来记录鼠标的上一次位置,对比当前位置,可以知道鼠标是左移还是右移了,不同的移动方向,我们希望显示出不同的图片。
最后使用move()函数将窗口移动到鼠标的位置。
void evle::mouseMoveEvent(QMouseEvent* event)//移动窗体
{
if (event->globalPos().x() < lastPos.x())
{
QPixmap pixw = QPixmap("Resources/3.png");
label->setPixmap(pixw);
}
else
{
QPixmap pixw = QPixmap("Resources/2.png");
label->setPixmap(pixw);
}
lastPos = event->globalPos();
this->move(event->globalPos() + relativePos);
}
最后一个鼠标函数是鼠标的释放函数,即在鼠标按键抬起的时候执行。
比如我们希望用鼠标将窗口移动到了足够靠近桌面边缘的地方,希望他的依附在桌面边缘上。我们首先要明确,桌面就像一个二维笛卡尔坐标系,只要你给出横纵坐标,便可以把图片移到对应的位置上。明确了这个思想,进行下面的编程就会方便许多。
我们可以通过width(),height()来获得对应窗口的大小,这一点你可以到qt creator中看ui文件中窗口的数据,会有更直观的体验。
(其实他完整写应该是this->width())
this->x() this->y() 可以得到窗口左上角在桌面上的全局坐标(注意横轴为x轴)。
然后你便可以设定,当窗口在桌面上什么位置的时候会有什么样的变化,比如图片发生变化,再比如,他会迅速的移动到桌面的边缘。
这个迅速的动作是靠一个动画实现的,也就是我们用的QPropertyAnimation这个类。他可以设置动画运行的时间,起点和终点等等。如果有兴趣的话,也可以在进一步深入了解。那么我们要实现上述的动作就很容易了,设定动画的起点终点,运行的时间,运行结束后,也就是到达桌面边缘后,换一张图片。
void evle::mouseReleaseEvent(QMouseEvent* event) //松开鼠标后自动贴边隐藏并且透明
{
QPropertyAnimation* pAnimation = new QPropertyAnimation(this, "geometry");
QDesktopWidget* pDesktopWidget = QApplication::desktop();//获得桌面
//窗口的宽和高
int tx = width();
int ty = height();
//QRect clientRect = desktopWidget->availableGeometry();得到相对于屏幕的绝对坐标
//QRect applicationRect = desktopWidget->screenGeometry();得到应用程序矩形
//获得屏幕宽度
int lx = pDesktopWidget->availableGeometry().width();
int ly = pDesktopWidget->availableGeometry().height();
if (this->x() < 2*tx )
{
pAnimation->setDuration(100);
pAnimation->setStartValue(QRect(this->x(), this->y(), width(), height())); //起始位置
pAnimation->setEndValue(QRect(-50, this->y(), width(), height())); //终点位置
pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPixmap pixw = QPixmap("Resources/4.png");
label->setPixmap(pixw);
//设置窗口透明度
//this->setWindowOpacity(0.3);
}
else if (this->x() > (lx - 2*tx))
{
pAnimation->setDuration(100);
pAnimation->setStartValue(QRect(this->x(), this->y(), width(), height()));
pAnimation->setEndValue(QRect(lx - 78, this->y(), width(), height()));
pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPixmap pixw = QPixmap("Resources/4_2.png");
label->setPixmap(pixw);
//this->setWindowOpacity(0.3);
}
else if (this->y() > (ly - 2*ty))
{
pAnimation->setDuration(100);
pAnimation->setStartValue(QRect(this->x(), this->y(), width(), height()));
pAnimation->setEndValue(QRect(this->x(), ly - ty , width(), height()));
pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPixmap pixw = QPixmap("Resources/5.png");
label->setPixmap(pixw);
//this->setWindowOpacity(0.3);
}
else if (this->y() < (2 * ty))
{
QPixmap pixw = QPixmap("Resources/8.png");
pAnimation->setDuration(100);
pAnimation->setStartValue(QRect(this->x(), this->y(), width(), height()));
pAnimation->setEndValue(QRect(this->x(),10, width(), height()));
pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
label->setPixmap(pixw);
//this->setWindowOpacity(0.3);
}
else
{
QPixmap pixw = QPixmap("Resources/1.png");
label->setPixmap(pixw);
}
}
到了这里,主要的功能和函数就介绍完了。