Go-Qt5開發之繪製文本(34)

繪圖簡介

Qt5繪畫系統能夠呈現矢量圖形,圖像,和大綱font-based文本。
我們也可以在程序中調用系統api自定義繪圖控件。

繪圖要在paintEvent()方法中實現。
在QPainter對象的begin()與end()方法間編寫繪圖代碼。
它會在控件或其他圖形設備上進行低級的圖形繪製。

案例說明

  • 在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。
  • 相信大多 數人和我一樣,剛開始的時候都認爲 drawText() 的 x, y 是字符串左上角的座標,其實不然,它是字符串的第一個字符的 origin 的座標,y 是字體的 base line 的 y 座標。
  • 本案例窗口顯示文本.
  • 參考文章:https://blog.csdn.net/TemetNosce/article/details/78068520

demo.go

package main

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/gui"
	"github.com/therecipe/qt/widgets"
	"os"
)

/*
我們先以窗體內Unicode文本的繪製爲例。

在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。
相信大多 數人和我一樣,剛開始的時候都認爲 drawText() 的 x, y 是字符串左上角的座標,其實不然,它是字符串的第一個字符的 origin 的座標,y 是字體的 base line 的 y 座標
*/

func InitUi() *widgets.QMainWindow {
	// 創建窗口
	app := widgets.NewQMainWindow(nil, 0)

	// 設置窗口的標題
	app.SetWindowTitle("Qt 教程")

	// 設置窗口的位置和大小
	app.SetGeometry2(300, 300, 300, 220)

	// 設置窗口的圖標,引用當前目錄下的web.png圖片
	app.SetWindowIcon(gui.NewQIcon5("images/app.ico"))

	// 佈局窗口組件載體
	widget := widgets.NewQWidget(app, core.Qt__Widget)
	//widget.SetGeometry(core.NewQRect4(300, 300, 300, 220))
	//widget.SetGeometry2(0, 0, 300, 220)
	app.SetCentralWidget(widget)

	// 狀態欄
	app.StatusBar()


	widget.ConnectPaintEvent(func(event *gui.QPaintEvent) {
		qp := gui.NewQPainter2(widget)
		//qp.Begin(widget)

		qp.SetRenderHint(gui.QPainter__Antialiasing, true)
		// 定義一個畫筆和一個字體用於繪製文本。
		qp.SetFont(gui.NewQFont2("Times", 100, 0, true))
		qp.SetPen2(gui.NewQColor3(0, 0, 0, 0))

		//qp.DrawText3(150, 150, "jEh")

		// 方法將文本繪製在窗體,顯示在中心
		qp.DrawText4(event.Rect(), int(core.QTextStream__AlignCenter), "text", widget.Rect())

		qp.End()

	})

	return app
}

func main() {
	// 創建一個應用程序對象
	// sys.argv參數是一個列表,從命令行輸入參數
	widgets.NewQApplication(len(os.Args), os.Args)

	// 初始化窗口
	app := InitUi()

	// 顯示組件
	app.Show()

	// 確保應用程序乾淨的退出
	widgets.QApplication_Exec()
}

demo2.go

package main

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/gui"
	"github.com/therecipe/qt/widgets"
	"os"
)

/*
我們先以窗體內Unicode文本的繪製爲例。

在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。

還是原來的問題,從 widget 的左上角開始繪製文本,那麼 y 就應該和 ascent 一樣大,但是怎麼得到 ascent 的值呢?難到需要我們記住每種字體的 ascent 的值嗎?這也是一種方法,如果願意,未嘗不可,但是,腦子夠用麼,幸好 QFontMetrics 就能夠給我們提供字體的信息,提供了很多函數,如取得 line height 用 height(),用 width() 計算字符串的寬度,ascent(), descent(), xHeight() 等, 函數的名字已經很好的表明它的作用,在此就不再一一介紹,更多的函數請參考 Qt 的幫助文檔。所以爲了達到我們的目的,只需要把 y = 0 修改爲 int y = metrics.ascent() 就可以了:
原文鏈接:https://blog.csdn.net/TemetNosce/article/details/78068520
*/

func InitUi() *widgets.QMainWindow {
	// 創建窗口
	app := widgets.NewQMainWindow(nil, 0)

	// 設置窗口的標題
	app.SetWindowTitle("Qt 教程")

	// 設置窗口的位置和大小
	app.SetGeometry2(300, 300, 300, 220)

	// 設置窗口的圖標,引用當前目錄下的web.png圖片
	app.SetWindowIcon(gui.NewQIcon5("images/app.ico"))

	// 佈局窗口組件載體
	widget := widgets.NewQWidget(app, core.Qt__Widget)
	//widget.SetGeometry(core.NewQRect4(300, 300, 300, 220))
	//widget.SetGeometry2(0, 0, 300, 220)
	app.SetCentralWidget(widget)

	// 狀態欄
	app.StatusBar()


	widget.ConnectPaintEvent(func(event *gui.QPaintEvent) {
		qp := gui.NewQPainter2(widget)
		//qp.Begin(widget)

		qp.SetRenderHint(gui.QPainter__Antialiasing, true)
		qp.SetFont(gui.NewQFont2("Times", 100, 0, true))
		metrics :=qp.FontMetrics()

		y := metrics.Ascent()
		qp.DrawText3(0, y, "jEh")
		qp.End()

	})

	return app
}

func main() {
	// 創建一個應用程序對象
	// sys.argv參數是一個列表,從命令行輸入參數
	widgets.NewQApplication(len(os.Args), os.Args)

	// 初始化窗口
	app := InitUi()

	// 顯示組件
	app.Show()

	// 確保應用程序乾淨的退出
	widgets.QApplication_Exec()
}

demo3.go

package main

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/gui"
	"github.com/therecipe/qt/widgets"
	"os"
)

/*
我們先以窗體內Unicode文本的繪製爲例。

在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。

還是原來的問題,從 widget 的左上角開始繪製文本,那麼 y 就應該和 ascent 一樣大,但是怎麼得到 ascent 的值呢?難到需要我們記住每種字體的 ascent 的值嗎?這也是一種方法,如果願意,未嘗不可,但是,腦子夠用麼,幸好 QFontMetrics 就能夠給我們提供字體的信息,提供了很多函數,如取得 line height 用 height(),用 width() 計算字符串的寬度,ascent(), descent(), xHeight() 等, 函數的名字已經很好的表明它的作用,在此就不再一一介紹,更多的函數請參考 Qt 的幫助文檔。所以爲了達到我們的目的,只需要把 y = 0 修改爲 int y = metrics.ascent() 就可以了:
原文鏈接:https://blog.csdn.net/TemetNosce/article/details/78068520

居中繪製文本
有了 QFontMetrics,想必對大家來說問題已經不大,得到字符串的寬、高、ascent,簡單的居中計算,就可以得到 origin 的座標了。
*/

func InitUi() *widgets.QMainWindow {
	// 創建窗口
	app := widgets.NewQMainWindow(nil, 0)

	// 設置窗口的標題
	app.SetWindowTitle("Qt 教程")

	// 設置窗口的位置和大小
	app.SetGeometry2(300, 300, 300, 220)

	// 設置窗口的圖標,引用當前目錄下的web.png圖片
	app.SetWindowIcon(gui.NewQIcon5("images/app.ico"))

	// 佈局窗口組件載體
	widget := widgets.NewQWidget(app, core.Qt__Widget)
	//widget.SetGeometry(core.NewQRect4(300, 300, 300, 220))
	//widget.SetGeometry2(0, 0, 300, 220)
	app.SetCentralWidget(widget)

	// 狀態欄
	app.StatusBar()


	widget.ConnectPaintEvent(func(event *gui.QPaintEvent) {
		qp := gui.NewQPainter2(widget)
		//qp.Begin(widget)

		qp.SetRenderHint(gui.QPainter__Antialiasing, true)
		qp.SetFont(gui.NewQFont2("Times", 100, 0, true))

		rect :=core.NewQRect4(20, 20, 300, 200)
		qp.DrawRect3(rect)

		// 居中繪製文本
		metrics :=qp.FontMetrics()

		stringHeight := metrics.Ascent() + metrics.Descent() // 不算 line gap
		stringWidth := metrics.AverageCharWidth() // 字符串的寬度
		x := rect.X() + (rect.Width() - stringWidth) / 2
		y := rect.Y() + (rect.Height() - stringHeight) / 2 + metrics.Ascent()
		qp.DrawText3(x, y, "jEh")

		// 繪製字符串的包圍矩形
		y = rect.Y() + (rect.Height() - stringHeight) / 2
		//qp.SetPen(core.Qt__lightGray)
		qp.DrawRect2(x, y, stringWidth, stringHeight)

		/*
		把字體的包圍矩形也畫出來,這樣就能很清晰的看到字符串的居中效果了。也許你還會問,這不是還有一點點沒有居中嗎?這個和字體有關係,換成等寬字體如 Menlo 後就可以看到確實是完全居中的,說明 QFontMetrics 得到的字體信息沒問題,只是有的字體爲了美觀漂亮作了一些調整,對於這些字體如果要完全的居中效果的話,只好在使用上面的計算方式後再手動的微調一下就好了。
		*/

		qp.End()

	})

	return app
}

func main() {
	// 創建一個應用程序對象
	// sys.argv參數是一個列表,從命令行輸入參數
	widgets.NewQApplication(len(os.Args), os.Args)

	// 初始化窗口
	app := InitUi()

	// 顯示組件
	app.Show()

	// 確保應用程序乾淨的退出
	widgets.QApplication_Exec()
}

demo4.go

package main

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/gui"
	"github.com/therecipe/qt/widgets"
	"os"
)

/*
我們先以窗體內Unicode文本的繪製爲例。

在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。

還是原來的問題,從 widget 的左上角開始繪製文本,那麼 y 就應該和 ascent 一樣大,但是怎麼得到 ascent 的值呢?難到需要我們記住每種字體的 ascent 的值嗎?這也是一種方法,如果願意,未嘗不可,但是,腦子夠用麼,幸好 QFontMetrics 就能夠給我們提供字體的信息,提供了很多函數,如取得 line height 用 height(),用 width() 計算字符串的寬度,ascent(), descent(), xHeight() 等, 函數的名字已經很好的表明它的作用,在此就不再一一介紹,更多的函數請參考 Qt 的幫助文檔。所以爲了達到我們的目的,只需要把 y = 0 修改爲 int y = metrics.ascent() 就可以了:
原文鏈接:https://blog.csdn.net/TemetNosce/article/details/78068520


換行繪製文本
drawText() 繪製文本有兩種方式,不會自動換行和在給定的矩形中自動換行,下面就舉例說明,先繪製一行很長但不會自動換行的文本,然後在給定的矩形 QRect(20, 35, 200, 80) 裏繪製會自動換行,向右靠齊的文本(發現超出矩形的字符不顯示)
*/

func InitUi() *widgets.QMainWindow {
	// 創建窗口
	app := widgets.NewQMainWindow(nil, 0)

	// 設置窗口的標題
	app.SetWindowTitle("Qt 教程")

	// 設置窗口的位置和大小
	app.SetGeometry2(300, 300, 300, 220)

	// 設置窗口的圖標,引用當前目錄下的web.png圖片
	app.SetWindowIcon(gui.NewQIcon5("images/app.ico"))

	// 佈局窗口組件載體
	widget := widgets.NewQWidget(app, core.Qt__Widget)
	//widget.SetGeometry(core.NewQRect4(300, 300, 300, 220))
	//widget.SetGeometry2(0, 0, 300, 220)
	app.SetCentralWidget(widget)

	// 狀態欄
	app.StatusBar()

	widget.ConnectPaintEvent(func(event *gui.QPaintEvent) {
		qp := gui.NewQPainter2(widget)
		//qp.Begin(widget)

		qp.SetRenderHint(gui.QPainter__Antialiasing, true)

		text := "QPainter provides highly optimized functions to do " +
			"most of the drawing GUI programs require. It can draw " +
			"everything from simple lines to complex shapes " +
			"like pies and chords. " +
			"看看是否也支持中文呢,如果不支持那就悲劇了!"
		rect := core.NewQRect4(20, 20, 300, 200)
		qp.DrawRect3(rect) // 畫出矩形,可以看到超出此矩形的部分文本不可見

		//core.Qt__TextWordWrap | core.Qt__AlignRight
		qp.DrawText4(rect, int(core.Qt__TextWordWrap), text, rect)
		qp.End()

	})

	return app
}

func main() {
	// 創建一個應用程序對象
	// sys.argv參數是一個列表,從命令行輸入參數
	widgets.NewQApplication(len(os.Args), os.Args)

	// 初始化窗口
	app := InitUi()

	// 顯示組件
	app.Show()

	// 確保應用程序乾淨的退出
	widgets.QApplication_Exec()
}

demo5.go

package main

import (
	"github.com/therecipe/qt/core"
	"github.com/therecipe/qt/gui"
	"github.com/therecipe/qt/widgets"
	"os"
)

/*
我們先以窗體內Unicode文本的繪製爲例。

在我們的示例中,我們繪製一些Cylliric文本。文本垂直和水平對齊。

還是原來的問題,從 widget 的左上角開始繪製文本,那麼 y 就應該和 ascent 一樣大,但是怎麼得到 ascent 的值呢?難到需要我們記住每種字體的 ascent 的值嗎?這也是一種方法,如果願意,未嘗不可,但是,腦子夠用麼,幸好 QFontMetrics 就能夠給我們提供字體的信息,提供了很多函數,如取得 line height 用 height(),用 width() 計算字符串的寬度,ascent(), descent(), xHeight() 等, 函數的名字已經很好的表明它的作用,在此就不再一一介紹,更多的函數請參考 Qt 的幫助文檔。所以爲了達到我們的目的,只需要把 y = 0 修改爲 int y = metrics.ascent() 就可以了:
原文鏈接:https://blog.csdn.net/TemetNosce/article/details/78068520


文本的包圍矩形
一般顯示的寬度應該是確定的,關鍵是高度的計算,可以逐個字符的把他們的寬度加起來(不同的字體每個字符的寬度不一樣),當大於顯示的寬度就換行,高度也對應的加上一行的高度,這樣就能計算出最終的高度了,也就知道了顯示消息的矩形大小,使用這個方法就能自適應的顯示消息了。

雖然我們已經知道了自適應顯示消息的原理,但是如果是我們自己來計算實現,難度還是不小的,其實 Qt 已經給我們提供了相關的 API,使用 QFontMetrics::boundingRect() 可以計算出包圍文本的矩形,然後在用上面的方法繪製文本就可以了,下面的程序,改變窗口的寬度,能動態的計算出顯示文本所有內容的包圍矩形,解決了上面提到的在給定的矩形中,文本太長時顯示不全的問題

*/

func InitUi() *widgets.QMainWindow {
	// 創建窗口
	app := widgets.NewQMainWindow(nil, 0)

	// 設置窗口的標題
	app.SetWindowTitle("Qt 教程")

	// 設置窗口的位置和大小
	app.SetGeometry2(300, 300, 300, 220)

	// 設置窗口的圖標,引用當前目錄下的web.png圖片
	app.SetWindowIcon(gui.NewQIcon5("images/app.ico"))

	// 佈局窗口組件載體
	widget := widgets.NewQWidget(app, core.Qt__Widget)
	//widget.SetGeometry(core.NewQRect4(300, 300, 300, 220))
	//widget.SetGeometry2(0, 0, 300, 220)
	app.SetCentralWidget(widget)

	// 狀態欄
	app.StatusBar()

	widget.ConnectPaintEvent(func(event *gui.QPaintEvent) {
		qp := gui.NewQPainter2(widget)
		//qp.Begin(widget)

		qp.SetRenderHint(gui.QPainter__Antialiasing, true)

		text := "QPainter provides highly optimized functions to do " +
			"most of the drawing GUI programs require. It can draw " +
			"everything from simple lines to complex shapes " +
			"like pies and chords. " +
			"看看是否也支持中文呢,如果不支持那就悲劇了!"

		width := widget.Width() - 40        // 顯示文本的寬度,爲窗口的寬度減去 40 像素
		flags := int(core.Qt__TextWordWrap) // 自動換行
		// 計算文本在指定寬度下的包圍矩形
		metrics := qp.FontMetrics()
		rect := core.NewQRect4(0, 0, width, 0)
		textBoundingRect := metrics.BoundingRect3(rect, flags, text, 4, 4)
		qp.Translate3(20, 20)
		qp.DrawRect3(textBoundingRect)
		qp.DrawText4(textBoundingRect, flags, text, rect)

		qp.End()

	})

	return app
}

func main() {
	// 創建一個應用程序對象
	// sys.argv參數是一個列表,從命令行輸入參數
	widgets.NewQApplication(len(os.Args), os.Args)

	// 初始化窗口
	app := InitUi()

	// 顯示組件
	app.Show()

	// 確保應用程序乾淨的退出
	widgets.QApplication_Exec()
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章