一、窗口繪制——基本方法
為江陰等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及江陰網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、江陰網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!自定義窗口:
Qt里允許自定義窗口控件,使之滿足特殊的要求:
1、可以修改其顯示,自行繪制
2、可以呈現(xiàn)動(dòng)態(tài)效果
3、可以添加事件,支持鼠標(biāo)和鍵盤操作
自定義的控件可以直接在Qt Designer 中使用,可以直接加到父窗口里。
步驟:
1、新建一個(gè)類,繼承于QWidget和QFrame,最好是繼承于QFrame
2、重寫以下函數(shù) void CellMonitor::paintEvent( QPaintEvent* event )
3、使用這個(gè)類
CircleWidget::CircleWidget(QWidget *parent) : QFrame(parent) { } CircleWidget::~CircleWidget() { } void CircleWidget::paintEvent(QPaintEvent * event) { QPainter painter(this); painter.setBrush(QBrush(QColor(0x00, 0xff, 0x00))); painter.drawEllipse(QPoint(100, 100), 100, 100); }
在Qt Designer里使用:
自定義的Widget可以和原生控件一樣,直接在Qt Designer里拖放布局。
1、拖放一個(gè)父類控件,如QFrame
2、Promote to ...具體化為子類控件,即可完成
二、窗口的繪制——幾何圖形的繪制
常用:
Line:直線
Rect:長(zhǎng)方形(含正方形)
Ellipse:橢圓(含圓形)
其他:
Arc:圓弧
Chord:封閉圓弧
polygon:多邊形
RGB顏色:
在繪圖時(shí)經(jīng)常要指定顏色,Qt里使用RGB顏色,即由Red、Green、Blue分量定義的顏色值。每個(gè)分量0 ~ 255
如:
QColor green(0, 0xFF, 0);
QColor white(0xFF, 0xFF, 0xFF);
QColor black(0, 0, 0);
QPen與QBrush:
在Qt中,有兩種繪制參數(shù)
QPen:負(fù)責(zé)線條的顏色和風(fēng)格
QBrush:負(fù)責(zé)填充的顏色和風(fēng)格
比如說,當(dāng)畫一個(gè)圓時(shí),由當(dāng)前QPen來決定線條,由QBrush來決定填充(所圍區(qū)域)
注意:
1、對(duì)于非閉合形狀,如Line,是不填充的
2、要先設(shè)置好色彩 然后再畫,不然畫完才設(shè)置顏色顯然是無意義的
常用的幾個(gè)類型:
QPoint:描述了一個(gè)點(diǎn)的坐標(biāo)
QSize:描述了寬度和高度
QRect:描述了一個(gè)矩形的坐標(biāo)和大小
另外,QPointF、QRectF是對(duì)應(yīng)的float版本
一般情況下,后繪制的窗口會(huì)覆蓋先前繪制的窗口
三、窗口的繪制——?jiǎng)赢嫷膶?shí)現(xiàn)
圖畫的運(yùn)動(dòng):
每秒鐘重繪n次,對(duì)人眼來說,它看起來就是運(yùn)動(dòng)的
步驟:
1、創(chuàng)建一個(gè)定時(shí)器
2、調(diào)用QWidget::update(),通知界面重繪
注意:
update()函數(shù)只是通知界面重新繪制,會(huì)在事件循環(huán)中產(chǎn)生一個(gè)“繪制事件(paint event)”,在適合的時(shí)候才會(huì)重新繪制 (簡(jiǎn)單的說,就是生成了一個(gè)重繪信號(hào),等待響應(yīng)處理,而并不是立刻重繪)
四、窗口的繪制——文字的繪制
1、顏色:QPen
2、字體:QFont
字體包含以下參數(shù):
family(字體):如 "Times" "宋體"
size(大小):如 10 16
weight(樣式): 如 QFont:Normal, QFont::Bold QFont::Light 等......
italic(斜體):true false
3、位置與對(duì)齊
painter.drawText(0, 0, width, 40 ,//指定位置
Qt::AlignHCenter | Qt::AlignVCenter, //指定對(duì)齊等屬性
"hello world")
);
示例代碼:
QPainter painter(this); QFont font("Times", 20, QFont::Light, true); painter.setPen(QColor(0xFF, 0, 0)); painter.setFont(font); painter.drawText(0, 0, width(), height(), Qt::AlignLeft | Qt::AlignTop, "Change World");
五、窗口的繪制——圖片的繪制
Qt中使用QPixmap表示圖片
圖片的來源:
Qt里的圖片有兩種加載方式:
1、文件系統(tǒng)中的文件
使用絕對(duì)路徑或相對(duì)路徑來指定
2、資源中的文件
:/xxx/Resources/XX.jpg (使用冒號(hào)開頭)
繪制參數(shù):
1、源矩形
可以繪制圖像的全部,也可以只繪制其中一部分
QRect source(0, 0, img_width, img_height); //源矩形
2、目標(biāo)矩形
可以填充到全部窗口,也可以只填充到一部分
QRect target(0, 0, width/2, height/2); //目標(biāo)矩形 painter.drawPixmap(target, m_picture, source); //繪制
注意事項(xiàng):
QPixmap應(yīng)該作為成員變量,只加載一次,這是因?yàn)椋?/p>
1、加載成本很高(開銷大)
2、也沒有必要反復(fù)加載
六、鼠標(biāo)的支持——基本概念
Qt中鼠標(biāo)事件分為四種:
1、按下 Press
2、抬起 Release
3、移動(dòng) Move
4、雙擊 Double Click
用QMouseEventl類表示一個(gè)鼠標(biāo)事件
x,y: 坐標(biāo)
globalX, globalY: 全局坐標(biāo)
button: 鼠標(biāo)左鍵、右鍵、中間
鼠標(biāo)事件繼承與 QWidget,因此重寫這4個(gè)事件的處理方法,就可以自定義控件支持鼠標(biāo)操作
void mouseDoubleClickEvent( QMouseEvent* event ); void mouseMoveEvent( QMouseEvent* event ); void mousePressEvent( QMouseEvent* event ); void mouseReleaseEvent( QMouseEvent* event );
小練習(xí):
寫一個(gè)程序,當(dāng)鼠標(biāo)按下時(shí),畫出鼠標(biāo)移動(dòng)的軌跡,直到松開為止
按下時(shí): m_pressedFlag = true;
移動(dòng)時(shí): 記錄軌跡
松開時(shí): m_pressedFlag = false;
效果如下:
實(shí)現(xiàn)代碼:
class MyWidget : public QFrame { Q_OBJECT public: MyWidget(QWidget *parent); ~MyWidget(); private: void paintEvent( QPaintEvent* event ); //鼠標(biāo)事件 void mouseDoubleClickEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: bool m_pressedFlag; QVector<QPoint> m_points; //存放軌跡的集合 }; MyWidget::MyWidget(QWidget *parent) : QFrame(parent) , m_pressedFlag(false) { m_points.resize(1024); } MyWidget::~MyWidget() { } void MyWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); int width = this->width(); int height = this->height(); //背景 painter.setBrush(QColor(0, 0, 0)); //黑色 painter.drawRect(0, 0, width, height); painter.setPen(QColor(255, 255, 255)); for (size_t i = 0; i < m_points.size() - 1; ++i) //遍歷 { QPoint& p1 = m_points[i]; QPoint& p2 = m_points[i + 1]; painter.drawLine(p1, p2); } } //忽略雙擊事件 void MyWidget::mouseDoubleClickEvent(QMouseEvent *event) { QWidget::mouseDoubleClickEvent(event); } void MyWidget::mouseMoveEvent(QMouseEvent *event) { if (m_pressedFlag == true) { QPoint pos = event->pos(); //顯示軌跡 m_points.push_back(pos); update(); //重繪 } } //鼠標(biāo)按下 void MyWidget::mousePressEvent(QMouseEvent *event) { m_pressedFlag = true; m_points.clear(); } //鼠標(biāo)抬起 void MyWidget::mouseReleaseEvent(QMouseEvent *event) { m_pressedFlag = false; }
七、鼠標(biāo)的支持——發(fā)射信號(hào)
事件與信號(hào):
自定義控件的事件發(fā)生時(shí),應(yīng)該以信號(hào)的形式發(fā)送出去。
例如:對(duì)于一個(gè)按鈕,當(dāng)它被按下時(shí)(press, release),對(duì)外發(fā)射了一個(gè)clicked()信號(hào)
自定義信號(hào)的方式如下:
class XXX { signals: void SignalName( QPoint pos ); }
當(dāng)事件發(fā)生時(shí),
emit SignalName( pos );
通過emit操作將信號(hào)發(fā)射出去。
注意:emit并非C++的語法,是Qt里面自己加的概念
小練習(xí):
區(qū)域截圖:加載一張圖片,選中一個(gè)區(qū)域,當(dāng)鼠標(biāo)松開后,發(fā)射一個(gè)信號(hào)
做出下面的效果:
代碼:
//////////////////////MyWidget.h/////////////////////////// class MyWidget : public QFrame { Q_OBJECT public: MyWidget(QWidget *parent); ~MyWidget(); private: void paintEvent( QPaintEvent* event ); //鼠標(biāo)支持 void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: bool m_pressedFlag; QPixmap m_picture; QPoint m_curPos; //鼠標(biāo)當(dāng)前位置 QPoint m_begin; QPoint m_end; }; ///////////////////////MyWidget.cpp/////////////////////////////////// MyWidget::MyWidget(QWidget *parent) : QFrame(parent) ,m_pressedFlag(false) ,m_begin(QPoint(0, 0)) ,m_end(QPoint(0, 0)) { m_picture.load("./Resources/MyPic.jpg"); //開銷大,寫在構(gòu)造函數(shù)中,只加載一次,而不是寫在paintEvent中,每次顯示 } MyWidget::~MyWidget() { } void MyWidget::paintEvent(QPaintEvent* event) { QPainter painter(this); int width = this->width(); int height = this->height(); //顯示背景圖片 painter.drawPixmap(0, 0, width, height, m_picture); //畫出區(qū)域 if (m_pressedFlag == true) { //畫一個(gè)十字交叉線 painter.setPen(QColor(255, 0, 0)); //紅色的區(qū)域?yàn)槭纸徊婢€ painter.drawLine(QPoint(0, m_curPos.y()), QPoint(width, m_curPos.y())); //水平 painter.drawLine(QPoint(m_curPos.x(), 0), QPoint(m_curPos.x(), height)); //畫出選中的區(qū)域 QRect selected(m_begin, m_end); painter.setPen(QColor(0, 0, 0)); //painter.setBrush(QColor(100, 100, 100)); painter.drawRect(selected); } } //鼠標(biāo)移動(dòng) void MyWidget::mouseMoveEvent(QMouseEvent *event) { if (m_pressedFlag = true) { m_curPos = event->pos(); m_end = m_curPos; update(); } } //鼠標(biāo)按下 void MyWidget::mousePressEvent(QMouseEvent *event) { m_pressedFlag = true; m_begin = event->pos(); m_end = m_begin; } //鼠標(biāo)抬起 void MyWidget::mouseReleaseEvent(QMouseEvent *event) { m_pressedFlag = false; } class Test11_7a_12_12 : public QMainWindow { Q_OBJECT public: Test11_7a_12_12(QWidget *parent = Q_NULLPTR); private: Ui::Test11_7a_12_12Class ui; private slots: int OnSelected(QRect area); }; Test11_7a_12_12::Test11_7a_12_12(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); //關(guān)聯(lián)自定義的控件發(fā)出的信號(hào) assert( connect( ui.frame, SIGNAL(selected(QRect)), this, SLOT(OnSelected(QRect)) ) ); } int Test11_7a_12_12::OnSelected(QRect area) { return 0; }
八、示例——正弦曲線
什么是曲線:
兩種視角:
1、一個(gè)曲線是由無數(shù)個(gè)點(diǎn)組成的 ( 可以用drawPaint()方法 )
2、一個(gè)曲線是由無數(shù)個(gè)線段組成的。 ( 可以用drawLine()方法 )
這里采用第二種視角,也就是線段的畫法,很多小線段首位連接在一起,形成一條“準(zhǔn)”曲線
直角坐標(biāo)系:
1、定義坐標(biāo)原點(diǎn)
origin()
2、坐標(biāo)轉(zhuǎn)換
GUI: 左上角為原點(diǎn),X向右增長(zhǎng),Y向下增長(zhǎng)
數(shù)學(xué)坐標(biāo)系:中心為原點(diǎn),X向右增長(zhǎng),Y向上增長(zhǎng)
代碼:
github:https://github.com/HonestFox/Qt/tree/master/12_13MySin
(提示: QSpainBox)
九、示例——自定義進(jìn)度條
由于Qt自帶的QSlider有點(diǎn)簡(jiǎn)陋,這里自己實(shí)現(xiàn)一個(gè)MySlider,實(shí)現(xiàn)以下功能
高亮狀態(tài):
鼠標(biāo)移入后,進(jìn)入高亮狀態(tài)
鼠標(biāo)移出后,回到普通狀態(tài)
觸發(fā)事件: :void focused(bool yes)
鼠標(biāo)點(diǎn)擊:
當(dāng)鼠標(biāo)點(diǎn)擊后,設(shè)置新的位置,并觸發(fā)事件:void clicked(int progress)
位置顯示:
給出提示框,動(dòng)態(tài)顯示當(dāng)前位置
void tracking(int progress, QPoint pos)
(要實(shí)現(xiàn)這個(gè)功能,需要單獨(dú)新建一個(gè)類)
getter / setter :
可以設(shè)置、獲取當(dāng)前值和范圍
void setRange(int range);
void setProgress(int progress);
int range() const;
int progress() const;
效果:
代碼:
github:https://github.com/HonestFox/Qt/tree/master/12_14MySlider
十、實(shí)戰(zhàn)——屏幕截圖工具
需求:
1、隱藏自身窗口
2、自由選區(qū)
3、保存為jpg文件
實(shí)現(xiàn):
1、截圖
Qt中的 QPixmap::grabWindow( QApplication::desktop()->winId() );方法
2、自由選區(qū)
以一個(gè)全屏的對(duì)話框來展示截圖
用鼠標(biāo)來選區(qū)一個(gè)區(qū)域:記錄開始點(diǎn)、結(jié)束點(diǎn)
3、特效:快門聲
QSound m_shutter("xxxx.wav");
m_shutter.play();
4、延時(shí)
QTimer::singleShot(300, this, SLOT(onDelayedCapture()));
為什么要延時(shí)呢,因?yàn)楫?dāng)我們點(diǎn)擊截圖按鈕,按道理是界面隱藏,緊接著打開一個(gè)記錄屏幕的窗口的,
但是,界面的隱藏是一個(gè)過程,因此需要延時(shí)。
5、保存圖片
QPixmap picture = ui.frame->pixmap();
picture.save(filename);
效果:
代碼:
github:
https://github.com/HonestFox/Qt/tree/master/12_14ScreenShot
————————————
尾巴
盡量少造輪子,多讀文檔。
像Qt這種龐大的框架,往往有大量現(xiàn)成的輪子
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
網(wǎng)站欄目:【Qt學(xué)習(xí)筆記】11.自定義控件CustomizetheWidget-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://aaarwkj.com/article0/cojcio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、App開發(fā)、服務(wù)器托管、軟件開發(fā)、小程序開發(fā)、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容