绘图简介
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()
}