组态软件–控件拖拽
个人最近也是在用Qt做组态软件,一开始用QGraphics来做组态软件的UI设计程序,说真的,说真的做出来还有点像样子,但是后续的二次开发存在很大的问题,所以第二次是参考了feiyangqingyun大神的属性设计的思路来做的,可以说做的挺顺利的大概10天就完成了大部分的工作。
首先展示一下做出来的效果
实现功能
控件的拖动缩放和选中的功能。
相关说明
看过feiyangqingyun的相关博客的同学应该发现了一个问题,自己建一个SelectWidget的QWidget类型的窗口,并配置了一切相关的参数,但是到头来Select绑定了对应的控件也根本不可能使得控件的拖动,但是缩放的功能是真的存在。这里你可能会意识到feiyangqingyun在上传核心代码时将其中的一些使得控件移动的程序删除掉了,需要用户的自行添加。
这里一些比较机智的同学可能会想到feiyangqingyun还有一个movewidget的程序绑定一个控件就可以使得控件移动的程序,添加进去岂不是完美。如果尝试了的话,控件在绑定了SelectWidget和movewidget之后,movewidget根本毫无作用。到这里,代码搬运习惯的人可能就慌了,这明摆着需要自行研读程序并将movewidget中的移动程序移动到Selectwidget中才能实现控件的移动的功能。
两种思路
第一种思路
将控件叠放到SelectWidget之上
bool SelectWidget::eventFilter(QObject *obj, QEvent *event)//此处程序是虚函数,就是空的不要手贱把这个程序删了
{
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if(obj==widget&&widget!=nullptr&&move)
{
if (mouseEvent->type() == QEvent::MouseButtonPress) {
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
if (mouseEvent->button() != Qt::LeftButton) {
return false;
}
widgetpressed=true;
widgetpressed2=true;
selected=true;
// sendSelect(widget);
sendSelect();
lastPoint = mouseEvent->globalPos();
point4=this->pos();
point5=QPoint(point4.x()+this->width(),point4.y()+this->height());
} else if (mouseEvent->type() == QEvent::MouseMove && widgetpressed) {
//计算坐标偏移值,调用move函数移动过去
int offsetX = mouseEvent->globalPos().x() - lastPoint.x();
int offsetY = mouseEvent->globalPos().y() - lastPoint.y();
this->setGeometry(point4.x()+offsetX,point4.y()+offsetY,point5.x()-point4.x(),point5.y()-point4.y());
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && widgetpressed) {
widgetpressed = false;
sendSelect2();
lastPoint=mouseEvent->globalPos();
}
return QWidget::eventFilter(obj,event);
}
else if(obj==this)
{
if (mouseEvent->type() == QEvent::MouseButtonPress) {
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
if(widgetpressed2==false)
{
emit presswidget();
widgetpressed2=false;
}
selected=true;
if (mouseEvent->button() == Qt::RightButton) {
}
//判断控件的区域是否包含了当前鼠标的坐标
if (this->rect().contains(mouseEvent->pos())) {
//lastPoint = mouseEvent->pos();
QPoint point1=mouseEvent->pos();
point2=this->pos();
point3=QPoint(point2.x()+this->width(),point2.y()+this->height());
//这一部分程序注释掉,功能不稳定
/* if(point1.x()<20&&point1.y()<20) pressedarea=1;//qDebug()<<"左上"<<endl;
else if(point1.x()<this->width()*2/3&& point1.x()>this->width()/3&&point1.y()<20) pressedarea=2;// qDebug()<<"中上"<<endl;
else if(point1.x()>point1.x()-20&&point1.y()<20) pressedarea=3;// qDebug()<<"右上"<<endl;
else if(point1.x()<20&&point1.y()>this->height()/3&&point1.y()<this->height()*2/3)pressedarea=4;// qDebug()<<"左中"<<endl;
else if(point1.x()>this->width()-20&&point1.y()>this->height()/3&&point1.y()<this->height()*2/3)pressedarea=5;//qDebug()<<"右中"<<endl;
else*/ if(point1.x()<20&&point1.y()>this->height()-20)pressedarea=6;// qDebug()<<"左下"<<endl;
else if(point1.x()<this->width()*2/3&& point1.x()>this->width()/3&&point1.y()>this->height()-20)pressedarea=7;//qDebug()<<"中下"<<endl;
else if(point1.x()>point1.x()-20&&point1.y()>this->height()-20) pressedarea=8; //qDebug()<<"右下"<<endl;
else pressedarea=0;
pressed = true;
}
} else if (mouseEvent->type() == QEvent::MouseMove && pressed) {
//计算坐标偏移值,调用move函数移动过去
int offsetX = mouseEvent->pos().x();
int offsetY = mouseEvent->pos().y();
int x = point3.x()-point2.x()- offsetX;
/*if(pressedarea==1)
{
this->setGeometry(point2.x()+offsetX,point2.y()+offsetY,point3.x()-point2.x()-offsetX,point3.y()-point2.y()-offsetY);
}
else if(pressedarea==2)
this->setGeometry(point2.x(),point2.y()+offsetY,point3.x()-point2.x(),point3.y()-point2.y()-offsetY);
else if(pressedarea==3)
this->setGeometry(point2.x(),point2.y()+offsetY,offsetX,point3.y()-point2.y()-offsetY);
else if(pressedarea==4)
this->setGeometry(point2.x()-(x-point3.x()+point2.x()),point2.y(),x,point3.y()-point2.y());
else if(pressedarea==5)
this->setGeometry(point2.x(),point2.y(),offsetX,point3.y()-point2.y());
else*/ if(pressedarea==6)
this->setGeometry(point2.x()-(x-point3.x()+point2.x()),point2.y(),x,offsetY);
else if(pressedarea==7)
this->setGeometry(point2.x(),point2.y(),point3.x()-point2.x(),offsetY);
else if(pressedarea==8)
this->setGeometry(point2.x(),point2.y(),offsetX,offsetY);
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) {
pressed = false;
//lastPoint=mouseEvent->globalPos();
}
}
return QWidget::eventFilter(obj,event);
}
这种程序需要将控件的parent设置成SelectWidget,直接将控件叠放到SelectWidget之上,这样控件的坐标一直就是相对于SelectWidget的,只需要移动缩放SelectWidget就可以实现控件的拖动和缩放,可以说极其的方便。但是弊端也是非常的明显的,后期在设置控件属性表时就无法获取控件属性的相应坐标和长宽信息,需要重新设置一个控件属性表来单独的设置控件parent的坐标和长宽信息,可能会影响外观且后期读写xml文件只是需要对xywh进行单独的处理,但是不可否认的是,这种方法设计的界面程序运行非常的流畅,出现意想不到的BUG’的概率也很低。但是这并不是一种主流的方法,毕竟后期会增加一些不必要的代码量,所以第二中才是比较主流的方法。
第二种方法
在同一widget下强行绑定SelectWidget和控件的坐标。
bool SelectWidget::eventFilter(QObject *obj, QEvent *event)//此处程序是虚函数,就是空的不要手贱把这个程序删了
{
QMouseEvent *mouseEvent = (QMouseEvent *)event;
if(obj==widget&&widget!=nullptr&&move)
{
if (mouseEvent->type() == QEvent::MouseButtonPress) {
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
if (mouseEvent->button() != Qt::LeftButton) {
return false;
}
widgetpressed=true;
widgetpressed2=true;
selected=true;
// sendSelect(widget);
sendSelect();
lastPoint = mouseEvent->globalPos();
point4=this->pos();
point5=QPoint(point4.x()+this->width(),point4.y()+this->height());
} else if (mouseEvent->type() == QEvent::MouseMove && widgetpressed) {
//计算坐标偏移值,调用move函数移动过去
int offsetX = mouseEvent->globalPos().x() - lastPoint.x();
int offsetY = mouseEvent->globalPos().y() - lastPoint.y();
this->setGeometry(point4.x()+offsetX,point4.y()+offsetY,point5.x()-point4.x(),point5.y()-point4.y());
widget->setGeometry(point4.x()+offsetX+5,point4.y()+offsetY+5,point5.x()-point4.x()-10,point5.y()-point4.y()-10);
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && widgetpressed) {
widgetpressed = false;
sendSelect2();
lastPoint=mouseEvent->globalPos();
}
else if (event->type() == QEvent::Resize) {
//设置当前窗体大小为跟随窗体的大小增加部分
this->setGeometry(widget->x()-5,widget->y()-5,widget->width()+10,widget->height()+10);
} else if (event->type() == QEvent::Move) {
//将当前窗体移到偏移位置
this->setGeometry(widget->x()-5,widget->y()-5,widget->width()+10,widget->height()+10);
}
return QWidget::eventFilter(obj,event);
}
else if(obj==this)
{
if (mouseEvent->type() == QEvent::MouseButtonPress) {
//如果限定了只能鼠标左键拖动则判断当前是否是鼠标左键
if(widgetpressed2==false)
{
emit presswidget();
widgetpressed2=false;
}
selected=true;
if (mouseEvent->button() == Qt::RightButton) {
}
//判断控件的区域是否包含了当前鼠标的坐标
if (this->rect().contains(mouseEvent->pos())) {
//lastPoint = mouseEvent->pos();
QPoint point1=mouseEvent->pos();
point2=this->pos();
point3=QPoint(point2.x()+this->width(),point2.y()+this->height());
//这一部分程序注释掉,功能不稳定
/* if(point1.x()<20&&point1.y()<20) pressedarea=1;//qDebug()<<"左上"<<endl;
else if(point1.x()<this->width()*2/3&& point1.x()>this->width()/3&&point1.y()<20) pressedarea=2;// qDebug()<<"中上"<<endl;
else if(point1.x()>point1.x()-20&&point1.y()<20) pressedarea=3;// qDebug()<<"右上"<<endl;
else if(point1.x()<20&&point1.y()>this->height()/3&&point1.y()<this->height()*2/3)pressedarea=4;// qDebug()<<"左中"<<endl;
else if(point1.x()>this->width()-20&&point1.y()>this->height()/3&&point1.y()<this->height()*2/3)pressedarea=5;//qDebug()<<"右中"<<endl;
else*/ if(point1.x()<20&&point1.y()>this->height()-20)pressedarea=6;// qDebug()<<"左下"<<endl;
else if(point1.x()<this->width()*2/3&& point1.x()>this->width()/3&&point1.y()>this->height()-20)pressedarea=7;//qDebug()<<"中下"<<endl;
else if(point1.x()>point1.x()-20&&point1.y()>this->height()-20) pressedarea=8; //qDebug()<<"右下"<<endl;
else pressedarea=0;
pressed = true;
}
} else if (mouseEvent->type() == QEvent::MouseMove && pressed) {
selected=true;
//计算坐标偏移值,调用move函数移动过去
int offsetX = mouseEvent->pos().x();
int offsetY = mouseEvent->pos().y();
int x = point3.x()-point2.x()- offsetX;
/*if(pressedarea==1)
{
this->setGeometry(point2.x()+offsetX,point2.y()+offsetY,point3.x()-point2.x()-offsetX,point3.y()-point2.y()-offsetY);
}
else if(pressedarea==2)
this->setGeometry(point2.x(),point2.y()+offsetY,point3.x()-point2.x(),point3.y()-point2.y()-offsetY);
else if(pressedarea==3)
this->setGeometry(point2.x(),point2.y()+offsetY,offsetX,point3.y()-point2.y()-offsetY);
else if(pressedarea==4)
this->setGeometry(point2.x()-(x-point3.x()+point2.x()),point2.y(),x,point3.y()-point2.y());
else if(pressedarea==5)
this->setGeometry(point2.x(),point2.y(),offsetX,point3.y()-point2.y());
else*/ if(pressedarea==6)
this->setGeometry(point2.x()-(x-point3.x()+point2.x()),point2.y(),x,offsetY);
else if(pressedarea==7)
this->setGeometry(point2.x(),point2.y(),point3.x()-point2.x(),offsetY);
else if(pressedarea==8)
this->setGeometry(point2.x(),point2.y(),offsetX,offsetY);
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) {
pressed = false;
//lastPoint=mouseEvent->globalPos();
}
}
return QWidget::eventFilter(obj,event);
}
毕竟本人比较菜,在设置坐标和大小的程序都使用的是setGeometry,这也可能使得程序在执行的时候可能不太流畅,如果需要可以自行进行优化,改成move和resize两个函数。
本人读研马上要找工作了,这些代码可能对我找工作有点帮助,所以就只能展示一部分。如果以后实在是用不到这些程序,可能会发到github上。
参考的博客
https://qtchina.blog.csdn.net/article/details/100703610