【Qt學(xué)習(xí)筆記】11.自定義控件CustomizetheWidget

一、窗口繪制——基本方法

成都創(chuàng)新互聯(lián)是一家專業(yè)提供常德企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、H5場景定制、小程序制作等業(yè)務(wù)。10年已為常德眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。

自定義窗口:

Qt里允許自定義窗口控件,使之滿足特殊的要求:

1、可以修改其顯示,自行繪制

2、可以呈現(xiàn)動態(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 ...具體化為子類控件,即可完成

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

二、窗口的繪制——幾何圖形的繪制

常用:

Line:直線

Rect:長方形(含正方形)

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、對于非閉合形狀,如Line,是不填充的

2、要先設(shè)置好色彩 然后再畫,不然畫完才設(shè)置顏色顯然是無意義的

常用的幾個(gè)類型:

QPoint:描述了一個(gè)點(diǎn)的坐標(biāo)

QSize:描述了寬度和高度

QRect:描述了一個(gè)矩形的坐標(biāo)和大小

另外,QPointF、QRectF是對應(yīng)的float版本

一般情況下,后繪制的窗口會覆蓋先前繪制的窗口

三、窗口的繪制——?jiǎng)赢嫷膶?shí)現(xiàn)

圖畫的運(yùn)動:

每秒鐘重繪n次,對人眼來說,它看起來就是運(yùn)動的

步驟:

1、創(chuàng)建一個(gè)定時(shí)器

2、調(diào)用QWidget::update(),通知界面重繪

注意:

update()函數(shù)只是通知界面重新繪制,會在事件循環(huán)中產(chǎn)生一個(gè)“繪制事件(paint event)”,在適合的時(shí)候才會重新繪制 (簡單的說,就是生成了一個(gè)重繪信號,等待響應(yīng)處理,而并不是立刻重繪)

四、窗口的繪制——文字的繪制

1、顏色:QPen

2、字體:QFont

字體包含以下參數(shù):

family(字體):如 "Times" "宋體"

size(大小):如 10  16

weight(樣式): 如 QFont:Normal, QFont::Bold QFont::Light 等......

italic(斜體):true false

3、位置與對齊

painter.drawText(0, 0, width, 40 ,//指定位置

        Qt::AlignHCenter | Qt::AlignVCenter,    //指定對齊等屬性

        "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)中的文件

使用絕對路徑或相對路徑來指定

2、資源中的文件

:/xxx/Resources/XX.jpg   (使用冒號開頭)

繪制參數(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、移動    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)移動的軌跡,直到松開為止

按下時(shí): m_pressedFlag = true;

移動時(shí): 記錄軌跡

松開時(shí): m_pressedFlag = false;

效果如下:

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

實(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ā)射信號

事件與信號:

自定義控件的事件發(fā)生時(shí),應(yīng)該以信號的形式發(fā)送出去。

例如:對于一個(gè)按鈕,當(dāng)它被按下時(shí)(press, release),對外發(fā)射了一個(gè)clicked()信號

自定義信號的方式如下:

class XXX
{
signals:
    void SignalName( QPoint pos );
}

當(dāng)事件發(fā)生時(shí),

emit SignalName( pos );

通過emit操作將信號發(fā)射出去。

注意:emit并非C++的語法,是Qt里面自己加的概念

小練習(xí):

區(qū)域截圖:加載一張圖片,選中一個(gè)區(qū)域,當(dāng)鼠標(biāo)松開后,發(fā)射一個(gè)信號

做出下面的效果:

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

代碼:

//////////////////////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)移動
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ā)出的信號
	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向右增長,Y向下增長

數(shù)學(xué)坐標(biāo)系:中心為原點(diǎn),X向右增長,Y向上增長

代碼:

github:https://github.com/HonestFox/Qt/tree/master/12_13MySin

(提示: QSpainBox)

九、示例——自定義進(jìn)度條

由于Qt自帶的QSlider有點(diǎ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)

位置顯示:

給出提示框,動態(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;

效果:

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

代碼:

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è)全屏的對話框來展示截圖

用鼠標(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);

效果:

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

【Qt學(xué)習(xí)筆記】11.自定義控件 Customize the Widget

代碼:

github:

https://github.com/HonestFox/Qt/tree/master/12_14ScreenShot

————————————

尾巴

盡量少造輪子,多讀文檔。

像Qt這種龐大的框架,往往有大量現(xiàn)成的輪子

本文題目:【Qt學(xué)習(xí)筆記】11.自定義控件CustomizetheWidget
網(wǎng)站路徑:http://muchs.cn/article2/ihsoic.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、動態(tài)網(wǎng)站服務(wù)器托管、外貿(mào)網(wǎng)站建設(shè)網(wǎng)站內(nèi)鏈、面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司