Doublebuffering

martedì 23 giugno 2009 - 13.54

jaxma Profilo | Newbie

ciao a tutti!!

sto realizzando un orologio analogico in vb.net. per evitare il fastidioso effetto dello "sfarfallio" del disegno, ho utilizzato la tecnica del doublebuffering. il problema è che se voglio utilizzare un menu contestuale non funziona, o meglio non compare. il codice che sto utilizzando è :


Public Class Form1
Inherits Form
Private context As BufferedGraphicsContext
Private grafx As BufferedGraphics
Private bufferingMode As Byte
Private timer1 As System.Windows.Forms.Timer
Private count As Byte
Dim IsmOUSEDOWN As Boolean
Dim MousePos As Point
Dim a, b, d, ore As Integer
Dim radianti, radianti_m, radianti_o As Double
Dim lungFrecciaSecondi As Double = 120
Dim lungFrecciaMinuti As Double = 110
Dim lungFrecciaOre As Double = 100
Dim cxsec, cysec, cxmin, cymin, cxOre, cyOre As Double
Friend WithEvents ContextMenuStrip1 As System.Windows.Forms.ContextMenuStrip
Private components As System.ComponentModel.IContainer
Friend WithEvents ModificaOraDiSistemaToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents ContextMenuStrip2 As System.Windows.Forms.ContextMenuStrip
Friend WithEvents ChiudiToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents ContextMenuStrip3 As System.Windows.Forms.ContextMenuStrip
Friend WithEvents CiaoToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
Friend WithEvents EsciToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem

Public Sub New()
' Configure the Form for this example.
Me.Text = "User double buffering"
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Me.Height = 422
Me.Width = 422
Me.StartPosition = FormStartPosition.CenterScreen

Me.TransparencyKey = Color.Blue

AddHandler Me.MouseDown, AddressOf Me.MouseDownHandler
AddHandler Me.Resize, AddressOf Me.ResizeHandler
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint, True)
AddHandler Me.Click, AddressOf Me.MouseDownHandler

' Configure a timer to draw graphics updates.
timer1 = New System.Windows.Forms.Timer()
timer1.Interval = 200
timer1.Start()
AddHandler timer1.Tick, AddressOf Me.OnTimer

bufferingMode = 2
count = 0

context = BufferedGraphicsManager.Current
context.MaximumBuffer = New Size(Me.Width + 1, Me.Height + 1)
grafx = context.Allocate(Me.CreateGraphics(), _
New Rectangle(0, 0, Me.Width - 100, Me.Height - 100))


DrawToBuffer(grafx.Graphics)
End Sub



Private Sub MouseDownHandler(ByVal sender As Object, ByVal e As MouseEventArgs)

Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
DrawToBuffer(grafx.Graphics)
Me.Refresh()

End Sub

Private Sub OnTimer(ByVal sender As Object, ByVal e As EventArgs)
' Draw randomly positioned ellipses to the buffer.
DrawToBuffer(grafx.Graphics)
bufferingMode = 2
' If in bufferingMode 2, draw to the form's HDC.
' If Then
' Render the graphics buffer to the form's HDC.
grafx.Render(Graphics.FromHwnd(Me.Handle))
' If in bufferingMode 0 or 1, draw in the paint method.
'Else
'Me.Refresh()
'End If
End Sub

Private Sub ResizeHandler(ByVal sender As Object, ByVal e As EventArgs)
' Re-create the graphics buffer for a new window size.
context.MaximumBuffer = New Size(Me.Width + 1, Me.Height + 1)
If (grafx IsNot Nothing) Then
grafx.Dispose()
grafx = Nothing
End If
grafx = context.Allocate(Me.CreateGraphics(), New Rectangle(0, 0, Me.Width, Me.Height))

' Cause the background to be cleared and redraw.
count = 6
DrawToBuffer(grafx.Graphics)
Me.Refresh()
End Sub

Private Sub DrawToBuffer(ByVal g As Graphics)

calcolaOrario()

g.FillRectangle(Brushes.Blue, New Rectangle(0, 0, 423, 423))
'-----------------------------------------------------
Dim e1, e2 As Integer
e1 = 10
e2 = 10
Dim pa As New GraphicsPath
pa.AddEllipse(e1, e2, 300, 300)
Dim br As New PathGradientBrush(pa)
br.CenterColor = Color.Black

Dim colors() As Color = {Color.Black}
br.SurroundColors = colors

'--------------------------------------------------------
Dim pen As New Pen(Color.DarkRed, 20)

g.DrawEllipse(pen, e1, e2, 300, 300)
g.DrawEllipse(Pens.DarkViolet, e1, e2, 300, 300)
g.DrawEllipse(Pens.CadetBlue, e1 - 9, e2 - 9, 318, 318)
g.FillEllipse(Brushes.DarkKhaki, e1, e2, 300, 300)
g.FillPath(br, pa)
Dim font1 As New Font("broadway", 16)
g.DrawString("1", font1, Brushes.White, 208 + e1, 22 + e2)
g.DrawString("2", font1, Brushes.White, 260 + e1, 70 + e2)
g.DrawString("3", font1, Brushes.White, 280 + e1, 137 + e2)
g.DrawString("4", font1, Brushes.White, 260 + e1, 204 + e2)
g.DrawString("5", font1, Brushes.White, 208 + e1, 256 + e2)
g.DrawString("6", font1, Brushes.White, 140 + e1, 272 + e2)
g.DrawString("7", font1, Brushes.White, 70 + e1, 256 + e2)
g.DrawString("8", font1, Brushes.White, 19 + e1, 204 + e2)
g.DrawString("9", font1, Brushes.White, 1 + e1, 137 + e2)
g.DrawString("10", font1, Brushes.White, 16 + e1, 70 + e2)
g.DrawString("11", font1, Brushes.White, 70 + e1, 17 + e2)
g.DrawString("12", font1, Brushes.White, 135 + e1, -4 + e2)

Dim s As String = System.DateTime.Now.Hour & " : " & System.DateTime.Now.Minute & " : " & System.DateTime.Now.Second
g.DrawString(s, font1, Brushes.Red, 90, 220)

'----lancette
Dim pen1 As New Pen(Color.DarkRed, 2)
Dim pen2 As New Pen(Color.Yellow, 4)
Dim pen3 As New Pen(Color.Red, 4)
pen1.StartCap = LineCap.Round
pen1.EndCap = LineCap.Flat
pen2.StartCap = LineCap.Round
pen2.EndCap = LineCap.Flat
pen3.StartCap = LineCap.Round
pen3.EndCap = LineCap.AnchorMask
radianti = (a * 3.14) / 180

cxsec = (Sin(radianti) * lungFrecciaSecondi) + 150
cysec = ((-Cos(radianti)) * lungFrecciaSecondi) + 150

radianti_m = (b * 3.14) / 180
cxmin = (Sin(radianti_m) * lungFrecciaMinuti) + 150
cymin = ((-Cos(radianti_m)) * lungFrecciaMinuti) + 150

radianti_o = (d * 3.14) / 180

cxOre = (Sin(radianti_o) * lungFrecciaOre) + 150
cyOre = (-Cos(radianti_o) * lungFrecciaOre) + 150


g.DrawLine(pen1, 152 + e1, 152 + e2, CInt(cxsec) + e1, CInt(cysec) + e2)
g.DrawLine(pen2, 152 + e1, 152 + e2, CInt(cxmin) + e1, CInt(cymin) + e2)
g.DrawLine(pen3, 152 + e1, 152 + e2, CInt(cxOre) + e1, CInt(cyOre) + e2)

End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
grafx.Render(e.Graphics)
End Sub

<STAThread()> _
Public Shared Sub Main(ByVal args() As String)
Application.Run(New Form1())
End Sub

grazie a tutti per il vostro aiuto

jaxma

Jeremy Profilo | Guru

Ciao Donato.
>il problema è che se voglio utilizzare un menu contestuale non funziona, o meglio non compare.
Il perchè non compaia il menu contestuale, lo immagino ...... ma ti da qualche errore in particolare????

Facci sapere...
Ciao

jaxma Profilo | Newbie

grazie innanzi tutto per la vostra cortesia.

in realtà non dà nessun messaggio d'errore. semplicemente non funziona. come se l'area di disegno non facesse parte del form..
jaxma

Jeremy Profilo | Guru

Ciao Donato.
Non ho mai utilizzato la tecnica del doublebuffering, ma suppongo che, questa tecnica, implichi un continuo Refresh del *disegno*, pertanto, il menu context viene chiuso al primo Refresh dopo la sua apertura.
Quello che potrei consigliarti, è di mostrare, al posto del menu contestuale, un Form gestendolo da un thread separato da quello principale ed, al suo interno, visualizzare le voci che avresti avuto nel menu contestuale.
Se la cosa ti sembra invece, non fattibile, facci sapere .... che ci ragioniamo su ulteriormente.

Ciao.

jaxma Profilo | Newbie

sono solo un newbie ma penso che tu abbia proprio ragione!! penso che la soluzione più semplice, in questo caso, sia proprio creare un nuovo Form con le fattezze di un menu.. voglio però provare un altro metodo (la tua osservazione mi ha aperto la mente!) e poi ti faccio sapere
jaxma

jaxma Profilo | Newbie

ciao ho trovato un sistema "poco convenzionale" ma sicuramente funzionale e semplice da implementare. in pratica sull'evento click (pulsante destro del mouse) faccio comparire un form semitrasparente (opacity 5%). la trasparenza non va ad inficiare la visibilità del disegno creato con Dbuffering (orologio) che continua ad aggiornarsi, per cui il menu contestuale stavolta mi appare! anziché costruire un nuovo menu-form riesco così ad utilizzare quello di default di VB.. grazie per il tuo aiuto è stato illuminante! fammi sapere se pensi che sia una idea valida
jaxma

Jeremy Profilo | Guru

>fammi sapere se pensi che sia una idea valida
Ancora meglio che la mia!!

Ad ogni modo .... facci sapere...
Ciao

jaxma Profilo | Newbie

cia ragazzi! per ora ho risolto in questo modo:

sull'evento Form1_MouseDown richiamo in fom chiamato form2
If e.Button = Windows.Forms.MouseButtons.Right Then
Form2.Show()
End If

il form2 è così settato:

FormBorderStyle =None
Opacity=2%
Show-inTaskBar=False
TopMost=true
size= 'la stessa dimensione del form di disegno aumentata di 5 pixel per sicurezza
in questo modo si evita che si possa spostare per errore il form1
contestMenuStrip= ContestMenuStrip1 ' questo controllo naturalmente deve essere aggiunto al
form2 e deve contenere tutte le voci che ci interessano
qui è riportata la routine di caricamento del form2 con alcuni aggiustamenti

Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
posiziona il form2 in maniera tale che si sovrapponga integralmente al form1
Dim a, b, MA, Mb As Integer
a = Form1.Location.X
b = Form1.Location.Y
Me.Location = New Point(a, b)

'questo codice serve ad evitare che il menu contestuale si apra nel punto (0,0) dello schermo -purtroppo è un difetto che non sono riuscito ad eliminare diversamente per il momento
MA = MousePosition.X
Mb = MousePosition.Y
ContextMenuStrip1.Show()
ContextMenuStrip1.Location = New Point(MA, Mb)

End Sub

saluti a tutti!
jaxma
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2025
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5