原文: http://zetcode.com/gui/vbgtk/customwidget/

您是否曾经看过某个应用,并想知道如何创建特定的 GUI 项目? 可能每个想成为程序员的人都有。 然后,您正在查看您最喜欢的 gui 库提供的小部件列表。 但是你找不到。 工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。

实际上有两种工具箱。 Spartan 工具包和重量级工具包。 FLTK 工具包是一种 spartan 工具包。 它仅提供了非常基本的小部件,并假定程序员将自己创建更复杂的小部件。 wxWidgets 是重量级的。 它有很多小部件。 但是,它不提供更专业的小部件。 例如,速度表小部件,即测量要刻录 CD 容量的小部件(例如,在 nero 中找到)。 工具箱通常也没有图表。

程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

刻录小部件

这是我们从头开始创建的小部件的示例。 可以在各种媒体刻录应用(例如 Nero 刻录 ROM)中找到此小部件。

custom.vb

  1. Imports Gtk
  2. NameSpace BurningWidget
  3. Public Class Burning
  4. Inherits DrawingArea
  5. Const PANEL_HEIGHT As Integer = 30
  6. Const DIVISIONS As Integer = 10
  7. Const FULL_CAPACITY As Double = 700
  8. Const MAX_CAPACITY As Double = 750
  9. Dim redColor As New Gdk.Color(1, 0.7, 0.7)
  10. Dim yellowColor As New Gdk.Color(1, 1, 0.7)
  11. Dim parent As Widget
  12. Dim num() As String = { _
  13. "75", "150", "225", "300", _
  14. "375", "450", "525", "600", _
  15. "675" _
  16. }
  17. Public Sub New(ByVal parent As Widget)
  18. Me.SetSizeRequest(1, PANEL_HEIGHT)
  19. Me.parent = parent
  20. AddHandler Me.ExposeEvent, AddressOf Me.OnExpose
  21. End Sub
  22. Private Sub OnExpose(ByVal sender As Object, ByVal e As ExposeEventArgs)
  23. Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
  24. Me.DrawCustomWidget(cc)
  25. Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
  26. disposeTarget.Dispose
  27. Dim disposeContext As IDisposable = CType(cc, IDisposable)
  28. disposeContext.Dispose
  29. End Sub
  30. Private Sub DrawCustomWidget(ByVal cc As Cairo.Context)
  31. cc.LineWidth = 0.8
  32. cc.SelectFontFace("Courier 10 Pitch", _
  33. Cairo.FontSlant.Normal, Cairo.FontWeight.Normal)
  34. cc.SetFontSize(11)
  35. Dim burn As Custom.GtkVBApp = CType(parent, Custom.GtkVBApp)
  36. Dim slid_width As Double = burn.GetCurrentWidth
  37. Dim width As Double = Allocation.Width
  38. Dim move As Double = width / DIVISIONS
  39. Dim till As Double = (width / MAX_CAPACITY) * slid_width
  40. Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY
  41. If slid_width >= FULL_CAPACITY
  42. cc.SetSourceRGB(1.0, 1.0, 0.72)
  43. cc.Rectangle(0, 0, full, PANEL_HEIGHT)
  44. cc.Clip
  45. cc.Paint
  46. cc.ResetClip
  47. cc.SetSourceRGB(1.0, 0.68, 0.68)
  48. cc.Rectangle(full, 0, till-full, PANEL_HEIGHT)
  49. cc.Clip
  50. cc.Paint
  51. cc.ResetClip
  52. Else
  53. cc.SetSourceRGB(1.0, 1.0, 0.72)
  54. cc.Rectangle(0, 0, till, PANEL_HEIGHT)
  55. cc.Clip
  56. cc.Paint
  57. cc.ResetClip
  58. End If
  59. cc.SetSourceRGB(0.35, 0.31, 0.24)
  60. For i As Integer = 1 To num.Length
  61. cc.MoveTo(i*move, 0)
  62. cc.LineTo(i*move, 5)
  63. cc.Stroke
  64. Dim extents As Cairo.TextExtents = cc.TextExtents(num(i-1))
  65. cc.MoveTo(i*move-extents.Width/2, 15)
  66. cc.TextPath(num(i-1))
  67. cc.Stroke
  68. Next
  69. End Sub
  70. End Class
  71. End Namespace

我们在窗口底部放置一个DrawingArea并手动绘制整个窗口小部件。 所有重要的代码都驻留在DrawCustomWidget中,这是从 Burning 类的OnExpose方法调用的。 此小部件以图形方式显示了介质的总容量和可供我们使用的可用空间。 该小部件由比例小部件控制。 自定义窗口小部件的最小值为 0,最大值为 750。如果值达到 700,则开始绘制红色。 这通常表示过度燃烧。

  1. Dim num() As String = { _
  2. "75", "150", "225", "300", _
  3. "375", "450", "525", "600", _
  4. "675" _
  5. }

这些数字显示在刻录小部件上。 它们显示了介质的容量。

  1. Dim burn As Custom.GtkVBApp = CType(parent, Custom.GtkVBApp)
  2. Dim slid_width As Double = burn.GetCurrentWidth

这两行从 scale 小部件获取当前数字。 我们获得父窗口小部件,并从父窗口小部件中获得当前值。

  1. Dim till As Double = (width / MAX_CAPACITY) * slid_width
  2. Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY

我们使用width变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。 till参数确定要绘制的总大小。 该值来自滑块小部件。 它占整个面积的一部分。 full参数确定了我们开始绘制红色的点。

  1. cc.SetSourceRGB(1.0, 1.0, 0.72)
  2. cc.Rectangle(0, 0, till, PANEL_HEIGHT)
  3. cc.Clip
  4. cc.Paint
  5. cc.ResetClip

此代码在此处绘制了一个黄色矩形,直到介质充满为止。

  1. Dim extents As Cairo.TextExtents = cc.TextExtents(num(i-1))
  2. cc.MoveTo(i*move-extents.Width/2, 15)
  3. cc.TextPath(num(i-1))
  4. cc.Stroke

这里的代码在刻录小部件上绘制数字。 我们计算TextExtents来正确定位文本。

burning.vb

  1. ' ZetCode Mono Visual Basic GTK# tutorial
  2. '
  3. ' In this program, we create
  4. ' a custom widget
  5. '
  6. ' author jan bodnar
  7. ' last modified May 2009
  8. ' website www.zetcode.com
  9. Imports Gtk
  10. NameSpace Custom
  11. Public Class GtkVBApp
  12. Inherits Window
  13. Const MAX_CAPACITY As Integer = 750
  14. Dim cur_value As Integer
  15. Dim burning As BurningWidget.Burning
  16. Public Sub New
  17. MyBase.New("Burning")
  18. Me.InitUI
  19. Me.SetDefaultSize(350, 200)
  20. Me.SetPosition(WindowPosition.Center)
  21. AddHandler Me.DeleteEvent, AddressOf Me.OnDelete
  22. Me.ShowAll
  23. End Sub
  24. Private Sub InitUI
  25. Dim vbox As New VBox(False, 2)
  26. Dim scale As New HScale(0, MAX_CAPACITY, 1)
  27. scale.SetSizeRequest(160, 35)
  28. AddHandler scale.ValueChanged, AddressOf Me.OnChanged
  29. Dim fixed As New Fixed
  30. fixed.Put(scale, 50, 50)
  31. vbox.PackStart(fixed)
  32. burning = New BurningWidget.Burning(Me)
  33. vbox.PackStart(burning, False, False, 0)
  34. Me.Add(vbox)
  35. End Sub
  36. Private Sub OnChanged(ByVal sender As Object, ByVal args As EventArgs)
  37. cur_value = sender.Value
  38. burning.QueueDraw
  39. End Sub
  40. Public Function GetCurrentWidth As Integer
  41. Return cur_value
  42. End Function
  43. Sub OnDelete(ByVal sender As Object, ByVal args As DeleteEventArgs)
  44. Application.Quit
  45. End Sub
  46. Public Shared Sub Main
  47. Application.Init
  48. Dim app As New GtkVBApp
  49. Application.Run
  50. End Sub
  51. End Class
  52. End Namespace

这是主要的类。

  1. Private Sub OnChanged(ByVal sender As Object, ByVal args As EventArgs)
  2. cur_value = sender.Value
  3. burning.QueueDraw
  4. End Sub

我们从小部件中获取值,并将其存储在cur_value变量中以备后用。 我们重新绘制刻录的小部件。

自定义小部件 - 图1

图:刻录小部件

在本章中,我们使用 GTK# 和 Visual Basic 创建了一个自定义窗口小部件。