Qt2.3.10制作冒泡式弹出对话框
Snail 07年7月第一个星期制作
制作冒泡式弹出对话框主要涉及2个技术要点(主要供触摸屏使用)
1 实用的Qtimer类的使用(计算鼠标在对象上的停留时间确定是否弹出属性对话框)
2 漂亮的对话框的绘制(主要是QWidget::setMask(const QBitmap& bitmap)的使用)
详细分析:
QTimer类的使用
QTimer的一般性使用 QTimer *timer = new QTimer( myObject ); connect( timer, SIGNAL(timeout()), myObject, SLOT(timerDone()) ); timer->start( 2000, TRUE ); // 2 seconds single-shot 注意: 1 当myObject销毁时,Qtimer会自动销毁。不需要手工删除。 2 QTimer的 int start ( int msec, bool sshot = FALSE ) 方法第二个参数sshot如果 为ture,则myObject的槽方法只会执行一次。不然的话会一直执行直到QTimer停止或者对象被销毁为止。 |
在本程序中如何使用QTimer类
//头文件 class MainPanel : public QWidget { // MainPanel为被测试面板,测试弹出属性框 Q_OBJECT public: MainPanel(QWidget *parent=0, const char *name=0, WFlags fl = 0); ~MainPanel() {} public slots: void holdMouseToPopupDialog(); //供QTimer链接的槽,确定是否弹出属性框 protected: virtual void mousePressEvent ( QMouseEvent * ); //这三个虚函数需要被覆盖用作计时 virtual void mouseReleaseEvent(QMouseEvent *); virtual void mouseMoveEvent(QMouseEvent *); private: QPoint* __popupPoint; //弹出面板的坐标,也就是要显示属性的物体 PopupInfoDialog* __propDialog; //这个属性框的制作放到后面 QTimer* __mouseHoldClicker; //创建一个Qtimer类成员对象 }; |
//代码文件 MainPanel::MainPanel(QWidget *parent, const char *name, WFlags fl) :QWidget(parent, name, fl) { __propDialog = new PopupInfoDialog(720,480,this,0,0,QDialog::WStyle_Customize | QDialog::WStyle_NoBorder | QDialog::WStyle_StaysOnTop); __mouseHoldClicker = new QTimer(this); __popupPoint = new QPoint(); //创建一个默认弹出点 connect(__mouseHoldClicker, SIGNAL(timeout()), this, SLOT(holdMouseToPopupDialog())); //链接QTimer和面板 }
void MainPanel::mousePressEvent(QMouseEvent * e) { //这个方法的意思是如果当鼠标按下(触摸屏的话就是手指按下) __popupPoint->setX(e->x()); //保存当前的坐标点 __popupPoint->setY(e->y()); __propDialog->hide(); //隐藏以前出现的弹出式属性框 __mouseHoldClicker->start(500, true); //以0.5秒计时,如果手指没有离开这个点,或者没有移动,则 //触发holdMouseToPopupDialog()槽一次。 }
void MainPanel::mouseReleaseEvent(QMouseEvent * e) { //这个方法的意思是如果手指离开触摸屏,就。。。 __mouseHoldClicker->stop(); //如果在槽还没有触发前就停止计时器,这样不用弹出属性框了 }
void MainPanel::mouseMoveEvent(QMouseEvent * e) { //这个方法的意思是如果手指移动了的话,就。。。。。。。。 if (e->x()-__popupPoint->x()>5 || e->y()- __popupPoint->y()>5) { //如果手指在5个像素内移动,就认为可接受的,如果超过5个 __mouseHoldClicker->stop(); //像素,则不予弹出对话框 } }
void MainPanel::holdMouseToPopupDialog() { //测试面板的槽,用来弹出属性框 __propDialog->popupAtPoint(__popupPoint->x(), __popupPoint->y()); __propDialog->show(); } |
在本程序中绘制漂亮的对话框
class PopupInfoDialog : public QDialog { Q_OBJECT public: PopupInfoDialog (int areaWidth = 800 ,int areaHeight = 600,QWidget * parent=0, const char * name=0, bool modal=FALSE, WFlags f=0 ); void popupAtPoint(int x,int y);
private: void __refreshMask(int popX, int popY); //重新刷新蒙板,隐藏对话框该的一些不需要显示的地方。 void __fillArrow(QPainter&,int,int,int,int,int,int); //这个是画这个东东的---à |
void PopupInfoDialog::popupAtPoint(int x, int y) { //对话框就弹出在这个点,在测试面板的 //holdMouseToPopupDialog()中调用此方法。 this->__refreshMask(x, y); this->show(); }
/*在这里,大致的实现过程是这样,QWidget可以通过一个QBitmap蒙板来大致决定需要显示哪些部分,我们就通过绘制蒙板来让QWidget显示蒙板同样大小区域来实现绘制任意形状的对话框的效果*/
void PopupInfoDialog::__refreshMask(int popX, int popY) { //重新刷新蒙板 QBitmap mask(__PopupWidth, __PopupHeight, true); //创建一个蒙板 QPainter painter(&mask); painter.setPen(popupBorder); painter.setBrush(blackBrush); //必须设置笔刷,得把绘制区域全部填充满 painter.drawRoundRect(50, 0, 300, 300, 10, 10);//300是实际显示内容框,10为圆角矩形圆角半径
int distanceToBorder; if (__areaWidth-popX >= __PopupWidth-50) {//右边能容纳弹出框 //这是一个简单的算法,在对象右边能显示对话框就在右边 if (popY <= __areaHeight/2) {//三角符号在弹出框的上边 //绘制属性对话框,不然就在左边绘制属性对话框。 if (popY <= __DialogToBorderDistance) { distanceToBorder = popY; } else { distanceToBorder = __DialogToBorderDistance; } __fillArrow(painter, 0, popY-distanceToBorder+20, 50, 100-20, 50, 100+20); this->move(popX, distanceToBorder); } else {//三角符号在弹出框的下边 int dx = popX; int dy = __areaHeight-__PopupHeight-__DialogToBorderDistance; if ((__areaHeight - popY) <= __DialogToBorderDistance) { dy = __areaHeight-__PopupHeight-(__areaHeight - popY)+20; } __fillArrow(painter, 0, popY-(dy-20), 50, 200-20, 50, 200+20); this->move(dx, dy); } } else {//弹出框放在左边 if (popY <= __areaHeight/2) {//三角符号在弹出框的上边 if (popY <= __DialogToBorderDistance) { distanceToBorder = popY; } else { distanceToBorder = __DialogToBorderDistance; } __fillArrow(painter, __PopupWidth, popY-distanceToBorder+20, __PopupWidth-51, 100-20, __PopupWidth-51, 100+20); this->move(popX-__PopupWidth, distanceToBorder); } else {//三角符号在弹出框的下边 int dx = popX-__PopupWidth; int dy = __areaHeight-__PopupHeight-__DialogToBorderDistance; if ((__areaHeight - popY) <= __DialogToBorderDistance) { dy = __areaHeight-__PopupHeight-(__areaHeight - popY)+20; } __fillArrow(painter, __PopupWidth, popY-dy+20, __PopupWidth-51, 200-20, __PopupWidth-51, 200+20); this->move(dx, dy); } } this->clearMask(); //清除原来的蒙板效果 this->setMask(mask); //添加新的蒙板效果 }
/*这个方法通过在给定的三点绘制多边形,达到绘制属性框箭头的效果 */ void PopupInfoDialog::__fillArrow(QPainter& painter, int p1x, int p1y, int p2x, int p2y, int p3x, int p3y) { QPointArray points; points.setPoints(3, p1x, p1y, p2x, p2y, p3x, p3y); painter.drawPolygon(points); } |
最后的效果图如下: