Grafika   otázka

VB.NET, Algoritmy, Grafika

Dobrý den,

ve své aplikaci vykreslím do pictureboxu značku (křížek).

Dále pak chci nakreslit výběrový obdelník, tak že kliknu a při pohymu myší se začíná vykreslovat obdelník.... v proceduře picturebox_mousemove tedy musím použít picturebox.Invalidate(), aby se obdelník správně vykresloval, nicméně po dobu vykreslování mi tím ostatní značky (křížky) zmizí. Lze tomu nějak zamezit, aby se invalidate aplikovalo pouze na obdelník a ne na křížky? Děkuji.

(Snad jsem popsal problém srozumitelně)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Všechno, co se má po Invalidate vykreslit, musí být v Paint

nahlásit spamnahlásit spam 0 odpovědětodpovědět

omlouvam se, ale porad mi to nejak nejde, nerozumim tomu.

Slo by tu hodit jednoduchou ukazku kdy by se nakreslil do picboxu krizek a pak pomoci mysi by se nakreslil obdelnik (neco jako dynamicke zoomovani v mapach), ktery by se vykresloval po tahu mysi a po pusteni tlacitka mysi by zmizel, ale krizek by zustal vykresleny celou dobu.... predem moc dekuju

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To není podle mě moc jednoduchá ukázka.

Zkuste raději popsat co nefunguje a poslat okementovaný nefungující kód.

Dotazy typu "nějak to nejde, napište to za mě" tu nejsou moc populární. Poradit ale určitě můžeme, je to zajímavý problém.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

OK, zkusím to nějak blíže popsat. Mám picturebox, ve kterém mám mapu a určité místo na mapě je označeno. Pokud chci na místo zazumovat (kliknu, natáhnu obdelník, pustím, zazumuje se na vybranou oblast). Při vykreslování obdelníku zoomu mi ale zmizí symbol označeného místa na mapě.

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.DrawImage(MapBitmap, 0, 0)
    End Sub

Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        If Draw = True Then
            If ZoomInBtn.Checked Or ZoomOutBtn.Checked = True Then
                f_XMax = e.X
                f_YMax = e.Y
                Dim p As New Pen(Color.FromArgb(255, 0, 0, 255), 2)
                grp.Clear(Color.Transparent)
                grp.DrawRectangle(p, m_XStart, m_YStart, f_XMax - m_XStart, f_YMax - m_YStart)
                PictureBox1.Invalidate()
            End If
            
        End If
    End Sub

Vykreslení symbolu mám ve zvláštní proceduře, není to jen obyčejný křížek, ale tošku složitější symbol. Zdyž je pomocná proměnná nastavená na true, symbol se vykreslí na urč. souřadnice, což zajistí, že při zazumování se vykreslí znovu. Ale problém je při vlastním zoomovaní kdy se vykresluje "zoomovaci obdelník"... tam je to díky invalidate smazáno.. a já to tam potřebuju.

Další věc, která mě trápí je dost pomalé vykreslování, ten zoomovací obdelník není vykreslován dost rychle, což způsobuje jeho trhané, neplynulé vykreslování.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

A co vykreslovat obdelník až v Paint?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jestli ovládáte základy grafiky, tj. umíte do PictureBox vykreslit co potřebujete, pak můžete použít událostí vyvolaných myší:

PictureBox1_MouseDown - zde si můžete např. poznamenat (zapsat do proměnné) polohu myši v okamžiku stisknutí tlačítka

PictureBox1_MouseMove - zde sledujte pohyb kurzoru zápisem souřadnic do proměnné

PictureBox1_MouseUp - zde si zapište do proměnné typu Boolean, že akce myší skončila, event. si můžete poznamenat (zapsat do proměnné) polohu myši v okamžiku uvolnění tlačítka

Pro provedení změny na PictureBox při vyjmenovaných událostech myši ukončete kód události s PictureBox1.Refresh. Tak vyvoláte událost PictureBox1_Paint

Do PictureBox1_Paint musíte dát vykreslení všeho, co chcete na PictureBoxu vidět. Ve vašem případu tam bude vykreslení křížku a vykreslování obdélníku s použitím souřadnic, které zaznamenáváte v PictureBox1_MouseMove. Vykreslování obdélníku podmíníte stavem proměnné signalizující průběh / ukončení akce, aby po MouseUp obdélník zmizel.

Vkreslování obdélníku by se hodilo pro výběr oblasti a třeba pro výběr nějakých prvků na PictureBox. Potom by bylo dobré ošetřit tažení myší po stisku tlačítka všemi směry, tj. výběr začínající v libovolném rohu budoucího obdélníku. Dobrá úloha, na začátečníka asi přáliš obtížná.

Jestli nevíte jak návod realizovat, pak zde nastudujte lekce pro začátečníky, grafika začíná na adrese:

http://vbnet.cz/clanek--47-vb_net_od_zac...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Místo PictureBox1.Refresh je vhodnější použít PictureBox1.Invalidate. Refresh je brutálnější a nevolá jenom Paint. Invalidate je určena přesně k tomuto účelu - k vyvolání události Paint.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji. Smím se zeptat, co ještě dělá Refresh navíc a proč se Invalidate při psaní nenabídne?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Příklad výběru oblasti na PictureBox

Public Class Form1
  Dim mDn, mMv, mUp, kLc As Point ' pro záznam souřadnic MouseDown, Move, Up... 
  Dim vR As Rectangle ' vybraná oblast
  Dim Tah, Kriz As Boolean ' pro řízení vykreslování
  Dim Fnt As Font = New Font("Verdana", 18, FontStyle.Bold) ' font, křížek pomocí písmene X

  Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
    PictureBox1.Dock = DockStyle.Fill
    PictureBox1.BackColor = Color.Ivory
  End Sub

  Private Sub PictureBox1_MouseDown(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    ' smazat předchozí výběr:
    mMv.X = 0 : mMv.Y = 0
    vR = New Rectangle(0, 0, 0, 0)
    Kriz = False
    Tah = False
    mDn = e.Location ' poloha kursoru
    PictureBox1.Invalidate() ' překreslit (smazat)
  End Sub

  Private Sub PictureBox1_MouseMove(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    If e.Button = Windows.Forms.MouseButtons.Left Then ' akce Move při stisknutém l. tl.
      Dim w As Integer = Me.Left + Me.Width - 5 ' pravý okraj PictureBox na obrazovce
      Dim h As Integer = Me.Top + Me.Height - 5 ' dtto spodní okraj
      ' omezení pohybu kursoru mimo okno:
      ' vlevo:
      If e.X < 0 Then
        Cursor.Position = New Point(Me.Left + 5, Cursor.Position.Y)
      End If
      ' nahoře:
      If e.Y < 0 Then
        Cursor.Position = New Point(Cursor.Position.X, Me.Top + 30)
      End If
      ' vpravo:
      If Cursor.Position.X >= w Then
        Cursor.Position = New Point(w, Cursor.Position.Y)
      End If
      ' dole:
      If Cursor.Position.Y > h Then
        Cursor.Position = New Point(Cursor.Position.X, h)
      End If
      mMv = e.Location ' aktuální souřadnice myši
      Tah = True ' probíhá tažení
      PictureBox1.Invalidate() ' překreslovat
    End If
  End Sub

  Private Sub PictureBox1_MouseUp(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
    ' konec akce:
    mMv = e.Location ' souřadnice na konci tažení
    mUp = e.Location
    kLc.X = mDn.X + (mMv.X - mDn.X) / 2 - 13 ' výpočet souřadnic pro křížek (X)  
    kLc.Y = mDn.Y + (mMv.Y - mDn.Y) / 2 - 14
    Kriz = True ' křížek kreslit
    Tah = False ' tažení skončilo
    mDn.X = 0 : mDn.Y = 0
    mMv.X = 0 : mMv.Y = 0
    PictureBox1.Invalidate()
  End Sub

  Private Sub PictureBox1_Paint(ByVal sender As Object, _
      ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    Dim mDn2 As Point ' pomocné souřadnice l. h. rohu
    Dim mRw, mRh As Integer ' šířka a výška obdélníku
    ' pro případ tažení vlevo a nahoru:
    mRw = Math.Abs(mMv.X - mDn.X) ' absolutní šířka
    mRh = Math.Abs(mMv.Y - mDn.Y) ' dtto výška
    If (mMv.X - mDn.X) < 0 Then
      ' záměna souřadnic při tažení vlevo
      mDn2.X = mMv.X
    Else
      mDn2.X = mDn.X
    End If

    If (mMv.Y - mDn.Y) < 0 Then
      ' záměna souřadnic při tažení nahoru
      mDn2.Y = mMv.Y
    Else
      mDn2.Y = mDn.Y
    End If
    If Tah Then
      ' vyplněný obdélník:
      e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(16, Color.Blue)), mDn2.X, mDn2.Y, mRw, mRh)
      ' orámování obdélníka:
      e.Graphics.DrawRectangle(New Pen(Color.DarkGray, 1), mDn2.X, mDn2.Y, mRw, mRh)
      vR = New Rectangle(mDn2.X, mDn2.Y, mRw, mRh) ' obdélník vybrané oblasti
    End If
    If Kriz Then
      e.Graphics.DrawString("X", Fnt, Brushes.DarkBlue, kLc.X, kLc.Y) ' křížek - znak X
      e.Graphics.DrawRectangle(New Pen(Color.Red, 1), vR) ' orámování vybrané oblasti - červeně
    End If
  End Sub

End Class

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback