Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it L'avatar di Vinsent
    Registrato dal
    May 2011
    Messaggi
    314

    [VB 2010 winform] Trascinare DrawString in una PicturBox

    Si può fare??? A me non sembra fattibile...
    Il programma serve a creare etichette da stampare su stampanti zebra, per ora ho questo casotto:
    L' anteprima è una PictureBox in cui scrivo con DrawString.
    Quando l' ho fatto usare al collega la prima cosa che ha fatto è stata cliccare sul testo per spostarlo con il mouse...

  2. #2
    Sì è fattibile, avevo realizzato qualcosa di simile solo che al posto di testi muovevo dei rettangoli. L'ideale sarebbe quello di realizzare un usercontrol, ma puoi anche continuare ad utilizzare la PictureBox, non ci dovrebbero essere particolari problemi.

    Per comodità dovresti tenere un array (o una lista) di oggetti di tipo "Scritta", che contiene il testo della scritta, le coordinate e la dimensione del carattere:
    codice:
    Public Class Scritta
        Public Property Testo() As String
        Public Property Posizione() As Point
        Public Property Carattere() As Byte
    End Class
    
    Private lista As New List(Of Scritta)
    'queste variabili servono per realizzare il drag & drop
    Private start As Point
    Private moving As Scritta
    Iterando sugli elementi della lista non ti sarà difficile disegnare le scritte:
    codice:
    For Each s As Scritta In lista
        e.Graphics.DrawString(...)
    Next
    Per gestire il drag&drop bisogna innanzitutto determinare quale elemento della lista è stato cliccato. Potresti scrivere una funzione come questa:
    codice:
    Private Function HitTest(ByVal x As Integer, ByVal y As Integer) As Scritta
        Dim ret As Scritta = Nothing
        Dim r As Rectangle
        Dim g As Graphics = CreateGraphics()
        Dim sz As SizeF
    
        For Each s As Scritta In lista
            'determina le dimensioni della scritta
            sz = g.MeasureString(s.Testo, New Font(Me.Font.FontFamily, s.Carattere))
    
            'crea un rettangolo con la stessa posizione e dimensione della scritta
            r = New Rectangle(s.Posizione, sz.ToSize)
    
            'verifica se il punto (x, y) è contenuto nel rettangolo
            If r.Contains(x, y) Then ret = s
        Next
    
        Return ret
    End Function
    Nell'evento MouseDown:
    codice:
    moving = HitTest(e.X, e.Y)
    start = New Point(e.X, e.Y)
    Nell'evento MouseMove:
    codice:
    If moving IsNot Nothing Then
        moving.Posizione = New Point(moving.Posizione.X + (e.X - start.X), moving.Posizione.Y + (e.Y - start.Y))
        start = New Point(e.X, e.Y)
        Me.Invalidate()
    End If
    Nell'evento MouseUp:
    codice:
    moving = Nothing
    Chi non cerca trova.

  3. #3
    Utente di HTML.it L'avatar di Vinsent
    Registrato dal
    May 2011
    Messaggi
    314
    Grazie e scusa se non ho risposto subito, volevo scrivere "ci sono riuscito!" ma in realtà mi sono incartato....programmo per hobby ed inoltre non mi sono impegnato molto sul tuo codice... ...ne comprendo o intuisco il perchè ma senza un' esempio "funzionante" faccio fatica, buona parte del codice non l' ho mai utilizzato.
    Comunque credo mi convenga la strada dell' usercontrol, mi porterebbe numerosi vantaggi:

    1 aggiungere righe, linee e rettangoli a runtime superando il limite attuale di 10
    2 farei sparire tutti quei textbox e numericupdown sulla sinistra migliorando l' aspetto e l' usabilità
    3 mi semplificherebbe la creazione del codice ZPL per stampare l' etichetta
    4 il codice sarà più elastico da modificare e gestire
    5 sicuramente mi stà sfuggendo qualche altro pregio...

    Attualmente, in linea di massima, il programma funziona così:
    all' avvio del form recupero i dpi del sistema, imposto un valore che rappresenta i dpi della stampante, li divido per ottenere un rapporto che mi servirà per lo ZPL, eseguo un calcolo aritmetico per convertire dpi, pollici e millimetri in modo da dimensionare la picturebox alle dimensioni fisiche dell' etichetta;

    con la modifica di testo, posizione e dimensione carattere (sub riga1 e riga1_1) si avvia la Sub (scrivi) che crea o aggiorna il testo sulla picturbox, a causa dei diversi font e dal diverso utilizzo di posizionamento tra Windows e la Zebra sono costretto ad inserire una variabile (ct1Diff) per ottenere un' anteprima fedele all' etichetta stampata perchè le coordinate in Windows tengono conto della spaziatura del carattere che aumenta con l' aumentare della dimensione del carattere mentre la Zebra no, per esempio in Windows un carattere dim. 10x10 con spaziatura 5 ha la posizione 15,15 mentre per la Zebra rimane 10,10, quando eseguo il DrawString sottraggo al numericupdown della posizione un valore ct1Diff ottenuto dall' altezza del font diviso per un valore (interlinea) ottenuto dopo diverse prove;

    al click sul button della stampa eseguo nuovamente un' operazione aritmetica per adattare le coordinate del testo in dpi tra Windows e Zebra, poi inserisco i valori di posizione, dimensione e testo in una stringa di codice ZPL e avvio la stampa.
    Per completezza il codice ZPL per stampare CIAO è:
    codice:
    ' inizio codice
    ^XA
    
    ' 20,20 posizione X Y, 25 dimensione font
    ^FO20,20^A0N,25^FDciao^FS
    
    '1 numero di etichette da stampare
    ^PQ1
    
    'fine codice
    ^XZ
    il codice sopra va scritto in un txt esclusi i commenti in stile VB è stampato sulla Zebra installata come "Generic/Text Only".
    Il codice di seguito è un' esempio per stampare una singola riga di testo, nel programma effettivo è moltiplicato per 10 oltre a qualcosa di simile (sempre x10) per disegnare rettangoli e linee inoltre tutte le variabili sono modificabili inclusa la dimensione dell' etichetta/picturebox.
    codice:
    Imports System.IO
    Imports System.Text
    
    Public Class Form1
    
        Dim interlinea As Decimal = CDec(1.8) ' valore approssimativo ottenuto da prove
        Dim miofont As String        ' lo lascio vuoto, usa il font di sistema...
        Dim ct1 As Single = 20       ' imposto un valore se no si incatasta
        Dim ct1Diff As Single = 1    ' imposto un valore se no si incatasta
        Dim rapporto_dpi As Decimal  ' rapporto tra dpi stampante/sistema
        Dim dpi_sistema As Decimal   ' dpi di windows
        Dim dpi_stampante As Decimal ' dpi stampante
        Dim etichetta As String      ' contenitore dello ZPL
    
        Private Sub Form1_Load() Handles MyBase.Load
            ' ottengo i dpi del sistema
            Dim g As Graphics = Me.CreateGraphics
            dpi_sistema = CDec(g.DpiX) 'Pixels per Inch
            g.Dispose()
    
            'calcolo il rapporto dpi
            dpi_stampante = 200
            rapporto_dpi = System.Math.Round(dpi_stampante / dpi_sistema)
    
            'imposto la dimensione della picturebox per rispecchiare
            'un' etichetta dalle dimensioni 110mm x 80mm
            PictureBox1.Width = CInt(System.Math.Round(110 * dpi_sistema / 25.4))
            PictureBox1.Height = CInt(System.Math.Round(80 * dpi_sistema / 25.4))
          
        End Sub
    
        Private Sub scrivi()
            PictureBox1.Refresh()
    
            Dim riga1 As Graphics = PictureBox1.CreateGraphics()
            Dim drawFont1 As New Font(miofont, ct1, FontStyle.Bold)
            ct1Diff = CSng(System.Math.Round(drawFont1.GetHeight / interlinea))
            riga1.DrawString(TextBox1.Text, drawFont1, Brushes.Black, _
            NumericUpDown_testo_X_1.Value - ct1Diff, _
            NumericUpDown_testo_Y_1.Value - ct1Diff)
    
        End Sub
    
        ' aggiorna la posizione del testo nell' anteprima
        Private Sub riga1() Handles TextBox1.TextChanged, NumericUpDown_testo_X_1.ValueChanged, _
            NumericUpDown_testo_Y_1.ValueChanged, NumericUpDown_car_1.ValueChanged
            scrivi()
        End Sub
    
        ' aggiorna la dimensione del testo nell' anteprima
        ' l' evento non è nella sub riga1 perchè altrimenti genera un' eccezione
        Private Sub riga1_1() Handles NumericUpDown_car_1.ValueChanged
            ct1 = NumericUpDown_car_1.Value
            scrivi()
        End Sub
    
        ' pezza per evitare sparizioni e apparazioni...
        Private Sub riscrivi() Handles Me.Paint
            scrivi()
        End Sub
    
        Private Sub crea_zpl() Handles Button1.Click
            Dim x91 As String = CStr(System.Math.Round(NumericUpDown_testo_X_1.Value * rapporto_dpi - ct1Diff))
            Dim y91 As String = CStr(System.Math.Round(NumericUpDown_testo_Y_1.Value * rapporto_dpi - ct1Diff))
            Dim c91 As String = CStr(System.Math.Round(NumericUpDown_car_1.Value * rapporto_dpi + ct1Diff))
    
            etichetta = "^XA" & vbCrLf & _
          "^FO" & x91 & "," & y91 & "^A0N," & c91 & "^FD" & TextBox1.Text & "^FS" & vbCrLf & _
          "^PQ1" &
          "^XZ"
            ' poi stampo
        End Sub
    End Class
    Scusate la lunghezza del post.

    Vincenzo

  4. #4
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    Ciao, ho scritto un controllo per fare ciò (trascinare elementi), il problema è che l'ho scritto in c#, se vuoi ti passo il codice (che magari puoi tradurre in vb) oppure puoi usarlo come libreria (senza tradurlo in vb).
    è possibile utilizzare qualsiasi elemento si voglia (linee, rettangoli, immagini ecc...) semplicemente ereditando da "Elemento" e sovrascrivendo il metodo scrivi (come mostrato nella classe alla fine dell'esempio)

    ecco una bozza di codice di come usarlo in vb.net (importato come libreria esterna)
    codice:
    Imports U235Anteprima
    
    Public Class Form1
        'inserisco nell'anteprima un immagine
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
                'dichiaro un tipo "Immagine" (più in basso una spiegazione di come creare tipi da utilizzare (esempio una linea)
                Dim imm As U235Anteprima.Immagine = New U235Anteprima.Immagine()
                'imposto l'immagine prendendo il percorso da OpenFileDialog1
                imm.Image = New Bitmap(OpenFileDialog1.FileName)
                'le do un nome
                imm.Nome = "immagine"
                'lo aggiungo alla lista di elementi dell'anteprima
                anteprima1.ListaElementi.Add(imm)
                'faccio ridisegnegnare l'anteprima
                anteprima1.Invalidate()
            End If
        End Sub
        'scelta font della scritta
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            If FontDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
                'cambio font alla textbox che conterrà la scritta
                Me.TextBox1.Font = FontDialog1.Font
            End If
        End Sub
    
        'al click creo un elemento di tipo "Scritta" e recupero il font e il testo dalla textbox1
        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            'dichiaro un tipo Scritta
            Dim stringa As U235Anteprima.Stringa = New U235Anteprima.Stringa()
            'imposto il font prendendolo dalla texbox1 (precedentemente impostato)
            stringa.Font = FontDialog1.Font
            'imposto il testo prendendolo dalla texbox1 (precedentemente scritto)
            stringa.Testo = Me.TextBox1.Text
            'imposto il nome che preferisco
            stringa.Nome = "stringa"
            'lo aggiungo alla lista
            anteprima1.ListaElementi.Add(stringa)
            'faccio ridisegnegnare l'anteprima
            anteprima1.Invalidate()
        End Sub
    
        'questo evento scaturisce quando clicco su un elemento con il tasto dx del mouse, in questo caso cancello l'elemento dalla lista
        Private Sub anteprima1_TastoDX(ByVal sender As System.Object, ByVal elemento As U235Anteprima.IElemento) Handles anteprima1.TastoDX
            'cancello l'elemento dalla lista
            anteprima1.ListaElementi.Remove(elemento)
        End Sub
    
        'questo evento scaturisce quando trascino un elemento nell'anteprima
        Private Sub anteprima1_Trascinamento(ByVal sender As System.Object, ByVal elemento As U235Anteprima.IElemento) Handles anteprima1.Trascinamento
            'qui inserisci il tuo codice per la stampante ricavando la posizione dall'elemento (che puoi ampliare ereditanto come vuoi)
            'comunque la posizione degli elementi la puoi senpre ricavare dalla lista dell'anteprima senza attendere o usare questo evento con :
    
            'elemento.Point
        End Sub
    
        'questo l'ho inserito per mostrarti il funzionamento della creazione di nuovi tipi di elementi (funziona come gli altri)
        'in basso potrai vedere un esempio di come creare appunto nuovi elementi (linee rettangoli icone ecc...)
        Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
            Dim Linea As Linea = New Linea()
            Linea.Pen = New Pen(Color.AliceBlue, 5)
            Linea.Size = New Size(NumericUpDown1.Value, 5)
            Linea.CorrezioneAngolo = 5
            Linea.Point = New Point(20, 20)
            Linea.Nome = "stringa"
            anteprima1.ListaElementi.Add(Linea)
            anteprima1.Invalidate()
        End Sub
    End Class
    
    'questo esempio mostra come creare nuovi elementi. basta ereditare da Elemento e sovrascrivere la sub scrivi, 
    'aggiungendo all'occorenza (come in questo caso il "Pen") altre variabili utili al caso.
    'il controllo chiamerà il metodo scrivi e modificherà la posizione data da "point"
    Public Class Linea
        Inherits Elemento
    
        Public Pen As Pen
        Public CorrezioneAngolo As Integer
        'sovrascrivo il metodo scrivi della classe di base
        Public Overrides Sub Scrivi(ByRef g As System.Windows.Forms.PaintEventArgs)
            'scrivo l'elemento grafico nel graphics del controllo
            g.Graphics.DrawLine(Pen, Point.X, Point.Y, Point.X + Size.Width, Point.Y + Size.Height - CorrezioneAngolo)
            MyBase.Scrivi(g)
        End Sub
    End Class
    qui il progetto demo in vb.net

    qui il progetto del controllo (in c#)

    P.S. i progetti sono solo delle bozze anche se perfettamente funzionanti.

  5. #5
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    ciao, se ti interessavano spero li abbia già scaricati, purtroppo dovevo rimuovere il link.

  6. #6
    Utente di HTML.it L'avatar di Vinsent
    Registrato dal
    May 2011
    Messaggi
    314
    Li avevo scaricati subitissimo , addirittura con il cellulare...
    Grazie mille, senza i tuoi esempi ci avrei messo qualche mese ad arrivarci, non che cosi cambi molto date le mie competenze*...ma almeno so di preciso cosa "studiare".
    Purtroppo l' usercontrol non posso usarlo come libreria perchè il programma richiederebbe l' installazione quindi mi servirebbero i privilegi di admin, cosa che non posso avere!!! mentre se includo il tutto nel programma copio l' exe e via.
    Devo studiarmi un po il c# per capire qual' è l' equivalente in vb e capirne "il perchè e il come", comunque in linea di massima riesco a seguire la logica del codice e questo per me è un' ottimo punto di partenza. Ho già imparato un paio di cose molto utili.
    Grazie ancora, ciao.

    Vincenzo

    *ho iniziato ad usare vb da qualche tempo, l' ho scelto perchè l' ultima volta che avevo programmato qualcosa lo avevo fatto con il basic del C64 o dello ZX...............

  7. #7
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    no, non richiede nessuna installazione, basta prendere la libreria e includerla nel progetto vb.net.

    come effettivamente ho fatto nel primo progrogetto di esempio, ovvero quello di cui ho postato la classe in vb.net.
    tieni presente che tutto il codice che hai visto era completo, ovvero un form con vari bottoni e box per aggiungere/rimuovere simmagini, stritte linee ecc...

    per usare il controllo bastano due righe di codice :
    codice:
    Dim stringa As U235Anteprima.Stringa = New U235Anteprima.Stringa()
    stringa.Font = FontDialog1.Font
    stringa.Testo = Me.TextBox1.Text
    stringa.Nome = "stringa"
    anteprima1.ListaElementi.Add(stringa)
    il resto lo fa il controllo, le posizioni degli elementi da mandare in stampa le trovi in anteprima1.ListaElementi(n).Point

    EDIT : sono 5 le righe di codice (non si capiva...)

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.