Snail 07年7月第一個星期製作
製作冒泡式彈出對話框主要涉及2個技術要點(主要供觸摸屏使用)
1 實用的Qtimer類的使用(計算鼠標在對象上的停留時間確定是否彈出屬性對話框)
2 漂亮的對話框的繪製(主要是QWidget::setMask(const QBitmap& bitmap)的使用)
詳細分析:
QTimer類的使用
QTimer的一般性使用
connect( timer, SIGNAL(timeout()),
myObject, SLOT(timerDone()) );
timer->start( 2000, TRUE ); // 2 seconds single-shot
注意: 1 當myObject銷燬時,Qtimer會自動銷燬。不需要手工刪除。
爲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);
} |
最後的效果圖如下: