Custom widget in Qyoto
In this part of the Visual Basic Qyoto programming tutorial, we will create a custom widget.
Toolkits usually provide only the most common widgets like buttons, text widgets, sliders etc. No toolkit can provide all possible widgets. Programmers must create such widgets by themselves. They do it by using the drawing tools provided by the toolkit. There are two possibilities. A programmer can modify or enhance an existing widget. Or he can create a custom widget from scratch.
The Burning widget
In the next example, we will create a custom burning widget. This widget can be seen in applications like Nero or K3B. The widget will be created from scratch.
Imports Qyoto
NameSpace Burning
Public Class Burning
Inherits QWidget
Const PANEL_HEIGHT As Integer = 30
Const DISTANCE As Integer = 19
Const LINE_WIDTH As Integer = 5
Const DIVISIONS As Integer = 10
Const FULL_CAPACITY As Double = 700.0
Const MAX_CAPACITY As Double = 750.0
Dim redColor As New QColor(255, 175, 175)
Dim yellowColor As New QColor(255, 255, 184)
Dim parent As QWidget
Dim num() As String = { _
"75", "150", "225", "300", _
"375", "450", "525", "600", _
"675" _
}
Public Sub New(ByVal parent As QWidget)
Me.parent = parent
MinimumHeight = PANEL_HEIGHT
End Sub
Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)
Dim painter As New QPainter(Me)
Me.DrawWidget(painter)
painter.End()
End Sub
Private Sub DrawWidget(ByVal painter As QPainter)
Dim burn As CustomWidget.VBQApp = CType(parent, CustomWidget.VBQApp)
Dim slid_width As Double = burn.GetCurrentWidth()
Dim width As Double = Size.Width()
Dim move As Double = width / DIVISIONS
Dim till As Double = (width / MAX_CAPACITY) * slid_width
Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY
If slid_width > FULL_CAPACITY
painter.SetPen(New QPen(New QBrush(yellowColor), 1))
painter.SetBrush(New QBrush(yellowColor))
painter.DrawRect(New QRectF(0, 0, full, PANEL_HEIGHT))
painter.SetPen(New QPen(New QBrush(redColor), 1))
painter.SetBrush(New QBrush(redColor))
painter.DrawRect(New QRectF(full+1, 0, till-full, PANEL_HEIGHT))
Else
If (slid_width > 0)
painter.SetPen(New QPen(New QBrush(yellowColor), 1))
painter.SetBrush(New QBrush(yellowColor))
painter.DrawRect(New QRectF(0, 0, till, PANEL_HEIGHT))
End If
End If
painter.SetPen(New QColor(90, 90, 90))
painter.SetBrush(BrushStyle.NoBrush)
painter.DrawRect(0, 0, Size.Width()-1, PANEL_HEIGHT-1)
Dim newFont As QFont = painter.Font()
newFont.SetPointSize(7)
painter.SetFont(newFont)
Dim metrics As New QFontMetrics(newFont)
For i As Integer = 1 to num.Length
painter.DrawLine(New QLineF(i*move, 1, i*move, LINE_WIDTH))
Dim w As Integer = metrics.Width(num(i-1))
painter.DrawText(New QPointF(i*move-w/2, DISTANCE), num(i-1))
Next
End Sub
End Class
End Namespace
In this file, we create the Burning widget.
Public Class Burning
Inherits QWidget
The custom widget is based on the QWidget widget.
Const PANEL_HEIGHT As Integer = 30 Const DISTANCE As Integer = 19 Const LINE_WIDTH As Integer = 5 Const DIVISIONS As Integer = 10 Const FULL_CAPACITY As Double = 700.0 Const MAX_CAPACITY As Double = 750.0
These are important constants. The PANEL_HEIGHT defines the height for the custom widget. The DISTANCE is the distance of the numbers on the scale from the top of their parent border. The LINE_WIDTH is the vertical line width. The DIVISIONS is the number of parts of the scale. The FULL_CAPACITY is the capacity of the media. After it is reached, overburning happens. This is visualized by a red color. The MAX_CAPACITY is the maximum capacity of a medium.
Dim num() As String = { _
"75", "150", "225", "300", _
"375", "450", "525", "600", _
"675" _
}
We use these numbers to build the scale of the Burning widget.
Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)
Dim painter As New QPainter(Me)
Me.DrawWidget(painter)
painter.End()
End Sub
The drawing of the custom widget is delegated to the DrawWidget() method.
Dim burn As CustomWidget.VBQApp = CType(parent, CustomWidget.VBQApp)
We retrieve the reference to the parent widget.
Dim slid_width As Double = burn.GetCurrentWidth()
We use it to get the currently selected slider value.
Dim width As Double = Size.Width()
We get the width of the widget. The width of the custom widget is dynamic. It can be resized by a user.
Dim till As Double = (width / MAX_CAPACITY) * slid_width Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY
We use the width variable to do the transformations. Between the values of the scale and the custom widget's measures. Note that we use floating point values. We get greater precision in drawing.
painter.SetPen(New QPen(New QBrush(redColor), 1)) painter.SetBrush(New QBrush(redColor)) painter.DrawRect(New QRectF(full+1, 0, till-full, PANEL_HEIGHT))
These three lines draw the red rectangle, indicating the overburning.
painter.DrawRect(0, 0, Size.Width()-1, PANEL_HEIGHT-1)
This is the perimeter of the widget. The outside rectangle.
painter.DrawLine(New QLineF(i*move, 1, i*move, LINE_WIDTH))
Here we draw the small vertical lines.
Dim w As Integer = metrics.Width(num(i-1)) painter.DrawText(New QPointF(i*move-w/2, DISTANCE), num(i-1))
Here we draw the numbers of the scale. To precisely position the numbers, we must get the width of the string.
Imports Qyoto
' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we create
' a custom widget
'
' @author jan bodnar
' website zetcode.com
' last modified May 2009
NameSpace CustomWidget
Public Class VBQApp
Inherits QWidget
Const MAX_CAPACITY As Integer = 750
Dim slider As QSlider
Dim widget As QWidget
Dim cur_width As Integer
Public Sub New()
Me.SetWindowTitle("The Burning Widget")
Me.InitUI()
Me.Resize(370, 200)
Me.Move(300, 300)
Me.Show()
End Sub
Private Sub InitUI()
slider = New QSlider(Qt.Orientation.Horizontal , Me)
slider.Maximum = MAX_CAPACITY
slider.SetGeometry(50, 50, 130, 30)
Connect(slider, SIGNAL("valueChanged(int)"), Me, _
SLOT("ValueChanged(int)"))
Dim vbox As New QVBoxLayout(Me)
Dim hbox As New QHBoxLayout
vbox.AddStretch(1)
widget = New Burning.Burning(Me)
hbox.AddWidget(widget, 0)
vbox.AddLayout(hbox)
SetLayout(vbox)
End Sub
<Q_SLOT()> _
Public Sub ValueChanged(ByVal val As Integer)
cur_width = val
widget.Repaint()
End Sub
Public Function GetCurrentWidth() As Integer
Return cur_width
End Function
Public Shared Sub Main(ByVal args() As String)
Dim qapp As New QApplication(args)
Dim app As New VBQApp
QApplication.Exec()
End Sub
End Class
NameSpace CustomWidget
This is the main file. Here we create the slider widget and use our custom widget.
widget = New Burning.Burning(Me) hbox.AddWidget(widget, 0)
We create the instance of the Burning widget and add it to the horizontal box.
<Q_SLOT()> _
Public Sub ValueChanged(ByVal val As Integer)
cur_width = val
widget.Repaint()
End Sub
When the value of the slider changes, we store it inside the cur_width variable and repaint the custom widget.
Public Function GetCurrentWidth() As Integer Return cur_width End Function
This method is called by the custom widget to get the actual slider value.
In this part of the Visual Basic Qyoto tutorial, we have demonstrated how to create a custom widget.